Completely re-implemented Felix event dispatching. The new approach does
not try to be generic and is specifically tailored to OSGi, which makes
the resulting code much simpler...we replace 6 classes using a lot of
indirection with one class that can pretty much be understood sequentially.
(FELIX-5)
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@424991 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
index cdae189..847bd40 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
@@ -153,7 +153,7 @@
if (sm != null)
{
- if(l instanceof SynchronousBundleListener)
+ if (l instanceof SynchronousBundleListener)
{
((SecurityManager) sm).checkPermission(new AdminPermission(m_bundle,
AdminPermission.LISTENER));
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
index 9724413..20d6a5e 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -86,11 +86,7 @@
private Object m_nextIdLock = new Object[0];
// List of event listeners.
- private FelixDispatchQueue m_dispatchQueue = null;
- // Re-usable event dispatchers.
- private Dispatcher m_frameworkDispatcher = null;
- private Dispatcher m_bundleDispatcher = null;
- private Dispatcher m_serviceDispatcher = null;
+ private EventDispatcher m_dispatcher = null;
// Service registry.
private ServiceRegistry m_registry = null;
@@ -215,7 +211,7 @@
m_uninstalledBundles = null;
m_cache = null;
m_nextId = 1L;
- m_dispatchQueue = null;
+ m_dispatcher = null;
m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
m_registry = new ServiceRegistry(m_logger);
@@ -327,8 +323,8 @@
m_factory = new ModuleFactoryImpl(m_logger);
m_policyCore.setModuleFactory(m_factory);
- // Initialize dispatch queue.
- m_dispatchQueue = new FelixDispatchQueue(m_logger);
+ // Initialize event dispatcher.
+ m_dispatcher = new EventDispatcher(m_logger);
// Initialize framework properties.
initializeFrameworkProperties();
@@ -379,7 +375,7 @@
catch (Exception ex)
{
m_factory = null;
- DispatchQueue.shutdown();
+ EventDispatcher.shutdown();
m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
throw new RuntimeException("Unable to start system bundle.");
}
@@ -591,7 +587,7 @@
}
// Shutdown event dispatching queue.
- DispatchQueue.shutdown();
+ EventDispatcher.shutdown();
// The framework is no longer in a usable state.
m_frameworkStatus = INITIAL_STATUS;
@@ -1246,7 +1242,7 @@
m_registry.ungetServices(bundle);
// Remove any listeners registered by this bundle.
- removeListeners(bundle);
+ m_dispatcher.removeListeners(bundle);
// The spec says to expect BundleException or
// SecurityException, so rethrow these exceptions.
@@ -1572,7 +1568,7 @@
// The spec says that we must remove all event
// listeners for a bundle when it is stopped.
- removeListeners(bundle);
+ m_dispatcher.removeListeners(bundle);
info.setState(Bundle.RESOLVED);
fireBundleEvent(BundleEvent.STOPPED, bundle);
@@ -1964,25 +1960,12 @@
protected void addBundleListener(Bundle bundle, BundleListener l)
{
- // The spec says do nothing if the listener is
- // already registered.
- BundleListenerWrapper old = (BundleListenerWrapper)
- m_dispatchQueue.getListener(BundleListener.class, l);
- if (old == null)
- {
- l = new BundleListenerWrapper(bundle, l);
- m_dispatchQueue.addListener(BundleListener.class, l);
- }
+ m_dispatcher.addListener(bundle, BundleListener.class, l, null);
}
protected void removeBundleListener(Bundle bundle, BundleListener l)
{
- BundleListenerWrapper old = (BundleListenerWrapper)
- m_dispatchQueue.getListener(BundleListener.class, l);
- if ((old != null) && old.getBundle().equals(bundle))
- {
- m_dispatchQueue.removeListener(BundleListener.class, l);
- }
+ m_dispatcher.removeListener(bundle, BundleListener.class, l);
}
/**
@@ -1997,20 +1980,8 @@
protected void addServiceListener(Bundle bundle, ServiceListener l, String f)
throws InvalidSyntaxException
{
- // The spec says if the listener is already registered,
- // then replace filter.
- ServiceListenerWrapper old = (ServiceListenerWrapper)
- m_dispatchQueue.getListener(ServiceListener.class, l);
- if (old != null)
- {
- old.setFilter((f == null) ? null : new FilterImpl(m_logger, f));
- }
- else
- {
- l = new ServiceListenerWrapper(
- bundle, l, (f == null) ? null : new FilterImpl(m_logger, f));
- m_dispatchQueue.addListener(ServiceListener.class, l);
- }
+ m_dispatcher.addListener(
+ bundle, ServiceListener.class, l, (f == null) ? null : new FilterImpl(m_logger, f));
}
/**
@@ -2022,67 +1993,17 @@
**/
protected void removeServiceListener(Bundle bundle, ServiceListener l)
{
- ServiceListenerWrapper old = (ServiceListenerWrapper)
- m_dispatchQueue.getListener(ServiceListener.class, l);
- if ((old != null) && old.getBundle().equals(bundle))
- {
- m_dispatchQueue.removeListener(ServiceListener.class, l);
- }
+ m_dispatcher.removeListener(bundle, ServiceListener.class, l);
}
protected void addFrameworkListener(Bundle bundle, FrameworkListener l)
{
- // The spec says do nothing if the listener is
- // already registered.
- FrameworkListenerWrapper old = (FrameworkListenerWrapper)
- m_dispatchQueue.getListener(FrameworkListener.class, l);
- if (old == null)
- {
- l = new FrameworkListenerWrapper(bundle, l);
- m_dispatchQueue.addListener(FrameworkListener.class, l);
- }
+ m_dispatcher.addListener(bundle, FrameworkListener.class, l, null);
}
protected void removeFrameworkListener(Bundle bundle, FrameworkListener l)
{
- FrameworkListenerWrapper old = (FrameworkListenerWrapper)
- m_dispatchQueue.getListener(FrameworkListener.class, l);
- if ((old != null) && old.getBundle().equals(bundle))
- {
- m_dispatchQueue.removeListener(FrameworkListener.class, l);
- }
- }
-
- /**
- * Remove all of the specified bundle's event listeners from
- * the framework.
- * @param bundle The bundle whose listeners are to be removed.
- **/
- private void removeListeners(Bundle bundle)
- {
- if (bundle == null)
- {
- return;
- }
-
- // Remove all listeners associated with the supplied bundle;
- // it is only possible to know the bundle associated with a
- // listener if the listener was wrapper by a ListenerWrapper,
- // so look for those.
- Object[] listeners = m_dispatchQueue.getListeners();
- for (int i = listeners.length - 2; i >= 0; i -= 2)
- {
- // Check for listener wrappers and then compare the bundle.
- if (listeners[i + 1] instanceof ListenerWrapper)
- {
- ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
- if ((lw.getBundle() != null) && (lw.getBundle().equals(bundle)))
- {
- m_dispatchQueue.removeListener(
- (Class) listeners[i], (EventListener) listeners[i+1]);
- }
- }
- }
+ m_dispatcher.removeListener(bundle, FrameworkListener.class, l);
}
/**
@@ -2191,7 +2112,7 @@
ServiceReference ref = (ServiceReference) refList.get(refIdx);
// Now check for castability.
- if (!isServiceAssignable(bundle, ref))
+ if (!Felix.isServiceAssignable(bundle, ref))
{
refList.remove(refIdx);
refIdx--;
@@ -2215,7 +2136,7 @@
* @return <tt>true</tt> if the requesting bundle is able to case
* the service object to a known type.
**/
- protected boolean isServiceAssignable(BundleImpl requester, ServiceReference ref)
+ public static boolean isServiceAssignable(Bundle requester, ServiceReference ref)
{
// Boolean flag.
boolean allow = true;
@@ -2854,19 +2775,7 @@
private void fireFrameworkEvent(
int type, Bundle bundle, Throwable throwable)
{
- if (m_frameworkDispatcher == null)
- {
- m_frameworkDispatcher = new Dispatcher() {
- public void dispatch(EventListener l, EventObject eventObj)
- {
- ((FrameworkListener) l)
- .frameworkEvent((FrameworkEvent) eventObj);
- }
- };
- }
- FrameworkEvent event = new FrameworkEvent(type, bundle, throwable);
- m_dispatchQueue.dispatch(
- m_frameworkDispatcher, FrameworkListener.class, event);
+ m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle, throwable));
}
/**
@@ -2877,20 +2786,7 @@
**/
private void fireBundleEvent(int type, Bundle bundle)
{
- if (m_bundleDispatcher == null)
- {
- m_bundleDispatcher = new Dispatcher() {
- public void dispatch(EventListener l, EventObject eventObj)
- {
- ((BundleListener) l)
- .bundleChanged((BundleEvent) eventObj);
- }
- };
- }
- BundleEvent event = null;
- event = new BundleEvent(type, bundle);
- m_dispatchQueue.dispatch(m_bundleDispatcher,
- BundleListener.class, event);
+ m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle));
}
/**
@@ -2901,31 +2797,7 @@
**/
private void fireServiceEvent(ServiceEvent event)
{
- if (m_serviceDispatcher == null)
- {
- m_serviceDispatcher = new Dispatcher() {
- public void dispatch(EventListener l, EventObject eventObj)
- {
-// TODO: Filter service events based on service permissions.
- if (l instanceof ListenerWrapper)
- {
- BundleImpl bundle = (BundleImpl) ((ServiceListenerWrapper) l).getBundle();
- if (isServiceAssignable(bundle, ((ServiceEvent) eventObj).getServiceReference()))
- {
- ((ServiceListener) l)
- .serviceChanged((ServiceEvent) eventObj);
- }
- }
- else
- {
- ((ServiceListener) l)
- .serviceChanged((ServiceEvent) eventObj);
- }
- }
- };
- }
- m_dispatchQueue.dispatch(m_serviceDispatcher,
- ServiceListener.class, event);
+ m_dispatcher.fireServiceEvent(event);
}
//
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/BundleListenerWrapper.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/BundleListenerWrapper.java
deleted file mode 100644
index 7915f12..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/BundleListenerWrapper.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import org.osgi.framework.*;
-
-public class BundleListenerWrapper extends ListenerWrapper implements BundleListener
-{
- public BundleListenerWrapper(Bundle bundle, BundleListener l)
- {
- super(bundle,
- (l instanceof SynchronousBundleListener)
- ? SynchronousBundleListener.class : BundleListener.class,
- l);
- }
-
- public void bundleChanged(final BundleEvent event)
- {
- // A bundle listener is either synchronous or asynchronous.
- // If the bundle listener is synchronous, then deliver the
- // event to bundles with a state of STARTING, STOPPING, or
- // ACTIVE. If the listener is asynchronous, then deliver the
- // event only to bundles that are STARTING or ACTIVE.
- if (((getListenerClass() == SynchronousBundleListener.class) &&
- ((getBundle().getState() == Bundle.STARTING) ||
- (getBundle().getState() == Bundle.STOPPING) ||
- (getBundle().getState() == Bundle.ACTIVE)))
- ||
- ((getBundle().getState() == Bundle.STARTING) ||
- (getBundle().getState() == Bundle.ACTIVE)))
- {
- if (System.getSecurityManager() != null)
- {
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run()
- {
- ((BundleListener) getListener()).bundleChanged(event);
- return null;
- }
- });
- }
- else
- {
- ((BundleListener) getListener()).bundleChanged(event);
- }
- }
- }
-}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java
deleted file mode 100644
index b27278d..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/DispatchQueue.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.util.*;
-
-import org.apache.felix.framework.Logger;
-
-/**
- * This class implements an event dispatching queue to simplify delivering
- * events to a list of event listener. To use this class, simply create an
- * instance and use it to keep track of your event listeners, much like
- * <tt>javax.swing.event.EventListenerList</tt>. To dispatch an event,
- * simply create an instance of a <tt>Dispatcher</tt> and pass the instance
- * to <tt>DispatchQueue.dispatch()</tt> method, for example:
- * <pre>
- * Dispatcher d = new Dispatcher() {
- * public void dispatch(EventListener l, Object eventObj)
- * {
- * ((FooListener) l).fooXXX((FooEvent) eventObj);
- * }
- * };
- * FooEvent event = new FooEvent(this);
- * dispatchQueue.dispatch(d, FooListener.class, event);
- * </pre>
- * In the above code substitute a specific listener and event for the
- * <tt>Foo</tt> listener and event. Since <tt>Dispatcher</tt>s are
- * reusable, it is probably a good idea to create one for each type of
- * event to be delivered and just reuse them everytime to avoid unnecessary
- * memory allocation.
- * <p>
- * Currently, the <tt>DispatchQueue</tt> creates an internal thread with
- * which all events are delivered; this means that events are never delivered
- * using the caller's thread.
-**/
-public class DispatchQueue
-{
- // Representation of an empty listener list.
- private static final Object[] m_emptyList = new Object[0];
-
- // The event listeners for a particular queue instance.
- private Object[] m_listeners = m_emptyList;
-
- // A single thread is used to deliver events for all dispatchers.
- private static Thread m_thread = null;
- private static String m_threadLock = "thread lock";
- private static boolean m_stopping = false;
- private static boolean m_stopped = false;
-
- // List of dispatch requests.
- private static final ArrayList m_requestList = new ArrayList();
- // Cached dispatch requests to avoid memory allocation.
- private static final ArrayList m_requestCache = new ArrayList();
- // The logger for dispatch queue.
- private static Logger m_logger = null;
-
- /**
- * Constructs a dispatch queue and starts a dispather thread if
- * necessary.
- **/
- public DispatchQueue(Logger logger)
- {
- synchronized (m_threadLock)
- {
- // Start event dispatching thread if necessary.
- if (m_thread == null)
- {
- m_logger = logger;
- m_thread = new Thread(new Runnable() {
- public void run()
- {
- DispatchQueue.run();
- }
- }, "FelixDispatchQueue");
- m_thread.start();
- }
- }
- }
-
- /**
- * Terminates the dispatching thread for a graceful shutdown
- * of the dispatching queue; the caller will block until the
- * dispatching thread has completed all pending dispatches.
- * Since there is only one thread per all instances of
- * <tt>DispatchQueue</tt>, this method should only be called
- * prior to exiting the JVM.
- **/
- public static void shutdown()
- {
- synchronized (m_threadLock)
- {
- // Return if already stopped.
- if (m_stopped)
- {
- return;
- }
-
- // Signal dispatch thread.
- m_stopping = true;
- synchronized (m_requestList)
- {
- m_requestList.notify();
- }
-
- // Wait for dispatch thread to stop.
- while (!m_stopped)
- {
- try {
- m_threadLock.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
- }
-
- public static Logger getLogger()
- {
- return m_logger;
- }
-
- /**
- * Returns a pointer to the array of event listeners. The array stores pairs
- * of associated <tt>Class</tt> and <tt>EventListener</tt> objects; a pair
- * corresponds to the arguments passed in to the <tt>addListener()</tt> method.
- * Even numbered array elements are the class object and odd numbered elements
- * are the corresponding event listener instance.
- *
- * @return guaranteed to return a non-null object array.
- **/
- public Object[] getListeners()
- {
- return m_listeners;
- }
-
- /**
- * Returns the listener if it is already in the dispatch queue.
- * @param clazz the class of the listener to find.
- * @param l the listener instance to find.
- * @return the listener instance or <tt>null</tt> if the listener was
- * not found.
- **/
- public EventListener getListener(Class clazz, EventListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
- else if (!clazz.isInstance(l))
- {
- throw new IllegalArgumentException(
- "Listener not of type " + clazz.getName());
- }
-
- // Lock the object.
- synchronized (this)
- {
- // Try to find the instance in our list.
- for (int i = 0; i < m_listeners.length; i += 2)
- {
- if ((m_listeners[i] == clazz) &&
- (m_listeners[i + 1].equals(l)))
- {
- return (EventListener) m_listeners[i + 1];
- }
- }
- }
-
- return null;
- }
-
- /**
- * Adds a listener to the dispatch queue's listener list; the listener
- * is then able to receive events.
- *
- * @param clazz the class object associated with the event listener type.
- * @param l the instance of the event listener to add.
- **/
- public void addListener(Class clazz, EventListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
- else if (!clazz.isInstance(l))
- {
- throw new IllegalArgumentException(
- "Listener not of type " + clazz.getName());
- }
-
- // Lock the object.
- synchronized (this)
- {
- // If we have no listeners, then just add the new listener.
- if (m_listeners == m_emptyList)
- {
- m_listeners = new Object[] { clazz, l };
- }
- // 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[m_listeners.length + 2];
- System.arraycopy(m_listeners, 0, newList, 0, m_listeners.length);
- newList[m_listeners.length] = clazz;
- newList[m_listeners.length + 1] = l;
- m_listeners = newList;
- }
- }
- }
-
- /**
- * Removes a listener from the dispatch queue's listener list; the listener
- * is no longer able to receive events.
- *
- * @param clazz the class object associated with the event listener type.
- * @param l the instance of the event listener to remove.
- **/
- public void removeListener(Class clazz, EventListener l)
- {
- // Verify listener.
- if (l == null)
- {
- throw new IllegalArgumentException("Listener is null");
- }
- else if (!clazz.isInstance(l))
- {
- throw new IllegalArgumentException(
- "Listener not of type " + clazz.getName());
- }
-
- // Lock the object.
- synchronized (this)
- {
- // Try to find the instance in our list.
- int idx = -1;
- for (int i = 0; i < m_listeners.length; i += 2)
- {
- if ((m_listeners[i] == clazz) &&
- (m_listeners[i + 1].equals(l)))
- {
- 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 ((m_listeners.length - 2) == 0)
- {
- m_listeners = m_emptyList;
- }
- // 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[m_listeners.length - 2];
- System.arraycopy(m_listeners, 0, newList, 0, idx);
- if (idx < newList.length)
- {
- System.arraycopy(m_listeners, idx + 2, newList, idx,
- newList.length - idx);
- }
- m_listeners = newList;
- }
- }
- }
- }
-
- /**
- * Dispatches an event to a set of event listeners using a specified
- * dispatcher object.
- *
- * @param d the dispatcher used to actually dispatch the event; this
- * varies according to the type of event listener.
- * @param clazz the class associated with the target event listener type;
- * only event listeners of this type will receive the event.
- * @param eventObj the actual event object to dispatch.
- **/
- public void dispatch(Dispatcher d, Class clazz, EventObject eventObj)
- {
- dispatch(m_listeners, d, clazz, eventObj);
- }
-
- protected void dispatch(
- Object[] listeners, Dispatcher d, Class clazz, EventObject eventObj)
- {
- // If dispatch thread is stopped, then ignore dispatch request.
- if (m_stopped)
- {
- return;
- }
-
- // First get a dispatch request from the cache or
- // create one if necessary.
- DispatchRequest dr = null;
- synchronized (m_requestCache)
- {
- if (m_requestCache.size() > 0)
- dr = (DispatchRequest) m_requestCache.remove(0);
- else
- dr = new DispatchRequest();
- }
-
- // Initialize dispatch request.
- dr.m_listeners = listeners;
- dr.m_dispatcher = d;
- dr.m_clazz = clazz;
- dr.m_eventObj = eventObj;
-
- // Lock the request list.
- synchronized (m_requestList)
- {
- // Add our request to the list.
- m_requestList.add(dr);
- // Notify the dispatch thread that there is
- // work to do.
- m_requestList.notify();
- }
- }
-
- private static void run()
- {
- DispatchRequest dr = null;
- while (true)
- {
- // Lock the request list so we can try to get a
- // dispatch request from it.
- synchronized (m_requestList)
- {
- // 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)
- {
- // Wait until some signals us for work.
- try {
- m_requestList.wait();
- } catch (InterruptedException ex) {
- m_logger.log(Logger.LOG_ERROR, "DispatchQueue: Thread interrupted.", ex);
- }
- }
-
- // If there are no events to dispatch and shutdown
- // has been called then exit, otherwise dispatch event.
- if ((m_requestList.size() == 0) && (m_stopping))
- {
- synchronized (m_threadLock)
- {
- m_stopped = true;
- m_threadLock.notifyAll();
- }
- return;
- }
-
- // Get the dispatch request.
- dr = (DispatchRequest) m_requestList.remove(0);
- }
-
- // Deliver event outside of synchronized block
- // so that we don't block other requests from being
- // queued during event processing.
-
- // Try to dispatch to the listeners.
- if (dr.m_listeners.length > 0)
- {
- // Notify appropriate listeners.
- for (int i = dr.m_listeners.length - 2; i >= 0; i -= 2)
- {
- if (dr.m_listeners[i] == dr.m_clazz)
- {
- try {
- dr.m_dispatcher.dispatch(
- (EventListener) dr.m_listeners[i + 1], dr.m_eventObj);
- } catch (Throwable th) {
- m_logger.log(Logger.LOG_ERROR, "DispatchQueue: Error during dispatch.", th);
- }
- }
- }
- }
-
- // Put dispatch request in cache.
- synchronized (m_requestCache)
- {
- m_requestCache.add(dr);
- }
- }
- }
-
- private static class DispatchRequest
- {
- public Object[] m_listeners = null;
- public Dispatcher m_dispatcher = null;
- public Class m_clazz = null;
- public EventObject m_eventObj = null;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Dispatcher.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Dispatcher.java
deleted file mode 100644
index 0496e3b..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/Dispatcher.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.util.EventListener;
-import java.util.EventObject;
-
-/**
- * This interface is used by <tt>DispatchQueue</tt> to dispatch events.
- * Generally speaking, each type of event to dispatch will have an instance
- * of a <tt>Dispatcher</tt> so that the dispatch queue can dispatch to
- * the appropriate listener method for the specific listener type,
- * for example:
- * <pre>
- * Dispatcher d = new Dispatcher() {
- * public void dispatch(EventListener l, EventObject eventObj)
- * {
- * ((FooListener) l).fooXXX((FooEvent) eventObj);
- * }
- * };
- * FooEvent event = new FooEvent(this);
- * dispatchQueue.dispatch(d, FooListener.class, event);
- * </pre>
- * In the above code substitute a specific listener and event for the
- * <tt>Foo</tt> listener and event. <tt>Dispatcher</tt>s can be reused, so
- * it is a good idea to cache them to avoid unnecessary memory allocations.
-**/
-public interface Dispatcher
-{
- /**
- * Dispatch an event to a specified event listener.
- *
- * @param l the event listener to receive the event.
- * @param eventObj the event to dispatch.
- **/
- public void dispatch(EventListener l, EventObject eventObj);
-}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
new file mode 100644
index 0000000..ddcc34c
--- /dev/null
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -0,0 +1,784 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.framework.util;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.Logger;
+import org.osgi.framework.*;
+
+public class EventDispatcher
+{
+ private static final int LISTENER_BUNDLE_OFFSET = 0;
+ private static final int LISTENER_CLASS_OFFSET = 1;
+ private static final int LISTENER_OBJECT_OFFSET = 2;
+ private static final int LISTENER_FILTER_OFFSET = 3;
+ private static final int LISTENER_SECURITY_OFFSET = 4;
+ private static final int LISTENER_ARRAY_INCREMENT = 5;
+
+ // Framework instance for this dispatcher.
+ private Logger m_logger = null;
+
+ // 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;
+
+ // A single thread is used to deliver events for all dispatchers.
+ private static Thread m_thread = null;
+ private static String m_threadLock = "thread lock";
+ private static boolean m_stopping = false;
+ private static boolean m_stopped = false;
+ // List of requests.
+ private static final ArrayList m_requestList = new ArrayList();
+ // Pooled requests to avoid memory allocation.
+ private static final ArrayList m_requestPool = new ArrayList();
+
+ public EventDispatcher(Logger logger)
+ {
+ m_logger = logger;
+
+ synchronized (m_threadLock)
+ {
+ // Start event dispatching thread if necessary.
+ if (m_thread == null)
+ {
+ m_thread = new Thread(new Runnable() {
+ public void run()
+ {
+ EventDispatcher.run();
+ }
+ }, "FelixDispatchQueue");
+ m_thread.start();
+ }
+ }
+ }
+
+ public static void shutdown()
+ {
+ synchronized (m_threadLock)
+ {
+ // Return if already stopped.
+ if (m_stopped)
+ {
+ return;
+ }
+
+ // Signal dispatch thread.
+ m_stopping = true;
+ synchronized (m_requestList)
+ {
+ m_requestList.notify();
+ }
+
+ // Wait for dispatch thread to stop.
+ while (!m_stopped)
+ {
+ try
+ {
+ m_threadLock.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ }
+ }
+ }
+ }
+
+ public void addListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+ {
+ // Verify the listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+ else if (!clazz.isInstance(l))
+ {
+ throw new IllegalArgumentException(
+ "Listener not of type " + clazz.getName());
+ }
+
+ // See if we can simply update the listener, if so then
+ // return immediately.
+ if (updateListener(bundle, clazz, l, filter))
+ {
+ return;
+ }
+
+ // Lock the object to add the listener.
+ synchronized (this)
+ {
+ Object[] listeners = null;
+ Object acc = null;
+
+ if (clazz == FrameworkListener.class)
+ {
+ listeners = m_frameworkListeners;
+ }
+ else if (clazz == BundleListener.class)
+ {
+ if (SynchronousBundleListener.class.isInstance(l))
+ {
+ listeners = m_syncBundleListeners;
+ }
+ else
+ {
+ listeners = m_bundleListeners;
+ }
+ }
+ else if (clazz == ServiceListener.class)
+ {
+ // Remember security context for filtering service events.
+ Object sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ acc = ((SecurityManager) sm).getSecurityContext();
+ }
+
+ listeners = m_serviceListeners;
+ }
+ else
+ {
+ 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;
+ }
+
+ if (clazz == FrameworkListener.class)
+ {
+ m_frameworkListeners = listeners;
+ }
+ else if (clazz == BundleListener.class)
+ {
+ if (SynchronousBundleListener.class.isInstance(l))
+ {
+ m_syncBundleListeners = listeners;
+ }
+ else
+ {
+ m_bundleListeners = listeners;
+ }
+ }
+ else if (clazz == ServiceListener.class)
+ {
+ m_serviceListeners = listeners;
+ }
+ }
+ }
+
+ public void removeListener(Bundle bundle, Class clazz, EventListener l)
+ {
+ // Verify listener.
+ if (l == null)
+ {
+ throw new IllegalArgumentException("Listener is null");
+ }
+ else if (!clazz.isInstance(l))
+ {
+ throw new IllegalArgumentException(
+ "Listener not of type " + clazz.getName());
+ }
+
+ // Lock the object to remove the listener.
+ synchronized (this)
+ {
+ Object[] listeners = null;
+
+ if (clazz == FrameworkListener.class)
+ {
+ listeners = m_frameworkListeners;
+ }
+ else if (clazz == BundleListener.class)
+ {
+ if (SynchronousBundleListener.class.isInstance(l))
+ {
+ listeners = m_syncBundleListeners;
+ }
+ else
+ {
+ listeners = m_bundleListeners;
+ }
+ }
+ else if (clazz == ServiceListener.class)
+ {
+ listeners = m_serviceListeners;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Unknown listener: " + l.getClass());
+ }
+
+ // Try to find the instance in our list.
+ int idx = -1;
+ for (int i = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT)
+ {
+ if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) &&
+ (listeners[i + LISTENER_CLASS_OFFSET] == clazz) &&
+ listeners[i + LISTENER_OBJECT_OFFSET].equals(l))
+ {
+ 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.length - LISTENER_ARRAY_INCREMENT) == 0)
+ {
+ listeners = m_emptyList;
+ }
+ // 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, idx);
+ if (idx < newList.length)
+ {
+ System.arraycopy(
+ listeners, idx + LISTENER_ARRAY_INCREMENT,
+ newList, idx, newList.length - idx);
+ }
+ listeners = newList;
+ }
+ }
+
+ if (clazz == FrameworkListener.class)
+ {
+ m_frameworkListeners = listeners;
+ }
+ else if (clazz == BundleListener.class)
+ {
+ if (SynchronousBundleListener.class.isInstance(l))
+ {
+ m_syncBundleListeners = listeners;
+ }
+ else
+ {
+ m_bundleListeners = listeners;
+ }
+ }
+ else if (clazz == ServiceListener.class)
+ {
+ m_serviceListeners = listeners;
+ }
+ }
+ }
+
+ public void removeListeners(Bundle bundle)
+ {
+ if (bundle == null)
+ {
+ return;
+ }
+
+ 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)
+ {
+ // 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[LISTENER_BUNDLE_OFFSET];
+ if (bundle.equals(registeredBundle))
+ {
+ Class clazz = (Class) listeners[LISTENER_CLASS_OFFSET];
+ EventListener l = (EventListener) listeners[LISTENER_OBJECT_OFFSET];
+ removeListener(bundle, clazz, l);
+ }
+ }
+
+ // 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)
+ {
+ // 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[LISTENER_BUNDLE_OFFSET];
+ if (bundle.equals(registeredBundle))
+ {
+ Class clazz = (Class) listeners[LISTENER_CLASS_OFFSET];
+ EventListener l = (EventListener) listeners[LISTENER_OBJECT_OFFSET];
+ removeListener(bundle, clazz, l);
+ }
+ }
+
+ // 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)
+ {
+ // 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[LISTENER_BUNDLE_OFFSET];
+ if (bundle.equals(registeredBundle))
+ {
+ Class clazz = (Class) listeners[LISTENER_CLASS_OFFSET];
+ EventListener l = (EventListener) listeners[LISTENER_OBJECT_OFFSET];
+ removeListener(bundle, clazz, l);
+ }
+ }
+
+ // 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)
+ {
+ // 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[LISTENER_BUNDLE_OFFSET];
+ if (bundle.equals(registeredBundle))
+ {
+ Class clazz = (Class) listeners[LISTENER_CLASS_OFFSET];
+ EventListener l = (EventListener) listeners[LISTENER_OBJECT_OFFSET];
+ removeListener(bundle, clazz, l);
+ }
+ }
+ }
+ }
+
+ public boolean updateListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+ {
+ synchronized (this)
+ {
+ Object[] listeners = null;
+
+ if (clazz == FrameworkListener.class)
+ {
+ listeners = m_frameworkListeners;
+ }
+ else if (clazz == BundleListener.class)
+ {
+ if (SynchronousBundleListener.class.isInstance(l))
+ {
+ 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.length; i += LISTENER_ARRAY_INCREMENT)
+ {
+ if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) &&
+ (listeners[i + LISTENER_CLASS_OFFSET] == clazz) &&
+ listeners[i + LISTENER_OBJECT_OFFSET].equals(l))
+ {
+ if (l instanceof FrameworkListener)
+ {
+ // The spec says to ignore this case.
+ }
+ else if (l instanceof BundleListener)
+ {
+ // The spec says to ignore this case.
+ }
+ else if (l instanceof ServiceListener)
+ {
+ // The spec says to update the filter in this case.
+ listeners[i + LISTENER_FILTER_OFFSET] = filter;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public void fireFrameworkEvent(FrameworkEvent event)
+ {
+ // Take a snapshot of the listener array.
+ Object[] listeners = null;
+ synchronized (this)
+ {
+ listeners = m_frameworkListeners;
+ }
+
+ // Fire all framework listeners on a separate thread.
+ fireEventAsynchronously(m_logger, Request.FRAMEWORK_EVENT, listeners, event);
+ }
+
+ public void fireBundleEvent(BundleEvent event)
+ {
+ // Take a snapshot of the listener array.
+ Object[] listeners = null;
+ Object[] syncListeners = null;
+ synchronized (this)
+ {
+ listeners = m_bundleListeners;
+ syncListeners = m_syncBundleListeners;
+ }
+
+ // Fire synchronous bundle listeners immediately on the calling thread.
+ fireEventImmediately(m_logger, Request.BUNDLE_EVENT, syncListeners, event);
+
+ // Fire asynchronous bundle listeners on a separate thread.
+ fireEventAsynchronously(m_logger, Request.BUNDLE_EVENT, listeners, event);
+ }
+
+ public void fireServiceEvent(ServiceEvent event)
+ {
+ // Take a snapshot of the listener array.
+ Object[] listeners = null;
+ synchronized (this)
+ {
+ listeners = m_serviceListeners;
+ }
+
+ // Fire all service events immediately on the calling thread.
+ fireEventImmediately(m_logger, Request.SERVICE_EVENT, listeners, event);
+ }
+
+ private void fireEventAsynchronously(
+ Logger logger, int type, Object[] listeners, EventObject event)
+ {
+ // If dispatch thread is stopped, then ignore dispatch request.
+ if (m_stopped || m_stopping)
+ {
+ return;
+ }
+
+ // First get a request from the pool or create one if necessary.
+ Request req = null;
+ synchronized (m_requestPool)
+ {
+ if (m_requestPool.size() > 0)
+ {
+ req = (Request) m_requestPool.remove(0);
+ }
+ else
+ {
+ req = new Request();
+ }
+ }
+
+ // Initialize dispatch request.
+ req.m_logger = logger;
+ req.m_type = type;
+ req.m_listeners = listeners;
+ req.m_event = event;
+
+ // Lock the request list.
+ synchronized (m_requestList)
+ {
+ // Add our request to the list.
+ m_requestList.add(req);
+ // Notify the dispatch thread that there is work to do.
+ m_requestList.notify();
+ }
+ }
+
+ private static void fireEventImmediately(
+ Logger logger, int type, Object[] listeners, EventObject event)
+ {
+ if (listeners.length > 0)
+ {
+ // Notify appropriate listeners.
+ for (int i = listeners.length - LISTENER_ARRAY_INCREMENT;
+ i >= 0;
+ i -= LISTENER_ARRAY_INCREMENT)
+ {
+ 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
+ {
+ 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);
+ }
+ }
+ catch (Throwable th)
+ {
+ logger.log(
+ Logger.LOG_ERROR,
+ "EventDispatcher: Error during dispatch.", th);
+ }
+ }
+ }
+ }
+
+ private static void invokeFrameworkListenerCallback(
+ Bundle bundle, final EventListener l, final EventObject event)
+ {
+ // The spec says only active bundles receive asynchronous events,
+ // but we will include starting bundles too otherwise
+ // it is impossible to see everything.
+ if ((bundle.getState() == Bundle.STARTING) ||
+ (bundle.getState() == Bundle.ACTIVE))
+ {
+ if (System.getSecurityManager() != null)
+ {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run()
+ {
+ ((FrameworkListener) l).frameworkEvent((FrameworkEvent) event);
+ return null;
+ }
+ });
+ }
+ else
+ {
+ ((FrameworkListener) l).frameworkEvent((FrameworkEvent) event);
+ }
+ }
+ }
+
+ private static void invokeBundleListenerCallback(
+ Bundle bundle, final EventListener l, final EventObject event)
+ {
+ // A bundle listener is either synchronous or asynchronous.
+ // If the bundle listener is synchronous, then deliver the
+ // event to bundles with a state of STARTING, STOPPING, or
+ // ACTIVE. If the listener is asynchronous, then deliver the
+ // event only to bundles that are STARTING or ACTIVE.
+ if (((SynchronousBundleListener.class.isAssignableFrom(l.getClass())) &&
+ ((bundle.getState() == Bundle.STARTING) ||
+ (bundle.getState() == Bundle.STOPPING) ||
+ (bundle.getState() == Bundle.ACTIVE)))
+ ||
+ ((bundle.getState() == Bundle.STARTING) ||
+ (bundle.getState() == Bundle.ACTIVE)))
+ {
+ if (System.getSecurityManager() != null)
+ {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run()
+ {
+ ((BundleListener) l).bundleChanged((BundleEvent) event);
+ return null;
+ }
+ });
+ }
+ else
+ {
+ ((BundleListener) l).bundleChanged((BundleEvent) event);
+ }
+ }
+ }
+
+ private static void invokeServiceListenerCallback(
+ Bundle bundle, final EventListener l, Filter filter, Object acc, final EventObject event)
+ {
+ // Service events should be delivered to STARTING,
+ // STOPPING, and ACTIVE bundles.
+ if ((bundle.getState() != Bundle.STARTING) &&
+ (bundle.getState() != Bundle.STOPPING) &&
+ (bundle.getState() != Bundle.ACTIVE))
+ {
+ return;
+ }
+
+ // Check that the bundle has permission to get at least
+ // one of the service interfaces; the objectClass property
+ // of the service stores its service interfaces.
+ ServiceReference ref = ((ServiceEvent) event).getServiceReference();
+ String[] objectClass = (String[]) ref.getProperty(Constants.OBJECTCLASS);
+
+ // On the safe side, if there is no objectClass property
+ // then ignore event altogether.
+ if (objectClass != null)
+ {
+ boolean hasPermission = false;
+
+ Object sm = System.getSecurityManager();
+ if ((acc != null) && (sm != null))
+ {
+ for (int i = 0;
+ !hasPermission && (i < objectClass.length);
+ i++)
+ {
+ try
+ {
+ ServicePermission perm =
+ new ServicePermission(
+ objectClass[i], ServicePermission.GET);
+ ((SecurityManager) sm).checkPermission(perm, acc);
+ hasPermission = true;
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+ else
+ {
+ hasPermission = true;
+ }
+
+ if (hasPermission)
+ {
+ // Dispatch according to the filter.
+ if ((filter == null) || filter.match(((ServiceEvent) event).getServiceReference()))
+ {
+ if (Felix.isServiceAssignable(bundle, ((ServiceEvent) event).getServiceReference()))
+ {
+ if (System.getSecurityManager() != null)
+ {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run()
+ {
+ ((ServiceListener) l).serviceChanged((ServiceEvent) event);
+ return null;
+ }
+ });
+ }
+ else
+ {
+ {
+ ((ServiceListener) l).serviceChanged((ServiceEvent) event);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This is the dispatching thread's main loop.
+ **/
+ private static void run()
+ {
+ Request req = null;
+ while (true)
+ {
+ // Lock the request list so we can try to get a
+ // dispatch request from it.
+ synchronized (m_requestList)
+ {
+ // 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)
+ {
+ // Wait until some signals us for work.
+ try
+ {
+ m_requestList.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ // Not much we can do here except for keep waiting.
+ }
+ }
+
+ // If there are no events to dispatch and shutdown
+ // has been called then exit, otherwise dispatch event.
+ if ((m_requestList.size() == 0) && (m_stopping))
+ {
+ synchronized (m_threadLock)
+ {
+ m_stopped = true;
+ m_threadLock.notifyAll();
+ }
+ return;
+ }
+
+ // Get the dispatch request.
+ req = (Request) m_requestList.remove(0);
+ }
+
+ // Deliver event outside of synchronized block
+ // so that we don't block other requests from being
+ // queued during event processing.
+ fireEventImmediately(req.m_logger, req.m_type, req.m_listeners, req.m_event);
+
+ // Put dispatch request in cache.
+ synchronized (m_requestPool)
+ {
+ req.m_logger = null;
+ req.m_type = -1;
+ req.m_listeners = null;
+ req.m_event = null;
+ m_requestPool.add(req);
+ }
+ }
+ }
+
+ private static class Request
+ {
+ public static final int FRAMEWORK_EVENT = 0;
+ public static final int BUNDLE_EVENT = 1;
+ public static final int SERVICE_EVENT = 2;
+
+ public Logger m_logger = null;
+ public int m_type = -1;
+ public Object[] m_listeners = null;
+ public EventObject m_event = null;
+ }
+}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java
deleted file mode 100644
index 354c05b..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FelixDispatchQueue.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.util.EventListener;
-import java.util.EventObject;
-
-import org.apache.felix.framework.Logger;
-import org.osgi.framework.*;
-
-/**
- * This is a subclass of <tt>DispatchQueue</tt> that specifically adds support
- * for <tt>SynchronousBundleListener</tt>s; the OSGi specification
- * says that synchronous bundle listeners should receive their events
- * immediately, i.e., they should not be delivered on a separate thread
- * like is the case with the <tt>DispatchQueue</tt>. To achieve this
- * functionality, this class overrides the dispatch method to automatically
- * fire any bundle events to synchronous bundle listeners using the
- * calling thread. In order to ensure that synchronous bundle listeners
- * do not receive an event twice, it wraps the passed in <tt>Dipatcher</tt>
- * instance so that it filters synchronous bundle listeners.
-**/
-public class FelixDispatchQueue extends DispatchQueue
-{
- public FelixDispatchQueue(Logger logger)
- {
- super(logger);
- }
-
- /**
- * Dispatches an event to a set of event listeners using a specified
- * dispatcher object. This overrides the definition of the super class
- * to deliver events to <tt>ServiceListener</tt>s and
- * <tt>SynchronousBundleListener</tt>s using
- * the calling thread instead of the event dispatching thread. All
- * other events are still delivered asynchronously.
- *
- * @param dispatcher the dispatcher used to actually dispatch the event; this
- * varies according to the type of event listener.
- * @param clazz the class associated with the target event listener type;
- * only event listeners of this type will receive the event.
- * @param eventObj the actual event object to dispatch.
- **/
- public void dispatch(Dispatcher dispatcher, Class clazz, EventObject eventObj)
- {
- Object[] listeners = getListeners();
-
- // If this is an event for service listeners, then dispatch it
- // immediately since service events are never asynchronous.
- if ((clazz == ServiceListener.class) && (listeners.length > 0))
- {
- // Notify appropriate listeners.
- for (int i = listeners.length - 2; i >= 0; i -= 2)
- {
- // If the original listener is a synchronous bundle listener
- // or a service listener, then dispatch event immediately
- // per the specification.
- ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
- if (lw.getListenerClass() == ServiceListener.class)
- {
- try {
- dispatcher.dispatch(
- (EventListener) lw, eventObj);
- } catch (Throwable th) {
- getLogger().log(
- Logger.LOG_ERROR,
- "FelixDispatchQueue: Error during dispatch.", th);
- }
- }
- }
- }
- // Dispatch bundle events to synchronous bundle listeners immediately,
- // but deliver to standard bundle listeners asynchronously.
- else if ((clazz == BundleListener.class) && (listeners.length > 0))
- {
- // Notify appropriate listeners.
- for (int i = listeners.length - 2; i >= 0; i -= 2)
- {
- // If the original listener is a synchronous bundle listener,
- // then dispatch event immediately per the specification.
- ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
- if (lw.getListenerClass() == SynchronousBundleListener.class)
- {
- try {
- dispatcher.dispatch(
- (EventListener) lw, eventObj);
- } catch (Throwable th) {
- getLogger().log(
- Logger.LOG_ERROR,
- "FelixDispatchQueue: Error during dispatch.", th);
- }
- }
- }
-
- // Wrap the dispatcher so that it ignores synchronous
- // bundle listeners since they have already been dispatched.
- IgnoreSynchronousDispatcher ignoreDispatcher = new IgnoreSynchronousDispatcher();
- ignoreDispatcher.setDispatcher(dispatcher);
-
- // Dispatch the bundle listener asynchronously.
- dispatch(listeners, ignoreDispatcher, clazz, eventObj);
- }
- // All other events are dispatched asynchronously.
- else
- {
- dispatch(listeners, dispatcher, clazz, eventObj);
- }
- }
-
- private static class IgnoreSynchronousDispatcher implements Dispatcher
- {
- private Dispatcher m_dispatcher = null;
-
- public void setDispatcher(Dispatcher dispatcher)
- {
- m_dispatcher = dispatcher;
- }
-
- public void dispatch(EventListener l, EventObject eventObj)
- {
- if (l instanceof ListenerWrapper)
- {
- ListenerWrapper lw = (ListenerWrapper) l;
- // Do not dispatch events to synchronous listeners,
- // since they are dispatched immediately above.
- if (!(lw.getListenerClass() == SynchronousBundleListener.class))
- {
- m_dispatcher.dispatch(l, eventObj);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FrameworkListenerWrapper.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FrameworkListenerWrapper.java
deleted file mode 100644
index e0cfdc9..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/FrameworkListenerWrapper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-import org.osgi.framework.*;
-
-public class FrameworkListenerWrapper extends ListenerWrapper implements FrameworkListener
-{
- public FrameworkListenerWrapper(Bundle bundle, FrameworkListener l)
- {
- super(bundle, FrameworkListener.class, l);
- }
-
- public void frameworkEvent(final FrameworkEvent event)
- {
- // The spec says only active bundles receive asynchronous events,
- // but we will include starting bundles too otherwise
- // it is impossible to see everything.
- if ((getBundle().getState() == Bundle.STARTING) ||
- (getBundle().getState() == Bundle.ACTIVE))
- {
- if (System.getSecurityManager() != null)
- {
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run()
- {
- ((FrameworkListener) getListener()).frameworkEvent(event);
- return null;
- }
- });
- }
- else
- {
- ((FrameworkListener) getListener()).frameworkEvent(event);
- }
- }
- }
-}
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ListenerWrapper.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ListenerWrapper.java
deleted file mode 100644
index eb40c93..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ListenerWrapper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2005 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.util.EventListener;
-
-import org.osgi.framework.Bundle;
-
-public class ListenerWrapper
-{
- // The bundle associated with the listener.
- private Bundle m_bundle = null;
- // Listener class.
- private Class m_class = null;
- // The original listener.
- private EventListener m_listener = null;
-
- public ListenerWrapper(Bundle bundle, Class clazz, EventListener l)
- {
- m_bundle = bundle;
- m_class = clazz;
- m_listener = l;
- }
-
- public Bundle getBundle()
- {
- return m_bundle;
- }
-
- protected Class getListenerClass()
- {
- return m_class;
- }
-
- protected EventListener getListener()
- {
- return m_listener;
- }
-
- public boolean equals(Object obj)
- {
- if (obj instanceof ListenerWrapper)
- {
- return (((ListenerWrapper) obj).m_listener == m_listener);
- }
- else if (obj instanceof EventListener)
- {
- return (obj == m_listener);
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ServiceListenerWrapper.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ServiceListenerWrapper.java
deleted file mode 100644
index 2d5f992..0000000
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/util/ServiceListenerWrapper.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.apache.felix.framework.util;
-
-import java.security.*;
-
-import org.osgi.framework.*;
-
-public class ServiceListenerWrapper extends ListenerWrapper implements ServiceListener
-{
- // LDAP query filter.
- private Filter m_filter = null;
- // Remember the security context.
- private Object m_acc = null;
-
- public ServiceListenerWrapper(Bundle bundle, ServiceListener l, Filter filter)
- {
- super(bundle, ServiceListener.class, l);
- m_filter = filter;
-
- // Remember security context for filtering
- // events based on security.
- Object sm = System.getSecurityManager();
-
- if (sm != null)
- {
- m_acc = ((SecurityManager) sm).getSecurityContext();
- }
- }
-
- public void setFilter(Filter filter)
- {
- m_filter = filter;
- }
-
- public void serviceChanged(final ServiceEvent event)
- {
- // Service events should be delivered to STARTING,
- // STOPPING, and ACTIVE bundles.
- if ((getBundle().getState() != Bundle.STARTING) &&
- (getBundle().getState() != Bundle.STOPPING) &&
- (getBundle().getState() != Bundle.ACTIVE))
- {
- return;
- }
-
- // Check that the bundle has permission to get at least
- // one of the service interfaces; the objectClass property
- // of the service stores its service interfaces.
- ServiceReference ref = event.getServiceReference();
- String[] objectClass = (String[]) ref.getProperty(Constants.OBJECTCLASS);
-
- // On the safe side, if there is no objectClass property
- // then ignore event altogether.
- if (objectClass != null)
- {
- boolean hasPermission = false;
-
- Object sm = System.getSecurityManager();
-
- if ((m_acc != null) && (sm != null))
- {
- for (int i = 0;
- !hasPermission && (i < objectClass.length);
- i++)
- {
- try
- {
- ServicePermission perm =
- new ServicePermission(
- objectClass[i], ServicePermission.GET);
- ((SecurityManager) sm).checkPermission(perm, m_acc);
- hasPermission = true;
- }
- catch (Exception ex)
- {
- }
- }
- }
- else
- {
- hasPermission = true;
- }
-
- if (hasPermission)
- {
- // Dispatch according to the filter.
- if ((m_filter == null) || m_filter.match(event.getServiceReference()))
- {
- if (System.getSecurityManager() != null)
- {
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run()
- {
- ((ServiceListener) getListener()).serviceChanged(event);
- return null;
- }
- });
- }
- else
- {
- ((ServiceListener) getListener()).serviceChanged(event);
- }
- }
- }
- }
- }
-}
\ No newline at end of file