Refactor event listener data structure to make it more amenable
to the R4.3 service event listener hook. (FELIX-3056)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1151599 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index c22f80f..e0651f5 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2034,7 +2034,7 @@
m_registry.ungetServices(bundle);
// Remove any listeners registered by this bundle.
- m_dispatcher.removeListeners(bundle);
+ m_dispatcher.removeListeners(bundle._getBundleContext());
// Clean up the bundle context.
((BundleContextImpl) bundle._getBundleContext()).invalidate();
@@ -2412,7 +2412,7 @@
// The spec says that we must remove all event
// listeners for a bundle when it is stopped.
- m_dispatcher.removeListeners(bundle);
+ m_dispatcher.removeListeners(bundle._getBundleContext());
// Clean up the bundle context.
((BundleContextImpl) bundle._getBundleContext()).invalidate();
@@ -3034,7 +3034,8 @@
try
{
- m_dispatcher.addListener(bundle, BundleListener.class, l, null);
+ m_dispatcher.addListener(
+ bundle._getBundleContext(), BundleListener.class, l, null);
}
finally
{
@@ -3044,7 +3045,8 @@
void removeBundleListener(BundleImpl bundle, BundleListener l)
{
- m_dispatcher.removeListener(bundle, BundleListener.class, l);
+ m_dispatcher.removeListener(
+ bundle._getBundleContext(), BundleListener.class, l);
}
/**
@@ -3076,7 +3078,7 @@
try
{
oldFilter = m_dispatcher.addListener(
- bundle, ServiceListener.class, l, newFilter);
+ bundle._getBundleContext(), ServiceListener.class, l, newFilter);
}
finally
{
@@ -3089,7 +3091,8 @@
if (oldFilter != null)
{
final Collection removed = Collections.singleton(
- new ListenerInfo(bundle, ServiceListener.class, l, oldFilter, null, true));
+ new ListenerInfo(bundle._getBundleContext(),
+ ServiceListener.class, l, oldFilter, null, true));
for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
@@ -3114,7 +3117,8 @@
// Invoke the ListenerHook.added() on all hooks.
final Collection added = Collections.singleton(
- new ListenerInfo(bundle, ServiceListener.class, l, newFilter, null, false));
+ new ListenerInfo(bundle.getBundleContext(),
+ ServiceListener.class, l, newFilter, null, false));
for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
@@ -3147,7 +3151,8 @@
void removeServiceListener(BundleImpl bundle, ServiceListener l)
{
org.osgi.framework.hooks.service.ListenerHook.ListenerInfo listener =
- m_dispatcher.removeListener(bundle, ServiceListener.class, l);
+ m_dispatcher.removeListener(
+ bundle._getBundleContext(), ServiceListener.class, l);
if (listener != null)
{
@@ -3193,7 +3198,8 @@
try
{
- m_dispatcher.addListener(bundle, FrameworkListener.class, l, null);
+ m_dispatcher.addListener(
+ bundle._getBundleContext(), FrameworkListener.class, l, null);
}
finally
{
@@ -3203,7 +3209,8 @@
void removeFrameworkListener(BundleImpl bundle, FrameworkListener l)
{
- m_dispatcher.removeListener(bundle, FrameworkListener.class, l);
+ m_dispatcher.removeListener(
+ bundle._getBundleContext(), FrameworkListener.class, l);
}
/**
diff --git a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
index 4da06a0..407ca63 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -28,7 +28,6 @@
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -57,10 +56,14 @@
private final Logger m_logger;
private final ServiceRegistry m_registry;
- private List<ListenerInfo> m_frameworkListeners = Collections.EMPTY_LIST;
- private List<ListenerInfo> m_bundleListeners = Collections.EMPTY_LIST;
- private List<ListenerInfo> m_syncBundleListeners = Collections.EMPTY_LIST;
- private List<ListenerInfo> m_serviceListeners = Collections.EMPTY_LIST;
+ private Map<BundleContext, List<ListenerInfo>>
+ m_fwkListeners = Collections.EMPTY_MAP;
+ private Map<BundleContext, List<ListenerInfo>>
+ m_bndlListeners = Collections.EMPTY_MAP;
+ private Map<BundleContext, List<ListenerInfo>>
+ m_syncBndlListeners = Collections.EMPTY_MAP;
+ private Map<BundleContext, List<ListenerInfo>>
+ m_svcListeners = Collections.EMPTY_MAP;
// A single thread is used to deliver events for all dispatchers.
private static Thread m_thread = null;
@@ -159,7 +162,7 @@
}
}
- public Filter addListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+ public Filter addListener(BundleContext bc, Class clazz, EventListener l, Filter filter)
{
// Verify the listener.
if (l == null)
@@ -174,7 +177,7 @@
// See if we can simply update the listener, if so then
// return immediately.
- Filter oldFilter = updateListener(bundle, clazz, l, filter);
+ Filter oldFilter = updateListener(bc, clazz, l, filter);
if (oldFilter != null)
{
return oldFilter;
@@ -183,22 +186,22 @@
// Lock the object to add the listener.
synchronized (this)
{
- List<ListenerInfo> listeners = null;
+ Map<BundleContext, List<ListenerInfo>> listeners = null;
Object acc = null;
if (clazz == FrameworkListener.class)
{
- listeners = m_frameworkListeners;
+ listeners = m_fwkListeners;
}
else if (clazz == BundleListener.class)
{
if (SynchronousBundleListener.class.isInstance(l))
{
- listeners = m_syncBundleListeners;
+ listeners = m_syncBndlListeners;
}
else
{
- listeners = m_bundleListeners;
+ listeners = m_bndlListeners;
}
}
else if (clazz == ServiceListener.class)
@@ -213,7 +216,7 @@
// registrations so we can fire ServiceEvent.MODIFIED_ENDMATCH
// events. We need a Set even if filter is null, since the
// listener can be updated and have a filter added later.
- listeners = m_serviceListeners;
+ listeners = m_svcListeners;
}
else
{
@@ -221,41 +224,36 @@
}
// Add listener.
- ListenerInfo listener =
- new ListenerInfo(bundle, clazz, l, filter, acc, false);
-
- List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(listeners.size() + 1);
- newListeners.addAll(listeners);
- newListeners.add(listener);
- listeners = newListeners;
+ ListenerInfo info = new ListenerInfo(bc, clazz, l, filter, acc, false);
+ listeners = addListenerInfo(listeners, info);
if (clazz == FrameworkListener.class)
{
- m_frameworkListeners = listeners;
+ m_fwkListeners = listeners;
}
else if (clazz == BundleListener.class)
{
if (SynchronousBundleListener.class.isInstance(l))
{
- m_syncBundleListeners = listeners;
+ m_syncBndlListeners = listeners;
}
else
{
- m_bundleListeners = listeners;
+ m_bndlListeners = listeners;
}
}
else if (clazz == ServiceListener.class)
{
- m_serviceListeners = listeners;
+ m_svcListeners = listeners;
}
}
return null;
}
public ListenerHook.ListenerInfo removeListener(
- Bundle bundle, Class clazz, EventListener l)
+ BundleContext bc, Class clazz, EventListener l)
{
- ListenerHook.ListenerInfo listenerInfo = null;
+ ListenerHook.ListenerInfo returnInfo = null;
// Verify listener.
if (l == null)
@@ -271,26 +269,26 @@
// Lock the object to remove the listener.
synchronized (this)
{
- List<ListenerInfo> listeners = null;
+ Map<BundleContext, List<ListenerInfo>> listeners = null;
if (clazz == FrameworkListener.class)
{
- listeners = m_frameworkListeners;
+ listeners = m_fwkListeners;
}
else if (clazz == BundleListener.class)
{
if (SynchronousBundleListener.class.isInstance(l))
{
- listeners = m_syncBundleListeners;
+ listeners = m_syncBndlListeners;
}
else
{
- listeners = m_bundleListeners;
+ listeners = m_bndlListeners;
}
}
else if (clazz == ServiceListener.class)
{
- listeners = m_serviceListeners;
+ listeners = m_svcListeners;
}
else
{
@@ -299,74 +297,63 @@
// Try to find the instance in our list.
int idx = -1;
- for (int i = 0; i < listeners.size(); i++)
+ for (Entry<BundleContext, List<ListenerInfo>> entry : listeners.entrySet())
{
- ListenerInfo listener = listeners.get(i);
- if (listener.getBundle().equals(bundle) &&
- (listener.getListenerClass() == clazz) &&
- (listener.getListener() == l))
+ List<ListenerInfo> infos = entry.getValue();
+ for (int i = 0; i < infos.size(); i++)
{
- // For service listeners, we must return some info about
- // the listener for the ListenerHook callback.
- if (ServiceListener.class == clazz)
+ ListenerInfo info = infos.get(i);
+ if (info.getBundleContext().equals(bc) &&
+ (info.getListenerClass() == clazz) &&
+ (info.getListener() == l))
{
- listenerInfo = new ListenerInfo(listeners.get(i), true);
+ // For service listeners, we must return some info about
+ // the listener for the ListenerHook callback.
+ if (ServiceListener.class == clazz)
+ {
+ returnInfo = new ListenerInfo(infos.get(i), true);
+ }
+ idx = i;
+ break;
}
- idx = i;
- break;
}
}
// If we have the instance, then remove it.
if (idx >= 0)
{
- // If this is the last listener, then point to empty list.
- if (listeners.size() == 1)
- {
- listeners = Collections.EMPTY_LIST;
- }
- // Otherwise, we need to do some array copying.
- // Notice, the old array is always valid, so if
- // the dispatch thread is in the middle of a dispatch,
- // then it has a reference to the old listener array
- // and is not affected by the new value.
- else
- {
- List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(listeners);
- newListeners.remove(idx);
- listeners = newListeners;
- }
+ listeners = removeListenerInfo(listeners, bc, idx);
}
if (clazz == FrameworkListener.class)
{
- m_frameworkListeners = listeners;
+ m_fwkListeners = listeners;
}
else if (clazz == BundleListener.class)
{
if (SynchronousBundleListener.class.isInstance(l))
{
- m_syncBundleListeners = listeners;
+ m_syncBndlListeners = listeners;
}
else
{
- m_bundleListeners = listeners;
+ m_bndlListeners = listeners;
}
}
else if (clazz == ServiceListener.class)
{
- m_serviceListeners = listeners;
+ m_svcListeners = listeners;
}
}
// Return information about the listener; this is null
// for everything but service listeners.
- return listenerInfo;
+ return returnInfo;
}
- public void removeListeners(Bundle bundle)
+ public void removeListeners(BundleContext bc)
{
- if (bundle == null)
+ if (bc == null)
{
return;
}
@@ -374,120 +361,48 @@
synchronized (this)
{
// Remove all framework listeners associated with the specified bundle.
- List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(m_frameworkListeners);
- for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
- {
- // Check if the bundle associated with the current listener
- // is the same as the specified bundle, if so remove the listener.
- if (bundle.equals(it.next().getBundle()))
- {
- it.remove();
- }
- }
- m_frameworkListeners = newListeners;
+ m_fwkListeners = removeListenerInfos(m_fwkListeners, bc);
// Remove all bundle listeners associated with the specified bundle.
- newListeners = new ArrayList<ListenerInfo>(m_bundleListeners);
- for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
- {
- // Check if the bundle associated with the current listener
- // is the same as the specified bundle, if so remove the listener.
- if (bundle.equals(it.next().getBundle()))
- {
- it.remove();
- }
- }
- m_bundleListeners = newListeners;
+ m_bndlListeners = removeListenerInfos(m_bndlListeners, bc);
// Remove all synchronous bundle listeners associated with
// the specified bundle.
- newListeners = new ArrayList<ListenerInfo>(m_syncBundleListeners);
- for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
- {
- // Check if the bundle associated with the current listener
- // is the same as the specified bundle, if so remove the listener.
- if (bundle.equals(it.next().getBundle()))
- {
- it.remove();
- }
- }
- m_syncBundleListeners = newListeners;
+ m_syncBndlListeners = removeListenerInfos(m_syncBndlListeners, bc);
// Remove all service listeners associated with the specified bundle.
- newListeners = new ArrayList<ListenerInfo>(m_serviceListeners);
- for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
- {
- // Check if the bundle associated with the current listener
- // is the same as the specified bundle, if so remove the listener.
- if (bundle.equals(it.next().getBundle()))
- {
- it.remove();
- }
- }
- m_serviceListeners = newListeners;
+ m_svcListeners = removeListenerInfos(m_svcListeners, bc);
}
}
- public Filter updateListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+ public Filter updateListener(BundleContext bc, Class clazz, EventListener l, Filter filter)
{
- synchronized (this)
+ if (clazz == ServiceListener.class)
{
- List<ListenerInfo> listeners = null;
-
- if (clazz == FrameworkListener.class)
+ synchronized (this)
{
- listeners = m_frameworkListeners;
- }
- else if (clazz == BundleListener.class)
- {
- if (SynchronousBundleListener.class.isInstance(l))
+ // See if the service listener is already registered; if so then
+ // update its filter per the spec.
+ List<ListenerInfo> infos = m_svcListeners.get(bc);
+ for (int i = 0; (infos != null) && (i < infos.size()); i++)
{
- listeners = m_syncBundleListeners;
- }
- else
- {
- listeners = m_bundleListeners;
- }
- }
- else if (clazz == ServiceListener.class)
- {
- listeners = m_serviceListeners;
- }
-
- // See if the listener is already registered, if so then
- // handle it according to the spec.
- for (int i = 0; i < listeners.size(); i++)
- {
- ListenerInfo listener = listeners.get(i);
- if (listener.getBundle().equals(bundle) &&
- (listener.getListenerClass() == clazz) &&
- (listener.getListener() == l))
- {
- Filter oldFilter = null;
- if (clazz == FrameworkListener.class)
- {
- // The spec says to ignore this case.
- }
- else if (clazz == BundleListener.class)
- {
- // The spec says to ignore this case.
- }
- else if (clazz == ServiceListener.class)
+ ListenerInfo info = infos.get(i);
+ if (info.getBundleContext().equals(bc) &&
+ (info.getListenerClass() == clazz) &&
+ (info.getListener() == l))
{
// The spec says to update the filter in this case.
- oldFilter = listener.getParsedFilter();
- listeners = new ArrayList<ListenerInfo>(listeners);
- listeners.set(i,
- new ListenerInfo(
- listener.getBundle(),
- listener.getListenerClass(),
- listener.getListener(),
- filter,
- listener.getSecurityContext(),
- listener.isRemoved()));
- m_serviceListeners = listeners;
+ Filter oldFilter = info.getParsedFilter();
+ ListenerInfo newInfo = new ListenerInfo(
+ info.getBundleContext(),
+ info.getListenerClass(),
+ info.getListener(),
+ filter,
+ info.getSecurityContext(),
+ info.isRemoved());
+ m_svcListeners = updateListenerInfo(m_svcListeners, i, newInfo);
+ return oldFilter;
}
- return oldFilter;
}
}
}
@@ -504,26 +419,24 @@
**/
public Collection<ListenerHook.ListenerInfo> getAllServiceListeners()
{
- List<ListenerInfo> listeners = null;
+ List<ListenerHook.ListenerInfo> listeners = new ArrayList<ListenerHook.ListenerInfo>();
synchronized (this)
{
- listeners = m_serviceListeners;
+ for (Entry<BundleContext, List<ListenerInfo>> entry : m_svcListeners.entrySet())
+ {
+ listeners.addAll(entry.getValue());
+ }
}
- return asTypedCollection(new ArrayList<ListenerHook.ListenerInfo>(listeners));
- }
-
- private static <S> Collection<S> asTypedCollection(Collection<?> c)
- {
- return (Collection<S>) c;
+ return listeners;
}
public void fireFrameworkEvent(FrameworkEvent event)
{
// Take a snapshot of the listener array.
- List<ListenerInfo> listeners = null;
+ Map<BundleContext, List<ListenerInfo>> listeners = null;
synchronized (this)
{
- listeners = m_frameworkListeners;
+ listeners = m_fwkListeners;
}
// Fire all framework listeners on a separate thread.
@@ -533,21 +446,18 @@
public void fireBundleEvent(BundleEvent event, Framework felix)
{
// Take a snapshot of the listener array.
- List<ListenerInfo> listeners = null;
- List<ListenerInfo> syncListeners = null;
+ Map<BundleContext, List<ListenerInfo>> listeners = null;
+ Map<BundleContext, List<ListenerInfo>> syncListeners = null;
synchronized (this)
{
- listeners = m_bundleListeners;
- syncListeners = m_syncBundleListeners;
+ listeners = m_bndlListeners;
+ syncListeners = m_syncBndlListeners;
}
// Create a whitelist of bundle context for bundle listeners,
// if we have hooks.
- List<ListenerInfo> allListeners = new ArrayList(listeners);
- allListeners.addAll(syncListeners);
- Set<BundleContext> whitelist =
- createWhitelistFromHooks(
- event, felix, allListeners, org.osgi.framework.hooks.bundle.EventHook.class);
+ Set<BundleContext> whitelist = createWhitelistFromHooks(event, felix,
+ listeners, syncListeners, org.osgi.framework.hooks.bundle.EventHook.class);
// Fire synchronous bundle listeners immediately on the calling thread.
fireEventImmediately(
@@ -569,25 +479,27 @@
final ServiceEvent event, final Dictionary oldProps, final Framework felix)
{
// Take a snapshot of the listener array.
- List<ListenerInfo> listeners = null;
+ Map<BundleContext, List<ListenerInfo>> listeners = null;
synchronized (this)
{
- listeners = m_serviceListeners;
+ listeners = m_svcListeners;
}
- // Create a whitelist of bundle context, if we have hooks.
- Set<BundleContext> whitelist =
- createWhitelistFromHooks(
- event, felix, listeners, org.osgi.framework.hooks.service.EventHook.class);
+ // Create a whitelist of bundle contexts for service listeners,
+ // if we have hooks.
+ Set<BundleContext> whitelist = createWhitelistFromHooks(event, felix,
+ listeners, null, org.osgi.framework.hooks.service.EventHook.class);
- // Fire all service events immediately on the calling thread.
+ // Fire synchronous bundle listeners immediately on the calling thread.
fireEventImmediately(
this, Request.SERVICE_EVENT, listeners, whitelist, event, oldProps);
}
-
private Set<BundleContext> createWhitelistFromHooks(
- EventObject event, Framework felix, List<ListenerInfo> listeners, Class hookClass)
+ EventObject event, Framework felix,
+ Map<BundleContext, List<ListenerInfo>> listeners1,
+ Map<BundleContext, List<ListenerInfo>> listeners2,
+ Class hookClass)
{
// Create a whitelist of bundle context, if we have hooks.
Set<BundleContext> whitelist = null;
@@ -595,14 +507,18 @@
if ((hooks != null) && !hooks.isEmpty())
{
whitelist = new HashSet<BundleContext>();
- for (ListenerInfo listener : listeners)
+ for (Entry<BundleContext, List<ListenerInfo>> entry : listeners1.entrySet())
{
- BundleContext bc = listener.getBundleContext();
- if (bc != null)
+ whitelist.add(entry.getKey());
+ }
+ if (listeners2 != null)
+ {
+ for (Entry<BundleContext, List<ListenerInfo>> entry : listeners2.entrySet())
{
- whitelist.add(bc);
+ whitelist.add(entry.getKey());
}
}
+
int originalSize = whitelist.size();
ShrinkableCollection<BundleContext> shrinkable =
new ShrinkableCollection<BundleContext>(whitelist);
@@ -657,7 +573,8 @@
}
private static void fireEventAsynchronously(
- EventDispatcher dispatcher, int type, List<ListenerInfo> listeners,
+ EventDispatcher dispatcher, int type,
+ Map<BundleContext, List<ListenerInfo>> listeners,
Set<BundleContext> whitelist, EventObject event)
{
//TODO: should possibly check this within thread lock, seems to be ok though without
@@ -699,48 +616,52 @@
}
private static void fireEventImmediately(
- EventDispatcher dispatcher, int type, List<ListenerInfo> listeners,
+ EventDispatcher dispatcher, int type,
+ Map<BundleContext, List<ListenerInfo>> listeners,
Set<BundleContext> whitelist, EventObject event, Dictionary oldProps)
{
if (!listeners.isEmpty())
{
// Notify appropriate listeners.
- for (ListenerInfo listener : listeners)
+ for (Entry<BundleContext, List<ListenerInfo>> entry : listeners.entrySet())
{
- Bundle bundle = listener.getBundle();
- EventListener l = listener.getListener();
- Filter filter = listener.getParsedFilter();
- Object acc = listener.getSecurityContext();
-
- // Only deliver events to bundles in the whitelist, if we have one.
- if ((whitelist == null) || whitelist.contains(bundle.getBundleContext()))
+ for (ListenerInfo info : entry.getValue())
{
- try
+ BundleContext bc = info.getBundleContext();
+ EventListener l = info.getListener();
+ Filter filter = info.getParsedFilter();
+ Object acc = info.getSecurityContext();
+
+ // Only deliver events to bundles in the whitelist, if we have one.
+ if ((whitelist == null) || whitelist.contains(bc))
{
- if (type == Request.FRAMEWORK_EVENT)
+ try
{
- invokeFrameworkListenerCallback(bundle, l, event);
+ if (type == Request.FRAMEWORK_EVENT)
+ {
+ invokeFrameworkListenerCallback(bc.getBundle(), l, event);
+ }
+ else if (type == Request.BUNDLE_EVENT)
+ {
+ invokeBundleListenerCallback(bc.getBundle(), l, event);
+ }
+ else if (type == Request.SERVICE_EVENT)
+ {
+ invokeServiceListenerCallback(
+ bc.getBundle(), l, filter, acc, event, oldProps);
+ }
}
- else if (type == Request.BUNDLE_EVENT)
+ catch (Throwable th)
{
- invokeBundleListenerCallback(bundle, l, event);
- }
- else if (type == Request.SERVICE_EVENT)
- {
- invokeServiceListenerCallback(
- bundle, l, filter, acc, event, oldProps);
- }
- }
- catch (Throwable th)
- {
- if ((type != Request.FRAMEWORK_EVENT)
- || (((FrameworkEvent) event).getType() != FrameworkEvent.ERROR))
- {
- dispatcher.m_logger.log(bundle,
- Logger.LOG_ERROR,
- "EventDispatcher: Error during dispatch.", th);
- dispatcher.fireFrameworkEvent(
- new FrameworkEvent(FrameworkEvent.ERROR, bundle, th));
+ if ((type != Request.FRAMEWORK_EVENT)
+ || (((FrameworkEvent) event).getType() != FrameworkEvent.ERROR))
+ {
+ dispatcher.m_logger.log(bc.getBundle(),
+ Logger.LOG_ERROR,
+ "EventDispatcher: Error during dispatch.", th);
+ dispatcher.fireFrameworkEvent(
+ new FrameworkEvent(FrameworkEvent.ERROR, bc.getBundle(), th));
+ }
}
}
}
@@ -899,6 +820,84 @@
}
}
+ private static Map<BundleContext, List<ListenerInfo>> addListenerInfo(
+ Map<BundleContext, List<ListenerInfo>> listeners, ListenerInfo info)
+ {
+ // Make a copy of the map, since we will be mutating it.
+ Map<BundleContext, List<ListenerInfo>> copy =
+ new HashMap<BundleContext, List<ListenerInfo>>(listeners);
+ // Remove the affected entry and make a copy so we can modify it.
+ List<ListenerInfo> infos = copy.remove(info.getBundleContext());
+ if (infos == null)
+ {
+ infos = new ArrayList<ListenerInfo>();
+ }
+ else
+ {
+ infos = new ArrayList<ListenerInfo>(infos);
+ }
+ // Add the new listener info.
+ infos.add(info);
+ // Put the listeners back into the copy of the map and return it.
+ copy.put(info.getBundleContext(), infos);
+ return copy;
+ }
+
+ private static Map<BundleContext, List<ListenerInfo>> updateListenerInfo(
+ Map<BundleContext, List<ListenerInfo>> listeners, int idx,
+ ListenerInfo info)
+ {
+ // Make a copy of the map, since we will be mutating it.
+ Map<BundleContext, List<ListenerInfo>> copy =
+ new HashMap<BundleContext, List<ListenerInfo>>(listeners);
+ // Remove the affected entry and make a copy so we can modify it.
+ List<ListenerInfo> infos = copy.remove(info.getBundleContext());
+ if (infos != null)
+ {
+ infos = new ArrayList<ListenerInfo>(infos);
+ // Update the new listener info.
+ infos.set(idx, info);
+ // Put the listeners back into the copy of the map and return it.
+ copy.put(info.getBundleContext(), infos);
+ return copy;
+ }
+ return listeners;
+ }
+
+ private static Map<BundleContext, List<ListenerInfo>> removeListenerInfo(
+ Map<BundleContext, List<ListenerInfo>> listeners, BundleContext bc, int idx)
+ {
+ // Make a copy of the map, since we will be mutating it.
+ Map<BundleContext, List<ListenerInfo>> copy =
+ new HashMap<BundleContext, List<ListenerInfo>>(listeners);
+ // Remove the affected entry and make a copy so we can modify it.
+ List<ListenerInfo> infos = copy.remove(bc);
+ if (infos != null)
+ {
+ infos = new ArrayList<ListenerInfo>(infos);
+ // Remove the listener info.
+ infos.remove(idx);
+ if (!infos.isEmpty())
+ {
+ // Put the listeners back into the copy of the map and return it.
+ copy.put(bc, infos);
+ }
+ return copy;
+ }
+ return listeners;
+ }
+
+ private static Map<BundleContext, List<ListenerInfo>> removeListenerInfos(
+ Map<BundleContext, List<ListenerInfo>> listeners, BundleContext bc)
+ {
+ // Make a copy of the map, since we will be mutating it.
+ Map<BundleContext, List<ListenerInfo>> copy =
+ new HashMap<BundleContext, List<ListenerInfo>>(listeners);
+ // Remove the affected entry and return the copy.
+ copy.remove(bc);
+ return copy;
+ }
+
/**
* This is the dispatching thread's main loop.
**/
@@ -945,7 +944,8 @@
// the invoked method shields us from exceptions by
// catching Throwables when it invokes callbacks.
fireEventImmediately(
- req.m_dispatcher, req.m_type, req.m_listeners, req.m_whitelist, req.m_event, null);
+ req.m_dispatcher, req.m_type, req.m_listeners,
+ req.m_whitelist, req.m_event, null);
// Put dispatch request in cache.
synchronized (m_requestPool)
@@ -968,7 +968,7 @@
public EventDispatcher m_dispatcher = null;
public int m_type = -1;
- public List<ListenerInfo> m_listeners = null;
+ public Map<BundleContext, List<ListenerInfo>> m_listeners = null;
public Set<BundleContext> m_whitelist = null;
public EventObject m_event = null;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java b/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java
index e007db4..e3a6403 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java
@@ -27,7 +27,7 @@
public class ListenerInfo implements ListenerHook.ListenerInfo
{
- private final Bundle m_bundle;
+ private final BundleContext m_context;
private final Class m_listenerClass;
private final EventListener m_listener;
private final Filter m_filter;
@@ -35,10 +35,10 @@
private final boolean m_removed;
public ListenerInfo(
- Bundle bundle, Class listenerClass, EventListener listener,
+ BundleContext context, Class listenerClass, EventListener listener,
Filter filter, Object acc, boolean removed)
{
- m_bundle = bundle;
+ m_context = context;
m_listenerClass = listenerClass;
m_listener = listener;
m_filter = filter;
@@ -48,7 +48,7 @@
public ListenerInfo(ListenerInfo info, boolean removed)
{
- m_bundle = info.m_bundle;
+ m_context = info.m_context;
m_listenerClass = info.m_listenerClass;
m_listener = info.m_listener;
m_filter = info.m_filter;
@@ -56,14 +56,9 @@
m_removed = removed;
}
- public Bundle getBundle()
- {
- return m_bundle;
- }
-
public BundleContext getBundleContext()
{
- return m_bundle.getBundleContext();
+ return m_context;
}
public Class getListenerClass()
@@ -114,20 +109,21 @@
}
ListenerInfo other = (ListenerInfo) obj;
- return other.m_listener == m_listener &&
- (m_filter == null ? other.m_filter == null : m_filter.equals(other.m_filter));
+ return (other.m_context == m_context)
+ && (other.m_listenerClass == m_listenerClass)
+ && (other.m_listener == m_listener)
+ && (m_filter == null ? other.m_filter == null : m_filter.equals(other.m_filter));
}
+
@Override
public int hashCode()
{
- int rc = 17;
-
- rc = 37 * rc + m_listener.hashCode();
- if (m_filter != null)
- {
- rc = 37 * rc + m_filter.hashCode();
- }
- return rc;
+ int hash = 7;
+ hash = 71 * hash + (this.m_context != null ? this.m_context.hashCode() : 0);
+ hash = 71 * hash + (this.m_listenerClass != null ? this.m_listenerClass.hashCode() : 0);
+ hash = 71 * hash + (this.m_listener != null ? this.m_listener.hashCode() : 0);
+ hash = 71 * hash + (this.m_filter != null ? this.m_filter.hashCode() : 0);
+ return hash;
}
}
\ No newline at end of file
diff --git a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
index 6c8bfaf..c4622a7 100644
--- a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
@@ -95,7 +95,7 @@
System.out.println("*** sl1");
}
};
- ed.addListener(b1, ServiceListener.class, sl1, null);
+ ed.addListener(b1.getBundleContext(), ServiceListener.class, sl1, null);
ServiceListener sl2 = new ServiceListener()
{
@@ -105,7 +105,7 @@
System.out.println("*** sl2");
}
};
- ed.addListener(b2, ServiceListener.class, sl2, null);
+ ed.addListener(b2.getBundleContext(), ServiceListener.class, sl2, null);
ServiceListener sl3 = new ServiceListener()
{
@@ -115,7 +115,7 @@
System.out.println("*** sl3");
}
};
- ed.addListener(b3, ServiceListener.class, sl3, null);
+ ed.addListener(b3.getBundleContext(), ServiceListener.class, sl3, null);
// --- make the invocation
ServiceReference sr = (ServiceReference) EasyMock.createNiceMock(ServiceReference.class);