Implement bundle hooks and fix a bug in service registry hooks.
(FELIX-3032, FELIX-3033)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1145325 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index 8e334ec..98a8282 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -175,7 +175,7 @@
// the result is the same as if the calling thread had
// won the race condition.
- return m_felix.getBundle(id);
+ return m_felix.getBundle(this, id);
}
public Bundle getBundle(String location)
@@ -199,7 +199,7 @@
// the result is the same as if the calling thread had
// won the race condition.
- return m_felix.getBundles();
+ return m_felix.getBundles(this);
}
public void addBundleListener(BundleListener l)
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index 9ee7f28..65321a3 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -1496,6 +1496,7 @@
{
try
{
+// TODO: OSGi R4.3 - Need to call all hooks in privileged block.
wh.weave(wci);
}
catch (Throwable th)
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 a5e5423..071818b 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -62,8 +62,6 @@
import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.framework.hooks.service.FindHook;
-import org.osgi.framework.hooks.service.ListenerHook;
import org.osgi.framework.startlevel.FrameworkStartLevel;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
@@ -2622,7 +2620,7 @@
Bundle origin, long id, String location, BundleArchive ba, InputStream is)
throws BundleException
{
- BundleImpl bundle = null;
+ BundleImpl existing, bundle = null;
// Acquire an install lock.
acquireInstallLock(location);
@@ -2638,169 +2636,167 @@
// If bundle location is already installed, then
// return it as required by the OSGi specification.
- bundle = (BundleImpl) getBundle(location);
- if (bundle != null)
+ existing = (BundleImpl) getBundle(location);
+ if (existing == null)
{
- return bundle;
- }
+ // Determine if this is a new or existing bundle.
+ boolean isNew = (ba == null);
- // Determine if this is a new or existing bundle.
- boolean isNew = (ba == null);
+ // If the bundle is new we must cache its JAR file.
+ if (isNew)
+ {
+ // First generate an identifier for it.
+ id = getNextId();
- // If the bundle is new we must cache its JAR file.
- if (isNew)
- {
- // First generate an identifier for it.
- id = getNextId();
-
- try
- {
- // Add the bundle to the cache.
- ba = m_cache.create(id, getInitialBundleStartLevel(), location, is);
- }
- catch (Exception ex)
- {
- throw new BundleException(
- "Unable to cache bundle: " + location, ex);
- }
- finally
- {
try
{
- if (is != null) is.close();
+ // Add the bundle to the cache.
+ ba = m_cache.create(id, getInitialBundleStartLevel(), location, is);
}
- catch (IOException ex)
+ catch (Exception ex)
+ {
+ throw new BundleException(
+ "Unable to cache bundle: " + location, ex);
+ }
+ finally
+ {
+ try
+ {
+ if (is != null) is.close();
+ }
+ catch (IOException ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to close input stream.", ex);
+ }
+ }
+ }
+ else
+ {
+ // If the bundle we are installing is not new,
+ // then try to purge old revisions before installing
+ // it; this is done just in case a "refresh"
+ // didn't occur last session...this would only be
+ // due to an error or system crash.
+ try
+ {
+ if (ba.isRemovalPending())
+ {
+ ba.purge();
+ }
+ }
+ catch (Exception ex)
{
m_logger.log(
Logger.LOG_ERROR,
- "Unable to close input stream.", ex);
+ "Could not purge bundle.", ex);
}
}
- }
- else
- {
- // If the bundle we are installing is not new,
- // then try to purge old revisions before installing
- // it; this is done just in case a "refresh"
- // didn't occur last session...this would only be
- // due to an error or system crash.
+
try
{
- if (ba.isRemovalPending())
+ // Acquire the global lock to create the bundle,
+ // since this impacts the global state.
+ boolean locked = acquireGlobalLock();
+ if (!locked)
{
- ba.purge();
+ throw new BundleException(
+ "Unable to acquire the global lock to install the bundle.");
+ }
+ try
+ {
+ bundle = new BundleImpl(this, ba);
+ }
+ finally
+ {
+ // Always release the global lock.
+ releaseGlobalLock();
+ }
+
+ if (!bundle.isExtension())
+ {
+ Object sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ ((SecurityManager) sm).checkPermission(
+ new AdminPermission(bundle, AdminPermission.LIFECYCLE));
+ }
+ }
+ else
+ {
+ m_extensionManager.addExtensionBundle(this, bundle);
+ m_resolver.addRevision(m_extensionManager.getRevision());
}
}
- catch (Exception ex)
+ catch (Throwable ex)
{
- m_logger.log(
- Logger.LOG_ERROR,
- "Could not purge bundle.", ex);
+ // If the bundle is new, then remove it from the cache.
+ // TODO: FRAMEWORK - Perhaps it should be removed if it is not new too.
+ if (isNew)
+ {
+ try
+ {
+ if (bundle != null)
+ {
+ bundle.closeAndDelete();
+ }
+ else if (ba != null)
+ {
+ ba.closeAndDelete();
+ }
+ }
+ catch (Exception ex1)
+ {
+ m_logger.log(bundle,
+ Logger.LOG_ERROR,
+ "Could not remove from cache.", ex1);
+ }
+ }
+ if (ex instanceof BundleException)
+ {
+ throw (BundleException) ex;
+ }
+ else if (ex instanceof AccessControlException)
+ {
+ throw (AccessControlException) ex;
+ }
+ else
+ {
+ throw new BundleException("Could not create bundle object.", ex);
+ }
}
- }
- try
- {
- // Acquire the global lock to create the bundle,
- // since this impacts the global state.
+ // Acquire global lock.
boolean locked = acquireGlobalLock();
if (!locked)
{
- throw new BundleException(
- "Unable to acquire the global lock to install the bundle.");
+ // If the calling thread holds bundle locks, then we might not
+ // be able to get the global lock.
+ throw new IllegalStateException(
+ "Unable to acquire global lock to add bundle.");
}
try
{
- bundle = new BundleImpl(this, ba);
+ // Use a copy-on-write approach to add the bundle
+ // to the installed maps.
+ Map[] maps = new Map[] {
+ new HashMap<String, BundleImpl>(m_installedBundles[LOCATION_MAP_IDX]),
+ new TreeMap<Long, BundleImpl>(m_installedBundles[IDENTIFIER_MAP_IDX])
+ };
+ maps[LOCATION_MAP_IDX].put(location, bundle);
+ maps[IDENTIFIER_MAP_IDX].put(new Long(bundle.getBundleId()), bundle);
+ m_installedBundles = maps;
}
finally
{
- // Always release the global lock.
releaseGlobalLock();
}
- if (!bundle.isExtension())
+ if (bundle.isExtension())
{
- Object sm = System.getSecurityManager();
- if (sm != null)
- {
- ((SecurityManager) sm).checkPermission(
- new AdminPermission(bundle, AdminPermission.LIFECYCLE));
- }
+ m_extensionManager.startExtensionBundle(this, bundle);
}
- else
- {
- m_extensionManager.addExtensionBundle(this, bundle);
- m_resolver.addRevision(m_extensionManager.getRevision());
- }
- }
- catch (Throwable ex)
- {
- // If the bundle is new, then remove it from the cache.
- // TODO: FRAMEWORK - Perhaps it should be removed if it is not new too.
- if (isNew)
- {
- try
- {
- if (bundle != null)
- {
- bundle.closeAndDelete();
- }
- else if (ba != null)
- {
- ba.closeAndDelete();
- }
- }
- catch (Exception ex1)
- {
- m_logger.log(bundle,
- Logger.LOG_ERROR,
- "Could not remove from cache.", ex1);
- }
- }
- if (ex instanceof BundleException)
- {
- throw (BundleException) ex;
- }
- else if (ex instanceof AccessControlException)
- {
- throw (AccessControlException) ex;
- }
- else
- {
- throw new BundleException("Could not create bundle object.", ex);
- }
- }
-
- // Acquire global lock.
- boolean locked = acquireGlobalLock();
- if (!locked)
- {
- // If the calling thread holds bundle locks, then we might not
- // be able to get the global lock.
- throw new IllegalStateException(
- "Unable to acquire global lock to add bundle.");
- }
- try
- {
- // Use a copy-on-write approach to add the bundle
- // to the installed maps.
- Map[] maps = new Map[] {
- new HashMap<String, BundleImpl>(m_installedBundles[LOCATION_MAP_IDX]),
- new TreeMap<Long, BundleImpl>(m_installedBundles[IDENTIFIER_MAP_IDX])
- };
- maps[LOCATION_MAP_IDX].put(location, bundle);
- maps[IDENTIFIER_MAP_IDX].put(new Long(bundle.getBundleId()), bundle);
- m_installedBundles = maps;
- }
- finally
- {
- releaseGlobalLock();
- }
-
- if (bundle.isExtension())
- {
- m_extensionManager.startExtensionBundle(this, bundle);
}
}
finally
@@ -2822,11 +2818,52 @@
}
}
- // Fire bundle event.
- fireBundleEvent(BundleEvent.INSTALLED, bundle, origin);
+ if (existing != null)
+ {
+ Set<ServiceReference<org.osgi.framework.hooks.bundle.FindHook>> hooks =
+ getHooks(org.osgi.framework.hooks.bundle.FindHook.class);
+ if (!hooks.isEmpty())
+ {
+ Collection<Bundle> bundles = new ArrayList<Bundle>(1);
+ bundles.add(existing);
+ bundles = new ShrinkableCollection<Bundle>(bundles);
+ for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
+ {
+ org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+ if (fh != null)
+ {
+// TODO: OSGi R4.3 - Call all hooks in privileged block.
+ try
+ {
+ fh.find(origin.getBundleContext(), bundles);
+ }
+ catch (Throwable th)
+ {
+ m_logger.doLog(
+ hook.getBundle(),
+ hook,
+ Logger.LOG_WARNING,
+ "Problem invoking bundle hook.",
+ th);
+ }
+ }
+ }
+ if (bundles.isEmpty())
+ {
+ throw new BundleException(
+ "Bundle installation rejected by hook.",
+ BundleException.REJECTED_BY_HOOK);
+ }
+ }
+ }
+ else
+ {
+ // Fire bundle event.
+ fireBundleEvent(BundleEvent.INSTALLED, bundle, origin);
+ }
// Return new bundle.
- return bundle;
+ return (existing != null) ? existing : bundle;
}
/**
@@ -2849,6 +2886,64 @@
* @return The bundle associated with the identifier or null if there
* is no bundle associated with the identifier.
**/
+ Bundle getBundle(BundleContext bc, long id)
+ {
+ BundleImpl bundle = (BundleImpl)
+ m_installedBundles[IDENTIFIER_MAP_IDX].get(new Long(id));
+ if (bundle != null)
+ {
+ List<BundleImpl> uninstalledBundles = m_uninstalledBundles;
+ for (int i = 0;
+ (bundle == null)
+ && (uninstalledBundles != null)
+ && (i < uninstalledBundles.size());
+ i++)
+ {
+ if (uninstalledBundles.get(i).getBundleId() == id)
+ {
+ bundle = uninstalledBundles.get(i);
+ }
+ }
+ }
+
+ Set<ServiceReference<org.osgi.framework.hooks.bundle.FindHook>> hooks =
+ getHooks(org.osgi.framework.hooks.bundle.FindHook.class);
+ if (!hooks.isEmpty() && (bundle != null))
+ {
+ Collection<Bundle> bundles = new ArrayList<Bundle>(1);
+ bundles.add(bundle);
+ bundles = new ShrinkableCollection<Bundle>(bundles);
+ for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
+ {
+ org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+ if (fh != null)
+ {
+// TODO: OSGi R4.3 - Call all hooks in privileged block.
+ try
+ {
+ fh.find(bc, bundles);
+ }
+ catch (Throwable th)
+ {
+ m_logger.doLog(
+ hook.getBundle(),
+ hook,
+ Logger.LOG_WARNING,
+ "Problem invoking bundle hook.",
+ th);
+ }
+ }
+ }
+ bundle = (bundles.isEmpty()) ? null : bundle;
+ }
+ return bundle;
+ }
+
+ /**
+ * Retrieves a bundle by its identifier and avoids bundles hooks.
+ *
+ * @return The bundle associated with the identifier or null.
+ **/
Bundle getBundle(long id)
{
BundleImpl bundle = (BundleImpl)
@@ -2879,14 +2974,49 @@
* @return An array containing all installed bundles or null if
* there are no installed bundles.
**/
+ Bundle[] getBundles(BundleContext bc)
+ {
+ Collection<Bundle> bundles = m_installedBundles[IDENTIFIER_MAP_IDX].values();
+ Set<ServiceReference<org.osgi.framework.hooks.bundle.FindHook>> hooks =
+ getHooks(org.osgi.framework.hooks.bundle.FindHook.class);
+ if (!hooks.isEmpty())
+ {
+ bundles = new ShrinkableCollection<Bundle>(new ArrayList(bundles));
+ for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks)
+ {
+ org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook);
+ if (fh != null)
+ {
+// TODO: OSGi R4.3 - Call all hooks in privileged block.
+ try
+ {
+ fh.find(bc, bundles);
+ }
+ catch (Throwable th)
+ {
+ m_logger.doLog(
+ hook.getBundle(),
+ hook,
+ Logger.LOG_WARNING,
+ "Problem invoking bundle hook.",
+ th);
+ }
+ }
+ }
+ }
+ return (Bundle[]) bundles.toArray(new Bundle[bundles.size()]);
+ }
+
+ /**
+ * Retrieves all installed bundles and avoids bundles hooks.
+ *
+ * @return An array containing all installed bundles or null if
+ * there are no installed bundles.
+ **/
Bundle[] getBundles()
{
- Map bundles = m_installedBundles[IDENTIFIER_MAP_IDX];
- if (bundles.isEmpty())
- {
- return null;
- }
- return (Bundle[]) bundles.values().toArray(new Bundle[bundles.size()]);
+ Collection<Bundle> bundles = m_installedBundles[IDENTIFIER_MAP_IDX].values();
+ return (Bundle[]) bundles.toArray(new Bundle[bundles.size()]);
}
void addBundleListener(BundleImpl bundle, BundleListener l)
@@ -2954,16 +3084,16 @@
}
// Invoke ListenerHook.removed() if filter updated.
- Set<ServiceReference<ListenerHook>> listenerHooks =
- m_registry.getHooks(ListenerHook.class);
+ Set<ServiceReference<org.osgi.framework.hooks.service.ListenerHook>> listenerHooks =
+ m_registry.getHooks(org.osgi.framework.hooks.service.ListenerHook.class);
if (oldFilter != null)
{
final Collection removed = Collections.singleton(
new ListenerHookInfoImpl(
((BundleImpl) bundle)._getBundleContext(), l, oldFilter.toString(), true));
- for (ServiceReference<ListenerHook> sr : listenerHooks)
+ for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
- ListenerHook lh = m_registry.getServiceSafely(this, sr);
+ org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
if (lh != null)
{
try
@@ -2986,9 +3116,9 @@
// Invoke the ListenerHook.added() on all hooks.
final Collection added = Collections.singleton(
new ListenerHookInfoImpl(((BundleImpl) bundle)._getBundleContext(), l, f, false));
- for (ServiceReference<ListenerHook> sr : listenerHooks)
+ for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
- ListenerHook lh = m_registry.getServiceSafely(this, sr);
+ org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
if (lh != null)
{
try
@@ -3017,18 +3147,18 @@
**/
void removeServiceListener(BundleImpl bundle, ServiceListener l)
{
- ListenerHook.ListenerInfo listener =
+ org.osgi.framework.hooks.service.ListenerHook.ListenerInfo listener =
m_dispatcher.removeListener(bundle, ServiceListener.class, l);
if (listener != null)
{
// Invoke the ListenerHook.removed() on all hooks.
- Set<ServiceReference<ListenerHook>> listenerHooks =
- m_registry.getHooks(ListenerHook.class);
+ Set<ServiceReference<org.osgi.framework.hooks.service.ListenerHook>> listenerHooks =
+ m_registry.getHooks(org.osgi.framework.hooks.service.ListenerHook.class);
Collection removed = Collections.singleton(listener);
- for (ServiceReference<ListenerHook> sr : listenerHooks)
+ for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
- ListenerHook lh = m_registry.getServiceSafely(this, sr);
+ org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
if (lh != null)
{
try
@@ -3147,9 +3277,12 @@
// Check to see if this a listener hook; if so, then we need
// to invoke the callback with all existing service listeners.
- if (ServiceRegistry.isHook(classNames, ListenerHook.class, svcObj))
+ if (ServiceRegistry.isHook(
+ classNames, org.osgi.framework.hooks.service.ListenerHook.class, svcObj))
{
- ListenerHook lh = (ListenerHook) m_registry.getServiceSafely(this, reg.getReference());
+ org.osgi.framework.hooks.service.ListenerHook lh =
+ (org.osgi.framework.hooks.service.ListenerHook)
+ getService(this, reg.getReference());
if (lh != null)
{
try
@@ -3228,11 +3361,11 @@
}
// activate findhooks
- Set<ServiceReference<FindHook>> findHooks =
- m_registry.getHooks(FindHook.class);
- for (ServiceReference<FindHook> sr : findHooks)
+ Set<ServiceReference<org.osgi.framework.hooks.service.FindHook>> findHooks =
+ m_registry.getHooks(org.osgi.framework.hooks.service.FindHook.class);
+ for (ServiceReference<org.osgi.framework.hooks.service.FindHook> sr : findHooks)
{
- FindHook fh = m_registry.getServiceSafely(this, sr);
+ org.osgi.framework.hooks.service.FindHook fh = getService(this, sr);
if (fh != null)
{
try
@@ -4156,12 +4289,12 @@
**/
void fireBundleEvent(int type, Bundle bundle)
{
- m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle));
+ m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle), this);
}
void fireBundleEvent(int type, Bundle bundle, Bundle origin)
{
- m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle, origin));
+ m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle, origin), this);
}
/**
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
index 8afa535..91436c0 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -18,18 +18,18 @@
*/
package org.apache.felix.framework;
-import java.net.ContentHandler;
import java.util.*;
import org.apache.felix.framework.capabilityset.CapabilitySet;
import org.apache.felix.framework.capabilityset.SimpleFilter;
import org.apache.felix.framework.wiring.BundleCapabilityImpl;
-
-import org.osgi.framework.*;
-import org.osgi.framework.hooks.resolver.ResolverHookFactory;
-import org.osgi.framework.hooks.service.*;
-import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.wiring.BundleCapability;
-import org.osgi.service.url.URLStreamHandlerService;
public class ServiceRegistry
{
@@ -53,13 +53,15 @@
new WeakHashMap<ServiceReference, ServiceReference>();
private final static Class<?>[] m_hookClasses = {
- EventHook.class,
- FindHook.class,
- ListenerHook.class,
- WeavingHook.class,
- ResolverHookFactory.class,
- URLStreamHandlerService.class,
- ContentHandler.class
+ org.osgi.framework.hooks.bundle.FindHook.class,
+ org.osgi.framework.hooks.bundle.EventHook.class,
+ org.osgi.framework.hooks.service.EventHook.class,
+ org.osgi.framework.hooks.service.FindHook.class,
+ org.osgi.framework.hooks.service.ListenerHook.class,
+ org.osgi.framework.hooks.weaving.WeavingHook.class,
+ org.osgi.framework.hooks.resolver.ResolverHookFactory.class,
+ org.osgi.service.url.URLStreamHandlerService.class,
+ java.net.ContentHandler.class
};
private final Map<Class<?>, Set<ServiceReference<?>>> m_allHooks =
new HashMap<Class<?>, Set<ServiceReference<?>>>();
@@ -243,19 +245,6 @@
return null;
}
- public <S> S getServiceSafely(Bundle bundle, ServiceReference<S> ref)
- {
- try
- {
- return getService(bundle, ref);
- }
- catch (ServiceException ex)
- {
- // Just ignore and return null.
- }
- return null;
- }
-
public <S> S getService(Bundle bundle, ServiceReference<S> ref)
{
UsageCount usage = null;
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 a8c3a5f..9d7f9a5 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
@@ -22,9 +22,11 @@
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.EventListener;
import java.util.EventObject;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
@@ -45,7 +47,6 @@
import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.SynchronousBundleListener;
-import org.osgi.framework.hooks.service.EventHook;
import org.osgi.framework.hooks.service.ListenerHook;
import org.osgi.framework.launch.Framework;
@@ -56,18 +57,15 @@
static final int LISTENER_OBJECT_OFFSET = 2;
static final int LISTENER_FILTER_OFFSET = 3;
static final int LISTENER_SECURITY_OFFSET = 4;
- static final int LISTENER_ARRAY_INCREMENT = 5;
+ static final int LISTENER_ARRAY_SIZE = 5;
private final Logger m_logger;
private final ServiceRegistry m_registry;
- // Representation of an empty listener list.
- private static final Object[] m_emptyList = new Object[0];
-
- private Object[] m_frameworkListeners = m_emptyList;
- private Object[] m_bundleListeners = m_emptyList;
- private Object[] m_syncBundleListeners = m_emptyList;
- private Object[] m_serviceListeners = m_emptyList;
+ private List<Object[]> m_frameworkListeners = Collections.EMPTY_LIST;
+ private List<Object[]> m_bundleListeners = Collections.EMPTY_LIST;
+ private List<Object[]> m_syncBundleListeners = Collections.EMPTY_LIST;
+ private List<Object[]> m_serviceListeners = Collections.EMPTY_LIST;
// A single thread is used to deliver events for all dispatchers.
private static Thread m_thread = null;
@@ -76,9 +74,9 @@
private static volatile boolean m_stopping = false;
// List of requests.
- private static final ArrayList m_requestList = new ArrayList();
+ private static final List<Request> m_requestList = new ArrayList<Request>();
// Pooled requests to avoid memory allocation.
- private static final ArrayList m_requestPool = new ArrayList();
+ private static final List<Request> m_requestPool = new ArrayList<Request>();
public EventDispatcher(Logger logger, ServiceRegistry registry)
{
@@ -190,7 +188,7 @@
// Lock the object to add the listener.
synchronized (this)
{
- Object[] listeners = null;
+ List<Object[]> listeners = null;
Object acc = null;
if (clazz == FrameworkListener.class)
@@ -227,32 +225,18 @@
throw new IllegalArgumentException("Unknown listener: " + l.getClass());
}
- // If we have no listeners, then just add the new listener.
- if (listeners == m_emptyList)
- {
- listeners = new Object[LISTENER_ARRAY_INCREMENT];
- listeners[LISTENER_BUNDLE_OFFSET] = bundle;
- listeners[LISTENER_CLASS_OFFSET] = clazz;
- listeners[LISTENER_OBJECT_OFFSET] = l;
- listeners[LISTENER_FILTER_OFFSET] = filter;
- listeners[LISTENER_SECURITY_OFFSET] = acc;
- }
- // 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
- {
- Object[] newList = new Object[listeners.length + LISTENER_ARRAY_INCREMENT];
- System.arraycopy(listeners, 0, newList, 0, listeners.length);
- newList[listeners.length + LISTENER_BUNDLE_OFFSET] = bundle;
- newList[listeners.length + LISTENER_CLASS_OFFSET] = clazz;
- newList[listeners.length + LISTENER_OBJECT_OFFSET] = l;
- newList[listeners.length + LISTENER_FILTER_OFFSET] = filter;
- newList[listeners.length + LISTENER_SECURITY_OFFSET] = acc;
- listeners = newList;
- }
+ // Add listener.
+ Object[] listener = new Object[LISTENER_ARRAY_SIZE];
+ listener[LISTENER_BUNDLE_OFFSET] = bundle;
+ listener[LISTENER_CLASS_OFFSET] = clazz;
+ listener[LISTENER_OBJECT_OFFSET] = l;
+ listener[LISTENER_FILTER_OFFSET] = filter;
+ listener[LISTENER_SECURITY_OFFSET] = acc;
+
+ List<Object[]> newListeners = new ArrayList<Object[]>(listeners.size() + 1);
+ newListeners.addAll(listeners);
+ newListeners.add(listener);
+ listeners = newListeners;
if (clazz == FrameworkListener.class)
{
@@ -296,7 +280,7 @@
// Lock the object to remove the listener.
synchronized (this)
{
- Object[] listeners = null;
+ List<Object[]> listeners = null;
if (clazz == FrameworkListener.class)
{
@@ -324,17 +308,18 @@
// Try to find the instance in our list.
int idx = -1;
- for (int i = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT)
+ for (int i = 0; i < listeners.size(); i++)
{
- if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) &&
- (listeners[i + LISTENER_CLASS_OFFSET] == clazz) &&
- (listeners[i + LISTENER_OBJECT_OFFSET] == l))
+ Object[] listener = listeners.get(i);
+ if (listener[LISTENER_BUNDLE_OFFSET].equals(bundle) &&
+ (listener[LISTENER_CLASS_OFFSET] == clazz) &&
+ (listener[LISTENER_OBJECT_OFFSET] == l))
{
// For service listeners, we must return some info about
// the listener for the ListenerHook callback.
if (ServiceListener.class == clazz)
{
- listenerInfo = wrapListener(listeners, i, true);
+ listenerInfo = wrapListener(listeners.get(i), true);
}
idx = i;
break;
@@ -345,9 +330,9 @@
if (idx >= 0)
{
// If this is the last listener, then point to empty list.
- if ((listeners.length - LISTENER_ARRAY_INCREMENT) == 0)
+ if (listeners.size() == 1)
{
- listeners = m_emptyList;
+ listeners = Collections.EMPTY_LIST;
}
// Otherwise, we need to do some array copying.
// Notice, the old array is always valid, so if
@@ -356,15 +341,9 @@
// and is not affected by the new value.
else
{
- Object[] newList = new Object[listeners.length - LISTENER_ARRAY_INCREMENT];
- System.arraycopy(listeners, 0, newList, 0, idx);
- if (idx < newList.length)
- {
- System.arraycopy(
- listeners, idx + LISTENER_ARRAY_INCREMENT,
- newList, idx, newList.length - idx);
- }
- listeners = newList;
+ List<Object[]> newListeners = new ArrayList<Object[]>(listeners);
+ newListeners.remove(idx);
+ listeners = newListeners;
}
}
@@ -404,73 +383,65 @@
synchronized (this)
{
// Remove all framework listeners associated with the specified bundle.
- Object[] listeners = m_frameworkListeners;
- for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
+ List<Object[]> newListeners = new ArrayList<Object[]>(m_frameworkListeners);
+ for (Iterator<Object[]> 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.
- Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
+ Object[] listener = it.next();
+ Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
if (bundle.equals(registeredBundle))
{
- Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET];
- EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
- removeListener(bundle, clazz, l);
+ it.remove();
}
}
+ m_frameworkListeners = newListeners;
// Remove all bundle listeners associated with the specified bundle.
- listeners = m_bundleListeners;
- for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
+ newListeners = new ArrayList<Object[]>(m_bundleListeners);
+ for (Iterator<Object[]> 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.
- Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
+ Object[] listener = it.next();
+ Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
if (bundle.equals(registeredBundle))
{
- Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET];
- EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
- removeListener(bundle, clazz, l);
+ it.remove();
}
}
+ m_bundleListeners = newListeners;
// Remove all synchronous bundle listeners associated with
// the specified bundle.
- listeners = m_syncBundleListeners;
- for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
+ newListeners = new ArrayList<Object[]>(m_syncBundleListeners);
+ for (Iterator<Object[]> 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.
- Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
+ Object[] listener = it.next();
+ Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
if (bundle.equals(registeredBundle))
{
- Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET];
- EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
- removeListener(bundle, clazz, l);
+ it.remove();
}
}
+ m_syncBundleListeners = newListeners;
// Remove all service listeners associated with the specified bundle.
- listeners = m_serviceListeners;
- for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
+ newListeners = new ArrayList<Object[]>(m_serviceListeners);
+ for (Iterator<Object[]> 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.
- Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
+ Object[] listener = it.next();
+ Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
if (bundle.equals(registeredBundle))
{
- Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET];
- EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
- removeListener(bundle, clazz, l);
+ it.remove();
}
}
+ m_serviceListeners = newListeners;
}
}
@@ -478,7 +449,7 @@
{
synchronized (this)
{
- Object[] listeners = null;
+ List<Object[]> listeners = null;
if (clazz == FrameworkListener.class)
{
@@ -502,11 +473,12 @@
// See if the listener is already registered, if so then
// handle it according to the spec.
- for (int i = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT)
+ for (int i = 0; i < listeners.size(); i++)
{
- if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) &&
- (listeners[i + LISTENER_CLASS_OFFSET] == clazz) &&
- (listeners[i + LISTENER_OBJECT_OFFSET] == l))
+ Object[] listener = listeners.get(i);
+ if (listener[LISTENER_BUNDLE_OFFSET].equals(bundle) &&
+ (listener[LISTENER_CLASS_OFFSET] == clazz) &&
+ (listener[LISTENER_OBJECT_OFFSET] == l))
{
Filter oldFilter = null;
if (clazz == FrameworkListener.class)
@@ -520,8 +492,8 @@
else if (clazz == ServiceListener.class)
{
// The spec says to update the filter in this case.
- oldFilter = (Filter) listeners[i + LISTENER_FILTER_OFFSET];
- listeners[i + LISTENER_FILTER_OFFSET] = filter;
+ oldFilter = (Filter) listener[LISTENER_FILTER_OFFSET];
+ listener[LISTENER_FILTER_OFFSET] = filter;
}
return oldFilter;
}
@@ -538,18 +510,19 @@
* @return Returns all existing service listener information into a collection of
* ListenerHook.ListenerInfo objects
**/
- public Collection /* <? extends ListenerHook.ListenerInfo> */ wrapAllServiceListeners(boolean removed)
+ public Collection /* <? extends ListenerHook.ListenerInfo> */
+ wrapAllServiceListeners(boolean removed)
{
- Object[] listeners = null;
+ List<Object[]> listeners = null;
synchronized (this)
{
listeners = m_serviceListeners;
}
List existingListeners = new ArrayList();
- for (int i = 0, j = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT, j++)
+ for (int i = 0; i < listeners.size(); i++)
{
- existingListeners.add(wrapListener(listeners, i, removed));
+ existingListeners.add(wrapListener(listeners.get(i), removed));
}
return existingListeners;
}
@@ -561,13 +534,13 @@
* @param offset The offset into the array of the listener to wrap.
* @return A ListenerHook.ListenerInfo object for the specified listener.
*/
- private static ListenerHook.ListenerInfo wrapListener(Object[] listeners, int offset, boolean removed)
+ private static ListenerHook.ListenerInfo wrapListener(Object[] listener, boolean removed)
{
- Filter filter = ((Filter)listeners[offset + LISTENER_FILTER_OFFSET]);
+ Filter filter = (Filter) listener[LISTENER_FILTER_OFFSET];
return new ListenerHookInfoImpl(
- ((Bundle)listeners[offset + LISTENER_BUNDLE_OFFSET]).getBundleContext(),
- (ServiceListener) listeners[offset + LISTENER_OBJECT_OFFSET],
+ ((Bundle)listener[LISTENER_BUNDLE_OFFSET]).getBundleContext(),
+ (ServiceListener) listener[LISTENER_OBJECT_OFFSET],
filter == null ? null : filter.toString(),
removed);
}
@@ -575,30 +548,38 @@
public void fireFrameworkEvent(FrameworkEvent event)
{
// Take a snapshot of the listener array.
- Object[] listeners = null;
+ List<Object[]> listeners = null;
synchronized (this)
{
listeners = m_frameworkListeners;
}
// Fire all framework listeners on a separate thread.
- fireEventAsynchronously(this, Request.FRAMEWORK_EVENT, listeners, event);
+ fireEventAsynchronously(this, Request.FRAMEWORK_EVENT, listeners, null, event);
}
- public void fireBundleEvent(BundleEvent event)
+ public void fireBundleEvent(BundleEvent event, Framework felix)
{
// Take a snapshot of the listener array.
- Object[] listeners = null;
- Object[] syncListeners = null;
+ List<Object[]> listeners = null;
+ List<Object[]> syncListeners = null;
synchronized (this)
{
listeners = m_bundleListeners;
syncListeners = m_syncBundleListeners;
}
+ // Create a whitelist of bundle context for bundle listeners,
+ // if we have hooks.
+ List<Object[]> allListeners = new ArrayList(listeners);
+ allListeners.addAll(syncListeners);
+ Set<BundleContext> whitelist =
+ createWhitelistFromHooks(
+ event, felix, allListeners, org.osgi.framework.hooks.bundle.EventHook.class);
+
// Fire synchronous bundle listeners immediately on the calling thread.
fireEventImmediately(
- this, Request.BUNDLE_EVENT, syncListeners, event, null);
+ this, Request.BUNDLE_EVENT, syncListeners, whitelist, event, null);
// The spec says that asynchronous bundle listeners do not get events
// of types STARTING, STOPPING, or LAZY_ACTIVATION.
@@ -607,7 +588,8 @@
(event.getType() != BundleEvent.LAZY_ACTIVATION))
{
// Fire asynchronous bundle listeners on a separate thread.
- fireEventAsynchronously(this, Request.BUNDLE_EVENT, listeners, event);
+ fireEventAsynchronously(
+ this, Request.BUNDLE_EVENT, listeners, whitelist, event);
}
}
@@ -615,32 +597,76 @@
final ServiceEvent event, final Dictionary oldProps, final Framework felix)
{
// Take a snapshot of the listener array.
- Object[] listeners = null;
+ List<Object[]> listeners = null;
synchronized (this)
{
listeners = m_serviceListeners;
}
- Set<ServiceReference<EventHook>> eventHooks = m_registry.getHooks(EventHook.class);
- if ((eventHooks != null) && !eventHooks.isEmpty())
+ // Create a whitelist of bundle context, if we have hooks.
+ Set<BundleContext> whitelist =
+ createWhitelistFromHooks(
+ event, felix, listeners, org.osgi.framework.hooks.service.EventHook.class);
+
+ // Fire all service events immediately on the calling thread.
+ fireEventImmediately(
+ this, Request.SERVICE_EVENT, listeners, whitelist, event, oldProps);
+ }
+
+
+ private Set<BundleContext> createWhitelistFromHooks(
+ EventObject event, Framework felix, List<Object[]> listeners, Class hookClass)
+ {
+ // Create a whitelist of bundle context, if we have hooks.
+ Set<BundleContext> whitelist = null;
+ Set<ServiceReference> hooks = m_registry.getHooks(hookClass);
+ if ((hooks != null) && !hooks.isEmpty())
{
- final ListenerBundleContextCollectionWrapper wrapper =
- new ListenerBundleContextCollectionWrapper(listeners);
- for (ServiceReference<EventHook> sr : eventHooks)
+ whitelist = new HashSet<BundleContext>();
+ for (Object[] listener : listeners)
+ {
+ BundleContext bc =
+ ((Bundle) listener[LISTENER_BUNDLE_OFFSET]).getBundleContext();
+ if (bc != null)
+ {
+ whitelist.add(bc);
+ }
+ }
+ int originalSize = whitelist.size();
+ ShrinkableCollection<BundleContext> shrinkable =
+ new ShrinkableCollection<BundleContext>(whitelist);
+ for (ServiceReference sr : hooks)
{
if (felix != null)
{
- EventHook eh = m_registry.getServiceSafely(felix, sr);
+ Object eh = null;
+ try
+ {
+ eh = m_registry.getService(felix, sr);
+ }
+ catch (Exception ex)
+ {
+ // If we can't get the hook, then ignore it.
+ }
if (eh != null)
{
try
{
- eh.event(event, wrapper);
+ if (eh instanceof org.osgi.framework.hooks.service.EventHook)
+ {
+ ((org.osgi.framework.hooks.service.EventHook)
+ eh).event((ServiceEvent) event, shrinkable);
+ }
+ else if (eh instanceof org.osgi.framework.hooks.bundle.EventHook)
+ {
+ ((org.osgi.framework.hooks.bundle.EventHook)
+ eh).event((BundleEvent) event, shrinkable);
+ }
}
catch (Throwable th)
{
m_logger.log(sr, Logger.LOG_WARNING,
- "Problem invoking service registry hook", th);
+ "Problem invoking event hook", th);
}
finally
{
@@ -649,17 +675,19 @@
}
}
}
-
- listeners = wrapper.getListeners();
+ // If the whitelist hasn't changed, then null it to avoid having
+ // to do whitelist lookups during event delivery.
+ if (originalSize == whitelist.size())
+ {
+ whitelist = null;
+ }
}
-
- // Fire all service events immediately on the calling thread.
- fireEventImmediately(
- this, Request.SERVICE_EVENT, listeners, event, oldProps);
+ return whitelist;
}
private static void fireEventAsynchronously(
- EventDispatcher dispatcher, int type, Object[] listeners, EventObject event)
+ EventDispatcher dispatcher, int type, List<Object[]> listeners,
+ Set<BundleContext> whitelist, EventObject event)
{
//TODO: should possibly check this within thread lock, seems to be ok though without
// If dispatch thread is stopped, then ignore dispatch request.
@@ -674,7 +702,7 @@
{
if (m_requestPool.size() > 0)
{
- req = (Request) m_requestPool.remove(0);
+ req = m_requestPool.remove(0);
}
else
{
@@ -686,6 +714,7 @@
req.m_dispatcher = dispatcher;
req.m_type = type;
req.m_listeners = listeners;
+ req.m_whitelist = whitelist;
req.m_event = event;
// Lock the request list.
@@ -699,46 +728,49 @@
}
private static void fireEventImmediately(
- EventDispatcher dispatcher, int type, Object[] listeners,
- EventObject event, Dictionary oldProps)
+ EventDispatcher dispatcher, int type, List<Object[]> listeners,
+ Set<BundleContext> whitelist, EventObject event, Dictionary oldProps)
{
- if (listeners.length > 0)
+ if (!listeners.isEmpty())
{
// Notify appropriate listeners.
- for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
+ for (Object[] listener : listeners)
{
- Bundle bundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
- EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
- Filter filter = (Filter) listeners[i + LISTENER_FILTER_OFFSET];
- Object acc = listeners[i + LISTENER_SECURITY_OFFSET];
- try
+ Bundle bundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
+ EventListener l = (EventListener) listener[LISTENER_OBJECT_OFFSET];
+ Filter filter = (Filter) listener[LISTENER_FILTER_OFFSET];
+ Object acc = listener[LISTENER_SECURITY_OFFSET];
+
+ // Only deliver events to bundles in the whitelist, if we have one.
+ if ((whitelist == null) || whitelist.contains(bundle.getBundleContext()))
{
- if (type == Request.FRAMEWORK_EVENT)
+ try
{
- invokeFrameworkListenerCallback(bundle, l, event);
+ if (type == Request.FRAMEWORK_EVENT)
+ {
+ invokeFrameworkListenerCallback(bundle, l, event);
+ }
+ else if (type == Request.BUNDLE_EVENT)
+ {
+ invokeBundleListenerCallback(bundle, l, event);
+ }
+ else if (type == Request.SERVICE_EVENT)
+ {
+ invokeServiceListenerCallback(
+ bundle, 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(bundle,
+ Logger.LOG_ERROR,
+ "EventDispatcher: Error during dispatch.", th);
+ dispatcher.fireFrameworkEvent(
+ new FrameworkEvent(FrameworkEvent.ERROR, bundle, th));
+ }
}
}
}
@@ -911,7 +943,7 @@
// Wait while there are no requests to dispatch. If the
// dispatcher thread is supposed to stop, then let the
// dispatcher thread exit the loop and stop.
- while ((m_requestList.size() == 0) && !m_stopping)
+ while (m_requestList.isEmpty() && !m_stopping)
{
// Wait until some signals us for work.
try
@@ -926,13 +958,13 @@
// If there are no events to dispatch and shutdown
// has been called then exit, otherwise dispatch event.
- if ((m_requestList.size() == 0) && (m_stopping))
+ if (m_requestList.isEmpty() && m_stopping)
{
return;
}
// Get the dispatch request.
- req = (Request) m_requestList.remove(0);
+ req = m_requestList.remove(0);
}
// Deliver event outside of synchronized block
@@ -942,7 +974,7 @@
// 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_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)
@@ -950,207 +982,13 @@
req.m_dispatcher = null;
req.m_type = -1;
req.m_listeners = null;
+ req.m_whitelist = null;
req.m_event = null;
m_requestPool.add(req);
}
}
}
- static class ListenerBundleContextCollectionWrapper implements Collection
- {
- private Object[] m_listeners;
-
- ListenerBundleContextCollectionWrapper(Object [] listeners)
- {
- m_listeners = listeners;
- }
-
- Object [] getListeners()
- {
- return m_listeners;
- }
-
- public boolean add(Object o)
- {
- throw new UnsupportedOperationException();
- }
-
- public boolean addAll(Collection c)
- {
- throw new UnsupportedOperationException();
- }
-
- public void clear()
- {
- m_listeners = new Object[0];
- }
-
- public boolean contains(Object o)
- {
- return indexOf(o) >= 0;
- }
-
- public boolean containsAll(Collection c)
- {
- for (Iterator it = c.iterator(); it.hasNext(); )
- {
- if (!contains(it.next()))
- {
- return false;
- }
- }
- return true;
- }
-
- private int indexOf(Object o)
- {
- if (!(o instanceof BundleContext))
- {
- return -1;
- }
-
- for (int i = m_listeners.length - LISTENER_ARRAY_INCREMENT;
- i >= 0;
- i -= LISTENER_ARRAY_INCREMENT)
- {
- Bundle bundle = (Bundle) m_listeners[i + LISTENER_BUNDLE_OFFSET];
- if (bundle != null)
- {
- if (bundle.getBundleContext().equals(o))
- {
- return i;
- }
- }
- }
- return -1;
- }
-
- public boolean isEmpty()
- {
- return m_listeners.length == 0;
- }
-
- public Iterator iterator()
- {
- return new WrapperIterator();
- }
-
- public boolean remove(Object o)
- {
- return removeIndex(indexOf(o));
- }
-
- private boolean removeIndex(int idx)
- {
- if (idx < 0)
- {
- return false;
- }
-
- Object [] newListeners = new Object[m_listeners.length - LISTENER_ARRAY_INCREMENT];
- System.arraycopy(m_listeners, 0, newListeners, 0, idx);
- System.arraycopy(m_listeners, idx + LISTENER_ARRAY_INCREMENT,
- newListeners, idx, newListeners.length - idx);
- m_listeners = newListeners;
-
- return true;
- }
-
- public boolean removeAll(Collection c)
- {
- boolean rv = false;
-
- for (Iterator it = c.iterator(); it.hasNext(); )
- {
- if (remove(it.next()))
- {
- rv = true;
- }
- }
-
- return rv;
- }
-
- public boolean retainAll(Collection c)
- {
- boolean rv = false;
-
- for (Iterator it = iterator(); it.hasNext(); )
- {
- if (!(c.contains(it.next())))
- {
- it.remove();
- rv = true;
- }
- }
-
- return rv;
- }
-
- public int size()
- {
- return m_listeners.length / LISTENER_ARRAY_INCREMENT;
- }
-
- public Object[] toArray()
- {
- Object [] array = new Object[size()];
- int idx = 0;
- for (Iterator it = iterator(); it.hasNext(); )
- {
- array[idx++] = it.next();
- }
- return array;
- }
-
- public Object[] toArray(Object[] a)
- {
- if (!(a.getClass().equals(Object[].class)))
- {
- throw new ArrayStoreException();
- }
- return toArray();
- }
-
- private class WrapperIterator implements Iterator
- {
- int curIdx = 0;
- int lastIdx = -1;
-
- private WrapperIterator() {}
-
- public boolean hasNext()
- {
- return curIdx < m_listeners.length;
- }
-
- public Object next()
- {
- if (!hasNext())
- {
- throw new NoSuchElementException();
- }
-
- Bundle b = (Bundle) m_listeners[curIdx + LISTENER_BUNDLE_OFFSET];
- lastIdx = curIdx;
- curIdx += LISTENER_ARRAY_INCREMENT;
- return b.getBundleContext();
- }
-
- public void remove()
- {
- if (lastIdx < 0)
- {
- throw new IllegalStateException();
- }
- removeIndex(lastIdx);
-
- curIdx = lastIdx;
- lastIdx = -1;
- }
- }
- }
-
private static class Request
{
public static final int FRAMEWORK_EVENT = 0;
@@ -1159,7 +997,8 @@
public EventDispatcher m_dispatcher = null;
public int m_type = -1;
- public Object[] m_listeners = null;
+ public List<Object[]> m_listeners = null;
+ public Set<BundleContext> m_whitelist = null;
public EventObject m_event = null;
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java
deleted file mode 100644
index ce0b3e7..0000000
--- a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.apache.felix.framework.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import junit.framework.TestCase;
-
-import org.easymock.EasyMock;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-public class EventDispatcherListenerWrapperTest extends TestCase
-{
- public void testRemove()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
- Bundle b3 = getMockBundle();
- BundleContext bc3 = b3.getBundleContext();
- Bundle b4 = getMockBundle();
- BundleContext bc4 = b4.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15), // LISTENER_SECURITY_OFFSET
- b3, // LISTENER_BUNDLE_OFFSET
- BundleContext.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- null, // LISTENER_FILTER_OFFSET
- Boolean.TRUE, // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- assertEquals(3, c.size());
- assertFalse(c.isEmpty());
- assertTrue(c.contains(bc1));
- assertTrue(c.contains(bc2));
- assertTrue(c.contains(bc3));
- assertFalse(c.contains(bc4));
-
- assertTrue(c.remove(bc2));
- assertEquals(2, c.size());
- assertTrue(c.contains(bc1));
- assertFalse(c.contains(bc2));
- assertTrue(c.contains(bc3));
- assertFalse(c.contains(bc4));
- assertFalse("Already removed", c.remove(bc2));
-
- Object[] actualListeners =
- ((EventDispatcher.ListenerBundleContextCollectionWrapper) c).getListeners();
- Object[] expectedListeners = new Object[EventDispatcher.LISTENER_ARRAY_INCREMENT * 2];
- System.arraycopy(listeners, 0, expectedListeners, 0,
- EventDispatcher.LISTENER_ARRAY_INCREMENT);
- System.arraycopy(
- listeners,
- EventDispatcher.LISTENER_ARRAY_INCREMENT * 2,
- expectedListeners,
- EventDispatcher.LISTENER_ARRAY_INCREMENT,
- EventDispatcher.LISTENER_ARRAY_INCREMENT);
- assertTrue(Arrays.equals(expectedListeners, actualListeners));
-
- assertTrue(c.remove(bc1));
- assertEquals(1, c.size());
- assertFalse(c.contains(bc1));
- assertFalse(c.contains(bc2));
- assertTrue(c.contains(bc3));
- assertFalse(c.contains(bc4));
- assertFalse(c.isEmpty());
-
- Object[] actualListeners2 =
- ((EventDispatcher.ListenerBundleContextCollectionWrapper) c).getListeners();
- Object[] expectedListeners2 = new Object[EventDispatcher.LISTENER_ARRAY_INCREMENT];
- System.arraycopy(
- listeners, EventDispatcher.LISTENER_ARRAY_INCREMENT * 2,
- expectedListeners2,
- 0,
- EventDispatcher.LISTENER_ARRAY_INCREMENT);
- assertTrue(Arrays.equals(expectedListeners2, actualListeners2));
-
- assertTrue(c.remove(bc3));
- assertEquals(0, c.size());
- assertFalse(c.contains(bc1));
- assertFalse(c.contains(bc2));
- assertFalse(c.contains(bc3));
- assertFalse(c.contains(bc4));
- assertTrue(c.isEmpty());
-
- Object[] actualListeners3 =
- ((EventDispatcher.ListenerBundleContextCollectionWrapper) c).getListeners();
- assertEquals(0, actualListeners3.length);
- }
-
- public void testIterator()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15) // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- Iterator it = c.iterator();
-
- assertEquals(2, c.size());
- assertTrue(it.hasNext());
- try
- {
- it.remove();
- fail("Should throw an exception");
- }
- catch (IllegalStateException ise)
- {
- // good
- }
- assertSame(bc1, it.next());
- it.remove();
- assertEquals(1, c.size());
-
- // Create another iterator and make sure it sees the removal of it
- Iterator it2 = c.iterator();
- assertTrue(it2.hasNext());
- assertSame(bc2, it2.next());
- assertFalse(it2.hasNext());
-
- // back to the origial iterator
-
- try
- {
- it.remove();
- fail("Should throw an exception");
- }
- catch (IllegalStateException ise)
- {
- // good
- }
- assertTrue(it.hasNext());
- try
- {
- it.remove();
- fail("Should throw an exception");
- }
- catch (IllegalStateException ise)
- {
- // good
- }
- assertSame(bc2, it.next());
- it.remove();
- assertEquals(0, c.size());
-
- assertFalse(it.hasNext());
- try
- {
- it.next();
- fail("Should throw an exception");
- }
- catch (NoSuchElementException nse)
- {
- // good
- }
- try
- {
- it.remove();
- fail("Should throw an exception");
- }
- catch (IllegalStateException ise)
- {
- // good
- }
- }
-
- public void testAdd()
- {
- Bundle b1 = getMockBundle();
- b1.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1,
- String.class,
- new Object(),
- "(some=filter)",
- null,
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- try
- {
- c.add(new Object());
- fail("Should not have been able to add to the collection");
- }
- catch (UnsupportedOperationException uoe)
- {
- // good
- }
- }
-
- public void testAddAll()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Object[] listeners =
- {
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- try
- {
- c.addAll(Collections.singleton(bc1));
- fail("Should not have been able to add to the collection");
- }
- catch (UnsupportedOperationException uoe)
- {
- // good
- }
- }
-
- public void testContainsAll()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
- Bundle b3 = getMockBundle();
- BundleContext bc3 = b3.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15), // LISTENER_SECURITY_OFFSET
- b3, // LISTENER_BUNDLE_OFFSET
- BundleContext.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- null, // LISTENER_FILTER_OFFSET
- Boolean.TRUE, // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
-
- assertTrue(c.containsAll(Collections.emptySet()));
- assertTrue(c.containsAll(Collections.singleton(bc2)));
- assertTrue(c.containsAll(Arrays.asList(new Object[]
- {
- bc2, bc1
- })));
- assertTrue(c.containsAll(Arrays.asList(new Object[]
- {
- bc3, bc2, bc1
- })));
- assertFalse(c.containsAll(Arrays.asList(new Object[]
- {
- bc3, bc2, bc1, new Object()
- })));
-
- assertEquals(3, c.size());
- c.clear();
- assertEquals(0, c.size());
- }
-
- public void testRemoveAll()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
- Bundle b3 = getMockBundle();
- BundleContext bc3 = b3.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15), // LISTENER_SECURITY_OFFSET
- b3, // LISTENER_BUNDLE_OFFSET
- BundleContext.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- null, // LISTENER_FILTER_OFFSET
- Boolean.TRUE, // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- assertFalse(c.removeAll(Collections.emptyList()));
- assertFalse(c.removeAll(Collections.singleton(new Object())));
- assertTrue(c.contains(bc2));
- assertTrue(c.removeAll(Arrays.asList(new Object[]
- {
- new Object(), bc2
- })));
- assertFalse(c.contains(bc2));
-
- assertEquals(2, c.size());
- assertTrue(c.removeAll(Arrays.asList(new Object[]
- {
- bc1, bc3
- })));
- assertEquals(0, c.size());
- }
-
- public void testRetainAll()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
- Bundle b3 = getMockBundle();
- BundleContext bc3 = b3.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15), // LISTENER_SECURITY_OFFSET
- b3, // LISTENER_BUNDLE_OFFSET
- BundleContext.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- null, // LISTENER_FILTER_OFFSET
- Boolean.TRUE, // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- assertFalse(c.retainAll(Arrays.asList(new Object[]
- {
- bc3, bc1, bc2
- })));
- assertTrue(Arrays.equals(new Object[]
- {
- bc1, bc2, bc3
- }, c.toArray()));
-
- assertTrue(c.retainAll(Arrays.asList(new Object[]
- {
- bc1, bc2, new Object()
- })));
- assertTrue(Arrays.equals(new Object[]
- {
- bc1, bc2
- }, c.toArray()));
-
- assertTrue(c.retainAll(Collections.emptyList()));
- assertEquals(0, c.size());
- }
-
- public void testToArray()
- {
- Bundle b1 = getMockBundle();
- BundleContext bc1 = b1.getBundleContext();
- Bundle b2 = getMockBundle();
- BundleContext bc2 = b2.getBundleContext();
-
- Object[] listeners = new Object[]
- {
- b1, // LISTENER_BUNDLE_OFFSET
- String.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some=filter)", // LISTENER_FILTER_OFFSET
- null, // LISTENER_SECURITY_OFFSET
- b2, // LISTENER_BUNDLE_OFFSET
- Integer.class, // LISTENER_CLASS_OFFSET
- new Object(), // LISTENER_OBJECT_OFFSET
- "(some.other=filter)", // LISTENER_FILTER_OFFSET
- new Integer(15), // LISTENER_SECURITY_OFFSET
- };
-
- Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
- assertTrue(Arrays.equals(new Object[]
- {
- bc1, bc2
- }, c.toArray()));
- assertTrue(Arrays.equals(new Object[]
- {
- bc1, bc2
- }, c.toArray(new Object[]
- {
- })));
-
- try
- {
- c.toArray(new String[]
- {
- });
- fail("Should not be allowed");
- }
- catch (ArrayStoreException ase)
- {
- // good
- }
- }
-
- private Bundle getMockBundle()
- {
- BundleContext bc = (BundleContext) EasyMock.createNiceMock(BundleContext.class);
- Bundle b = (Bundle) EasyMock.createNiceMock(Bundle.class);
- EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
- b.getState();
- EasyMock.expectLastCall().andReturn(Integer.valueOf(Bundle.ACTIVE)).anyTimes();
-
- EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
- EasyMock.replay(new Object[]
- {
- b, bc
- });
-
- return b;
- }
-}
\ No newline at end of file