/* * Copyright 2016 Guillaume Nodet * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * * See the License for the specific language governing permissions and * limitations under the License. */ package org.ops4j.pax.cdi.extension.impl.support; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicLong; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.BundleListener; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkListener; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceObjects; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; public class PrivateRegistryWrapper implements BundleContext { public static final String PRIVATE = "org.ops4j.pax.cdi.private"; private final BundleContext delegate; private final List<PrivateServiceRegistration<?>> registrations = new CopyOnWriteArrayList<>(); private final List<ListenerInfo> listeners = new CopyOnWriteArrayList<>(); public PrivateRegistryWrapper(BundleContext bundleContext) { this.delegate = bundleContext; } @Override public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException { if (filter != null && filter.contains(PRIVATE)) { addPrivateServiceListener(listener, filter); } else { delegate.addServiceListener(listener, filter); } } @Override public void removeServiceListener(ServiceListener listener) { removePrivateServiceListener(listener); delegate.removeServiceListener(listener); } @Override public ServiceReference<?>[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { if (filter != null && filter.contains(PRIVATE)) { return getPrivateServiceReferences(clazz, filter); } else { return delegate.getServiceReferences(clazz, filter); } } @Override public ServiceRegistration<?> registerService(String[] clazzes, Object service, Dictionary<String, ?> properties) { if (properties != null && properties.get(PRIVATE) != null) { return registerPrivate(clazzes, service, properties); } else { return delegate.registerService(clazzes, service, properties); } } @Override public <S> S getService(ServiceReference<S> reference) { if (reference instanceof PrivateServiceRegistration) { return getPrivateService(reference); } else { return delegate.getService(reference); } } @Override public boolean ungetService(ServiceReference<?> reference) { if (reference instanceof PrivateServiceRegistration) { return ungetPrivateService(reference); } else { return delegate.ungetService(reference); } } static class ListenerInfo { final ServiceListener listener; final Filter filter; public ListenerInfo(ServiceListener listener, Filter filter) { this.listener = listener; this.filter = filter; } } private void addPrivateServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException { Filter flt = delegate.createFilter(filter); listeners.add(new ListenerInfo(listener, flt)); } private void removePrivateServiceListener(ServiceListener listener) { final Iterator<ListenerInfo> each = listeners.iterator(); while (each.hasNext()) { if (each.next().listener == listener) { each.remove(); } } } private <S> ServiceRegistration<S> registerPrivate(String[] clazzes, Object svc, Dictionary<String, ?> properties) { PrivateServiceRegistration<S> reg = new PrivateServiceRegistration<>(clazzes, svc, properties); registrations.add(reg); ServiceEvent event = new ServiceEvent(ServiceEvent.REGISTERED, reg); for (ListenerInfo li : listeners) { if (li.filter.match(reg)) { li.listener.serviceChanged(event); } } return reg; } private ServiceReference<?>[] getPrivateServiceReferences(String clazz, String filter) throws InvalidSyntaxException { Filter flt = delegate.createFilter(clazz != null ? "(&(objectClass=" + clazz + ")" + filter + ")" : filter); List<ServiceReference<?>> refs = new ArrayList<>(); for (PrivateServiceRegistration<?> reg : registrations) { if (flt.match(reg)) { refs.add(reg); } } return refs.toArray(new ServiceReference[refs.size()]); } private <S> S getPrivateService(ServiceReference<S> reference) { PrivateServiceRegistration<S> reg = (PrivateServiceRegistration<S>) reference; if (reg.service instanceof ServiceFactory) { return (S) ((ServiceFactory) reg.service).getService(getBundle(), reg); } return (S) reg.service; } private <S> void unregisterPrivate(PrivateServiceRegistration<S> reg) { registrations.remove(reg); ServiceEvent event = new ServiceEvent(ServiceEvent.UNREGISTERING, reg); for (ListenerInfo li : listeners) { if (li.filter.match(reg)) { li.listener.serviceChanged(event); } } } private boolean ungetPrivateService(ServiceReference<?> reference) { return false; } @Override public void addServiceListener(ServiceListener listener) { delegate.addServiceListener(listener); } @Override public ServiceRegistration<?> registerService(String clazz, Object service, Dictionary<String, ?> properties) { return delegate.registerService(clazz, service, properties); } @Override public <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> properties) { return delegate.registerService(clazz, service, properties); } @Override public <S> ServiceRegistration<S> registerService(Class<S> clazz, ServiceFactory<S> factory, Dictionary<String, ?> properties) { return delegate.registerService(clazz, factory, properties); } @Override public ServiceReference<?>[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException { return delegate.getAllServiceReferences(clazz, filter); } @Override public ServiceReference<?> getServiceReference(String clazz) { return delegate.getServiceReference(clazz); } @Override public <S> ServiceReference<S> getServiceReference(Class<S> clazz) { return delegate.getServiceReference(clazz); } @Override public <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter) throws InvalidSyntaxException { return delegate.getServiceReferences(clazz, filter); } @Override public <S> ServiceObjects<S> getServiceObjects(ServiceReference<S> reference) { return delegate.getServiceObjects(reference); } @Override public String getProperty(String key) { return delegate.getProperty(key); } @Override public Bundle getBundle() { return delegate.getBundle(); } @Override public Bundle installBundle(String location, InputStream input) throws BundleException { return delegate.installBundle(location, input); } @Override public Bundle installBundle(String location) throws BundleException { return delegate.installBundle(location); } @Override public Bundle getBundle(long id) { return delegate.getBundle(id); } @Override public Bundle[] getBundles() { return delegate.getBundles(); } @Override public void addBundleListener(BundleListener listener) { delegate.addBundleListener(listener); } @Override public void removeBundleListener(BundleListener listener) { delegate.removeBundleListener(listener); } @Override public void addFrameworkListener(FrameworkListener listener) { delegate.addFrameworkListener(listener); } @Override public void removeFrameworkListener(FrameworkListener listener) { delegate.removeFrameworkListener(listener); } @Override public File getDataFile(String filename) { return delegate.getDataFile(filename); } @Override public Filter createFilter(String filter) throws InvalidSyntaxException { return delegate.createFilter(filter); } @Override public Bundle getBundle(String location) { return delegate.getBundle(location); } private final AtomicLong privateServiceId = new AtomicLong(0); class PrivateServiceRegistration<S> implements ServiceRegistration<S>, ServiceReference<S> { private final Hashtable<String, ?> properties; private final Object service; public PrivateServiceRegistration(String[] clazzes, Object svc, Dictionary<String, ?> properties) { Hashtable<String, Object> props = new Hashtable<>(); for (Enumeration<String> elem = properties.keys(); elem.hasMoreElements();) { String key = elem.nextElement(); props.put(key, properties.get(key)); } props.put(Constants.OBJECTCLASS, clazzes); props.put(Constants.SERVICE_ID, privateServiceId.decrementAndGet()); this.properties = props; this.service = svc; } @Override public ServiceReference<S> getReference() { return this; } @Override public void setProperties(Dictionary<String, ?> properties) { throw new UnsupportedOperationException(); } @Override public void unregister() { unregisterPrivate(this); } @Override public Object getProperty(String key) { return properties.get(key); } @Override public String[] getPropertyKeys() { Set<String> keys = properties.keySet(); return keys.toArray(new String[keys.size()]); } @Override public Bundle getBundle() { throw new UnsupportedOperationException(); } @Override public Bundle[] getUsingBundles() { throw new UnsupportedOperationException(); } @Override public boolean isAssignableTo(Bundle bundle, String className) { return true; } @Override public int compareTo(Object reference) { ServiceReference other = (ServiceReference) reference; Long id = (Long) getProperty(Constants.SERVICE_ID); Long otherId = (Long) other.getProperty(Constants.SERVICE_ID); if (id.equals(otherId)) { return 0; // same service } Object rankObj = getProperty(Constants.SERVICE_RANKING); Object otherRankObj = other.getProperty(Constants.SERVICE_RANKING); // If no rank, then spec says it defaults to zero. rankObj = (rankObj == null) ? new Integer(0) : rankObj; otherRankObj = (otherRankObj == null) ? new Integer(0) : otherRankObj; // If rank is not Integer, then spec says it defaults to zero. Integer rank = (rankObj instanceof Integer) ? (Integer) rankObj : new Integer(0); Integer otherRank = (otherRankObj instanceof Integer) ? (Integer) otherRankObj : new Integer(0); // Sort by rank in ascending order. if (rank.compareTo(otherRank) < 0) { return -1; // lower rank } else if (rank.compareTo(otherRank) > 0) { return 1; // higher rank } // If ranks are equal, then sort by service id in descending order. return (id.compareTo(otherId) < 0) ? 1 : -1; } } }