Added final patch for service registry hooks. (FELIX-905,FELIX-906)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@782664 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 b2afc02..3ac2488 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2398,9 +2398,6 @@
return null;
}
- // Private member for method below.
- private Comparator m_comparator = null;
-
/**
* Implementation for BundleContext.getBundles(). Retrieves
* all installed bundles.
@@ -2449,13 +2446,20 @@
// Invoke the ListenerHook.added() on all hooks.
List listenerHooks = m_registry.getListenerHooks();
- Collection c = Collections.singleton(new ListenerHookInfoImpl(bundle.getBundleContext(), f));
+ final Collection c = Collections.singleton(
+ new ListenerHookInfoImpl(bundle.getBundleContext(), f));
for (int i = 0; i < listenerHooks.size(); i++)
{
- ((ListenerHook) listenerHooks.get(i)).added(c);
+ ServiceRegistry.invokeHook(listenerHooks.get(i), this, new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ ((ListenerHook) hook).added(c);
+ }
+ });
}
}
-
+
/**
* Implementation for BundleContext.removeServiceListener().
* Removes service listeners from the listener list.
@@ -2570,8 +2574,15 @@
// to invoke the callback with all existing service listeners.
if (m_registry.isHook(classNames, ListenerHook.class, svcObj))
{
- ListenerHook lHook = (ListenerHook) svcObj;
- lHook.added(m_dispatcher.wrapAllServiceListeners());
+ Object hookRef = ServiceRegistry.getHookRef(svcObj, reg);
+ ServiceRegistry.invokeHook(hookRef, this, new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ ((ListenerHook) hook).
+ added(m_dispatcher.wrapAllServiceListeners());
+ }
+ });
}
// TODO: CONCURRENCY - Reconsider firing event here, outside of the
@@ -2595,7 +2606,8 @@
* @throws InvalidSyntaxException
*/
ServiceReference[] getServiceReferences(
- BundleImpl bundle, String className, String expr, boolean checkAssignable)
+ final BundleImpl bundle, final String className,
+ final String expr, final boolean checkAssignable)
throws InvalidSyntaxException
{
// Define filter if expression is not null.
@@ -2606,7 +2618,7 @@
}
// Ask the service registry for all matching service references.
- List refList = m_registry.getServiceReferences(className, filter);
+ final List refList = m_registry.getServiceReferences(className, filter);
// Filter on assignable references
if (checkAssignable)
@@ -2625,22 +2637,27 @@
}
}
+ // activate findhooks
+ List findHooks = m_registry.getFindHooks();
+ for (int i = 0; i < findHooks.size(); i++)
+ {
+ ServiceRegistry.invokeHook(findHooks.get(i), this, new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ ((FindHook) hook).find(bundle.getBundleContext(),
+ className,
+ expr,
+ !checkAssignable,
+ new ShrinkableCollection(refList));
+ }
+ });
+ }
+
if (refList.size() > 0)
{
- // activate findhooks
- List findHooks = m_registry.getFindHooks();
- for (int i = 0; i < findHooks.size(); i++)
- {
- ((FindHook) findHooks.get(i)).find(
- bundle.getBundleContext(),
- className,
- expr,
- !checkAssignable,
- new ShrinkableCollection(refList));
- }
-
return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
- }
+ }
return null;
}
@@ -3432,7 +3449,7 @@
**/
private void fireServiceEvent(ServiceEvent event)
{
- m_dispatcher.fireServiceEvent(event);
+ m_dispatcher.fireServiceEvent(event, this);
}
//
diff --git a/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java b/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java
new file mode 100644
index 0000000..62dde99
--- /dev/null
+++ b/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public interface InvokeHookCallback
+{
+ void invokeHook(Object hook);
+}
\ No newline at end of file
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 90fd2e5..fc35627 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -23,6 +23,7 @@
import org.apache.felix.framework.util.FelixConstants;
import org.osgi.framework.*;
import org.osgi.framework.hooks.service.*;
+import org.osgi.framework.launch.Framework;
public class ServiceRegistry
{
@@ -73,12 +74,13 @@
synchronized (this)
{
- // Keep track of registered hooks.
- addHooks(classNames, svcObj);
-
// Create the service registration.
reg = new ServiceRegistrationImpl(
this, bundle, classNames, new Long(m_currentServiceId++), svcObj, dict);
+
+ // Keep track of registered hooks.
+ addHooks(classNames, svcObj, reg);
+
// Get the bundles current registered services.
ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
m_serviceRegsMap.put(bundle, addServiceRegistration(regs, reg));
@@ -90,7 +92,7 @@
public void unregisterService(Bundle bundle, ServiceRegistration reg)
{
// If this is a hook, it should be removed.
- removeHook(((ServiceRegistrationImpl) reg).getService());
+ removeHook(reg);
synchronized (this)
{
@@ -731,13 +733,13 @@
}
}
- private void addHooks(String[] classNames, Object svcObj)
+ private void addHooks(String[] classNames, Object svcObj, ServiceRegistration reg)
{
if (isHook(classNames, EventHook.class, svcObj))
{
synchronized (m_eventHookLock)
{
- m_eventHooks = addToArray(m_eventHooks, svcObj);
+ m_eventHooks = addHookToArray(m_eventHooks, svcObj, reg);
}
}
@@ -745,7 +747,7 @@
{
synchronized (m_findHookLock)
{
- m_findHooks = addToArray(m_findHooks, svcObj);
+ m_findHooks = addHookToArray(m_findHooks, svcObj, reg);
}
}
@@ -753,21 +755,28 @@
{
synchronized (m_listenerHookLock)
{
- m_listenerHooks = addToArray(m_listenerHooks, svcObj);
+ m_listenerHooks = addHookToArray(m_listenerHooks, svcObj, reg);
}
}
}
- private static Object[] addToArray(Object[] src, Object svcObj)
+ private static Object[] addHookToArray(Object[] src, Object svcObj, ServiceRegistration reg)
{
+ Object hookRef = getHookRef(svcObj, reg);
+
Object[] dst = new Object[src.length + 1];
System.arraycopy(src, 0, dst, 0, src.length);
- dst[src.length] = svcObj;
+ dst[src.length] = hookRef;
return dst;
}
boolean isHook(String[] classNames, Class hookClass, Object svcObj)
{
+ if (svcObj instanceof ServiceFactory)
+ {
+ return Arrays.asList(classNames).contains(hookClass.getName());
+ }
+
if (hookClass.isAssignableFrom(svcObj.getClass()))
{
String hookName = hookClass.getName();
@@ -782,41 +791,64 @@
return false;
}
- private void removeHook(Object svcObj)
+ private void removeHook(ServiceRegistration reg)
{
- if (svcObj instanceof EventHook)
+ Object svcObj = ((ServiceRegistrationImpl) reg).getService();
+ String [] classNames = (String[]) reg.getReference().getProperty(Constants.OBJECTCLASS);
+
+ if (isHook(classNames, EventHook.class, svcObj))
{
- synchronized (m_eventHookLock)
+ synchronized (m_eventHookLock)
{
- m_eventHooks = removeFromArray(m_eventHooks, svcObj);
+ m_eventHooks = removeFromHookArray(m_eventHooks, svcObj, reg);
}
}
-
- if (svcObj instanceof FindHook)
+
+ if (isHook(classNames, FindHook.class, svcObj))
{
synchronized (m_findHookLock)
{
- m_findHooks = removeFromArray(m_findHooks, svcObj);
+ m_findHooks = removeFromHookArray(m_findHooks, svcObj, reg);
}
}
- if (svcObj instanceof ListenerHook)
+ if (isHook(classNames, ListenerHook.class, svcObj))
{
synchronized (m_listenerHookLock)
{
- m_listenerHooks = removeFromArray(m_listenerHooks, svcObj);
+ m_listenerHooks = removeFromHookArray(m_listenerHooks, svcObj, reg);
}
}
}
- private static Object[] removeFromArray(Object[] src, Object svcObj)
+ private static Object[] removeFromHookArray(Object[] src, Object svcObj, ServiceRegistration reg)
{
Object[] dst = src;
int idx = -1;
for (int i = 0; i < src.length; i++)
{
- if (src[i].equals(svcObj))
+ boolean found = false;
+ if (svcObj instanceof ServiceFactory)
+ {
+ if (src[i] instanceof Object[])
+ {
+ Object [] arrElem = (Object []) src[i];
+ if (arrElem[0].equals(svcObj) && arrElem[1].equals(reg))
+ {
+ found = true;
+ }
+ }
+ }
+ else
+ {
+ if (src[i].equals(svcObj))
+ {
+ found = true;
+ }
+ }
+
+ if (found)
{
idx = i;
break;
@@ -868,6 +900,76 @@
}
}
+ /**
+ * Returns a hook reference object that can be passed to the
+ * {@link #invokeHook(Object, Framework, InvokeHookCallback)} method.
+ * @param svcObj The Service Object. Either the service itself, or a <tt>ServiceFactory</tt>
+ * object.
+ * @param reg The associated <tt>ServiceRegistration</tt>.
+ * @return In the case of a <tt>ServiceFactory</tt> an Object[2] with both the
+ * factory and the <tt>ServiceRegistration</tt> is returned. In all other
+ * cases the svcObj is returned as passed in. This is the behavior expected
+ * by the {@link #invokeHook(Object, Framework, InvokeHookCallback)} method.
+ */
+ static Object getHookRef(Object svcObj, ServiceRegistration reg)
+ {
+ if (svcObj instanceof ServiceFactory)
+ {
+ return new Object[] {svcObj, reg};
+ }
+ else
+ {
+ return svcObj;
+ }
+ }
+
+ /**
+ * Invokes a Service Registry Hook
+ * @param hookRef The hook to be invoked, this is an element on the list returned by the
+ * {@link #getEventHooks()}, {@link #getFindHooks()} or {@link #getListenerHooks()}
+ * methods. It could either contain the hook object itself or an Object[2] when a
+ * ServiceFactory is used. In that case the first element is the hook ServiceFactory
+ * and the second element is its ServiceRegistration.
+ * @param framework The framework that is invoking the hook, typically the Felix object.
+ * @param callback This is a callback object that is invoked with the actual hook object to
+ * be used, either the plain hook, or one obtained from the ServiceFactory.
+ */
+ public static void invokeHook(
+ Object hookRef, Framework framework, InvokeHookCallback callback)
+ {
+ Object hook;
+ boolean serviceFactory;
+ if (hookRef instanceof Object[])
+ {
+ serviceFactory = true;
+ Object[] array = (Object[]) hookRef;
+ ServiceFactory hookFactory = (ServiceFactory) array[0];
+ ServiceRegistration sr = (ServiceRegistration) array[1];
+ hook = hookFactory.getService(framework, sr);
+ }
+ else
+ {
+ serviceFactory = false;
+ hook = hookRef;
+ }
+
+ try
+ {
+ callback.invokeHook(hook);
+ // TODO: SERVICE HOOKS - Check that "services in use" is handled
+ }
+ finally
+ {
+ if (serviceFactory)
+ {
+ Object [] array = (Object []) hookRef;
+ ServiceFactory hookFactory = (ServiceFactory) array[0];
+ ServiceRegistration sr = (ServiceRegistration) array[1];
+ hookFactory.ungetService(framework, sr, hook);
+ }
+ }
+ }
+
private static class UsageCount
{
public int m_count = 0;
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 96b7e97..38cac23 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
@@ -28,6 +28,7 @@
import java.util.List;
import java.util.NoSuchElementException;
+import org.apache.felix.framework.InvokeHookCallback;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.ServiceRegistry;
import org.osgi.framework.AllServiceListener;
@@ -44,8 +45,9 @@
import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.SynchronousBundleListener;
-import org.osgi.framework.hooks.service.ListenerHook;
import org.osgi.framework.hooks.service.EventHook;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.framework.launch.Framework;
public class EventDispatcher
{
@@ -69,7 +71,7 @@
// A single thread is used to deliver events for all dispatchers.
private static Thread m_thread = null;
- private static String m_threadLock = new String("thread lock");
+ private final static String m_threadLock = new String("thread lock");
private static int m_references = 0;
private static volatile boolean m_stopping = false;
@@ -606,7 +608,7 @@
}
}
- public void fireServiceEvent(ServiceEvent event)
+ public void fireServiceEvent(final ServiceEvent event, Framework felix)
{
// Take a snapshot of the listener array.
Object[] listeners = null;
@@ -620,11 +622,20 @@
List eventHooks = m_serviceRegistry.getEventHooks();
if ((eventHooks != null) && (eventHooks.size() > 0))
{
- ListenerBundleContextCollectionWrapper wrapper =
+ final ListenerBundleContextCollectionWrapper wrapper =
new ListenerBundleContextCollectionWrapper(listeners);
for (int i = 0; i < eventHooks.size(); i++)
{
- ((EventHook) eventHooks.get(i)).event(event, wrapper);
+ if (felix != null)
+ {
+ ServiceRegistry.invokeHook(eventHooks.get(i), felix, new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ ((EventHook) hook).event(event, wrapper);
+ }
+ });
+ }
}
listeners = wrapper.getListeners();
diff --git a/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
new file mode 100644
index 0000000..d0c8845
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
@@ -0,0 +1,389 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.easymock.MockControl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.hooks.service.EventHook;
+import org.osgi.framework.hooks.service.FindHook;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.framework.launch.Framework;
+
+public class ServiceRegistryTest extends TestCase
+{
+ public void testRegisterEventHookService()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ EventHook hook = new EventHook()
+ {
+ public void event(ServiceEvent event, Collection contexts)
+ {
+ }
+ };
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {EventHook.class.getName()}, hook, new Hashtable());
+ assertEquals(1, sr.getEventHooks().size());
+ assertSame(hook, sr.getEventHooks().iterator().next());
+ assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterEventHookServiceFactory()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
+ sfControl.replay();
+ ServiceFactory sf = (ServiceFactory) sfControl.getMock();
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {EventHook.class.getName()}, sf, new Hashtable());
+ assertEquals(1, sr.getEventHooks().size());
+ Object [] arr = (Object[]) sr.getEventHooks().iterator().next();
+ assertEquals(2, arr.length);
+ assertSame(sf, arr[0]);
+ assertTrue(arr[1] instanceof ServiceRegistration);
+ assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterFindHookService()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ FindHook hook = new FindHook()
+ {
+ public void find(BundleContext context, String name, String filter,
+ boolean allServices, Collection references)
+ {
+ }
+ };
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {FindHook.class.getName()}, hook, new Hashtable());
+ assertEquals(1, sr.getFindHooks().size());
+ assertSame(hook, sr.getFindHooks().iterator().next());
+ assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterFindHookServiceFactory()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
+ sfControl.replay();
+ ServiceFactory sf = (ServiceFactory) sfControl.getMock();
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {FindHook.class.getName()}, sf, new Hashtable());
+ assertEquals(1, sr.getFindHooks().size());
+ Object [] arr = (Object[]) sr.getFindHooks().iterator().next();
+ assertEquals(2, arr.length);
+ assertSame(sf, arr[0]);
+ assertTrue(arr[1] instanceof ServiceRegistration);
+ assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterListenerHookService()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ ListenerHook hook = new ListenerHook()
+ {
+
+ public void added(Collection listeners)
+ {
+ }
+
+ public void removed(Collection listener)
+ {
+ }
+ };
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {ListenerHook.class.getName()}, hook, new Hashtable());
+ assertEquals(1, sr.getListenerHooks().size());
+ assertSame(hook, sr.getListenerHooks().iterator().next());
+ assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterListenerHookServiceFactory()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
+ sfControl.replay();
+ ServiceFactory sf = (ServiceFactory) sfControl.getMock();
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {ListenerHook.class.getName()}, sf, new Hashtable());
+ assertEquals(1, sr.getListenerHooks().size());
+ Object [] arr = (Object[]) sr.getListenerHooks().iterator().next();
+ assertEquals(2, arr.length);
+ assertSame(sf, arr[0]);
+ assertTrue(arr[1] instanceof ServiceRegistration);
+ assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterCombinedService()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ class CombinedService implements ListenerHook, FindHook, EventHook, Runnable
+ {
+ public void added(Collection listeners)
+ {
+ }
+
+ public void removed(Collection listener)
+ {
+ }
+
+ public void find(BundleContext context, String name, String filter,
+ boolean allServices, Collection references)
+ {
+ }
+
+ public void event(ServiceEvent event, Collection contexts)
+ {
+ }
+
+ public void run()
+ {
+ }
+
+ }
+ CombinedService hook = new CombinedService();
+
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {
+ Runnable.class.getName(),
+ ListenerHook.class.getName(),
+ FindHook.class.getName(),
+ EventHook.class.getName()}, hook, new Hashtable());
+ assertEquals(1, sr.getListenerHooks().size());
+ assertSame(hook, sr.getListenerHooks().iterator().next());
+ assertEquals(1, sr.getEventHooks().size());
+ assertSame(hook, sr.getEventHooks().iterator().next());
+ assertEquals(1, sr.getFindHooks().size());
+ assertSame(hook, sr.getFindHooks().iterator().next());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getFindHooks().size());
+ assertEquals("Should be no hooks left after unregistration", 0, sr.getListenerHooks().size());
+ }
+
+ public void testRegisterPlainService()
+ {
+ MockControl control = MockControl.createNiceControl(Bundle.class);
+ Bundle b = (Bundle) control.getMock();
+ control.replay();
+
+ ServiceRegistry sr = new ServiceRegistry(new Logger());
+ String svcObj = "hello";
+ assertEquals("Precondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Precondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Precondition failed", 0, sr.getListenerHooks().size());
+ ServiceRegistration reg = sr.registerService(b, new String [] {String.class.getName()}, svcObj, new Hashtable());
+ assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
+ assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
+
+ sr.unregisterService(b, reg);
+ assertEquals("Unregistration should have no effect", 0, sr.getEventHooks().size());
+ assertEquals("Unregistration should have no effect", 0, sr.getFindHooks().size());
+ assertEquals("Unregistration should have no effect", 0, sr.getListenerHooks().size());
+ }
+
+ public void testInvokeHook()
+ {
+ final List result = new ArrayList();
+ InvokeHookCallback callback = new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ result.add(hook);
+ }
+ };
+
+ MockControl control = MockControl.createNiceControl(Framework.class);
+ Framework fr = (Framework) control.getMock();
+ control.replay();
+
+ FindHook hook = new FindHook()
+ {
+ public void find(BundleContext context, String name, String filter,
+ boolean allServices, Collection references)
+ {
+ }
+ };
+ assertSame(hook, ServiceRegistry.getHookRef(hook, null));
+
+ assertEquals("Precondition failed", 0, result.size());
+ ServiceRegistry.invokeHook(hook, fr, callback);
+ assertEquals(1, result.size());
+ assertSame(hook, result.iterator().next());
+ }
+
+ public void testInvokeHookFactory()
+ {
+ final List result = new ArrayList();
+ InvokeHookCallback callback = new InvokeHookCallback()
+ {
+ public void invokeHook(Object hook)
+ {
+ result.add(hook);
+ }
+ };
+
+ MockControl control = MockControl.createNiceControl(Framework.class);
+ Framework fr = (Framework) control.getMock();
+ control.replay();
+
+ final FindHook hook = new FindHook()
+ {
+ public void find(BundleContext context, String name, String filter,
+ boolean allServices, Collection references)
+ {
+ }
+ };
+
+ final List sfGet = new ArrayList();
+ final List sfUnget = new ArrayList();
+ ServiceFactory sf = new ServiceFactory()
+ {
+ public Object getService(Bundle b, ServiceRegistration reg)
+ {
+ sfGet.add(reg);
+ return hook;
+ }
+
+ public void ungetService(Bundle b, ServiceRegistration reg, Object svcObj)
+ {
+ sfUnget.add(reg);
+ assertSame(svcObj, hook);
+ }
+ };
+
+ MockControl control2 = MockControl.createNiceControl(ServiceRegistration.class);
+ ServiceRegistration reg = (ServiceRegistration) control2.getMock();
+ control2.replay();
+
+ Object [] arg = new Object[2];
+ arg[0] = sf;
+ arg[1] = reg;
+ Object [] arg2 = (Object[]) ServiceRegistry.getHookRef(sf, reg);
+ assertTrue(Arrays.equals(arg, arg2));
+
+ assertEquals("Precondition failed", 0, result.size());
+ assertEquals("Precondition failed", 0, sfGet.size());
+ assertEquals("Precondition failed", 0, sfUnget.size());
+ ServiceRegistry.invokeHook(arg, fr, callback);
+ assertEquals(1, result.size());
+ assertSame(hook, result.iterator().next());
+ assertEquals(1, sfGet.size());
+ assertEquals(1, sfUnget.size());
+ assertSame(reg, sfGet.iterator().next());
+ assertSame(reg, sfUnget.iterator().next());
+ }
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java