You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2009/06/16 23:44:50 UTC

svn commit: r785419 - in /felix/trunk/framework/src: main/java/org/apache/felix/framework/ main/java/org/apache/felix/framework/util/ test/java/org/apache/felix/framework/ test/java/org/apache/felix/framework/util/

Author: rickhall
Date: Tue Jun 16 21:44:50 2009
New Revision: 785419

URL: http://svn.apache.org/viewvc?rev=785419&view=rev
Log:
Implemented ServiceEvent.MODIFIED_ENDMATCH. (FELIX-1244)

Added:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SmallSet.java
Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
    felix/trunk/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
    felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java
    felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Tue Jun 16 21:44:50 2009
@@ -28,6 +28,7 @@
 import org.apache.felix.framework.ext.SecurityProvider;
 import org.apache.felix.framework.searchpolicy.*;
 import org.apache.felix.framework.ModuleImpl.ModuleClassLoader;
+import org.apache.felix.framework.ServiceRegistry.ServiceRegistryCallbacks;
 import org.apache.felix.framework.util.*;
 import org.apache.felix.framework.util.manifestparser.*;
 import org.apache.felix.moduleloader.*;
@@ -616,18 +617,13 @@
             m_nextId = Math.max(m_nextId, loadNextId());
 
             // Create service registry.
-            m_registry = new ServiceRegistry(m_logger);
-            m_dispatcher.setServiceRegistry(m_registry);
-
-            // Add a listener to the service registry; this is
-            // used to distribute service registry events to
-            // service listeners.
-            m_registry.addServiceListener(new ServiceListener() {
-                public void serviceChanged(ServiceEvent event)
+            m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
+                public void serviceChanged(ServiceEvent event, ServiceRegistration reg)
                 {
-                    fireServiceEvent(event);
+                    fireServiceEvent(event, reg);
                 }
             });
+            m_dispatcher.setServiceRegistry(m_registry);
 
             // The framework is now in its startup sequence.
             setBundleStateAndNotify(this, Bundle.STARTING);
@@ -3623,12 +3619,12 @@
     /**
      * Fires service events.
      *
-     * @param type The type of service event to fire.
-     * @param ref The service reference associated with the event.
+     * @param event The service event to fire.
+     * @param reg The service registration associated with the service object.
     **/
-    private void fireServiceEvent(ServiceEvent event)
+    private void fireServiceEvent(ServiceEvent event, ServiceRegistration reg)
     {
-        m_dispatcher.fireServiceEvent(event, this);
+        m_dispatcher.fireServiceEvent(event, reg, this);
     }
 
     //

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java Tue Jun 16 21:44:50 2009
@@ -31,23 +31,23 @@
 class ServiceRegistrationImpl implements ServiceRegistration
 {
     // Service registry.
-    private ServiceRegistry m_registry = null;
+    private final ServiceRegistry m_registry;
     // Bundle implementing the service.
-    private Bundle m_bundle = null;
+    private final Bundle m_bundle;
     // Interfaces associated with the service object.
-    private String[] m_classes = null;
+    private final String[] m_classes;
     // Service Id associated with the service object.
-    private Long m_serviceId = null;
+    private final Long m_serviceId;
     // Service object.
-    private Object m_svcObj = null;
+    private volatile Object m_svcObj;
     // Service factory interface.
-    private ServiceFactory m_factory = null;
+    private volatile ServiceFactory m_factory;
     // Associated property dictionary.
     private volatile Map m_propMap = new StringMap(false);
     // Re-usable service reference.
-    private ServiceReferenceImpl m_ref = null;
+    private final ServiceReferenceImpl m_ref;
     // Flag indicating that we are unregistering.
-    private boolean m_isUnregistering = false;
+    private volatile boolean m_isUnregistering = false;
 
     public ServiceRegistrationImpl(
         ServiceRegistry registry, Bundle bundle,
@@ -82,7 +82,7 @@
         m_svcObj = null;
     }
 
-    public ServiceReference getReference()
+    public synchronized ServiceReference getReference()
     {
         // Make sure registration is valid.
         if (!isValid())
@@ -95,16 +95,24 @@
 
     public void setProperties(Dictionary dict)
     {
-        // Make sure registration is valid.
-        if (!isValid())
+        Map oldProps, newProps;
+        synchronized (this)
         {
-            throw new IllegalStateException(
-                "The service registration is no longer valid.");
+            // Make sure registration is valid.
+            if (!isValid())
+            {
+                throw new IllegalStateException(
+                    "The service registration is no longer valid.");
+            }
+            // Remember old properties.
+            oldProps = m_propMap;
+            // Set the properties.
+            initializeProperties(dict);
+            // Keep local reference to new properties.
+            newProps = m_propMap;
         }
-        // Set the properties.
-        initializeProperties(dict);
         // Tell registry about it.
-        m_registry.servicePropertiesModified(this);
+        m_registry.servicePropertiesModified(this, oldProps, newProps);
     }
 
     public void unregister()
@@ -136,7 +144,7 @@
      * @return <tt>true</tt> if the specified class is reachable from the
      *         service object's class loader, <tt>false</tt> otherwise.
     **/
-    protected boolean isClassAccessible(Class clazz)
+    private boolean isClassAccessible(Class clazz)
     {
         try
         {
@@ -153,18 +161,18 @@
         return false;
     }
 
-    protected Object getProperty(String key)
+    Object getProperty(String key)
     {
         return m_propMap.get(key);
     }
 
-    protected String[] getPropertyKeys()
+    private String[] getPropertyKeys()
     {
         Set s = m_propMap.keySet();
         return (String[]) s.toArray(new String[s.size()]);
     }
 
-    protected Bundle[] getUsingBundles()
+    private Bundle[] getUsingBundles()
     {
         return m_registry.getUsingBundles(m_ref);
     }
@@ -180,7 +188,7 @@
         return m_svcObj;
     }
 
-    protected Object getService(Bundle acqBundle)
+    Object getService(Bundle acqBundle)
     {
         // If the service object is a service factory, then
         // let it create the service object.
@@ -212,7 +220,7 @@
         }
     }
 
-    protected void ungetService(Bundle relBundle, Object svcObj)
+    void ungetService(Bundle relBundle, Object svcObj)
     {
         // If the service object is a service factory, then
         // let it release the service object.

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java Tue Jun 16 21:44:50 2009
@@ -38,7 +38,7 @@
     // Maps bundle to an array of usage counts.
     private Map m_inUseMap = new HashMap();
 
-    private ServiceListener m_serviceListener = null;
+    private final ServiceRegistryCallbacks m_callbacks;
 
     private final Object m_eventHookLock = new Object();
     private Object[] m_eventHooks = new Object[0];
@@ -47,9 +47,10 @@
     private final Object m_listenerHookLock = new Object();
     private Object[] m_listenerHooks = new Object[0];
 
-    public ServiceRegistry(Logger logger)
+    public ServiceRegistry(Logger logger, ServiceRegistryCallbacks callbacks)
     {
         m_logger = logger;
+        m_callbacks = callbacks;
     }
 
     public synchronized ServiceReference[] getRegisteredServices(Bundle bundle)
@@ -85,7 +86,13 @@
             ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
             m_serviceRegsMap.put(bundle, addServiceRegistration(regs, reg));
         }
-        fireServiceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()));
+
+        // Notify callback objects about registered service.
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(
+                new ServiceEvent(ServiceEvent.REGISTERED, reg.getReference()), reg);
+        }
         return reg;
     }
 
@@ -107,9 +114,12 @@
             m_serviceRegsMap.put(bundle, removeServiceRegistration(regs, reg));
         }
 
-        // Fire the service event which gives all client bundles the
-        // opportunity to unget their service object.
-        fireServiceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()));
+        // Notify callback objects about unregistering service.
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(
+                new ServiceEvent(ServiceEvent.UNREGISTERING, reg.getReference()), reg);
+        }
 
         // Now forcibly unget the service object for all stubborn clients.
         synchronized (this)
@@ -498,9 +508,13 @@
         return bundles;
     }
 
-    public void servicePropertiesModified(ServiceRegistration reg)
+    void servicePropertiesModified(ServiceRegistration reg, Map oldProps, Map newProps)
     {
-        fireServiceChanged(new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()));
+        if (m_callbacks != null)
+        {
+            m_callbacks.serviceChanged(
+                new ServiceEvent(ServiceEvent.MODIFIED, reg.getReference()), reg);
+        }
     }
 
     public Logger getLogger()
@@ -554,82 +568,6 @@
         return regs;
     }
 
-    public synchronized void addServiceListener(ServiceListener l)
-    {
-        m_serviceListener = ServiceListenerMulticaster.add(m_serviceListener, l);
-    }
-
-    public synchronized void removeServiceListener(ServiceListener l)
-    {
-        m_serviceListener = ServiceListenerMulticaster.remove(m_serviceListener, l);
-    }
-
-    protected void fireServiceChanged(ServiceEvent event)
-    {
-        // Grab a copy of the listener list.
-        ServiceListener listener;
-        synchronized (this)
-        {
-            listener = m_serviceListener;
-        }
-        // If not null, then dispatch event.
-        if (listener != null)
-        {
-            listener.serviceChanged(event);
-        }
-    }
-
-    private static class ServiceListenerMulticaster implements ServiceListener
-    {
-        protected ServiceListener m_a = null, m_b = null;
-
-        protected ServiceListenerMulticaster(ServiceListener a, ServiceListener b)
-        {
-            m_a = a;
-            m_b = b;
-        }
-
-        public void serviceChanged(ServiceEvent e)
-        {
-            m_a.serviceChanged(e);
-            m_b.serviceChanged(e);
-        }
-
-        public static ServiceListener add(ServiceListener a, ServiceListener b)
-        {
-            if (a == null)
-            {
-                return b;
-            }
-            else if (b == null)
-            {
-                return a;
-            }
-            else
-            {
-                return new ServiceListenerMulticaster(a, b);
-            }
-        }
-
-        public static ServiceListener remove(ServiceListener a, ServiceListener b)
-        {
-            if ((a == null) || (a == b))
-            {
-                return null;
-            }
-            else if (a instanceof ServiceListenerMulticaster)
-            {
-                return add(
-                    remove(((ServiceListenerMulticaster) a).m_a, b),
-                    remove(((ServiceListenerMulticaster) a).m_b, b));
-            }
-            else
-            {
-                return a;
-            }
-        }
-    }
-
     /**
      * Utility method to retrieve the specified bundle's usage count for the
      * specified service reference.
@@ -976,4 +914,9 @@
         public ServiceReference m_ref = null;
         public Object m_svcObj = null;
     }
-}
+
+    public interface ServiceRegistryCallbacks
+    {
+        void serviceChanged(ServiceEvent event, ServiceRegistration reg);
+    }
+}
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/EventDispatcher.java Tue Jun 16 21:44:50 2009
@@ -28,6 +28,7 @@
 import java.util.List;
 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;
@@ -44,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;
@@ -51,12 +53,13 @@
 
 public class EventDispatcher
 {
-    private static final int LISTENER_BUNDLE_OFFSET = 0;
-    private static final int LISTENER_CLASS_OFFSET = 1;
-    private static final int LISTENER_OBJECT_OFFSET = 2;
-    private static final int LISTENER_FILTER_OFFSET = 3;
-    private static final int LISTENER_SECURITY_OFFSET = 4;
-    private static final int LISTENER_ARRAY_INCREMENT = 5;
+    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_MATECHEDSET_OFFSET = 4;
+    static final int LISTENER_SECURITY_OFFSET = 5;
+    static final int LISTENER_ARRAY_INCREMENT = 6;
 
     private Logger m_logger = null;
     private volatile ServiceRegistry m_serviceRegistry = null;
@@ -198,6 +201,7 @@
         synchronized (this)
         {
             Object[] listeners = null;
+            Set set = null;
             Object acc = null;
 
             if (clazz == FrameworkListener.class)
@@ -223,7 +227,11 @@
                 {
                     acc = ((SecurityManager) sm).getSecurityContext();
                 }
-
+                // We need to create a Set for keeping track of matching service
+                // registrations so we can fire ServiceEvent.MODIFIED_ENDMATCH
+                // events. We need a Set even if filter is null, since the
+                // listener can be updated and have a filter added later.
+                set = new SmallSet();
                 listeners = m_serviceListeners;
             }
             else
@@ -239,6 +247,7 @@
                 listeners[LISTENER_CLASS_OFFSET] = clazz;
                 listeners[LISTENER_OBJECT_OFFSET] = l;
                 listeners[LISTENER_FILTER_OFFSET] = filter;
+                listeners[LISTENER_MATECHEDSET_OFFSET] = set;
                 listeners[LISTENER_SECURITY_OFFSET] = acc;
             }
             // Otherwise, we need to do some array copying.
@@ -254,6 +263,7 @@
                 newList[listeners.length + LISTENER_CLASS_OFFSET] = clazz;
                 newList[listeners.length + LISTENER_OBJECT_OFFSET] = l;
                 newList[listeners.length + LISTENER_FILTER_OFFSET] = filter;
+                newList[listeners.length + LISTENER_MATECHEDSET_OFFSET] = set;
                 newList[listeners.length + LISTENER_SECURITY_OFFSET] = acc;
                 listeners = newList;
             }
@@ -523,6 +533,7 @@
                     {
                         // The spec says to update the filter in this case.
                         listeners[i + LISTENER_FILTER_OFFSET] = filter;
+                        ((Set) listeners[i + LISTENER_MATECHEDSET_OFFSET]).clear();
                     }
                     return true;
                 }
@@ -596,7 +607,7 @@
         }
 
         // Fire synchronous bundle listeners immediately on the calling thread.
-        fireEventImmediately(m_logger, Request.BUNDLE_EVENT, syncListeners, event);
+        fireEventImmediately(m_logger, Request.BUNDLE_EVENT, syncListeners, event, null);
 
         // The spec says that asynchronous bundle listeners do not get events
         // of types STARTING, STOPPING, or LAZY_ACTIVATION.
@@ -609,7 +620,8 @@
         }
     }
 
-    public void fireServiceEvent(final ServiceEvent event, Framework felix)
+    public void fireServiceEvent(
+        final ServiceEvent event, final ServiceRegistration reg, final Framework felix)
     {
         // Take a snapshot of the listener array.
         Object[] listeners = null;
@@ -644,7 +656,7 @@
         }
 
         // Fire all service events immediately on the calling thread.
-        fireEventImmediately(m_logger, Request.SERVICE_EVENT, listeners, event);
+        fireEventImmediately(m_logger, Request.SERVICE_EVENT, listeners, event, reg);
     }
 
     private void fireEventAsynchronously(
@@ -688,7 +700,8 @@
     }
 
     private static void fireEventImmediately(
-        Logger logger, int type, Object[] listeners, EventObject event)
+        Logger logger, int type, Object[] listeners, EventObject event,
+        ServiceRegistration reg)
     {
         if (listeners.length > 0)
         {
@@ -700,6 +713,7 @@
                 Bundle bundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET];
                 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET];
                 Filter filter = (Filter) listeners[i + LISTENER_FILTER_OFFSET];
+                Set matchedSet = (Set) listeners[i + LISTENER_MATECHEDSET_OFFSET];
                 Object acc = listeners[i + LISTENER_SECURITY_OFFSET];
                 try
                 {
@@ -713,7 +727,8 @@
                     }
                     else if (type == Request.SERVICE_EVENT)
                     {
-                        invokeServiceListenerCallback(bundle, l, filter, acc, event);
+                        invokeServiceListenerCallback(
+                            bundle, l, filter, matchedSet, acc, event, reg);
                     }
                 }
                 catch (Throwable th)
@@ -786,7 +801,9 @@
     }
 
     private static void invokeServiceListenerCallback(
-        Bundle bundle, final EventListener l, Filter filter, Object acc, final EventObject event)
+        Bundle bundle, final EventListener l, Filter filter,
+        Set matchedSet, Object acc, final EventObject event,
+        final ServiceRegistration reg)
     {
         // Service events should be delivered to STARTING,
         // STOPPING, and ACTIVE bundles.
@@ -837,11 +854,24 @@
             if (hasPermission)
             {
                 // Dispatch according to the filter.
-                if ((filter == null) || filter.match(((ServiceEvent) event).getServiceReference()))
+                boolean matched = (filter == null)
+                    || filter.match(((ServiceEvent) event).getServiceReference());
+
+                if (matched)
                 {
                     if ((l instanceof AllServiceListener) ||
                         Util.isServiceAssignable(bundle, ((ServiceEvent) event).getServiceReference()))
                     {
+                        // If we have a filter, then record the matching service
+                        // registration so we can know when to fire a MODIFIED_ENDMATCH
+                        // event if the filter no longer matches.
+                        if (filter != null)
+                        {
+                            synchronized (matchedSet)
+                            {
+                                matchedSet.add(reg);
+                            }
+                        }
                         if (System.getSecurityManager() != null)
                         {
                             AccessController.doPrivileged(new PrivilegedAction() {
@@ -854,9 +884,37 @@
                         }
                         else
                         {
-                            {
-                                ((ServiceListener) l).serviceChanged((ServiceEvent) event);
-                            }
+                            ((ServiceListener) l).serviceChanged((ServiceEvent) event);
+                        }
+                    }
+                }
+                // We need to send an MODIFIED_ENDMATCH event if the listener
+                // matched previously.
+                else if (((ServiceEvent) event).getType() == ServiceEvent.MODIFIED)
+                {
+                    boolean removed = false;
+                    synchronized (matchedSet)
+                    {
+                        removed = matchedSet.remove(reg);
+                    }
+                    if (removed)
+                    {
+                        final ServiceEvent se = new ServiceEvent(
+                            ServiceEvent.MODIFIED_ENDMATCH,
+                            ((ServiceEvent) event).getServiceReference());
+                        if (System.getSecurityManager() != null)
+                        {
+                            AccessController.doPrivileged(new PrivilegedAction() {
+                                public Object run()
+                                {
+                                    ((ServiceListener) l).serviceChanged(se);
+                                    return null;
+                                }
+                            });
+                        }
+                        else
+                        {
+                            ((ServiceListener) l).serviceChanged(se);
                         }
                     }
                 }
@@ -909,7 +967,7 @@
             // NOTE: We don't catch any exceptions here, because
             // the invoked method shields us from exceptions by
             // catching Throwables when it invokes callbacks.
-            fireEventImmediately(req.m_logger, req.m_type, req.m_listeners, req.m_event);
+            fireEventImmediately(req.m_logger, req.m_type, req.m_listeners, req.m_event, null);
 
             // Put dispatch request in cache.
             synchronized (m_requestPool)

Added: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SmallSet.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SmallSet.java?rev=785419&view=auto
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SmallSet.java (added)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SmallSet.java Tue Jun 16 21:44:50 2009
@@ -0,0 +1,198 @@
+/*
+ * 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.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class SmallSet implements Set
+{
+    private Object[] m_objs;
+    private Set m_set;
+
+    public synchronized int size()
+    {
+        if (m_objs != null)
+        {
+            return m_objs.length;
+        }
+        else if (m_set != null)
+        {
+            return m_set.size();
+        }
+        return 0;
+    }
+
+    public synchronized boolean isEmpty()
+    {
+        return (size() == 0);
+    }
+
+    public synchronized boolean contains(Object obj)
+    {
+        boolean found = false;
+        if (obj != null)
+        {
+            if (m_objs != null)
+            {
+                for (int i = 0; !found && (i < m_objs.length); i++)
+                {
+                    found = m_objs[i].equals(obj);
+                }
+            }
+            else
+            {
+                found = (m_set == null) ? false : m_set.contains(obj);
+            }
+        }
+        return found;
+    }
+
+    public synchronized Iterator iterator()
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized Object[] toArray()
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized Object[] toArray(Object[] arg0)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized boolean add(Object obj)
+    {
+        boolean found = contains(obj);
+        if (!found)
+        {
+            if (size() < 10)
+            {
+                if (m_objs == null)
+                {
+                    m_objs = new Object[] { obj };
+                }
+                else
+                {
+                    Object[] tobjs = new Object[m_objs.length + 1];
+                    System.arraycopy(m_objs, 0, tobjs, 0, m_objs.length);
+                    tobjs[m_objs.length] = obj;
+                    m_objs = tobjs;
+                }
+            }
+            else
+            {
+                if (m_set == null)
+                {
+                    m_set = new HashSet();
+                    for (int i = 0; i < m_objs.length; i++)
+                    {
+                        m_set.add(m_objs[i]);
+                    }
+                    m_objs = null;
+                }
+                m_set.add(obj);
+            }
+        }
+        return !found;
+    }
+
+    public synchronized boolean remove(Object obj)
+    {
+        boolean found = contains(obj);
+        if (found)
+        {
+            if (size() < 10)
+            {
+                if (m_objs.length == 1)
+                {
+                    m_objs = null;
+                }
+                else
+                {
+                    int idx = -1;
+                    for (int i = 0; (idx < 0) && (i < m_objs.length); i++)
+                    {
+                        if (m_objs[i].equals(obj))
+                        {
+                            idx = i;
+                        }
+                    }
+
+                    if (idx >= 0)
+                    {
+                        Object[] tobjs = new Object[m_objs.length - 1];
+                        System.arraycopy(m_objs, 0, tobjs, 0, idx);
+                        if (idx < tobjs.length)
+                        {
+                            System.arraycopy(
+                                m_objs, idx + 1, tobjs, idx, tobjs.length - idx);
+                        }
+                        m_objs = tobjs;
+                    }
+                }
+            }
+            else
+            {
+                m_set.remove(obj);
+                if (m_set.size() < 10)
+                {
+                    m_objs = new Object[m_set.size()];
+                    int i = 0;
+                    for (Iterator it = m_set.iterator(); it.hasNext(); )
+                    {
+                        m_objs[i++] = it.next();
+                    }
+                    m_set = null;
+                }
+            }
+        }
+        return found;
+    }
+
+    public synchronized boolean containsAll(Collection arg0)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized boolean addAll(Collection arg0)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized boolean retainAll(Collection arg0)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized boolean removeAll(Collection arg0)
+    {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public synchronized void clear()
+    {
+        m_objs = null;
+        m_set = null;
+    }
+}
\ No newline at end of file

Modified: felix/trunk/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java (original)
+++ felix/trunk/framework/src/test/java/org/apache/felix/framework/ServiceRegistryTest.java Tue Jun 16 21:44:50 2009
@@ -45,7 +45,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         EventHook hook = new EventHook() 
         {
             public void event(ServiceEvent event, Collection contexts) 
@@ -74,7 +74,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
         sfControl.replay();
         ServiceFactory sf = (ServiceFactory) sfControl.getMock();
@@ -103,7 +103,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         FindHook hook = new FindHook() 
         {
             public void find(BundleContext context, String name, String filter,
@@ -133,7 +133,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
         sfControl.replay();
         ServiceFactory sf = (ServiceFactory) sfControl.getMock();
@@ -162,10 +162,9 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         ListenerHook hook = new ListenerHook() 
         {
-
             public void added(Collection listeners) 
             {
             }
@@ -196,7 +195,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         MockControl sfControl = MockControl.createNiceControl(ServiceFactory.class);
         sfControl.replay();
         ServiceFactory sf = (ServiceFactory) sfControl.getMock();
@@ -225,7 +224,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         class CombinedService implements ListenerHook, FindHook, EventHook, Runnable
         {
             public void added(Collection listeners) 
@@ -256,10 +255,10 @@
         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());
+            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());
@@ -279,7 +278,7 @@
         Bundle b = (Bundle) control.getMock();
         control.replay();
         
-        ServiceRegistry sr = new ServiceRegistry(new Logger());
+        ServiceRegistry sr = new ServiceRegistry(new Logger(), null);
         String svcObj = "hello";        
         assertEquals("Precondition failed", 0, sr.getEventHooks().size());
         assertEquals("Precondition failed", 0, sr.getFindHooks().size());
@@ -386,4 +385,4 @@
         assertSame(reg, sfGet.iterator().next());        
         assertSame(reg, sfUnget.iterator().next());        
     }
-}
+}
\ No newline at end of file

Modified: felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java (original)
+++ felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherListenerWrapperTest.java Tue Jun 16 21:44:50 2009
@@ -45,21 +45,24 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15),
-            b3,
-            BundleContext.class,
-            new Object(),
-            null,
-            Boolean.TRUE,
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15),       // LISTENER_SECURITY_OFFSET
+            b3,                    // LISTENER_BUNDLE_OFFSET
+            BundleContext.class,   // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            null,                  // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            Boolean.TRUE,          // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -80,9 +83,15 @@
 
         Object[] actualListeners =
             ((EventDispatcher.ListenerBundleContextCollectionWrapper) c).getListeners();
-        Object[] expectedListeners = new Object[10];
-        System.arraycopy(listeners, 0, expectedListeners, 0, 5);
-        System.arraycopy(listeners, 10, expectedListeners, 5, 5);
+        Object[] expectedListeners = new Object[EventDispatcher.LISTENER_ARRAY_INCREMENT * 2];
+        System.arraycopy(listeners, 0, expectedListeners, 0,
+            EventDispatcher.LISTENER_ARRAY_INCREMENT);
+        System.arraycopy(
+            listeners,
+            EventDispatcher.LISTENER_ARRAY_INCREMENT * 2,
+            expectedListeners,
+            EventDispatcher.LISTENER_ARRAY_INCREMENT,
+            EventDispatcher.LISTENER_ARRAY_INCREMENT);
         assertTrue(Arrays.equals(expectedListeners, actualListeners));
 
         assertTrue(c.remove(bc1));
@@ -95,8 +104,12 @@
 
         Object[] actualListeners2 =
             ((EventDispatcher.ListenerBundleContextCollectionWrapper) c).getListeners();
-        Object[] expectedListeners2 = new Object[5];
-        System.arraycopy(listeners, 10, expectedListeners2, 0, 5);
+        Object[] expectedListeners2 = new Object[EventDispatcher.LISTENER_ARRAY_INCREMENT];
+        System.arraycopy(
+            listeners, EventDispatcher.LISTENER_ARRAY_INCREMENT * 2,
+            expectedListeners2,
+            0,
+            EventDispatcher.LISTENER_ARRAY_INCREMENT);
         assertTrue(Arrays.equals(expectedListeners2, actualListeners2));
 
         assertTrue(c.remove(bc3));
@@ -121,16 +134,18 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15)
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15)        // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -260,21 +275,24 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15),
-            b3,
-            BundleContext.class,
-            new Object(),
-            null,
-            Boolean.TRUE,
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15),       // LISTENER_SECURITY_OFFSET
+            b3,                    // LISTENER_BUNDLE_OFFSET
+            BundleContext.class,   // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            null,                  // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            Boolean.TRUE,          // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -310,21 +328,24 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15),
-            b3,
-            BundleContext.class,
-            new Object(),
-            null,
-            Boolean.TRUE,
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15),       // LISTENER_SECURITY_OFFSET
+            b3,                    // LISTENER_BUNDLE_OFFSET
+            BundleContext.class,   // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            null,                  // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            Boolean.TRUE,          // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -356,21 +377,24 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15),
-            b3,
-            BundleContext.class,
-            new Object(),
-            null,
-            Boolean.TRUE,
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15),       // LISTENER_SECURITY_OFFSET
+            b3,                    // LISTENER_BUNDLE_OFFSET
+            BundleContext.class,   // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            null,                  // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            Boolean.TRUE,          // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -405,16 +429,18 @@
 
         Object[] listeners = new Object[]
         {
-            b1,
-            String.class,
-            new Object(),
-            "(some=filter)",
-            null,
-            b2,
-            Integer.class,
-            new Object(),
-            "(some.other=filter)",
-            new Integer(15),
+            b1,                    // LISTENER_BUNDLE_OFFSET
+            String.class,          // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some=filter)",       // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            null,                  // LISTENER_SECURITY_OFFSET
+            b2,                    // LISTENER_BUNDLE_OFFSET
+            Integer.class,         // LISTENER_CLASS_OFFSET
+            new Object(),          // LISTENER_OBJECT_OFFSET
+            "(some.other=filter)", // LISTENER_FILTER_OFFSET
+            null,                  // LISTENER_MATECHEDSET_OFFSET
+            new Integer(15),       // LISTENER_SECURITY_OFFSET
         };
 
         Collection c = new EventDispatcher.ListenerBundleContextCollectionWrapper(listeners);
@@ -458,4 +484,4 @@
 
         return b;
     }
-}
\ No newline at end of file
+}

Modified: felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java?rev=785419&r1=785418&r2=785419&view=diff
==============================================================================
--- felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java (original)
+++ felix/trunk/framework/src/test/java/org/apache/felix/framework/util/EventDispatcherTest.java Tue Jun 16 21:44:50 2009
@@ -78,7 +78,7 @@
         };
 
         Logger logger = new Logger();
-        ServiceRegistry registry = new ServiceRegistry(logger)
+        ServiceRegistry registry = new ServiceRegistry(logger, null)
         {
             public List getEventHooks()
             {
@@ -155,7 +155,7 @@
                 framework
             });
 
-        ed.fireServiceEvent(event, framework);
+        ed.fireServiceEvent(event, null, framework);
         assertEquals(1, fired.size());
         assertSame(sl3, fired.iterator().next());
 
@@ -181,4 +181,4 @@
 
         return b;
     }
-}
\ No newline at end of file
+}