Author: davidb Date: Thu Dec 11 07:11:10 2014 New Revision: 1644564 URL: http://svn.apache.org/r1644564 Log: FELIX-4726 Prevent service hooks from hiding things for the system bundle
Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1644564&r1=1644563&r2=1644564&view=diff ============================================================================== --- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original) +++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Thu Dec 11 07:11:10 2014 @@ -3530,6 +3530,9 @@ public class Felix extends BundleImpl im } } + // If the requesting bundle is the system bundle, ignore the effects of the findhooks + List resRefList = (bundle == this ? new ArrayList(refList) : refList); + // activate findhooks Set<ServiceReference<org.osgi.framework.hooks.service.FindHook>> findHooks = m_registry.getHooks(org.osgi.framework.hooks.service.FindHook.class); @@ -3560,9 +3563,12 @@ public class Felix extends BundleImpl im } } - if (refList.size() > 0) + // We return resRefList which is normally the same as refList and therefore any modifications + // to refList are also visible to resRefList. However in the case of the system bundle being + // the requestor, resRefList is a copy of the original list before the hooks were invoked. + if (resRefList.size() > 0) { - return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]); + return (ServiceReference[]) resRefList.toArray(new ServiceReference[resRefList.size()]); } return null; Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java?rev=1644564&r1=1644563&r2=1644564&view=diff ============================================================================== --- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java (original) +++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java Thu Dec 11 07:11:10 2014 @@ -576,16 +576,32 @@ public class EventDispatcher m_registry.getHooks(org.osgi.framework.hooks.service.EventListenerHook.class); if ((elhs != null) && !elhs.isEmpty()) { - // Create shrinkable map with shrinkable collections. + List<ListenerInfo> systemBundleListeners = null; + + // The mutable map is used to keep the lists that underpin the shrinkable collections. + Map<BundleContext, List<ListenerInfo>> mutableMap = + new HashMap<BundleContext, List<ListenerInfo>>(); + // Create map with shrinkable collections. Map<BundleContext, Collection<ListenerHook.ListenerInfo>> shrinkableMap = new HashMap<BundleContext, Collection<ListenerHook.ListenerInfo>>(); for (Entry<BundleContext, List<ListenerInfo>> entry : listeners.entrySet()) { - Collection shrinkableCollection = - new ShrinkableCollection(new ArrayList(entry.getValue())); - shrinkableMap.put( - entry.getKey(), - shrinkableCollection); + BundleContext bc = entry.getKey(); + ArrayList<ListenerInfo> mutableList = new ArrayList<ListenerInfo>(entry.getValue()); + mutableMap.put(bc, mutableList); + + // We want to pass the list as a generic collection to Shrinkable Collection. + // Need to convert to raw type before we can do this... + ArrayList ml = mutableList; + + Collection<ListenerHook.ListenerInfo> shrinkableCollection = + new ShrinkableCollection<ListenerHook.ListenerInfo>(ml); + shrinkableMap.put(bc, shrinkableCollection); + + // Keep a copy of the System Bundle Listeners, as they might be removed by the hooks, but we + // actually need to keep them in the end. + if (bc == felix.getBundleContext()) + systemBundleListeners = new ArrayList<ListenerInfo>(entry.getValue()); } shrinkableMap = new ShrinkableMap<BundleContext, Collection<ListenerHook.ListenerInfo>> @@ -623,18 +639,28 @@ public class EventDispatcher } } } + // TODO: OSGi R4.3 - Should check and only do this if there was a change. -// Also, it is inefficient to have to create new lists for the values. + + // the listeners map should only contain List values, and not Shrinkable + // Collections. Therefore we create a new map from the lists that are + // the delegates for the Shrinkable Collections. Any changes made by the + // hooks will have propagated to these maps. Map<BundleContext, List<ListenerInfo>> newMap = new HashMap<BundleContext, List<ListenerInfo>>(); - for (Entry entry : shrinkableMap.entrySet()) + for (Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>> entry : shrinkableMap.entrySet()) { - if (!((Collection) entry.getValue()).isEmpty()) + if (!entry.getValue().isEmpty()) { - newMap.put((BundleContext) entry.getKey(), - new ArrayList<ListenerInfo>((Collection) entry.getValue())); + newMap.put(entry.getKey(), mutableMap.get(entry.getKey())); } } + + // Put the system bundle listeners back, because they really need to be called + // regardless whether they were removed by the hooks or not. + if (systemBundleListeners != null) + newMap.put(felix.getBundleContext(), systemBundleListeners); + listeners = newMap; } @@ -652,16 +678,23 @@ public class EventDispatcher Set<ServiceReference<T>> hooks = m_registry.getHooks(hookClass); if ((hooks != null) && !hooks.isEmpty()) { + boolean systemBundleListener = false; + BundleContext systemBundleContext = felix.getBundleContext(); + whitelist = new HashSet<BundleContext>(); for (Entry<BundleContext, List<ListenerInfo>> entry : listeners1.entrySet()) { whitelist.add(entry.getKey()); + if (entry.getKey() == systemBundleContext) + systemBundleListener = true; } if (listeners2 != null) { for (Entry<BundleContext, List<ListenerInfo>> entry : listeners2.entrySet()) { whitelist.add(entry.getKey()); + if (entry.getKey() == systemBundleContext) + systemBundleListener = true; } } @@ -710,6 +743,16 @@ public class EventDispatcher } } } + + if (systemBundleListener && !whitelist.contains(systemBundleContext)) + { + // The system bundle cannot be removed from the listeners, so if it was + // removed, add it back in. Note that this cannot be prevented by the shrinkable + // since the effect of removing the system bundle from the listeners must be + // visible between the event hooks. + whitelist.add(systemBundleContext); + } + // If the whitelist hasn't changed, then null it to avoid having // to do whitelist lookups during event delivery. if (originalSize == whitelist.size())