Some clean up in preparation for implementing event listener hook. (FELIX-3056)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1151194 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 071818b..c22f80f 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -32,7 +32,7 @@
import org.apache.felix.framework.resolver.ResolveException;
import org.apache.felix.framework.util.EventDispatcher;
import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.ListenerHookInfoImpl;
+import org.apache.felix.framework.util.ListenerInfo;
import org.apache.felix.framework.util.MapToDictionary;
import org.apache.felix.framework.util.SecureAction;
import org.apache.felix.framework.util.ShrinkableCollection;
@@ -3071,12 +3071,12 @@
}
Filter oldFilter;
+ Filter newFilter = (f == null) ? null : FrameworkUtil.createFilter(f);
try
{
oldFilter = m_dispatcher.addListener(
- bundle, ServiceListener.class, l,
- (f == null) ? null : FrameworkUtil.createFilter(f));
+ bundle, ServiceListener.class, l, newFilter);
}
finally
{
@@ -3089,8 +3089,7 @@
if (oldFilter != null)
{
final Collection removed = Collections.singleton(
- new ListenerHookInfoImpl(
- ((BundleImpl) bundle)._getBundleContext(), l, oldFilter.toString(), true));
+ new ListenerInfo(bundle, ServiceListener.class, l, oldFilter, null, true));
for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
@@ -3115,7 +3114,7 @@
// Invoke the ListenerHook.added() on all hooks.
final Collection added = Collections.singleton(
- new ListenerHookInfoImpl(((BundleImpl) bundle)._getBundleContext(), l, f, false));
+ new ListenerInfo(bundle, ServiceListener.class, l, newFilter, null, false));
for (ServiceReference<org.osgi.framework.hooks.service.ListenerHook> sr : listenerHooks)
{
org.osgi.framework.hooks.service.ListenerHook lh = getService(this, sr);
@@ -3287,7 +3286,7 @@
{
try
{
- lh.added(m_dispatcher.wrapAllServiceListeners(false));
+ lh.added(m_dispatcher.getAllServiceListeners());
}
catch (Throwable th)
{
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 9d7f9a5..4da06a0 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
@@ -26,10 +26,12 @@
import java.util.Dictionary;
import java.util.EventListener;
import java.util.EventObject;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.NoSuchElementException;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import org.apache.felix.framework.Logger;
@@ -52,20 +54,13 @@
public class EventDispatcher
{
- static final int LISTENER_BUNDLE_OFFSET = 0;
- static final int LISTENER_CLASS_OFFSET = 1;
- 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_SIZE = 5;
-
private final Logger m_logger;
private final ServiceRegistry m_registry;
- 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;
+ private List<ListenerInfo> m_frameworkListeners = Collections.EMPTY_LIST;
+ private List<ListenerInfo> m_bundleListeners = Collections.EMPTY_LIST;
+ private List<ListenerInfo> m_syncBundleListeners = Collections.EMPTY_LIST;
+ private List<ListenerInfo> m_serviceListeners = Collections.EMPTY_LIST;
// A single thread is used to deliver events for all dispatchers.
private static Thread m_thread = null;
@@ -188,7 +183,7 @@
// Lock the object to add the listener.
synchronized (this)
{
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
Object acc = null;
if (clazz == FrameworkListener.class)
@@ -226,14 +221,10 @@
}
// 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;
+ ListenerInfo listener =
+ new ListenerInfo(bundle, clazz, l, filter, acc, false);
- List<Object[]> newListeners = new ArrayList<Object[]>(listeners.size() + 1);
+ List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(listeners.size() + 1);
newListeners.addAll(listeners);
newListeners.add(listener);
listeners = newListeners;
@@ -280,7 +271,7 @@
// Lock the object to remove the listener.
synchronized (this)
{
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
if (clazz == FrameworkListener.class)
{
@@ -310,16 +301,16 @@
int idx = -1;
for (int i = 0; i < listeners.size(); i++)
{
- Object[] listener = listeners.get(i);
- if (listener[LISTENER_BUNDLE_OFFSET].equals(bundle) &&
- (listener[LISTENER_CLASS_OFFSET] == clazz) &&
- (listener[LISTENER_OBJECT_OFFSET] == l))
+ ListenerInfo listener = listeners.get(i);
+ if (listener.getBundle().equals(bundle) &&
+ (listener.getListenerClass() == clazz) &&
+ (listener.getListener() == l))
{
// For service listeners, we must return some info about
// the listener for the ListenerHook callback.
if (ServiceListener.class == clazz)
{
- listenerInfo = wrapListener(listeners.get(i), true);
+ listenerInfo = new ListenerInfo(listeners.get(i), true);
}
idx = i;
break;
@@ -341,7 +332,7 @@
// and is not affected by the new value.
else
{
- List<Object[]> newListeners = new ArrayList<Object[]>(listeners);
+ List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(listeners);
newListeners.remove(idx);
listeners = newListeners;
}
@@ -383,14 +374,12 @@
synchronized (this)
{
// Remove all framework listeners associated with the specified bundle.
- List<Object[]> newListeners = new ArrayList<Object[]>(m_frameworkListeners);
- for (Iterator<Object[]> it = newListeners.iterator(); it.hasNext(); )
+ List<ListenerInfo> newListeners = new ArrayList<ListenerInfo>(m_frameworkListeners);
+ for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
{
// Check if the bundle associated with the current listener
// is the same as the specified bundle, if so remove the listener.
- Object[] listener = it.next();
- Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
- if (bundle.equals(registeredBundle))
+ if (bundle.equals(it.next().getBundle()))
{
it.remove();
}
@@ -398,14 +387,12 @@
m_frameworkListeners = newListeners;
// Remove all bundle listeners associated with the specified bundle.
- newListeners = new ArrayList<Object[]>(m_bundleListeners);
- for (Iterator<Object[]> it = newListeners.iterator(); it.hasNext(); )
+ newListeners = new ArrayList<ListenerInfo>(m_bundleListeners);
+ for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
{
// Check if the bundle associated with the current listener
// is the same as the specified bundle, if so remove the listener.
- Object[] listener = it.next();
- Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
- if (bundle.equals(registeredBundle))
+ if (bundle.equals(it.next().getBundle()))
{
it.remove();
}
@@ -414,14 +401,12 @@
// Remove all synchronous bundle listeners associated with
// the specified bundle.
- newListeners = new ArrayList<Object[]>(m_syncBundleListeners);
- for (Iterator<Object[]> it = newListeners.iterator(); it.hasNext(); )
+ newListeners = new ArrayList<ListenerInfo>(m_syncBundleListeners);
+ for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
{
// Check if the bundle associated with the current listener
// is the same as the specified bundle, if so remove the listener.
- Object[] listener = it.next();
- Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
- if (bundle.equals(registeredBundle))
+ if (bundle.equals(it.next().getBundle()))
{
it.remove();
}
@@ -429,14 +414,12 @@
m_syncBundleListeners = newListeners;
// Remove all service listeners associated with the specified bundle.
- newListeners = new ArrayList<Object[]>(m_serviceListeners);
- for (Iterator<Object[]> it = newListeners.iterator(); it.hasNext(); )
+ newListeners = new ArrayList<ListenerInfo>(m_serviceListeners);
+ for (Iterator<ListenerInfo> it = newListeners.iterator(); it.hasNext(); )
{
// Check if the bundle associated with the current listener
// is the same as the specified bundle, if so remove the listener.
- Object[] listener = it.next();
- Bundle registeredBundle = (Bundle) listener[LISTENER_BUNDLE_OFFSET];
- if (bundle.equals(registeredBundle))
+ if (bundle.equals(it.next().getBundle()))
{
it.remove();
}
@@ -449,7 +432,7 @@
{
synchronized (this)
{
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
if (clazz == FrameworkListener.class)
{
@@ -475,10 +458,10 @@
// handle it according to the spec.
for (int i = 0; i < listeners.size(); i++)
{
- Object[] listener = listeners.get(i);
- if (listener[LISTENER_BUNDLE_OFFSET].equals(bundle) &&
- (listener[LISTENER_CLASS_OFFSET] == clazz) &&
- (listener[LISTENER_OBJECT_OFFSET] == l))
+ ListenerInfo listener = listeners.get(i);
+ if (listener.getBundle().equals(bundle) &&
+ (listener.getListenerClass() == clazz) &&
+ (listener.getListener() == l))
{
Filter oldFilter = null;
if (clazz == FrameworkListener.class)
@@ -492,8 +475,17 @@
else if (clazz == ServiceListener.class)
{
// The spec says to update the filter in this case.
- oldFilter = (Filter) listener[LISTENER_FILTER_OFFSET];
- listener[LISTENER_FILTER_OFFSET] = filter;
+ oldFilter = listener.getParsedFilter();
+ listeners = new ArrayList<ListenerInfo>(listeners);
+ listeners.set(i,
+ new ListenerInfo(
+ listener.getBundle(),
+ listener.getListenerClass(),
+ listener.getListener(),
+ filter,
+ listener.getSecurityContext(),
+ listener.isRemoved()));
+ m_serviceListeners = listeners;
}
return oldFilter;
}
@@ -510,45 +502,25 @@
* @return Returns all existing service listener information into a collection of
* ListenerHook.ListenerInfo objects
**/
- public Collection /* <? extends ListenerHook.ListenerInfo> */
- wrapAllServiceListeners(boolean removed)
+ public Collection<ListenerHook.ListenerInfo> getAllServiceListeners()
{
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
synchronized (this)
{
listeners = m_serviceListeners;
}
-
- List existingListeners = new ArrayList();
- for (int i = 0; i < listeners.size(); i++)
- {
- existingListeners.add(wrapListener(listeners.get(i), removed));
- }
- return existingListeners;
+ return asTypedCollection(new ArrayList<ListenerHook.ListenerInfo>(listeners));
}
- /**
- * Wraps the information about a given listener in a ListenerHook.ListenerInfo
- * object.
- * @param listeners The array of listeners.
- * @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[] listener, boolean removed)
+ private static <S> Collection<S> asTypedCollection(Collection<?> c)
{
- Filter filter = (Filter) listener[LISTENER_FILTER_OFFSET];
-
- return new ListenerHookInfoImpl(
- ((Bundle)listener[LISTENER_BUNDLE_OFFSET]).getBundleContext(),
- (ServiceListener) listener[LISTENER_OBJECT_OFFSET],
- filter == null ? null : filter.toString(),
- removed);
+ return (Collection<S>) c;
}
public void fireFrameworkEvent(FrameworkEvent event)
{
// Take a snapshot of the listener array.
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
synchronized (this)
{
listeners = m_frameworkListeners;
@@ -561,8 +533,8 @@
public void fireBundleEvent(BundleEvent event, Framework felix)
{
// Take a snapshot of the listener array.
- List<Object[]> listeners = null;
- List<Object[]> syncListeners = null;
+ List<ListenerInfo> listeners = null;
+ List<ListenerInfo> syncListeners = null;
synchronized (this)
{
listeners = m_bundleListeners;
@@ -571,7 +543,7 @@
// Create a whitelist of bundle context for bundle listeners,
// if we have hooks.
- List<Object[]> allListeners = new ArrayList(listeners);
+ List<ListenerInfo> allListeners = new ArrayList(listeners);
allListeners.addAll(syncListeners);
Set<BundleContext> whitelist =
createWhitelistFromHooks(
@@ -597,7 +569,7 @@
final ServiceEvent event, final Dictionary oldProps, final Framework felix)
{
// Take a snapshot of the listener array.
- List<Object[]> listeners = null;
+ List<ListenerInfo> listeners = null;
synchronized (this)
{
listeners = m_serviceListeners;
@@ -615,7 +587,7 @@
private Set<BundleContext> createWhitelistFromHooks(
- EventObject event, Framework felix, List<Object[]> listeners, Class hookClass)
+ EventObject event, Framework felix, List<ListenerInfo> listeners, Class hookClass)
{
// Create a whitelist of bundle context, if we have hooks.
Set<BundleContext> whitelist = null;
@@ -623,10 +595,9 @@
if ((hooks != null) && !hooks.isEmpty())
{
whitelist = new HashSet<BundleContext>();
- for (Object[] listener : listeners)
+ for (ListenerInfo listener : listeners)
{
- BundleContext bc =
- ((Bundle) listener[LISTENER_BUNDLE_OFFSET]).getBundleContext();
+ BundleContext bc = listener.getBundleContext();
if (bc != null)
{
whitelist.add(bc);
@@ -686,7 +657,7 @@
}
private static void fireEventAsynchronously(
- EventDispatcher dispatcher, int type, List<Object[]> listeners,
+ EventDispatcher dispatcher, int type, List<ListenerInfo> listeners,
Set<BundleContext> whitelist, EventObject event)
{
//TODO: should possibly check this within thread lock, seems to be ok though without
@@ -728,18 +699,18 @@
}
private static void fireEventImmediately(
- EventDispatcher dispatcher, int type, List<Object[]> listeners,
+ EventDispatcher dispatcher, int type, List<ListenerInfo> listeners,
Set<BundleContext> whitelist, EventObject event, Dictionary oldProps)
{
if (!listeners.isEmpty())
{
// Notify appropriate listeners.
- for (Object[] listener : listeners)
+ for (ListenerInfo listener : listeners)
{
- 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];
+ Bundle bundle = listener.getBundle();
+ EventListener l = listener.getListener();
+ Filter filter = listener.getParsedFilter();
+ Object acc = listener.getSecurityContext();
// Only deliver events to bundles in the whitelist, if we have one.
if ((whitelist == null) || whitelist.contains(bundle.getBundleContext()))
@@ -997,7 +968,7 @@
public EventDispatcher m_dispatcher = null;
public int m_type = -1;
- public List<Object[]> m_listeners = null;
+ public List<ListenerInfo> m_listeners = null;
public Set<BundleContext> m_whitelist = null;
public EventObject m_event = null;
}
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ListenerHookInfoImpl.java b/framework/src/main/java/org/apache/felix/framework/util/ListenerHookInfoImpl.java
deleted file mode 100644
index fbd3704..0000000
--- a/framework/src/main/java/org/apache/felix/framework/util/ListenerHookInfoImpl.java
+++ /dev/null
@@ -1,83 +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 org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.hooks.service.ListenerHook;
-
-public class ListenerHookInfoImpl implements ListenerHook.ListenerInfo
-{
- private final BundleContext m_context;
- private final ServiceListener m_listener;
- private final String m_filter;
- private boolean m_removed;
-
- public ListenerHookInfoImpl(BundleContext context, ServiceListener listener, String filter, boolean removed)
- {
- m_context = context;
- m_listener = listener;
- m_filter = filter;
- m_removed = removed;
- }
-
- public BundleContext getBundleContext()
- {
- return m_context;
- }
-
- public String getFilter()
- {
- return m_filter;
- }
-
- public boolean isRemoved()
- {
- return m_removed;
- }
-
- public boolean equals(Object obj)
- {
- if (obj == this)
- {
- return true;
- }
-
- if (!(obj instanceof ListenerHookInfoImpl))
- {
- return false;
- }
-
- ListenerHookInfoImpl other = (ListenerHookInfoImpl) obj;
- return other.m_listener == m_listener &&
- (m_filter == null ? other.m_filter == null : m_filter.equals(other.m_filter));
- }
-
- public int hashCode()
- {
- int rc = 17;
-
- rc = 37 * rc + m_listener.hashCode();
- if (m_filter != null)
- {
- rc = 37 * rc + m_filter.hashCode();
- }
- return rc;
- }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java b/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java
new file mode 100644
index 0000000..e007db4
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/util/ListenerInfo.java
@@ -0,0 +1,133 @@
+/*
+ * 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.EventListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.hooks.service.ListenerHook;
+
+
+public class ListenerInfo implements ListenerHook.ListenerInfo
+{
+ private final Bundle m_bundle;
+ private final Class m_listenerClass;
+ private final EventListener m_listener;
+ private final Filter m_filter;
+ private final Object m_acc;
+ private final boolean m_removed;
+
+ public ListenerInfo(
+ Bundle bundle, Class listenerClass, EventListener listener,
+ Filter filter, Object acc, boolean removed)
+ {
+ m_bundle = bundle;
+ m_listenerClass = listenerClass;
+ m_listener = listener;
+ m_filter = filter;
+ m_acc = acc;
+ m_removed = removed;
+ }
+
+ public ListenerInfo(ListenerInfo info, boolean removed)
+ {
+ m_bundle = info.m_bundle;
+ m_listenerClass = info.m_listenerClass;
+ m_listener = info.m_listener;
+ m_filter = info.m_filter;
+ m_acc = info.m_acc;
+ m_removed = removed;
+ }
+
+ public Bundle getBundle()
+ {
+ return m_bundle;
+ }
+
+ public BundleContext getBundleContext()
+ {
+ return m_bundle.getBundleContext();
+ }
+
+ public Class getListenerClass()
+ {
+ return m_listenerClass;
+ }
+
+ public EventListener getListener()
+ {
+ return m_listener;
+ }
+
+ public Filter getParsedFilter()
+ {
+ return m_filter;
+ }
+
+ public String getFilter()
+ {
+ if (m_filter != null)
+ {
+ return m_filter.toString();
+ }
+ return null;
+ }
+
+ public Object getSecurityContext()
+ {
+ return m_acc;
+ }
+
+ public boolean isRemoved()
+ {
+ return m_removed;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof ListenerInfo))
+ {
+ return false;
+ }
+
+ ListenerInfo other = (ListenerInfo) obj;
+ return other.m_listener == m_listener &&
+ (m_filter == null ? other.m_filter == null : m_filter.equals(other.m_filter));
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int rc = 17;
+
+ rc = 37 * rc + m_listener.hashCode();
+ if (m_filter != null)
+ {
+ rc = 37 * rc + m_filter.hashCode();
+ }
+ return rc;
+ }
+}
\ No newline at end of file