Commit patch to fix some issues with service registry hooks that were
causing them to fail the TCK. (FELIX-1277)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@799087 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 d141c5b..ced9680 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2586,22 +2586,34 @@
     void addServiceListener(Bundle bundle, ServiceListener l, String f)
         throws InvalidSyntaxException
     {
-        m_dispatcher.addListener(
+        Filter oldFilter = m_dispatcher.addListener(
             bundle, ServiceListener.class, l, (f == null) ? null : FrameworkUtil.createFilter(f));
 
-        // Invoke the ListenerHook.added() on all hooks.
         List listenerHooks = m_registry.getListenerHooks();
-        final Collection c = Collections.singleton(
-            new ListenerHookInfoImpl(bundle.getBundleContext(), f));
+        if (oldFilter != null)
+        {
+            final Collection removed = Collections.singleton(
+                new ListenerHookInfoImpl(bundle.getBundleContext(), l, oldFilter.toString(), true));
+            InvokeHookCallback removedCallback = new ListenerHookRemovedCallback(removed);
+            for (int i = 0; i < listenerHooks.size(); i++)
+            {
+                m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, removedCallback);
+            };
+        }
+
+        // Invoke the ListenerHook.added() on all hooks.
+        final Collection added = Collections.singleton(
+            new ListenerHookInfoImpl(bundle.getBundleContext(), l, f, false));
+        InvokeHookCallback addedCallback = new InvokeHookCallback()
+        {
+            public void invokeHook(Object hook)
+            {
+                ((ListenerHook) hook).added(added);
+            }
+        };
         for (int i = 0; i < listenerHooks.size(); i++)
         {
-            ServiceRegistry.invokeHook(listenerHooks.get(i), this, new InvokeHookCallback()
-            {
-                public void invokeHook(Object hook)
-                {
-                    ((ListenerHook) hook).added(c);
-                }
-            });
+            m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, addedCallback);
         }
     }
 
@@ -2622,9 +2634,10 @@
             // Invoke the ListenerHook.removed() on all hooks.
             List listenerHooks = m_registry.getListenerHooks();
             Collection c = Collections.singleton(listener);
+            InvokeHookCallback callback = new ListenerHookRemovedCallback(c);
             for (int i = 0; i < listenerHooks.size(); i++)
             {
-                ((ListenerHook) listenerHooks.get(i)).removed(c);
+                m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, callback);
             }
         }
     }
@@ -2719,13 +2732,12 @@
         // to invoke the callback with all existing service listeners.
         if (m_registry.isHook(classNames, ListenerHook.class, svcObj))
         {
-            Object hookRef = ServiceRegistry.getHookRef(svcObj, reg);
-            ServiceRegistry.invokeHook(hookRef, this, new InvokeHookCallback()
+            m_registry.invokeHook(reg.getReference(), this, new InvokeHookCallback()
             {
                 public void invokeHook(Object hook)
                 {
                     ((ListenerHook) hook).
-                        added(m_dispatcher.wrapAllServiceListeners());
+                        added(m_dispatcher.wrapAllServiceListeners(false));
                 }
             });
         }
@@ -2784,19 +2796,20 @@
 
         // activate findhooks
         List findHooks = m_registry.getFindHooks();
+        InvokeHookCallback callback = new InvokeHookCallback()
+        {
+            public void invokeHook(Object hook)
+            {
+                ((FindHook) hook).find(bundle.getBundleContext(),
+                    className,
+                    expr,
+                    !checkAssignable,
+                    new ShrinkableCollection(refList));
+            }
+        };
         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));
-                }
-            });
+            m_registry.invokeHook((ServiceReference) findHooks.get(i), this, callback);
         }
 
         if (refList.size() > 0)
@@ -4297,6 +4310,21 @@
         }
     }
 
+    private static class ListenerHookRemovedCallback implements InvokeHookCallback
+    {
+        private final Collection /* ListenerHookInfo */ m_removed;
+
+        ListenerHookRemovedCallback(Collection /* ListenerHookInfo */ removed)
+        {
+            m_removed = removed;
+        }
+
+        public void invokeHook(Object hook)
+        {
+            ((ListenerHook) hook).removed(m_removed);
+        }
+    }
+
     //
     // Locking related methods.
     //
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 8e2b055..ddd4e53 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -367,7 +367,7 @@
     {
         private ServiceReferenceImpl() {}
 
-        ServiceRegistrationImpl getServiceRegistration()
+        ServiceRegistrationImpl getRegistration()
         {
             return ServiceRegistrationImpl.this;
         }
@@ -465,7 +465,7 @@
                         // Get the service registration and ask it to check
                         // if the service object is assignable to the requesting
                         // bundle's class.
-                        allow = getServiceRegistration().isClassAccessible(requestClass);
+                        allow = getRegistration().isClassAccessible(requestClass);
                     }
                     catch (Exception ex)
                     {
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 ce09d85..413e331 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -27,7 +27,7 @@
 
 public class ServiceRegistry
 {
-    private Logger m_logger = null;
+    private final Logger m_logger;
     private long m_currentServiceId = 1L;
     // Maps bundle to an array of service registrations.
     private Map m_serviceRegsMap = new HashMap();
@@ -40,12 +40,9 @@
 
     private final ServiceRegistryCallbacks m_callbacks;
 
-    private final Object m_eventHookLock = new Object();
-    private Object[] m_eventHooks = new Object[0];
-    private final Object m_findHookLock = new Object();
-    private Object[] m_findHooks = new Object[0];
-    private final Object m_listenerHookLock = new Object();
-    private Object[] m_listenerHooks = new Object[0];
+    private final Set m_eventHooks = new TreeSet(Collections.reverseOrder());
+    private final Set m_findHooks = new TreeSet(Collections.reverseOrder());
+    private final Set m_listenerHooks = new TreeSet(Collections.reverseOrder());
 
     public ServiceRegistry(Logger logger, ServiceRegistryCallbacks callbacks)
     {
@@ -78,9 +75,9 @@
             // 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);
+            addHooks(classNames, svcObj, reg.getReference());
 
             // Get the bundles current registered services.
             ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
@@ -99,7 +96,7 @@
     public void unregisterService(Bundle bundle, ServiceRegistration reg)
     {
         // If this is a hook, it should be removed.
-        removeHook(reg);
+        removeHook(reg.getReference());
 
         synchronized (this)
         {
@@ -202,7 +199,8 @@
                 else if (className != null)
                 {
                     String[] objectClass = (String[])
-                        ((ServiceRegistrationImpl) regs[regIdx]).getProperty(FelixConstants.OBJECTCLASS);
+                        ((ServiceRegistrationImpl) regs[regIdx])
+                            .getProperty(FelixConstants.OBJECTCLASS);
                     for (int classIdx = 0;
                         classIdx < objectClass.length;
                         classIdx++)
@@ -248,7 +246,8 @@
         Object svcObj = null;
 
         // Get the service registration.
-        ServiceRegistrationImpl reg = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getServiceRegistration();
+        ServiceRegistrationImpl reg =
+            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();
 
         synchronized (this)
         {
@@ -338,7 +337,8 @@
     public boolean ungetService(Bundle bundle, ServiceReference ref)
     {
         UsageCount usage = null;
-        ServiceRegistrationImpl reg = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getServiceRegistration();
+        ServiceRegistrationImpl reg =
+            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();
 
         synchronized (this)
         {
@@ -384,7 +384,7 @@
             {
                 // Remove reference from usages array.
                 ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
-                    .getServiceRegistration().ungetService(bundle, usage.m_svcObj);
+                    .getRegistration().ungetService(bundle, usage.m_svcObj);
             }
         }
         finally
@@ -454,7 +454,7 @@
     }
 
     public synchronized Bundle[] getUsingBundles(ServiceReference ref)
-    {
+    {        
         Bundle[] bundles = null;
         for (Iterator iter = m_inUseMap.entrySet().iterator(); iter.hasNext(); )
         {
@@ -646,50 +646,40 @@
         }
     }
 
-    private void addHooks(String[] classNames, Object svcObj, ServiceRegistration reg)
+    private void addHooks(String[] classNames, Object svcObj, ServiceReference ref)
     {
         if (isHook(classNames, EventHook.class, svcObj))
         {
-            synchronized (m_eventHookLock)
+            synchronized (m_eventHooks)
             {
-                m_eventHooks = addHookToArray(m_eventHooks, svcObj, reg);
+                m_eventHooks.add(ref);
             }
         }
 
         if (isHook(classNames, FindHook.class, svcObj))
         {
-            synchronized (m_findHookLock)
+            synchronized (m_findHooks)
             {
-                m_findHooks = addHookToArray(m_findHooks, svcObj, reg);
+                m_findHooks.add(ref);
             }
         }
 
         if (isHook(classNames, ListenerHook.class, svcObj))
         {
-            synchronized (m_listenerHookLock)
+            synchronized (m_listenerHooks)
             {
-                m_listenerHooks = addHookToArray(m_listenerHooks, svcObj, reg);
+                m_listenerHooks.add(ref);
             }
         }
     }
-
-    private static Object[] addHookToArray(Object[] src, Object svcObj, ServiceRegistration reg)
+    
+    static boolean isHook(String[] classNames, Class hookClass, Object svcObj)
     {
-        Object hookRef = getHookRef(svcObj, reg);
-
-        Object[] dst = new Object[src.length + 1];
-        System.arraycopy(src, 0, dst, 0, src.length);
-        dst[src.length] = hookRef;
-        return dst;
-    }
-
-    boolean isHook(String[] classNames, Class hookClass, Object svcObj)
-    {
-        if (svcObj instanceof ServiceFactory)
+        if (svcObj instanceof ServiceFactory) 
         {
             return Arrays.asList(classNames).contains(hookClass.getName());
         }
-
+        
         if (hookClass.isAssignableFrom(svcObj.getClass()))
         {
             String hookName = hookClass.getName();
@@ -704,96 +694,42 @@
         return false;
     }
 
-    private void removeHook(ServiceRegistration reg)
+    private void removeHook(ServiceReference ref)
     {
-        Object svcObj = ((ServiceRegistrationImpl) reg).getService();
-        String [] classNames = (String[]) reg.getReference().getProperty(Constants.OBJECTCLASS);
-
-        if (isHook(classNames, EventHook.class, svcObj))
+        Object svcObj = ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
+            .getRegistration().getService();
+        String [] classNames = (String[]) ref.getProperty(Constants.OBJECTCLASS);
+        
+        if (isHook(classNames, EventHook.class, svcObj)) 
         {
-            synchronized (m_eventHookLock)
+            synchronized (m_eventHooks) 
             {
-                m_eventHooks = removeFromHookArray(m_eventHooks, svcObj, reg);
+                m_eventHooks.remove(ref);
             }
         }
-
-        if (isHook(classNames, FindHook.class, svcObj))
+        
+        if (isHook(classNames, FindHook.class, svcObj)) 
         {
-            synchronized (m_findHookLock)
+            synchronized (m_findHooks)
             {
-                m_findHooks = removeFromHookArray(m_findHooks, svcObj, reg);
+                m_findHooks.remove(ref);
             }
         }
 
         if (isHook(classNames, ListenerHook.class, svcObj))
         {
-            synchronized (m_listenerHookLock)
+            synchronized (m_listenerHooks)
             {
-                m_listenerHooks = removeFromHookArray(m_listenerHooks, svcObj, reg);
+                m_listenerHooks.remove(ref);
             }
         }
     }
 
-    private static Object[] removeFromHookArray(Object[] src, Object svcObj, ServiceRegistration reg)
-    {
-        Object[] dst = src;
-
-        int idx = -1;
-        for (int i = 0; i < src.length; i++)
-        {
-            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;
-            }
-        }
-
-        if (idx >= 0)
-        {
-            if (src.length == 1)
-            {
-                dst = new Object[0];
-            }
-            else
-            {
-                dst = new Object[src.length - 1];
-                System.arraycopy(dst, 0, src, 0, idx);
-                if (idx < dst.length)
-                {
-                    System.arraycopy(
-                        src, idx + 1, dst, idx, dst.length - idx);
-                }
-            }
-        }
-
-        return dst;
-    }
-
     public List getEventHooks()
     {
         synchronized (m_eventHooks)
         {
-            return Collections.unmodifiableList(Arrays.asList(m_eventHooks));
+            return new ArrayList(m_eventHooks);
         }
     }
 
@@ -801,7 +737,7 @@
     {
         synchronized (m_findHooks)
         {
-            return Collections.unmodifiableList(Arrays.asList(m_findHooks));
+            return new ArrayList(m_findHooks);
         }
     }
 
@@ -809,80 +745,38 @@
     {
         synchronized (m_listenerHooks)
         {
-            return Collections.unmodifiableList(Arrays.asList(m_listenerHooks));
+            return new ArrayList(m_listenerHooks);
         }
     }
-
-    /**
-     * 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 ref The ServiceReference associated with the hook to be invoked, the hook
+     *        service object will be obtained through this object.
      * @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
+     * @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)
+    public void invokeHook(
+        ServiceReference ref, 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
+        Object hook = getService(framework, ref);
+        
+        try 
         {
             callback.invokeHook(hook);
-            // TODO: SERVICE HOOKS - Check that "services in use" is handled
         }
-        finally
+        catch (Throwable th)
         {
-            if (serviceFactory)
-            {
-                Object [] array = (Object []) hookRef;
-                ServiceFactory hookFactory = (ServiceFactory) array[0];
-                ServiceRegistration sr = (ServiceRegistration) array[1];
-                hookFactory.ungetService(framework, sr, hook);
-            }
+            m_logger.log(ref, Logger.LOG_WARNING,
+                "Problem invoking Service Registry Hook", th);
         }
-    }
-
+        finally 
+        {
+            ungetService(framework, ref);
+        }
+    }    
+    
     private static class UsageCount
     {
         public int m_count = 0;
@@ -894,4 +788,21 @@
     {
         void serviceChanged(ServiceEvent event, Dictionary oldProps);
     }
+    
+    private static class ServiceRankingComparator implements Comparator 
+    {
+        public int compare(Object o1, Object o2) 
+        {
+            if (!(o1 instanceof ServiceRegistration) ||
+                !(o2 instanceof ServiceRegistration)) 
+            {
+                return 0;
+            }
+            
+            ServiceReference r1 = ((ServiceRegistration) o1).getReference();
+            ServiceReference r2 = ((ServiceRegistration) o2).getReference();
+
+            return -r1.compareTo(r2);
+        }        
+    }
 }
\ No newline at end of file
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 a74f0b9..4d45b5d 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
@@ -45,6 +45,7 @@
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServicePermission;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.framework.hooks.service.EventHook;
 import org.osgi.framework.hooks.service.ListenerHook;
@@ -175,7 +176,7 @@
         }
     }
 
-    public void addListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+    public Filter addListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
     {
         // Verify the listener.
         if (l == null)
@@ -190,9 +191,10 @@
 
         // See if we can simply update the listener, if so then
         // return immediately.
-        if (updateListener(bundle, clazz, l, filter))
+        Filter oldFilter = updateListener(bundle, clazz, l, filter);
+        if (oldFilter != null)
         {
-            return;
+            return oldFilter;
         }
 
         // Lock the object to add the listener.
@@ -282,8 +284,9 @@
                 m_serviceListeners = listeners;
             }
         }
+        return null;
     }
-
+    
     public ListenerHook.ListenerInfo removeListener(
         Bundle bundle, Class clazz, EventListener l)
     {
@@ -341,7 +344,7 @@
                     // the listener for the ListenerHook callback.
                     if (ServiceListener.class == clazz)
                     {
-                        listenerInfo = wrapListener(listeners, i);
+                        listenerInfo = wrapListener(listeners, i, true);
                     }
                     idx = i;
                     break;
@@ -481,7 +484,7 @@
         }
     }
 
-    public boolean updateListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
+    public Filter updateListener(Bundle bundle, Class clazz, EventListener l, Filter filter)
     {
         synchronized (this)
         {
@@ -515,6 +518,7 @@
                     (listeners[i + LISTENER_CLASS_OFFSET] == clazz) &&
                     (listeners[i + LISTENER_OBJECT_OFFSET] == l))
                 {
+                    Filter oldFilter = null;
                     if (clazz == FrameworkListener.class)
                     {
                         // The spec says to ignore this case.
@@ -526,14 +530,15 @@
                     else if (clazz == ServiceListener.class)
                     {
                         // The spec says to update the filter in this case.
+                        oldFilter = (Filter) listeners[i + LISTENER_FILTER_OFFSET];
                         listeners[i + LISTENER_FILTER_OFFSET] = filter;
                     }
-                    return true;
+                    return oldFilter;
                 }
             }
         }
 
-        return false;
+        return null;
     }
 
     /**
@@ -543,7 +548,7 @@
      * @return Returns all existing service listener information into a collection of
      *         ListenerHook.ListenerInfo objects
     **/
-    public Collection /* <? extends ListenerHook.ListenerInfo> */ wrapAllServiceListeners()
+    public Collection /* <? extends ListenerHook.ListenerInfo> */ wrapAllServiceListeners(boolean removed)
     {
         Object[] listeners = null;
         synchronized (this)
@@ -554,7 +559,7 @@
         List existingListeners = new ArrayList();
         for (int i = 0, j = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT, j++)
         {
-            existingListeners.add(wrapListener(listeners, i));
+            existingListeners.add(wrapListener(listeners, i, removed));
         }
         return existingListeners;
     }
@@ -566,13 +571,15 @@
      * @param offset The offset into the array of the listener to wrap.
      * @return A ListenerHook.ListenerInfo object for the specified listener.
      */
-    private static ListenerHook.ListenerInfo wrapListener(Object[] listeners, int offset)
+    private static ListenerHook.ListenerInfo wrapListener(Object[] listeners, int offset, boolean removed)
     {
         Filter filter = ((Filter)listeners[offset + LISTENER_FILTER_OFFSET]);
 
         return new ListenerHookInfoImpl(
             ((Bundle)listeners[offset + LISTENER_BUNDLE_OFFSET]).getBundleContext(),
-            filter == null ? null : filter.toString());
+            (ServiceListener) listeners[offset + LISTENER_OBJECT_OFFSET], 
+            filter == null ? null : filter.toString(),
+            removed);
     }
 
     public void fireFrameworkEvent(FrameworkEvent event)
@@ -631,17 +638,19 @@
             {
                 final ListenerBundleContextCollectionWrapper wrapper =
                     new ListenerBundleContextCollectionWrapper(listeners);
+                InvokeHookCallback callback = new InvokeHookCallback() 
+                {
+                    public void invokeHook(Object hook) 
+                    {
+                        ((EventHook) hook).event(event, wrapper);                            
+                    }                        
+                }; 
                 for (int i = 0; i < eventHooks.size(); i++)
                 {
-                    if (felix != null)
+                    if (felix != null) 
                     {
-                        ServiceRegistry.invokeHook(eventHooks.get(i), felix, new InvokeHookCallback()
-                        {
-                            public void invokeHook(Object hook)
-                            {
-                                ((EventHook) hook).event(event, wrapper);
-                            }
-                        });
+                        m_serviceRegistry.invokeHook(
+                            (ServiceReference) eventHooks.get(i), felix, callback);
                     }
                 }
 
@@ -1164,4 +1173,4 @@
         public Object[] m_listeners = null;
         public EventObject m_event = null;
     }
-}
\ No newline at end of file
+}
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
index 5f034cc..fbd3704 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/ListenerHookInfoImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/ListenerHookInfoImpl.java
@@ -19,17 +19,22 @@
 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, String filter)
+    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()
@@ -44,6 +49,35 @@
 
     public boolean isRemoved()
     {
-        throw new UnsupportedOperationException("Not supported yet.");
+        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/test/java/org/apache/felix/framework/ServiceRegistryTest.java b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
index 562da2f..7034774 100644
--- a/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
@@ -19,7 +19,6 @@
 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;
@@ -31,6 +30,7 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.hooks.service.EventHook;
 import org.osgi.framework.hooks.service.FindHook;
@@ -58,7 +58,9 @@
         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());
+        assertTrue(sr.getEventHooks().iterator().next() instanceof ServiceReference);
+        assertSame(reg.getReference(), sr.getEventHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
         assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
         assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
         
@@ -84,10 +86,8 @@
         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);
+        assertSame(reg.getReference(), sr.getEventHooks().iterator().next());
+        assertSame(sf, ((ServiceRegistrationImpl) reg).getService());        
         assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
         assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
 
@@ -117,7 +117,8 @@
         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());
+        assertSame(reg.getReference(), sr.getFindHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
         assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
         assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
 
@@ -143,10 +144,8 @@
         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);
+        assertSame(reg.getReference(), sr.getFindHooks().iterator().next());
+        assertSame(sf, ((ServiceRegistrationImpl) reg).getService());        
         assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
         assertEquals("Postcondition failed", 0, sr.getListenerHooks().size());
 
@@ -179,7 +178,8 @@
         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());
+        assertSame(reg.getReference(), sr.getListenerHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
         assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
         assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
 
@@ -205,10 +205,8 @@
         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);
+        assertSame(reg.getReference(), sr.getListenerHooks().iterator().next());
+        assertSame(sf, ((ServiceRegistrationImpl) reg).getService());        
         assertEquals("Postcondition failed", 0, sr.getEventHooks().size());
         assertEquals("Postcondition failed", 0, sr.getFindHooks().size());
 
@@ -260,11 +258,14 @@
             FindHook.class.getName(),
             EventHook.class.getName()}, hook, new Hashtable());
         assertEquals(1, sr.getListenerHooks().size());
-        assertSame(hook, sr.getListenerHooks().iterator().next());
+        assertSame(reg.getReference(), sr.getListenerHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
         assertEquals(1, sr.getEventHooks().size());
-        assertSame(hook, sr.getEventHooks().iterator().next());
+        assertSame(reg.getReference(), sr.getEventHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
         assertEquals(1, sr.getFindHooks().size());
-        assertSame(hook, sr.getFindHooks().iterator().next());
+        assertSame(reg.getReference(), sr.getFindHooks().iterator().next());
+        assertSame(hook, ((ServiceRegistrationImpl) reg).getService());
 
         sr.unregisterService(b, reg);
         assertEquals("Should be no hooks left after unregistration", 0, sr.getEventHooks().size());
@@ -296,6 +297,8 @@
     
     public void testInvokeHook() 
     {
+        ServiceRegistry sr = new ServiceRegistry(null, null);
+        
         final List result = new ArrayList();
         InvokeHookCallback callback = new InvokeHookCallback() 
         {
@@ -316,16 +319,19 @@
             {
             }            
         };
-        assertSame(hook, ServiceRegistry.getHookRef(hook, null));
+        ServiceRegistration reg = new ServiceRegistrationImpl(sr, null, null, null, 
+            hook, new Hashtable());
         
         assertEquals("Precondition failed", 0, result.size());
-        ServiceRegistry.invokeHook(hook, fr, callback);
+        sr.invokeHook(reg.getReference(), fr, callback);
         assertEquals(1, result.size());
         assertSame(hook, result.iterator().next());
     }
     
     public void testInvokeHookFactory() 
     {
+        ServiceRegistry sr = new ServiceRegistry(null, null);
+
         final List result = new ArrayList();
         InvokeHookCallback callback = new InvokeHookCallback() 
         {
@@ -364,25 +370,19 @@
             }            
         };
 
-        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));
+        ServiceRegistration reg = new ServiceRegistrationImpl(sr, null, 
+            new String[] {FindHook.class.getName()}, null, 
+            sf, new Hashtable());       
     
         assertEquals("Precondition failed", 0, result.size());
         assertEquals("Precondition failed", 0, sfGet.size());
         assertEquals("Precondition failed", 0, sfUnget.size());
-        ServiceRegistry.invokeHook(arg, fr, callback);
+        sr.invokeHook(reg.getReference(), 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());        
-    }
-}
\ No newline at end of file
+    } 
+}
diff --git a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
index b66cff9..3dff2c5 100644
--- a/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
@@ -19,10 +19,10 @@
 package org.apache.felix.framework.util;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -78,20 +78,11 @@
         };
 
         Logger logger = new Logger();
-        ServiceRegistry registry = new ServiceRegistry(logger, null)
-        {
-            public List getEventHooks()
-            {
-                return Collections.unmodifiableList(
-                    Arrays.asList(new EventHook[]
-                    {
-                        eh1, eh2
-                    }));
-            }
-        };
+        ServiceRegistry registry = new ServiceRegistry(logger, null);
+        registry.registerService(null, new String [] {EventHook.class.getName()}, eh1, new Hashtable());
+        registry.registerService(null, new String [] {EventHook.class.getName()}, eh2, new Hashtable());
 
         // -- Set up event dispatcher
-
         EventDispatcher ed = EventDispatcher.start(logger);
         EventDispatcher.shutdown(); // stop the thread - would be nicer if we could create one without a thread for testing
         ed.setServiceRegistry(registry);
@@ -181,4 +172,4 @@
 
         return b;
     }
-}
\ No newline at end of file
+}