More refactoring to service registry hook handling to match
byte-code weaving hook handling. (FELIX-2959)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1127267 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
index e8014ea..e2a1464 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleWiringImpl.java
@@ -1366,7 +1366,7 @@
                     Set<ServiceReference<WeavingHook>> hooks =
                         felix.getHooks(WeavingHook.class);
                     WovenClassImpl wci = null;
-                    if ((hooks != null) && !hooks.isEmpty())
+                    if (!hooks.isEmpty())
                     {
                         // Create woven class to be used for hooks.
                         wci = new WovenClassImpl(name, BundleWiringImpl.this, bytes);
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 0dfcf10..a6e009d 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -606,8 +606,16 @@
                 m_activatorList = (List) m_configMutableMap.get(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP);
                 m_activatorList = (m_activatorList == null) ? new ArrayList() : new ArrayList(m_activatorList);
 
+                // Create service registry.
+                m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
+                    public void serviceChanged(ServiceEvent event, Dictionary oldProps)
+                    {
+                        fireServiceEvent(event, oldProps);
+                    }
+                });
+
                 // Initialize event dispatcher.
-                m_dispatcher = EventDispatcher.start(m_logger);
+                m_dispatcher = EventDispatcher.start(m_logger, m_registry);
 
                 // Create the bundle cache, if necessary, so that we can reload any
                 // installed bundles.
@@ -742,15 +750,6 @@
                 // keep the max value.
                 m_nextId = Math.max(m_nextId, loadNextId());
 
-                // Create service registry.
-                m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
-                    public void serviceChanged(ServiceEvent event, Dictionary oldProps)
-                    {
-                        fireServiceEvent(event, oldProps);
-                    }
-                });
-                m_dispatcher.setServiceRegistry(m_registry);
-
                 // The framework is now in its startup sequence.
                 setBundleStateAndNotify(this, Bundle.STARTING);
 
@@ -2904,26 +2903,50 @@
             final Collection removed = Collections.singleton(
                 new ListenerHookInfoImpl(
                 ((BundleImpl) bundle)._getBundleContext(), l, oldFilter.toString(), true));
-            InvokeHookCallback removedCallback = new ListenerHookRemovedCallback(removed);
             for (ServiceReference<ListenerHook> sr : listenerHooks)
             {
-                m_registry.invokeHook(sr, this, removedCallback);
+                ListenerHook lh = m_registry.getServiceSafely(this, sr);
+                if (lh != null)
+                {
+                    try
+                    {
+                        lh.removed(removed);
+                    }
+                    catch (Throwable th)
+                    {
+                        m_logger.log(sr, Logger.LOG_WARNING,
+                            "Problem invoking service registry hook", th);
+                    }
+                    finally
+                    {
+                        m_registry.ungetService(this, sr);
+                    }
+                }
             }
         }
 
         // Invoke the ListenerHook.added() on all hooks.
         final Collection added = Collections.singleton(
             new ListenerHookInfoImpl(((BundleImpl) bundle)._getBundleContext(), l, f, false));
-        InvokeHookCallback addedCallback = new InvokeHookCallback()
-        {
-            public void invokeHook(Object hook)
-            {
-                ((ListenerHook) hook).added(added);
-            }
-        };
         for (ServiceReference<ListenerHook> sr : listenerHooks)
         {
-            m_registry.invokeHook(sr, this, addedCallback);
+            ListenerHook lh = m_registry.getServiceSafely(this, sr);
+            if (lh != null)
+            {
+                try
+                {
+                    lh.added(added);
+                }
+                catch (Throwable th)
+                {
+                    m_logger.log(sr, Logger.LOG_WARNING,
+                        "Problem invoking service registry hook", th);
+                }
+                finally
+                {
+                    m_registry.ungetService(this, sr);
+                }
+            }
         }
     }
 
@@ -2944,11 +2967,26 @@
             // Invoke the ListenerHook.removed() on all hooks.
             Set<ServiceReference<ListenerHook>> listenerHooks =
                 m_registry.getHooks(ListenerHook.class);
-            Collection c = Collections.singleton(listener);
-            InvokeHookCallback callback = new ListenerHookRemovedCallback(c);
+            Collection removed = Collections.singleton(listener);
             for (ServiceReference<ListenerHook> sr : listenerHooks)
             {
-                m_registry.invokeHook(sr, this, callback);
+                ListenerHook lh = m_registry.getServiceSafely(this, sr);
+                if (lh != null)
+                {
+                    try
+                    {
+                        lh.removed(removed);
+                    }
+                    catch (Throwable th)
+                    {
+                        m_logger.log(sr, Logger.LOG_WARNING,
+                            "Problem invoking service registry hook", th);
+                    }
+                    finally
+                    {
+                        m_registry.ungetService(this, sr);
+                    }
+                }
             }
         }
     }
@@ -3053,14 +3091,23 @@
         // to invoke the callback with all existing service listeners.
         if (ServiceRegistry.isHook(classNames, ListenerHook.class, svcObj))
         {
-            m_registry.invokeHook(reg.getReference(), this, new InvokeHookCallback()
+            ListenerHook lh = (ListenerHook) m_registry.getServiceSafely(this, reg.getReference());
+            if (lh != null)
             {
-                public void invokeHook(Object hook)
+                try
                 {
-                    ((ListenerHook) hook).
-                        added(m_dispatcher.wrapAllServiceListeners(false));
+                    lh.added(m_dispatcher.wrapAllServiceListeners(false));
                 }
-            });
+                catch (Throwable th)
+                {
+                    m_logger.log(reg.getReference(), Logger.LOG_WARNING,
+                        "Problem invoking service registry hook", th);
+                }
+                finally
+                {
+                    m_registry.ungetService(this, reg.getReference());
+                }
+            }
         }
 
         // TODO: CONCURRENCY - Reconsider firing event here, outside of the
@@ -3125,20 +3172,29 @@
         // activate findhooks
         Set<ServiceReference<FindHook>> findHooks =
             m_registry.getHooks(FindHook.class);
-        InvokeHookCallback callback = new InvokeHookCallback()
-        {
-            public void invokeHook(Object hook)
-            {
-                ((FindHook) hook).find(bundle._getBundleContext(),
-                    className,
-                    expr,
-                    !checkAssignable,
-                    new ShrinkableCollection(refList));
-            }
-        };
         for (ServiceReference<FindHook> sr : findHooks)
         {
-            m_registry.invokeHook(sr, this, callback);
+            FindHook fh = m_registry.getServiceSafely(this, sr);
+            if (fh != null)
+            {
+                try
+                {
+                    fh.find(bundle._getBundleContext(),
+                        className,
+                        expr,
+                        !checkAssignable,
+                        new ShrinkableCollection(refList));
+                }
+                catch (Throwable th)
+                {
+                    m_logger.log(sr, Logger.LOG_WARNING,
+                        "Problem invoking service registry hook", th);
+                }
+                finally
+                {
+                    m_registry.ungetService(this, sr);
+                }
+            }
         }
 
         if (refList.size() > 0)
@@ -4992,21 +5048,6 @@
         }
     }
 
-    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);
-        }
-    }
-
     // Compares bundles by start level. Within a start level,
     // bundles are sorted by bundle ID.
     private static class StartLevelTuple implements Comparable<StartLevelTuple>
diff --git a/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java b/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java
deleted file mode 100644
index 62dde99..0000000
--- a/framework/src/main/java/org/apache/felix/framework/InvokeHookCallback.java
+++ /dev/null
@@ -1,24 +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;
-
-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 98d6026..fe0a079 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -238,7 +238,20 @@
         return null;
     }
 
-    public Object getService(Bundle bundle, ServiceReference ref)
+    public <S> S getServiceSafely(Bundle bundle, ServiceReference<S> ref)
+    {
+        try
+        {
+            return getService(bundle, ref);
+        }
+        catch (ServiceException ex)
+        {
+            // Just ignore and return null.
+        }
+        return null;
+    }
+
+    public <S> S getService(Bundle bundle, ServiceReference<S> ref)
     {
         UsageCount usage = null;
         Object svcObj = null;
@@ -331,7 +344,7 @@
             }
         }
 
-        return svcObj;
+        return (S) svcObj;
     }
 
     public boolean ungetService(Bundle bundle, ServiceReference ref)
@@ -757,34 +770,6 @@
         return (SortedSet<ServiceReference<S>>) (SortedSet) ss;
     }
 
-    /**
-     * Invokes a Service Registry Hook
-     * @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
-     *        be used, either the plain hook, or one obtained from the ServiceFactory.
-     */
-    public void invokeHook(
-        ServiceReference ref, Framework framework, InvokeHookCallback callback)
-    {
-        Object hook = getService(framework, ref);
-
-        try
-        {
-            callback.invokeHook(hook);
-        }
-        catch (Throwable th)
-        {
-            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;
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 6b7c8a1..c77ee55 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
@@ -30,7 +30,6 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-import org.apache.felix.framework.InvokeHookCallback;
 import org.apache.felix.framework.Logger;
 import org.apache.felix.framework.ServiceRegistry;
 import org.osgi.framework.AllServiceListener;
@@ -60,7 +59,7 @@
     static final int LISTENER_ARRAY_INCREMENT = 5;
 
     private final Logger m_logger;
-    private volatile ServiceRegistry m_serviceRegistry = null;
+    private final ServiceRegistry m_registry;
 
     // Representation of an empty listener list.
     private static final Object[] m_emptyList = new Object[0];
@@ -81,14 +80,15 @@
     // Pooled requests to avoid memory allocation.
     private static final ArrayList m_requestPool = new ArrayList();
 
-    private EventDispatcher(Logger logger)
+    private EventDispatcher(Logger logger, ServiceRegistry registry)
     {
         m_logger = logger;
+        m_registry = registry;
     }
 
-    public static EventDispatcher start(Logger logger)
+    public static EventDispatcher start(Logger logger, ServiceRegistry registry)
     {
-        EventDispatcher eventDispatcher = new EventDispatcher(logger);
+        EventDispatcher eventDispatcher = new EventDispatcher(logger, registry);
 
         synchronized (m_threadLock)
         {
@@ -128,11 +128,6 @@
         return eventDispatcher;
     }
 
-    public void setServiceRegistry(ServiceRegistry sr)
-    {
-        m_serviceRegistry = sr;
-    }
-
     public static void shutdown()
     {
         synchronized (m_threadLock)
@@ -630,31 +625,36 @@
             listeners = m_serviceListeners;
         }
 
-        if (m_serviceRegistry != null)
+        Set<ServiceReference<EventHook>> eventHooks = m_registry.getHooks(EventHook.class);
+        if ((eventHooks != null) && !eventHooks.isEmpty())
         {
-            Set<ServiceReference<EventHook>> eventHooks =
-                m_serviceRegistry.getHooks(EventHook.class);
-            if ((eventHooks != null) && !eventHooks.isEmpty())
+            final ListenerBundleContextCollectionWrapper wrapper =
+                new ListenerBundleContextCollectionWrapper(listeners);
+            for (ServiceReference<EventHook> sr : eventHooks)
             {
-                final ListenerBundleContextCollectionWrapper wrapper =
-                    new ListenerBundleContextCollectionWrapper(listeners);
-                InvokeHookCallback callback = new InvokeHookCallback()
+                if (felix != null)
                 {
-                    public void invokeHook(Object hook)
+                    EventHook eh = m_registry.getServiceSafely(felix, sr);
+                    if (eh != null)
                     {
-                        ((EventHook) hook).event(event, wrapper);
-                    }
-                };
-                for (ServiceReference<EventHook> sr : eventHooks)
-                {
-                    if (felix != null)
-                    {
-                        m_serviceRegistry.invokeHook(sr, felix, callback);
+                        try
+                        {
+                            eh.event(event, wrapper);
+                        }
+                        catch (Throwable th)
+                        {
+                            m_logger.log(sr, Logger.LOG_WARNING,
+                                "Problem invoking service registry hook", th);
+                        }
+                        finally
+                        {
+                            m_registry.ungetService(felix, sr);
+                        }
                     }
                 }
-
-                listeners = wrapper.getListeners();
             }
+
+            listeners = wrapper.getListeners();
         }
 
         // Fire all service events immediately on the calling thread.
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 ac1c25d..c8c8a9e 100644
--- a/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
@@ -18,10 +18,8 @@
  */
 package org.apache.felix.framework;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Hashtable;
-import java.util.List;
 
 import junit.framework.TestCase;
 
@@ -35,7 +33,6 @@
 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
 {
@@ -294,95 +291,4 @@
         assertEquals("Unregistration should have no effect", 0, sr.getHooks(FindHook.class).size());
         assertEquals("Unregistration should have no effect", 0, sr.getHooks(ListenerHook.class).size());
     }
-
-    public void testInvokeHook()
-    {
-        ServiceRegistry sr = new ServiceRegistry(null, null);
-
-        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)
-            {
-            }
-        };
-        ServiceRegistration reg = new ServiceRegistrationImpl(sr, null, null, null,
-            hook, new Hashtable());
-
-        assertEquals("Precondition failed", 0, result.size());
-        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()
-        {
-            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);
-            }
-        };
-
-        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());
-        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());
-    }
 }
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 3dff2c5..1c04eb5 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
@@ -83,9 +83,8 @@
         registry.registerService(null, new String [] {EventHook.class.getName()}, eh2, new Hashtable());
 
         // -- Set up event dispatcher
-        EventDispatcher ed = EventDispatcher.start(logger);
+        EventDispatcher ed = EventDispatcher.start(logger, registry);
         EventDispatcher.shutdown(); // stop the thread - would be nicer if we could create one without a thread for testing
-        ed.setServiceRegistry(registry);
 
         // -- Register some listeners
         final List fired = Collections.synchronizedList(new ArrayList());