felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From uiter...@apache.org
Subject svn commit: r1487101 [1/2] - in /felix/sandbox/uiterlix/dependencymanager/core: ./ .externalToolBuilders/ .settings/ src/main/java/org/apache/felix/dm/ src/main/java/org/apache/felix/dm/impl/ src/main/java/org/apache/felix/dm/impl/dependencies/ src/mai...
Date Tue, 28 May 2013 20:30:01 GMT
Author: uiterlix
Date: Tue May 28 20:30:00 2013
New Revision: 1487101

URL: http://svn.apache.org/r1487101
Log:
work in progress in component serialization.

Added:
    felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.m2e.core.prefs
    felix/sandbox/uiterlix/dependencymanager/core/bnd.bnd
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
      - copied, changed from r1364521, felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AdvancedMultiPropertyFilterIndex.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/Filter.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/Property.java
Modified:
    felix/sandbox/uiterlix/dependencymanager/core/.classpath
    felix/sandbox/uiterlix/dependencymanager/core/.externalToolBuilders/Maven_Ant_Builder.launch
    felix/sandbox/uiterlix/dependencymanager/core/.project
    felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.jdt.core.prefs
    felix/sandbox/uiterlix/dependencymanager/core/pom.xml
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/Component.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyService.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/ServiceDependency.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/BundleContextInterceptor.java
    felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/ServiceRegistryCache.java

Modified: felix/sandbox/uiterlix/dependencymanager/core/.classpath
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/.classpath?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/.classpath (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/.classpath Tue May 28 20:30:00 2013
@@ -1,11 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-  <classpathentry kind="src" path="src/main/java" including="**/*.java"/>
-  <classpathentry kind="src" path="." including="LICENSE*|NOTICE*|DEPENDENCIES*|*.txt" excluding="**/*.java"/>
-  <classpathentry kind="output" path="target/classes"/>
-  <classpathentry kind="var" path="M2_REPO/org/easymock/easymock/2.4/easymock-2.4.jar"/>
-  <classpathentry kind="var" path="M2_REPO/junit/junit/4.0/junit-4.0.jar"/>
-  <classpathentry kind="var" path="M2_REPO/org/mockito/mockito-all/1.7/mockito-all-1.7.jar"/>
-  <classpathentry kind="var" path="M2_REPO/org/osgi/org.osgi.compendium/4.2.0/org.osgi.compendium-4.2.0.jar"/>
-  <classpathentry kind="var" path="M2_REPO/org/osgi/org.osgi.core/4.2.0/org.osgi.core-4.2.0.jar"/>
-  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-</classpath>
\ No newline at end of file
+	<classpathentry including="**/*.java" kind="src" path="src/main/java"/>
+	<classpathentry excluding="**/*.java" including="LICENSE*|NOTICE*|DEPENDENCIES*|*.txt" kind="src" path=""/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Modified: felix/sandbox/uiterlix/dependencymanager/core/.externalToolBuilders/Maven_Ant_Builder.launch
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/.externalToolBuilders/Maven_Ant_Builder.launch?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/.externalToolBuilders/Maven_Ant_Builder.launch (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/.externalToolBuilders/Maven_Ant_Builder.launch Tue May 28 20:30:00 2013
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
   <booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
   <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,clean"/>

Modified: felix/sandbox/uiterlix/dependencymanager/core/.project
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/.project?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/.project (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/.project Tue May 28 20:30:00 2013
@@ -1,22 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-  <name>org.apache.felix.dependencymanager</name>
-  <comment>Apache Felix is an OSGi implementation. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>
-  <projects/>
-  <buildSpec>
-    <buildCommand>
-      <name>org.eclipse.jdt.core.javabuilder</name>
-    </buildCommand>
-    <buildCommand>
-      <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
-      <arguments>
-        <dictionary>
-          <key>LaunchConfigHandle</key>
-          <value>&lt;project&gt;/.externalToolBuilders/Maven_Ant_Builder.launch</value>
-        </dictionary>
-      </arguments>
-    </buildCommand>
-  </buildSpec>
-  <natures>
-    <nature>org.eclipse.jdt.core.javanature</nature>
-  </natures>
-</projectDescription>
\ No newline at end of file
+	<name>org.apache.felix.dependencymanager</name>
+	<comment>Apache Felix is an OSGi implementation. NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.</comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+			<arguments>
+				<dictionary>
+					<key>LaunchConfigHandle</key>
+					<value>&lt;project&gt;/.externalToolBuilders/Maven_Ant_Builder.launch</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>bndtools.core.bndbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>bndtools.core.bndnature</nature>
+	</natures>
+</projectDescription>

Modified: felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.jdt.core.prefs
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.jdt.core.prefs?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.jdt.core.prefs (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.jdt.core.prefs Tue May 28 20:30:00 2013
@@ -1,3 +1,6 @@
-#Fri Feb 10 10:40:26 CET 2012
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.3
+#Fri Jul 20 08:52:08 CEST 2012
 eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.3
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.4

Added: felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.m2e.core.prefs
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.m2e.core.prefs?rev=1487101&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.m2e.core.prefs (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/.settings/org.eclipse.m2e.core.prefs Tue May 28 20:30:00 2013
@@ -0,0 +1,5 @@
+#Fri Jul 20 08:51:50 CEST 2012
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

Added: felix/sandbox/uiterlix/dependencymanager/core/bnd.bnd
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/bnd.bnd?rev=1487101&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/bnd.bnd (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/bnd.bnd Tue May 28 20:30:00 2013
@@ -0,0 +1,11 @@
+Bundle-SymbolicName: org.apache.felix.dependencymanager
+-buildpath: osgi.core;version=4.2.0,\
+	osgi.compendium
+Private-Package: org.apache.felix.dm.impl,\
+	org.apache.felix.dm.impl.dependencies,\
+	org.apache.felix.dm.impl.index,\
+	org.apache.felix.dm.impl.metatype
+Export-Package: org.apache.felix.dm,\
+	org.apache.felix.dm.tracker
+Bundle-Version: 3.1.1-SNAPSHOT
+-includeresource: src/main/java
\ No newline at end of file

Modified: felix/sandbox/uiterlix/dependencymanager/core/pom.xml
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/pom.xml?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/pom.xml (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/pom.xml Tue May 28 20:30:00 2013
@@ -30,7 +30,7 @@
     </properties>
     <name>Apache Felix Dependency Manager</name>
     <artifactId>org.apache.felix.dependencymanager</artifactId>
-    <version>3.1.0-SNAPSHOT</version>
+    <version>3.1.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
     <dependencies>
         <dependency>
@@ -88,7 +88,6 @@
                         <Export-Package>org.apache.felix.dm;version="3.0.0";provide:=true,org.apache.felix.dm.tracker;version="3.1.0";provide:=true</Export-Package>
                         <Import-Package>*</Import-Package>
                         <Private-Package>org.apache.felix.dm.impl, org.apache.felix.dm.impl.*</Private-Package>
-                        <!-- Uncomment this next line to include source code in the bundle. -->
                         <Include-Resource>src/main/java</Include-Resource>
                     </instructions>
                 </configuration>

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/Component.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/Component.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/Component.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/Component.java Tue May 28 20:30:00 2013
@@ -296,4 +296,5 @@ public interface Component {
      * Returns the instance variable name of auto configuration of the specified class.
      */
     public String getAutoConfigInstance(Class clazz);
+   
 }

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java Tue May 28 20:30:00 2013
@@ -38,10 +38,11 @@ import org.apache.felix.dm.impl.dependen
 import org.apache.felix.dm.impl.dependencies.ResourceDependencyImpl;
 import org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl;
 import org.apache.felix.dm.impl.dependencies.TemporalServiceDependencyImpl;
+import org.apache.felix.dm.impl.index.AdvancedMultiPropertyFilterIndex;
 import org.apache.felix.dm.impl.index.AspectFilterIndex;
-import org.apache.felix.dm.impl.index.MultiPropertyExactFilter;
 import org.apache.felix.dm.impl.index.ServiceRegistryCache;
 import org.apache.felix.dm.impl.metatype.PropertyMetaDataImpl;
+import org.apache.felix.dm.impl.metatype.Resource;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
@@ -78,6 +79,7 @@ public class DependencyManager {
     }
     
     DependencyManager(BundleContext context, Logger logger) {
+    	System.out.println("THIS IS XUI DEPENDENCY MANAGER!");
         m_context = createContext(context);
         m_logger = logger;
         synchronized (m_dependencyManagers) {
@@ -106,8 +108,9 @@ public class DependencyManager {
                         m_serviceRegistryCache.addFilterIndex(new AspectFilterIndex());
                     }
                     else {
-                        String[] propList = props[i].split(",");
-                        m_serviceRegistryCache.addFilterIndex(new MultiPropertyExactFilter(propList));
+//                    	String[] propList = props[i].split(",");
+//                    	m_serviceRegistryCache.addFilterIndex(new MultiPropertyExactFilter(propList));
+                      m_serviceRegistryCache.addFilterIndex(new AdvancedMultiPropertyFilterIndex(props[i]));
                     }
                 }
             }
@@ -160,9 +163,9 @@ public class DependencyManager {
      * 
      * @param service the service to add
      */
-    public void add(Component service) {
-        m_components.add(service);
-        service.start();
+    public void add(final Component service) {
+		m_components.add(service);
+		service.start();
     }
 
     /**
@@ -171,9 +174,9 @@ public class DependencyManager {
      * 
      * @param service the service to remove
      */
-    public void remove(Component service) {
-        service.stop();
-        m_components.remove(service);
+    public void remove(final Component service) {
+		service.stop();
+		m_components.remove(service);
     }
 
     /**

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyService.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyService.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyService.java Tue May 28 20:30:00 2013
@@ -18,7 +18,12 @@
  */
 package org.apache.felix.dm;
 
+import org.apache.felix.dm.impl.SerialExecutor;
+import org.osgi.framework.BundleContext;
+
 /**
+ * Interface to the component, so dependencies can interact with it.
+ * 
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public interface DependencyService {
@@ -42,18 +47,58 @@ public interface DependencyService {
      * @param dependency the dependency
      */
     public void dependencyChanged(Dependency dependency);
-    
+
+    /**
+     * Returns the component instance.
+     * 
+     * @return component instance
+     */
     public Object getService(); // is also defined on the Service interface
+    
+    /**
+     * Initializes the component. Instantiates it and injects the default injectables such
+     * as {@link BundleContext} and {@link DependencyManager}.
+     */
     public void initService(); // was an implementation method TODO we use it in ConfDepImpl but should not (probably)
+    
+    /**
+     * Returns <code>true</code> if this component is registered. In other words, all
+     * its required dependencies are available.
+     * 
+     * @return <code>true</code> if the component is registered
+     */
     public boolean isRegistered(); // impl method
+    
+    /**
+     * Returns a list of all instances that are part of the composition for this component.
+     * 
+     * @return an array of instances
+     */
     public Object[] getCompositionInstances(); // impl method
     
+    /**
+     * Returns <code>true</code> if this component is instantiated.
+     * 
+     * @return <code>true</code> if this component is instantiated
+     */
     public boolean isInstantiated();
     
     /**
      * Can be called by the dependency whenever it wants to invoke callback methods.
      */
     public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters);
-    
+
+    /**
+     * Returns the component interface.
+     * 
+     * @return the component interface
+     */
     public Component getServiceInterface();
+    
+    /**
+     * TODO
+     * @return
+     */
+    public SerialExecutor getSerialExecutor();
+    
 }

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/ServiceDependency.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/ServiceDependency.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/ServiceDependency.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/ServiceDependency.java Tue May 28 20:30:00 2013
@@ -209,4 +209,6 @@ public interface ServiceDependency exten
     public ServiceDependency setPropagate(Object instance, String method);
 
     public ServiceDependency setInstanceBound(boolean isInstanceBound);    
+    
+    public void enableDebug(String debugKey);
 }

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java Tue May 28 20:30:00 2013
@@ -23,6 +23,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -106,6 +107,10 @@ public class ComponentImpl implements Co
     private Map m_autoConfigInstance = new HashMap();
     
     private boolean m_isStarted = false;
+    private boolean m_changingState = false;
+    //debug
+	private StackTraceElement[] unregisterStackTrace;
+	
 
     public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
         synchronized (VOID) {
@@ -132,198 +137,205 @@ public class ComponentImpl implements Co
         synchronized (m_dependencies) {
             oldState = m_state;
             newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
+//            m_state = newState;
         }
         calculateStateChanges(oldState, newState);
     }
     
     private void calculateStateChanges(final State oldState, final State newState) {
-        if (oldState.isInactive() && (newState.isTrackingOptional())) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    activateService(newState);
-                }});
-        }
-        if (oldState.isInactive() && (newState.isWaitingForRequired())) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    startTrackingRequired(newState);
-                }});
-        }
-        if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    activateService(newState);
-                }});
-        }
-        if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    stopTrackingRequired(oldState);
-                }});
-        }
-        if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    // TODO as far as I can see there is nothing left to do here
-                    // unbindService(newState);
-                }});
-        }
-        if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    deactivateService(oldState);
-                }});
-        }
-        if (oldState.isTrackingOptional() && newState.isBound()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    bindService(newState);
-                }});
-        }
-        if (oldState.isTrackingOptional() && newState.isInactive()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    deactivateService(oldState);
-                    stopTrackingRequired(oldState);
-                }});
-        }
-        if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    deactivateService(oldState);
-                }});
-        }
-        if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    deactivateService(oldState);
-                    stopTrackingRequired(oldState);
-                }});
-        }
-        if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    bindService(newState);
-                }});
-        }
-        if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    unbindService(oldState);
-                }});
-        }
-        if (oldState.isBound() && newState.isWaitingForRequired()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    unbindService(oldState);
-                    deactivateService(oldState);
-                }});
-        }
-        if (oldState.isBound() && newState.isInactive()) {
-            m_executor.enqueue(new Runnable() {
-                public void run() {
-                    unbindService(oldState);
-                    deactivateService(oldState);
-                    stopTrackingRequired(oldState);
-                }});
-        }
-        m_executor.execute();
+    	boolean canChangeState = false;
+    	synchronized (this) {
+			if (!m_changingState) {
+				m_changingState = true;
+				canChangeState = m_changingState;
+			}
+		}
+    	if (canChangeState) {
+    		System.err.println("changing state from " + oldState + " to " + newState);
+    		m_state = newState;
+	        if (oldState.isInactive() && (newState.isTrackingOptional())) {
+	                activateService(newState);
+	        }
+	        if (oldState.isInactive() && (newState.isWaitingForRequired())) {
+	                startTrackingRequired(newState);
+	        }
+	        if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
+	                activateService(newState);
+	        }
+	        if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
+	                stopTrackingRequired(oldState);
+	        }
+	        if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
+	                    // TODO as far as I can see there is nothing left to do here
+	                    // unbindService(newState);
+	        }
+	        if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
+	                deactivateService(oldState);
+	        }
+	        if (oldState.isTrackingOptional() && newState.isBound()) {
+	                bindService(newState);
+	        }
+	        if (oldState.isTrackingOptional() && newState.isInactive()) {
+	                deactivateService(oldState);
+	                stopTrackingRequired(oldState);
+	        }
+	        if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
+	                deactivateService(oldState);
+	        }
+	        if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
+	                deactivateService(oldState);
+	                stopTrackingRequired(oldState);
+	        }
+	        if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
+	                bindService(newState);
+	        }
+	        if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
+	                unbindService(oldState);
+	        }
+	        if (oldState.isBound() && newState.isWaitingForRequired()) {
+	                unbindService(oldState);
+	                deactivateService(oldState);
+	        }
+	        if (oldState.isBound() && newState.isInactive()) {
+	                unbindService(oldState);
+	                deactivateService(oldState);
+	                stopTrackingRequired(oldState);
+	        }
+	        synchronized (this) {
+	        	State nextOldState = null;
+	        	State nextNewState = null;
+				synchronized (m_dependencies) {
+					nextOldState = m_state;
+					// starting the dependency above might have triggered another state change, so
+					// we have to fetch the current state again
+					nextNewState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+				}
+				m_changingState = false;
+				if (!nextOldState.equals(nextNewState)) {
+					System.err.println("next: " + nextOldState + " to " + nextNewState);
+					calculateStateChanges(nextOldState, nextNewState);
+				}
+	        }
+    	} else {
+    		System.err.println("ignoring stateChange " + oldState + " to " + newState);
+    	}
     }
     
     // TODO fix code duplication between add(Dependency) and add(List)
     public Component add(final Dependency dependency) {
-    	State oldState, newState;
-        synchronized (m_dependencies) {
-        	oldState = m_state;
-            m_dependencies.add(dependency);
-        }
-        
-        // if we're inactive, don't do anything, otherwise we might want to start
-        // the dependency
-        if (!oldState.isInactive()) {
-            // if the dependency is required, it should be started regardless of the state
-            // we're in
-            if (dependency.isRequired()) {
-                ((DependencyActivation) dependency).start(this);
-            }
-            else {
-                // if the dependency is optional, it should only be started if we're in
-                // bound state
-                if (oldState.isBound()) {
-                    ((DependencyActivation) dependency).start(this);
-                }
-            }
-        }
+    	Runnable addDependencyRunnable = new Runnable() {
 
-        synchronized (m_dependencies) {
-            oldState = m_state;
-            // starting the dependency above might have triggered another state change, so
-            // we have to fetch the current state again
-            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
-        }
-        calculateStateChanges(oldState, newState);
+			public void run() {
+				State oldState, newState;
+				synchronized (m_dependencies) {
+					oldState = m_state;
+					m_dependencies.add(dependency);
+				}
+				
+				// if we're inactive, don't do anything, otherwise we might want to start
+				// the dependency
+				if (!oldState.isInactive()) {
+					// if the dependency is required, it should be started regardless of the state
+					// we're in
+					if (dependency.isRequired()) {
+						((DependencyActivation) dependency).start(ComponentImpl.this);
+					}
+					else {
+						// if the dependency is optional, it should only be started if we're in
+						// bound state
+						if (oldState.isBound()) {
+							((DependencyActivation) dependency).start(ComponentImpl.this);
+						}
+					}
+				}
+				
+				synchronized (m_dependencies) {
+					oldState = m_state;
+					// starting the dependency above might have triggered another state change, so
+					// we have to fetch the current state again
+					newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+//					m_state = newState;
+				}
+				calculateStateChanges(oldState, newState);
+			}
+    		
+    	};
+    	m_executor.execute(addDependencyRunnable);
         return this;
     }
     
-    public Component add(List dependencies) {
-        State oldState, newState;
-        synchronized (m_dependencies) {
-            oldState = m_state;
-            for (int i = 0; i < dependencies.size(); i++) {
-                m_dependencies.add(dependencies.get(i));
-            }
-        }
-        
-        // if we're inactive, don't do anything, otherwise we might want to start
-        // the dependencies
-        if (!oldState.isInactive()) {
-            for (int i = 0; i < dependencies.size(); i++) {
-                Dependency dependency = (Dependency) dependencies.get(i);
-                // if the dependency is required, it should be started regardless of the state
-                // we're in
-                if (dependency.isRequired()) {
-                    ((DependencyActivation) dependency).start(this);
-                }
-                else {
-                    // if the dependency is optional, it should only be started if we're in
-                    // bound state
-                    if (oldState.isBound()) {
-                        ((DependencyActivation) dependency).start(this);
-                    }
-                }
-            }
-        }
+    public Component add(final List dependencies) {
+    	Runnable addDependenciesRunnable = new Runnable() {
 
-        synchronized (m_dependencies) {
-            oldState = m_state;
-            // starting the dependency above might have triggered another state change, so
-            // we have to fetch the current state again
-            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
-        }
-        calculateStateChanges(oldState, newState);
+			public void run() {
+				State oldState, newState;
+				synchronized (m_dependencies) {
+					oldState = m_state;
+					for (int i = 0; i < dependencies.size(); i++) {
+						m_dependencies.add(dependencies.get(i));
+					}
+				}
+				
+				// if we're inactive, don't do anything, otherwise we might want to start
+				// the dependencies
+				if (!oldState.isInactive()) {
+					for (int i = 0; i < dependencies.size(); i++) {
+						Dependency dependency = (Dependency) dependencies.get(i);
+						// if the dependency is required, it should be started regardless of the state
+						// we're in
+						if (dependency.isRequired()) {
+							((DependencyActivation) dependency).start(ComponentImpl.this);
+						}
+						else {
+							// if the dependency is optional, it should only be started if we're in
+							// bound state
+							if (oldState.isBound()) {
+								((DependencyActivation) dependency).start(ComponentImpl.this);
+							}
+						}
+					}
+				}
+				
+				synchronized (m_dependencies) {
+					oldState = m_state;
+					// starting the dependency above might have triggered another state change, so
+					// we have to fetch the current state again
+					newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+//					m_state = newState;
+				}
+				calculateStateChanges(oldState, newState);
+				
+			}
+    		
+    	};
+    	m_executor.execute(addDependenciesRunnable);
         return this;
     }
 
-    public Component remove(Dependency dependency) {
-    	State oldState, newState;
-        synchronized (m_dependencies) {
-        	oldState = m_state;
-            m_dependencies.remove(dependency);
-        }
-        if (oldState.isAllRequiredAvailable() || ((oldState.isWaitingForRequired() || oldState.isWaitingForRequiredInstantiated()) && dependency.isRequired())) {
-        	((DependencyActivation) dependency).stop(this);
-        }
-        synchronized (m_dependencies) {
-            // starting the dependency above might have triggered another state change, so
-            // we have to fetch the current state again
-            oldState = m_state;
-            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
-        }
-        calculateStateChanges(oldState, newState);
+    public Component remove(final Dependency dependency) {
+    	Runnable removeDependencyRunnable = new Runnable() {
+			
+			public void run() {
+				State oldState, newState;
+				synchronized (m_dependencies) {
+					oldState = m_state;
+					m_dependencies.remove(dependency);
+				}
+				if (oldState.isAllRequiredAvailable() || ((oldState.isWaitingForRequired() || oldState.isWaitingForRequiredInstantiated()) && dependency.isRequired())) {
+					((DependencyActivation) dependency).stop(ComponentImpl.this);
+				}
+				synchronized (m_dependencies) {
+					// starting the dependency above might have triggered another state change, so
+					// we have to fetch the current state again
+					oldState = m_state;
+					newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+//					m_state = newState;
+				}
+				calculateStateChanges(oldState, newState);
+				
+			}
+		};
+		m_executor.execute(removeDependencyRunnable);
         return this;
     }
 
@@ -350,7 +362,7 @@ public class ComponentImpl implements Co
         synchronized (m_dependencies) {
         	oldState = m_state;
             newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
+//            m_state = newState;
         }
         if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
         	updateInstance(dependency);
@@ -373,7 +385,7 @@ public class ComponentImpl implements Co
         synchronized (m_dependencies) {
         	oldState = m_state;
             newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
-            m_state = newState;
+//            m_state = newState;
         }
         if (newState.isAllRequiredAvailable()) {
         	updateInstance(dependency);
@@ -381,30 +393,57 @@ public class ComponentImpl implements Co
         calculateStateChanges(oldState, newState);
     }
 
-    public synchronized void start() {
-    	if (!m_isStarted) {
-    	    m_isStarted = true;
-	        State oldState, newState;
-	        synchronized (m_dependencies) {
-	            oldState = m_state;
-	            newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
-	            m_state = newState;
-	        }
-	        calculateStateChanges(oldState, newState);
-    	}
+    public void start() {
+    	Runnable startRunnable = new Runnable() {
+			
+			public void run() {
+				boolean needsStarting = false;
+				synchronized (ComponentImpl.this) {
+					if (!m_isStarted) {
+						m_isStarted = true;
+						needsStarting = true;
+					}
+				}
+				if (needsStarting) {
+					State oldState, newState;
+					synchronized (m_dependencies) {
+						oldState = m_state;
+						newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
+//						m_state = newState;
+					}
+					calculateStateChanges(oldState, newState);
+				}
+				
+			}
+		};
+		m_executor.enqueue(startRunnable);
+		m_executor.execute();
     }
 
-    public synchronized void stop() {
-        if (m_isStarted) {
-            m_isStarted = false;
-	        State oldState, newState;
-	        synchronized (m_dependencies) {
-	            oldState = m_state;
-	            newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
-	            m_state = newState;
-	        }
-	        calculateStateChanges(oldState, newState);
-    	}
+    public void stop() {
+    	Runnable stopRunnable = new Runnable() {
+			
+			public void run() {
+				boolean needsStopping = false;
+				synchronized (ComponentImpl.this) {
+					if (m_isStarted) {
+						m_isStarted = false;
+						needsStopping = true;
+					}
+				}
+				if (needsStopping) {
+					State oldState, newState;
+					synchronized (m_dependencies) {
+						oldState = m_state;
+						newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
+//						m_state = newState;
+					}
+					calculateStateChanges(oldState, newState);
+				}
+			}
+		};
+		m_executor.enqueue(stopRunnable);
+		m_executor.execute();
     }
 
     public synchronized Component setInterface(String serviceName, Dictionary properties) {
@@ -479,10 +518,18 @@ public class ComponentImpl implements Co
 	    return null;
 	}
 
-	public synchronized Component setServiceProperties(Dictionary serviceProperties) {
-	    m_serviceProperties = serviceProperties;
-	    if ((m_registration != null) && (m_serviceName != null)) {
-	        m_registration.setProperties(calculateServiceProperties());
+	public Component setServiceProperties(Dictionary serviceProperties) {
+	    boolean needsProperties = false;
+	    Dictionary properties = null;
+	    synchronized (this) {
+	        m_serviceProperties = serviceProperties;
+	        if ((m_registration != null) && (m_serviceName != null)) {
+	            properties = calculateServiceProperties();
+	            needsProperties = true;
+	        }
+	    }
+	    if (needsProperties) {
+	        m_registration.setProperties(properties);
 	    }
 	    return this;
 	}
@@ -587,7 +634,7 @@ public class ComponentImpl implements Co
         // itself
         invoke(init);
         // see if any of this caused further state changes
-        calculateStateChanges();
+//        calculateStateChanges();
     }
 
     private void bindService(State state) {
@@ -890,18 +937,29 @@ public class ComponentImpl implements Co
     private void unregisterService() {
         m_isBound = false;
         if (m_serviceName != null) {
-            m_registration.unregister();
-            configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
-            m_registration = null;
+        	if (m_registration != null) { 
+        		m_registration.unregister();
+        		configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
+        		m_registration = null;
+        		if ("true".equals(System.getProperty("dm.dumpUnregisterStack", "false"))) {
+        			unregisterStackTrace = Thread.currentThread().getStackTrace();
+        		}
+        	} else {
+        		if (unregisterStackTrace == null) {
+        			throw new IllegalStateException("Attempt to unregister a component that has already been unregistered.");
+        		} else {
+        			throw new IllegalStateException("Attempt to unregister a component that has already been unregistered. Previous stack = " + Arrays.toString(unregisterStackTrace));
+        		}
+        	}
         }
     }
 
     private void updateInstance(Dependency dependency) {
         if (dependency.isAutoConfig()) {
             configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
-            if (dependency.isPropagated() && m_registration != null) {
-                m_registration.setProperties(calculateServiceProperties());
-            }
+        }
+        if (dependency.isPropagated() && m_registration != null) {
+            m_registration.setProperties(calculateServiceProperties());
         }
     }
 
@@ -1162,4 +1220,8 @@ public class ComponentImpl implements Co
         }
         return -1;
     }
+
+	public SerialExecutor getSerialExecutor() {
+		return m_executor;
+	}
 }

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java Tue May 28 20:30:00 2013
@@ -272,5 +272,6 @@ public class FilterService implements Co
 
     public BundleContext getBundleContext() {
         return m_component.getBundleContext();
-    };
+    }
+
 }
\ No newline at end of file

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java Tue May 28 20:30:00 2013
@@ -33,6 +33,7 @@ import java.util.NoSuchElementException;
 public final class SerialExecutor {
     private final LinkedList m_workQueue = new LinkedList();
     private Runnable m_active;
+    private Thread m_activeThread;
     
     /**
      * Enqueue a new task for later execution. This method is
@@ -68,6 +69,20 @@ public final class SerialExecutor {
     		scheduleNext();
     	}
     }
+    
+    public void execute(Runnable runnable) {
+    	boolean inCurrentThread = false;
+    	synchronized (this) {
+    		inCurrentThread = Thread.currentThread().equals(m_activeThread);
+    	}
+		if (inCurrentThread) {
+			// do immediately
+			runnable.run();
+		} else {
+			enqueue(runnable);
+			execute();
+		}
+    }
 
     private void scheduleNext() {
     	Runnable active;
@@ -79,6 +94,11 @@ public final class SerialExecutor {
     			m_active = null;
     		}
     		active = m_active;
+    		if (m_active != null) {
+    			m_activeThread = Thread.currentThread();
+    		} else {
+    			m_activeThread = null;
+    		}
     	}
     	if (active != null) {
             active.run();

Modified: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java?rev=1487101&r1=1487100&r2=1487101&view=diff
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java Tue May 28 20:30:00 2013
@@ -200,6 +200,10 @@ public class ResourceDependencyImpl exte
     		long counter;
     		Object[] services;
     		synchronized (this) {
+    			if (m_resources.indexOf(resource) == -1) {
+    				m_logger.log(Logger.LOG_WARNING, "handleResourceRemoved called for unknown resource: " + resource);
+    				return;
+    			}
     			m_resourceProperties.remove(m_resources.indexOf(resource));
     		    m_resources.remove(resource);
     			counter = m_resources.size();

Copied: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java (from r1364521, felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java)
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java?p2=felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java&p1=felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java&r1=1364521&r2=1487101&rev=1487101&view=diff
==============================================================================
--- felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java (original)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java Tue May 28 20:30:00 2013
@@ -28,9 +28,11 @@ import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.Properties;
 import java.util.Set;
 
@@ -83,6 +85,16 @@ public class ServiceDependencyImpl exten
     private String m_propagateCallbackMethod;
     private final Map m_sr = new HashMap(); /* <DependencyService, Set<Tuple<ServiceReference, Object>> */
 	private Map m_componentByRank = new HashMap(); /* <Component, Map<Long, Map<Integer, Tuple>>> */
+	
+	private boolean m_debug = false;
+	private String m_debugKey = null;
+	
+	private final LinkedList m_injectionQueue = new LinkedList();
+	
+	public void enableDebug(String key) {
+		this.m_debug = true;
+		this.m_debugKey = key;
+	}
     
     private static final Comparator COMPARATOR = new Comparator() {
         public int getRank(ServiceReference ref) {
@@ -416,7 +428,13 @@ public class ServiceDependencyImpl exten
             }
         }
         if (needsStarting) {
-            m_tracker.open();
+        	// when the swapped callback is set, also track the aspects
+        	boolean trackAllServices = false;
+        	boolean trackAllAspects = false;
+        	if (m_callbackSwapped != null) {
+        		trackAllAspects = true;
+        	} 
+        	m_tracker.open(trackAllServices, trackAllAspects);
         }
     }
 
@@ -447,78 +465,125 @@ public class ServiceDependencyImpl exten
         return service;
     }
 
-    public void addedService(ServiceReference ref, Object service) {
-        boolean makeAvailable = makeAvailable();
+    public void addedService(final ServiceReference ref, final Object service) {
+    	if (m_debug) {
+    		debug("addedservice: " + ref);
+    	}
+//        final boolean makeAvailable = makeAvailable();
         
         Object[] services;
         synchronized (this) {
             services = m_services.toArray();
         }
         for (int i = 0; i < services.length; i++) {
-            DependencyService ds = (DependencyService) services[i];
-            if (makeAvailable) {
-                if (ds.isInstantiated() && isInstanceBound() && isRequired()) {
-                    invokeAdded(ds, ref, service);
-                }
-                // The dependency callback will be defered until all required dependency are available.
-                ds.dependencyAvailable(this);
-                if (!isRequired()) {
-                    // For optional dependency, we always invoke callback, because at this point, we know
-                    // that the service has been started, and the service start method has been called.
-                    // (See the ServiceImpl.bindService method, which will activate optional dependencies using 
-                    // startTrackingOptional() method). 
-                    invokeAdded(ds, ref, service);
-                }
-            }
-            else {
-                ds.dependencyChanged(this);
-                // At this point, either the dependency is optional (meaning that the service has been started,
-                // because if not, then our dependency would not be active); or the dependency is required,
-                // meaning that either the service is not yet started, or already started.
-                // In all cases, we have to inject the required dependency.
-                
-                // we only try to invoke the method here if we are really already instantiated
-                if (ds.isInstantiated() && ds.getCompositionInstances().length > 0) {
-                    invokeAdded(ds, ref, service);
-                }
-            }
+            final DependencyService ds = (DependencyService) services[i];
+            
+            Runnable addedServiceRunnable = new Runnable() {
+
+				public void run() {
+					final boolean makeAvailable = makeAvailable();
+					if (makeAvailable) {
+						if (ds.isInstantiated() && isInstanceBound() && isRequired()) {
+							if (m_debug) {
+								debug("invoke added: " + ref);
+							}
+							invokeAdded(ds, ref, service); //**
+						}
+						// The dependency callback will be deferred until all required dependency are available.
+						if (m_debug) {
+							debug("dependency available: " + ref);
+						}
+						ds.dependencyAvailable(ServiceDependencyImpl.this); 
+						if (!isRequired()) {
+							// For optional dependency, we always invoke callback, because at this point, we know
+							// that the service has been started, and the service start method has been called.
+							// (See the ServiceImpl.bindService method, which will activate optional dependencies using 
+							// startTrackingOptional() method).
+							if (m_debug) {
+								debug("invoke added: " + ref);
+							}
+							invokeAdded(ds, ref, service); //**
+						}
+					}
+					else {
+						if (m_debug) {
+							debug("dependency changed: " + ref);
+						}
+						ds.dependencyChanged(ServiceDependencyImpl.this); 
+						// At this point, either the dependency is optional (meaning that the service has been started,
+						// because if not, then our dependency would not be active); or the dependency is required,
+						// meaning that either the service is not yet started, or already started.
+						// In all cases, we have to inject the required dependency.
+						
+						// we only try to invoke the method here if we are really already instantiated
+						if (ds.isInstantiated() && ds.getCompositionInstances().length > 0) {
+							if (m_debug) {
+								debug("invoke added: " + ref);
+							}
+							invokeAdded(ds, ref, service); //**
+						}
+					}
+				} 
+            };
+            ds.getSerialExecutor().execute(addedServiceRunnable);
         }
     }
 
-    public void modifiedService(ServiceReference ref, Object service) {
+    public void modifiedService(final ServiceReference ref, final Object service) {
         Object[] services;
         synchronized (this) {
             services = m_services.toArray();
         }
         for (int i = 0; i < services.length; i++) {
-            DependencyService ds = (DependencyService) services[i];
-            ds.dependencyChanged(this);
-            if (ds.isRegistered()) {
-                invokeChanged(ds, ref, service);
-            }
+            final DependencyService ds = (DependencyService) services[i];
+            Runnable modifiedServiceRunnable = new Runnable() {
+
+				public void run() {
+					ds.dependencyChanged(ServiceDependencyImpl.this);
+					if (ds.isRegistered()) {
+						invokeChanged(ds, ref, service);
+					}
+				}
+            	
+            };
+            ds.getSerialExecutor().execute(modifiedServiceRunnable);
         }
     }
 
-    public void removedService(ServiceReference ref, Object service) {
-        boolean makeUnavailable = makeUnavailable();
-        
+    public void removedService(final ServiceReference ref, final Object service) {
+    	if (m_debug) {
+    		debug("removedservice: " + ref);
+    	}
+        final boolean makeUnavailable = makeUnavailable();
+        if (m_debug) {
+        	debug("make unavailable: " + makeUnavailable);
+        }
         Object[] services;
         synchronized (this) {
             services = m_services.toArray();
         }
 
         for (int i = 0; i < services.length; i++) {
-            DependencyService ds = (DependencyService) services[i];
-            if (makeUnavailable) {
-                ds.dependencyUnavailable(this);
-                if (!isRequired() || (ds.isInstantiated() && isInstanceBound())) {
-                    invokeRemoved(ds, ref, service);
-                }
-            }
-            else {
-                ds.dependencyChanged(this);
-                invokeRemoved(ds, ref, service);
-            }
+            final DependencyService ds = (DependencyService) services[i];
+            
+            Runnable removedServiceRunnable = new Runnable() {
+
+				public void run() {
+					if (makeUnavailable) {
+						ds.dependencyUnavailable(ServiceDependencyImpl.this);
+						// when the dependency is optional or the dependency is instance bound and the component is instantiated (and the dependency is required)
+						// then remove is invoked. In other cases the removed has been when the component was unconfigured.
+						if (!isRequired() || (ds.isInstantiated() && isInstanceBound())) {
+							invokeRemoved(ds, ref, service);
+						}
+					}
+					else {
+						ds.dependencyChanged(ServiceDependencyImpl.this);
+						invokeRemoved(ds, ref, service);
+					}
+				}
+            };
+            ds.getSerialExecutor().execute(removedServiceRunnable);
         }
         // unget what we got in addingService (see ServiceTracker 701.4.1)
         m_context.ungetService(ref);
@@ -526,6 +591,9 @@ public class ServiceDependencyImpl exten
     }
     
     public void invokeAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
+    	if (m_debug) {
+    		debug("invoke added");
+    	}
         boolean added = false;
         synchronized (m_sr) {
             Set set = (Set) m_sr.get(dependencyService);
@@ -546,14 +614,39 @@ public class ServiceDependencyImpl exten
         }
     }
     
-    private void handleAspectAwareAdded(DependencyService dependencyService, ServiceReference reference, Object service) {
+    private synchronized void waitForCallbackLock(Runnable runnable) {
+    	while (m_injectionQueue.indexOf(runnable) != 0) {
+    		try {
+				wait();
+			} catch (InterruptedException e) {
+			}
+    	}
+    }
+    
+    private synchronized void enqueueCallback(Runnable runnable) {
+    	m_injectionQueue.addLast(runnable);
+    }
+    
+    private synchronized void releaseCallback(Runnable runnable) {
+    	m_injectionQueue.remove(runnable);
+    	notifyAll();
+    }
+    
+    private void handleAspectAwareAdded(final DependencyService dependencyService, final ServiceReference reference, final Object service) {
+    	if (m_debug) {
+    		debug("aspectawareadded: " + reference.getProperty("service.ranking"));
+    	}
 		if (componentIsDependencyManagerFactory(dependencyService)) {
 			// component is either aspect or adapter factory instance, these must be ignored.
 			return;
 		}
 		boolean invokeAdded = false;
+		boolean invokeSwapped = false;
 		Integer ranking = ServiceUtil.getRankingAsInteger(reference);
-		Tuple highestRankedService = null;
+		Tuple newHighestRankedService = null;
+		Tuple prevHighestRankedService = null;
+		Runnable callbackRunnable = null;
+		Map rankings = null;
 		synchronized (m_componentByRank) {
 			Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
 			Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
@@ -562,7 +655,7 @@ public class ServiceDependencyImpl exten
 				componentMap = new HashMap(); /* <Long, Map<Integer, Tuple>> */
 				m_componentByRank.put(dependencyService, componentMap);
 			}
-			Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
+			rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
 			if (rankings == null) {
 				// new component added
 				rankings = new HashMap(); /* <Integer, Tuple> */
@@ -572,14 +665,86 @@ public class ServiceDependencyImpl exten
 			} 
 			
 			if (!invokeAdded) {
-				highestRankedService = swapHighestRankedService(dependencyService, originalServiceId, reference, service, ranking);
+				// current highest ranked
+				prevHighestRankedService = (Tuple)getHighestRankedService(dependencyService, originalServiceId).getValue();
+				newHighestRankedService = swapHighestRankedService(dependencyService, originalServiceId, reference, service, ranking);
+				if (m_debug) {
+					debug("prevhigh: " + prevHighestRankedService.getServiceReference().getProperty("service.ranking") + ", new high: " + newHighestRankedService.getServiceReference().getProperty("service.ranking"));
+				}
+				if (!prevHighestRankedService.getServiceReference().equals(newHighestRankedService.getServiceReference())) {
+					// new highest ranked service
+					if (m_debug) {
+						debug("New highest ranked to swap to");
+					}
+					invokeSwapped = true;
+				} else {
+					if (m_debug) {
+						debug("Ignoring lower ranked or irrelevant swap");
+					}
+				}
+			}
+			if (m_debug) {
+				debug(m_componentByRank.toString());
+			}
+			
+			// up until this point should be synchronized on m_componentsByRank to keep integrity of the administration and consequences
+			// then the do phase comes, here we want to guarantee the effects of this operation are done like they were synchronized, however
+			// synchronization on m_componentsByRank to too course grained here, so we'd like to switch to synchronization on the
+			// original service id, therefore we're using our own guarded block to ensure the correct order.
+			
+			if (invokeAdded) {
+				if (m_debug) {
+					debug("invoke added: " + reference.getProperty("service.ranking"));
+				}
+				callbackRunnable = createCallbackRunnable(dependencyService, reference, service, m_callbackAdded);
+				enqueueCallback(callbackRunnable);
+			} else if (invokeSwapped) {
+				if (m_debug) {
+					debug("invoke swapped: " + newHighestRankedService.getServiceReference().getProperty("service.ranking") + " replacing " + prevHighestRankedService.getServiceReference().getProperty("service.ranking"));
+				}
+				callbackRunnable = createSwapRunnable(dependencyService, prevHighestRankedService.getServiceReference(), prevHighestRankedService.getService(), newHighestRankedService.getServiceReference(), newHighestRankedService.getService());
+				enqueueCallback(callbackRunnable);
+			}    	
+		}
+		if (callbackRunnable != null) {
+			waitForCallbackLock(callbackRunnable);
+			synchronized (rankings) {
+				releaseCallback(callbackRunnable);
+				execute(callbackRunnable);
 			}
 		}
-		if (invokeAdded) {
-			invoke(dependencyService, reference, service, m_callbackAdded);
-		} else {
-			invokeSwappedCallback(dependencyService, highestRankedService.getServiceReference(), highestRankedService.getService(), reference, service);
-		}    	
+    }
+    
+    private Runnable createCallbackRunnable(final DependencyService dependencyService, final ServiceReference reference, final Object service, final String callback) {
+    	return new Runnable() {
+			public void run() {
+				invoke(dependencyService, reference, service, callback);			
+			}
+			public String toString() {
+				return callback + " on " + dependencyService;
+			}
+		};
+    }
+    
+    private Runnable createSwapRunnable(final DependencyService dependencyService, final ServiceReference prevReference, final Object prevService, final ServiceReference newReference, final Object newService) {
+    	return new Runnable() {
+			public void run() {
+				invokeSwappedCallback(dependencyService, prevReference, prevService, newReference, newService);					
+			}
+			public String toString() {
+				return "swap on " + dependencyService;
+			}
+		};
+    }
+    
+    private void execute(Runnable runnable) {
+    	runnable.run();
+    }
+    
+    private void debug(String message) {
+    	if (m_debug) {
+    		System.out.println("[" + m_debugKey + "] " + Thread.currentThread().getId() + " : " + message);
+    	}
     }
     
     private boolean componentIsDependencyManagerFactory(DependencyService dependencyService) {
@@ -594,13 +759,14 @@ public class ServiceDependencyImpl exten
     }
     
 	private Tuple swapHighestRankedService(DependencyService dependencyService, Long serviceId, ServiceReference newReference, Object newService, Integer newRanking) {
-		// does a component with a higher ranking exists
+		// does a component with a higher ranking exist
 		synchronized (m_componentByRank) {
 			Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
 			Map rankings = (Map) componentMap.get(serviceId); /* <Integer, Tuple> */
-			Entry highestEntry = getHighestRankedService(dependencyService, serviceId); /* <Integer, Tuple> */
-			rankings.remove(highestEntry.getKey());
+//			Entry highestEntry = getHighestRankedService(dependencyService, serviceId); /* <Integer, Tuple> */
+//			rankings.remove(highestEntry.getKey());
 			rankings.put(newRanking, new Tuple(newReference, newService));
+			Entry highestEntry = getHighestRankedService(dependencyService, serviceId); /* <Integer, Tuple> */
 			return (Tuple) highestEntry.getValue();
 		}
 	}
@@ -643,6 +809,9 @@ public class ServiceDependencyImpl exten
 		// 1) a call to added(original-service)
 		// 2) that causes a swap
 		// 3) a call to removed(aspect-service) <-- that's what we're talking about
+		if (m_debug) {
+			debug(m_componentByRank.toString());
+		}
 		return (componentMap != null && rankings != null && rankings.size() == 1 && ((Entry)rankings.entrySet().iterator().next()).getKey()
 				.equals(ServiceUtil.getRankingAsInteger(reference)));
 	}
@@ -653,11 +822,17 @@ public class ServiceDependencyImpl exten
     }
 
     public void invokeRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
+    	if (m_debug) {
+    		debug("invoke removed");
+    	}
         boolean removed = false;
         synchronized (m_sr) {
             Set set = (Set) m_sr.get(dependencyService);
             removed = (set != null && set.remove(new Tuple(reference, service)));
         }
+        if (m_debug) {
+        	debug("removed: " + removed);
+        }
         if (removed) {
         	if (m_callbackSwapped != null) {
         		handleAspectAwareRemoved(dependencyService, reference, service);
@@ -669,26 +844,56 @@ public class ServiceDependencyImpl exten
     }
     
 	private void handleAspectAwareRemoved(DependencyService dependencyService, ServiceReference reference, Object service) {
+		if (m_debug) {
+			debug("aspectawareremoved: " + reference.getProperty("service.ranking"));
+		}
 		if (componentIsDependencyManagerFactory(dependencyService)) {
 			// component is either aspect or adapter factory instance, these must be ignored.
 			return;
 		}
+		// we might need to swap here too!
+		boolean invokeRemoved = false;
 		Long serviceId = ServiceUtil.getServiceIdAsLong(reference);
-			synchronized (m_componentByRank) {
-				if (isLastService(dependencyService, reference, service, serviceId)) {
-					invoke(dependencyService, reference, service, m_callbackRemoved);
+		Tuple prevHighestRankedService = null;
+		Tuple newHighestRankedService = null;
+		boolean invokeSwapped = false;
+		Map rankings = null;
+		Runnable callbackRunnable = null;
+		synchronized (m_componentByRank) {
+			Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
+			if (isLastService(dependencyService, reference, service, serviceId)) {
+				invokeRemoved = true;
+			} else {
+				// not the last service, but should we swap?
+				prevHighestRankedService = (Tuple)getHighestRankedService(dependencyService, originalServiceId).getValue();
+				if (prevHighestRankedService.getServiceReference().equals(reference)) {
+					// swapping out
+					if (m_debug) {
+						debug("Swap out on remove!");
+					}
+					invokeSwapped = true;
 				}
-				Long originalServiceId = ServiceUtil.getServiceIdAsLong(reference);
+			}
+			if (m_debug) {
+				debug("is last service: " + invokeRemoved);
+			}
+			// cleanup
+			try {
 				Map componentMap = (Map) m_componentByRank.get(dependencyService); /* <Long, Map<Integer, Tuple>> */
 				if (componentMap != null) {
-					Map rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
+					rankings = (Map) componentMap.get(originalServiceId); /* <Integer, Tuple> */
+					List rankingsToRemove = new ArrayList();
 					for (Iterator entryIterator = rankings.entrySet().iterator(); entryIterator.hasNext(); ) {
 						Entry mapEntry = (Entry) entryIterator.next();
 						if (((Tuple)mapEntry.getValue()).getServiceReference().equals(reference)) {
 							// remove the reference
-							rankings.remove(mapEntry.getKey());
+							// rankings.remove(mapEntry.getKey());
+							rankingsToRemove.add(mapEntry.getKey());
 						}
 					}
+					for (Iterator rankingIterator = rankingsToRemove.iterator(); rankingIterator.hasNext(); ) {
+						rankings.remove(rankingIterator.next());
+					}
 					if (rankings.size() == 0) {
 						componentMap.remove(originalServiceId);
 					}
@@ -696,10 +901,41 @@ public class ServiceDependencyImpl exten
 						m_componentByRank.remove(dependencyService);
 					}
 				}
+			} catch (Exception e) {
+				e.printStackTrace();
 			}
+			// determine current highest ranked service
+			if (invokeSwapped) {
+				newHighestRankedService = (Tuple)getHighestRankedService(dependencyService, originalServiceId).getValue();
+			}
+			if (invokeRemoved) {
+				// handle invoke outside the sync block since we won't know what will happen there
+				if (m_debug) {
+					debug("invoke removed: " + reference.getProperty("service.ranking"));
+				}
+				callbackRunnable = createCallbackRunnable(dependencyService, reference, service, m_callbackRemoved);
+				enqueueCallback(callbackRunnable);
+			} else if (invokeSwapped) {
+				if (m_debug) {
+					debug("invoke swapped: " + newHighestRankedService.getServiceReference().getProperty("service.ranking") + " replacing " + prevHighestRankedService.getServiceReference().getProperty("service.ranking"));
+				}
+				callbackRunnable = createSwapRunnable(dependencyService, prevHighestRankedService.getServiceReference(), prevHighestRankedService.getService(), newHighestRankedService.getServiceReference(), newHighestRankedService.getService());
+				enqueueCallback(callbackRunnable);
+			}
+		}
+		if (callbackRunnable != null) {
+			waitForCallbackLock(callbackRunnable);
+			synchronized (rankings) {
+				releaseCallback(callbackRunnable);
+				execute(callbackRunnable);
+			}
+		}
 	}    
 
     public void invoke(DependencyService dependencyService, ServiceReference reference, Object service, String name) {
+    	if (m_debug) {
+    		debug("invoke: " + name);
+    	}
         if (name != null) {
             dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name, 
                 new Class[][] {
@@ -724,11 +960,26 @@ public class ServiceDependencyImpl exten
 			throw new IllegalStateException("Attempt to swap a service for a service with the same rank! previousReference: " + previousReference + ", currentReference: " + currentServiceReference);
 		}
 		
-		component.invokeCallbackMethod(getCallbackInstances(component), m_callbackSwapped, new Class[][] { { m_trackedServiceName, m_trackedServiceName },
-				{ Object.class, Object.class }, { ServiceReference.class, m_trackedServiceName, ServiceReference.class, m_trackedServiceName },
-				{ ServiceReference.class, Object.class, ServiceReference.class, Object.class } }, new Object[][] { { previous, current },
-				{ previous, current }, { previousReference, previous, currentServiceReference, current },
-				{ previousReference, previous, currentServiceReference, current } });
+		component.invokeCallbackMethod(getCallbackInstances(component), m_callbackSwapped, new Class[][] { 
+					{ m_trackedServiceName, m_trackedServiceName },
+					{ Object.class, Object.class }, 
+					{ ServiceReference.class, m_trackedServiceName, ServiceReference.class, m_trackedServiceName },
+					{ ServiceReference.class, Object.class, ServiceReference.class, Object.class }, 
+					{ Component.class, m_trackedServiceName, m_trackedServiceName },
+					{ Component.class, Object.class, Object.class }, 
+					{ Component.class, ServiceReference.class, m_trackedServiceName, ServiceReference.class, m_trackedServiceName },
+					{ Component.class, ServiceReference.class, Object.class, ServiceReference.class, Object.class } 
+				}, 
+				new Object[][] { 
+					{ previous, current },
+					{ previous, current }, 
+					{ previousReference, previous, currentServiceReference, current },
+					{ previousReference, previous, currentServiceReference, current },
+					{ component, previous, current },
+					{ component, previous, current }, 
+					{ component, previousReference, previous, currentServiceReference, current },
+					{ component, previousReference, previous, currentServiceReference, current } 					
+				});
 	}    
 
     protected synchronized boolean makeAvailable() {
@@ -740,7 +991,7 @@ public class ServiceDependencyImpl exten
     }
     
     private synchronized boolean makeUnavailable() {
-        if ((isAvailable()) && (!m_tracker.hasReference())) {
+        if ((isAvailable()) && (m_tracker.getServiceReference() == null)) {
             m_isAvailable = false;
             return true;
         }
@@ -1066,6 +1317,9 @@ public class ServiceDependencyImpl exten
     }
 
     public void invokeAdded(DependencyService service) {
+    	if (m_debug) {
+    		debug("invoke added due to configure. (component is activated)");
+    	}
         ServiceReference[] refs = m_tracker.getServiceReferences();
         if (refs != null) {
             for (int i = 0; i < refs.length; i++) {
@@ -1077,20 +1331,27 @@ public class ServiceDependencyImpl exten
     }
     
     public void invokeRemoved(DependencyService service) {
+    	if (m_debug) {
+    		debug("invoke removed due to unconfigure. (component is destroyed)");
+    	}
         Set references = null;
+        Object[] tupleArray = null;
         synchronized (m_sr) {
             references = (Set) m_sr.get(service);
+            // is this null check necessary ??
+            if (references != null) {
+	            tupleArray = references.toArray(new Tuple[references.size()]);
+//	           	references.clear();
+            }
         }
-        Tuple[] refs = (Tuple[]) (references != null ? references.toArray(new Tuple[references.size()]) : new Tuple[0]);
+
+        Tuple[] refs = (Tuple[]) (tupleArray != null ?  tupleArray : new Tuple[0]);
     
         for (int i = 0; i < refs.length; i++) {
             ServiceReference sr = refs[i].getServiceReference();
             Object svc = refs[i].getService();
             invokeRemoved(service, sr, svc);
         }
-        if (references != null) {
-            references.clear();
-        }
     }
 
     public Dictionary getProperties() {



Mime
View raw message