FELIX-3186 Applied the patch, with some improvements.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1226520 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
index 8d3a04d..e0b5d3e 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
@@ -243,6 +243,15 @@
     }
     
     /**
+     * Creates a new adapter service.
+     * @return the adapter service
+     * @see DependencyManager#createAdapterService(Class, String, String, String, String, String)
+     */
+    public Component createAdapterService(Class serviceInterface, String serviceFilter, String add, String change, String remove, String swap) {
+        return m_manager.createAdapterService(serviceInterface, serviceFilter, add, change, remove, swap);
+    }  
+    
+    /**
      * Creates a new resource adapter service.
      * 
      * @return the resource adapter service
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 3da661d..befe82a 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -391,8 +391,13 @@
      * @param add name of the callback method to invoke on add
      * @param change name of the callback method to invoke on change
      * @param remove name of the callback method to invoke on remove
+     * @param swap name of the callback method to invoke on swap
      * @return a service that acts as a factory for generating adapters
      */
+    public Component createAdapterService(Class serviceInterface, String serviceFilter, String add, String change, String remove, String swap) {
+        return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, add, change, remove, swap);
+    }
+    
     public Component createAdapterService(Class serviceInterface, String serviceFilter, String add, String change, String remove) {
         return new AdapterServiceImpl(this, serviceInterface, serviceFilter, null, add, change, remove);
     }
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
index c77a628..991fe90 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
@@ -21,7 +21,6 @@
 import java.net.URL;
 import java.util.Dictionary;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -64,13 +63,12 @@
      * Set some service properties to all already instantiated services.
      */
     public void setServiceProperties(Dictionary serviceProperties) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).setServiceProperties(serviceProperties);
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).setServiceProperties(serviceProperties);
         }
     }
     
@@ -78,96 +76,93 @@
      * Remove a StateListener from all already instantiated services.
      */
     public void addStateListener(ComponentStateListener listener) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).addStateListener(listener);
-        } 
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).addStateListener(listener);
+        }
     }
 
     /**
      * Remove a StateListener from all already instantiated services.
      */
     public void removeStateListener(ComponentStateListener listener) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).removeStateListener(listener);
-        } 
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).removeStateListener(listener);
+        }
     }
     
     /**
      * Add a Dependency to all already instantiated services.
      */
     public void addDependency(Dependency d) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).add(d);
-        } 
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).add(d);
+        }
     }
     
     /**
      * Add a Dependency to all already instantiated services.
      */
     public void addDependencies(List dependencies) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).add(dependencies);
-        } 
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).add(dependencies);
+        }
     }
 
     /**
      * Remove a Dependency from all instantiated services.
      */
     public void removeDependency(Dependency d) {
-        Map services = new HashMap();
-        synchronized (this) {
-            services.putAll(m_services);
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
         }
-        Iterator i = services.values().iterator();
-        while (i.hasNext()) {
-            ((Component) i.next()).remove(d);
-        } 
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).remove(d);
+        }
     }
     
     // callbacks for FactoryConfigurationAdapterImpl
     public void updated(String pid, Dictionary properties) throws ConfigurationException {
         try {
             Component service;
-            synchronized (this) {
+            synchronized (m_services) {
                 service = (Component) m_services.get(pid);
             }
             if (service == null) { 
                 service = createService(new Object[] { properties });
-                synchronized (this) {
+                synchronized (m_services) {
                     m_services.put(pid, service);
                 }
                 m_manager.add(service);
-            } else {
+            }
+            else {
                 updateService(new Object[] { properties, service });
             }
         }
-        
         catch (Throwable t) {
             if (t instanceof ConfigurationException) {
                 throw (ConfigurationException) t;
-            } else if (t.getCause() instanceof ConfigurationException) {
+            }
+            else if (t.getCause() instanceof ConfigurationException) {
                 throw (ConfigurationException) t.getCause();
-            } else {
+            }
+            else {
                 throw new ConfigurationException(null, "Could not create service for ManagedServiceFactory Pid " + pid, t);
             }
         }
@@ -175,11 +170,10 @@
 
     public void deleted(String pid) {
         Component service = null;
-        synchronized (this) {
+        synchronized (m_services) {
             service = (Component) m_services.remove(pid);
         }
-        if (service != null)
-        {
+        if (service != null) {
             m_manager.remove(service);
         }
     }
@@ -187,60 +181,79 @@
     // callbacks for resources
     public void added(URL resource) {
         Component newService = createService(new Object[] { resource });
-        m_services.put(resource, newService);
+        synchronized (m_services) {
+            m_services.put(resource, newService);
+        }
         m_manager.add(newService);
     }
 
     public void removed(URL resource) {
-        Component newService = (Component) m_services.remove(resource);
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(resource);
+        }
         if (newService == null) {
             throw new IllegalStateException("Service should not be null here.");
         }
-        else {
-            m_manager.remove(newService);
-        }
+        m_manager.remove(newService);
     }
     
     // callbacks for services
     public void added(ServiceReference ref, Object service) {
         Component newService = createService(new Object[] { ref, service });
-        m_services.put(ref, newService);
+        synchronized (m_services) {
+            m_services.put(ref, newService);
+        }
         m_manager.add(newService);
     }
     
     public void removed(ServiceReference ref, Object service) {
-        Component newService = (Component) m_services.remove(ref);
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(ref);
+        }
         if (newService == null) {
             throw new IllegalStateException("Service should not be null here.");
         }
-        else {
-            m_manager.remove(newService);
+        m_manager.remove(newService);
+    }
+    
+    public void swapped(ServiceReference oldRef, Object oldService, ServiceReference newRef, Object newService) {
+        synchronized (m_services) {
+        	Component service = (Component) m_services.remove(oldRef);
+        	m_services.put(newRef, service);
         }
     }
     
     // callbacks for bundles
     public void added(Bundle bundle) {
         Component newService = createService(new Object[] { bundle });
-        m_services.put(bundle, newService);
+        synchronized (m_services) {
+            m_services.put(bundle, newService);
+        }
         m_manager.add(newService);
     }
     
     public void removed(Bundle bundle) {
-        Component newService = (Component) m_services.remove(bundle);
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(bundle);
+        }
         if (newService == null) {
             throw new IllegalStateException("Service should not be null here.");
         }
-        else {
-            m_manager.remove(newService);
-        }
+        m_manager.remove(newService);
     }
-    
+      
     public void stop() { 
-        Iterator i = m_services.values().iterator();
-        while (i.hasNext()) {
-            m_manager.remove((Component) i.next());
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+            m_services.clear();
         }
-        m_services.clear();
+        for (int i = 0; i < components.length; i++) {
+            m_manager.remove((Component) components[i]);
+        }
     }    
     
     public void configureAutoConfigState(Component target, Component source) {
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java
index 7bb6f75..b9b39b2 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java
@@ -46,13 +46,22 @@
      * @param change
      * @param remove
      */
-    public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
+    public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
         super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
-        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove))
+        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, swap))
                  .add(dm.createServiceDependency()
                       .setService(adapteeInterface, adapteeFilter)
                       .setAutoConfig(false)
-                      .setCallbacks("added", "removed"));
+                      .setCallbacks("added", null, "removed", "swapped"));
+    }	
+	
+    public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, null))
+                 .add(dm.createServiceDependency()
+                      .setService(adapteeInterface, adapteeFilter)
+                      .setAutoConfig(false)
+                      .setCallbacks("added", null, "removed", "swapped"));
     }
     
     public class AdapterImpl extends AbstractDecorator {
@@ -61,14 +70,16 @@
         private final String m_add;
         private final String m_change;
         private final String m_remove;
+        private final String m_swap;
         private final String m_autoConfig;
         
-        public AdapterImpl(Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
+        public AdapterImpl(Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
             m_adapteeInterface = adapteeInterface;
             m_adapteeFilter = adapteeFilter;
             m_autoConfig = autoConfig;
             m_add = add;
             m_change = change;
+            m_swap = swap;
             m_remove = remove;
         }
         
@@ -95,13 +106,15 @@
             List dependencies = m_component.getDependencies();
             dependencies.remove(0);
             ServiceDependency dependency = m_manager.createServiceDependency()
-                 .setService(m_adapteeInterface, ref)
+            	 // create a dependency on both the service id we're adapting and possible aspects for this given service id
+            	 .setService(m_adapteeInterface, "(|(" + Constants.SERVICE_ID + "=" + ref.getProperty(Constants.SERVICE_ID) 
+            			 	+ ")(" + DependencyManager.ASPECT + "=" + ref.getProperty(Constants.SERVICE_ID) + "))")
                  .setRequired(true);
             if (m_autoConfig != null) {
                 dependency.setAutoConfig(m_autoConfig);
             }
-            if (m_add != null || m_change != null || m_remove != null) {
-                dependency.setCallbacks(m_add, m_change, m_remove);
+            if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
+                dependency.setCallbacks(m_add, m_change, m_remove, m_swap);
             }
             
             Component service = m_manager.createComponent()
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
index fc3184a..09b20c0 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
@@ -538,7 +538,8 @@
         	// when a changed callback is specified we might not call the added callback just yet
         	if (m_callbackSwapped != null) {
         		handleAspectAwareAdded(dependencyService, reference, service);
-        	} else {
+        	}
+        	else {
         		invoke(dependencyService, reference, service, m_callbackAdded);
         	}
         }
@@ -553,7 +554,6 @@
 		Integer ranking = ServiceUtil.getRankingAsInteger(reference);
 		Tuple highestRankedService = null;
 		synchronized (m_componentByRank) {
-		    // TODO would be nicer if there was a ServiceUtil method for this...
 			Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
 			Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
 			if (componentMap == null) {
@@ -581,11 +581,16 @@
 		}    	
     }
     
-	private boolean componentIsDependencyManagerFactory(DependencyService dependencyService) {
-	    // TODO review if we can be a bit smarter with these package name checks
-		return dependencyService.getService() != null && dependencyService.getService().getClass().getName().startsWith("org.apache.felix.dm")
-			&& !dependencyService.getService().getClass().getName().startsWith("org.apache.felix.dm.test");
-	}
+    private boolean componentIsDependencyManagerFactory(DependencyService dependencyService) {
+        Object component = dependencyService.getService();
+        if (component != null) {
+            String className = component.getClass().getName();
+            return className.startsWith("org.apache.felix.dm")
+                && !className.startsWith("org.apache.felix.dm.impl.AdapterServiceImpl$AdapterImpl")
+                && !className.startsWith("org.apache.felix.dm.test");
+        }
+        return false;
+    }
     
 	private Tuple swapHighestRankedService(DependencyService dependencyService, Long serviceId, ServiceReference newReference, Object newService, Integer newRanking) {
 		// does a component with a higher ranking exists
@@ -655,7 +660,8 @@
         if (removed) {
         	if (m_callbackSwapped != null) {
         		handleAspectAwareRemoved(dependencyService, reference, service);
-        	} else {
+        	}
+        	else {
         		invoke(dependencyService, reference, service, m_callbackRemoved);
         	}
         }