You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/05/14 17:39:33 UTC

svn commit: r1594607 - /felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java

Author: pderop
Date: Wed May 14 15:39:32 2014
New Revision: 1594607

URL: http://svn.apache.org/r1594607
Log:
- Added setExecutor method.
- Committed a patch in handleChange method which avoids recursive calls to handleChange method. 
Indeed, This can happen when we are calling the component's init method from 
within the execution of the handleChange->performTransition method calls, and also when the component's init method adds some *available* instance bound dependencies. 
At this point, this triggers a recursive call to handleChange method, which we are currently executing. 
Since this would mess around with the initial execution of the handleChange method, we are using a special flag, which prevent this kind of problem.

Notice that this has the advantage of not forcing users to add all instance-bound dependencies in one shot (from the init method), and also it simplifies the
performTransition method.

- Fixed handleRemoved() method.


Modified:
    felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java

Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java?rev=1594607&r1=1594606&r2=1594607&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java Wed May 14 15:39:32 2014
@@ -22,6 +22,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.osgi.framework.BundleContext;
@@ -44,7 +45,7 @@ public class ComponentImpl implements Co
 					new Class[] { ServiceRegistration.class },
 					new DefaultNullObject());
     private static final Class[] VOID = new Class[] {};
-	private final SerialExecutor m_executor = new SerialExecutor(new Logger(null));
+	private volatile Executor m_executor = new SerialExecutor(new Logger(null));
 	private ComponentState m_state = ComponentState.INACTIVE;
 	private final CopyOnWriteArrayList<DependencyContext> m_dependencies = new CopyOnWriteArrayList<>();
 	private final List<ComponentStateListener> m_listeners = new CopyOnWriteArrayList<>();
@@ -79,6 +80,7 @@ public class ComponentImpl implements Co
 	private volatile Object m_compositionManager;
 	private volatile String m_compositionManagerGetMethod;
 	private volatile Object m_compositionManagerInstance;
+    private boolean m_handlingChange;
 
     static class SCDImpl implements ComponentDependencyDeclaration {
         private final String m_name;
@@ -123,10 +125,15 @@ public class ComponentImpl implements Co
         m_id = m_idGenerator.getAndIncrement();
     }
 
-	public SerialExecutor getExecutor() {
+	public Executor getExecutor() {
 		return m_executor;
 	}
 	
+	public Component setExecutor(Executor executor) {
+	    m_executor = executor;
+	    return this;
+	}
+	
 	@Override
 	public Component add(final Dependency[] dependencies) {
 		getExecutor().execute(new Runnable() {
@@ -259,7 +266,11 @@ public class ComponentImpl implements Co
     @Override
     public void handleRemoved(DependencyContext dc, Event e) {
         Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
-        dc.setAvailable(!(dependencyEvents.contains(e) && dependencyEvents.size() == 1));
+        int size = dependencyEvents.size();
+        if (dependencyEvents.contains(e)) {
+            size --; // the dependency is currently registered and is about to be removed.
+        }
+        dc.setAvailable(size > 0);
         handleChange();
         
         // Now, really remove the dependency event, because next, we'll possibly invoke updateInstance, which will
@@ -312,14 +323,29 @@ public class ComponentImpl implements Co
     }
 
     private void handleChange() {
-        ComponentState oldState;
-        ComponentState newState;
-        do {
-            oldState = m_state;
-            newState = calculateNewState(oldState);
-            m_state = newState;
+        // At this point, our component is starting, stopping, or a dependency is being added/changed/removed. 
+        // So, we have to calculate a new state change for this component.
+        // Now, if we decide to call the component's init method, then at this point, if the component adds
+        // some additional instance-bound (and *available*) dependencies, then this will trigger a recursive call to 
+        // our handleChange method, which we are currently executing. Since this would mess around with the execution of 
+        // our current handleChange method execution , we are using a special "m_handlingChange" flag, which avoids this 
+        // kind of problem. 
+        
+        if (! m_handlingChange) {
+            try {
+                m_handlingChange = true;
+                ComponentState oldState;
+                ComponentState newState;
+                do {
+                    oldState = m_state;
+                    newState = calculateNewState(oldState);
+                    m_state = newState;
+                }
+                while (performTransition(oldState, newState));
+            } finally {
+                m_handlingChange = false;
+            }
         }
-        while (performTransition(oldState, newState));
     }
     
 	/** Based on the current state, calculate the new state. */
@@ -367,11 +393,8 @@ public class ComponentImpl implements Co
 			instantiateComponent();
 			invokeAddRequiredDependencies();
 			invokeAutoConfigDependencies();
-			ComponentState stateBeforeCallingInit = m_state;
-	        invoke(m_callbackInit); // may change current state if some available dependencies are added !
-	        if (stateBeforeCallingInit == m_state) {
-	            notifyListeners(newState); // init did not change current state, we can notify about this new state
-	        }
+	        invoke(m_callbackInit); 
+	        notifyListeners(newState);
 			return true;
 		}
 		if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && newState == ComponentState.TRACKING_OPTIONAL) {
@@ -569,7 +592,7 @@ public class ComponentImpl implements Co
                     m_componentInstance = createInstance((Class) m_componentDefinition);
                 }
                 catch (Exception e) {
-                    e.printStackTrace();
+                    m_logger.log(Logger.LOG_ERROR, "Could not instantiate class " + m_componentDefinition, e);
                 }
             }
             else {
@@ -749,12 +772,12 @@ public class ComponentImpl implements Co
 
 	private void notifyListeners(ComponentState state) {
 		for (ComponentStateListener l : m_listeners) {
-			l.changed(state);
+			l.changed(this, state);
 		}
 	}
 	
 	private void notifyListener(ComponentStateListener l, ComponentState state) {
-	    l.changed(state);
+	    l.changed(this, state);
 	}
 
 	public boolean isAvailable() {