FELIX-279 - Concurrency Issues when enabling components

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@538123 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
index 0115d58..9e6a869 100644
--- a/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
@@ -109,24 +109,141 @@
         
         m_state = STATE_DISABLED;
         m_dependencyManagers = new ArrayList();
+
+        Activator.trace("Component created", m_componentMetadata);
     }
     
+    //---------- Asynchronous frontend to state change methods ----------------
+    
+    /**
+     * Enables this component and - if satisfied - also activates it. If
+     * enabling the component fails for any reason, the component ends up
+     * disabled.
+     * <p>
+     * This method ignores the <i>enabled</i> flag of the component metadata
+     * and just enables as requested.
+     * <p>
+     * This method schedules the enablement for asynchronous execution.
+     */
+    public final void enable() {
+        getActivator().schedule( new Runnable()
+        {
+            public void run()
+            {
+                enableInternal();
+            }
+        } );
+    }
+    
+    /**
+     * Activates this component if satisfied. If any of the dependencies is
+     * not met, the component is not activated and remains unsatisifed.
+     * <p>
+     * This method schedules the activation for asynchronous execution.
+     */
+    public final void activate() {
+        getActivator().schedule( new Runnable()
+        {
+            public void run()
+            {
+                activateInternal();
+            }
+        } );
+    }
+    
+    /**
+     * Reconfigures this component by deactivating and activating it. During
+     * activation the new configuration data is retrieved from the Configuration
+     * Admin Service.
+     */
+    public final void reconfigure()
+    {
+        Activator.trace( "Deactivating and Activating to reconfigure", m_componentMetadata );
+        reactivate();
+    }
+    
+    /**
+     * Cycles this component by deactivating it and - if still satisfied -
+     * activating it again.
+     * <p>
+     * This method schedules the reactivation for asynchronous execution.
+     */
+    public final void reactivate() {
+        getActivator().schedule( new Runnable()
+        {
+            public void run()
+            {
+                deactivateInternal();
+                Activator.trace( "Dependency Manager: RECREATING", m_componentMetadata ); 
+                activateInternal();
+            }
+        } );
+    }
+    
+    /**
+     * Deactivates the component.
+     * <p>
+     * This method schedules the deactivation for asynchronous execution.
+     */
+    public final void deactivate() {
+        getActivator().schedule( new Runnable()
+        {
+            public void run()
+            {
+                deactivateInternal();
+            }
+        } );
+    }
+    
+    /**
+     * Disables this component and - if active - first deactivates it. The
+     * component may be reenabled by calling the {@link #enable()} method.
+     * <p>
+     * This method schedules the disablement for asynchronous execution.
+     */
+    public final void disable() {
+        getActivator().schedule( new Runnable()
+        {
+            public void run()
+            {
+                disableInternal();
+            }
+        } );
+    }
+    
+    /**
+     * Disposes off this component deactivating and disabling it first as
+     * required. After disposing off the component, it may not be used anymore.
+     * <p>
+     * This method unlike the other state change methods immediately takes
+     * action and disposes the component. The reason for this is, that this
+     * method has to actually complete before other actions like bundle stopping
+     * may continue.
+     */
+    public final void dispose() {
+        disposeInternal();
+    }
+
+    //---------- internal immediate state change methods ----------------------
+    // these methods must only be called from a separate thread by calling
+    // the respective asynchronous (public) method
+    
     /**
      * Enable this component
      * 
      * @return true if enabling was successful
      */
-    public synchronized boolean enable() {
+    private void enableInternal() {
     	
         if (getState() == STATE_DESTROYED)
         {
             Activator.error( "Destroyed Component cannot be enabled", m_componentMetadata );
-            return false;
+            return;
         }
         else if (getState() != STATE_DISABLED)
         {
             Activator.trace( "Component is already enabled", m_componentMetadata );
-            return true;
+            return;
         }
         
         Activator.trace("Enabling component", m_componentMetadata);
@@ -149,20 +266,20 @@
 	        }
 	
             // enter enabled state before trying to activate
-	        setState(STATE_ENABLED);
+	        setState( STATE_ENABLED );
 	        
-	        activate();
-	        
-	        return true;
+            Activator.trace("Component enabled", m_componentMetadata);
+
+            // immediately activate the compopnent, no need to schedule again
+	        activateInternal();
     	}
     	catch(Exception ex)
     	{
-    		Activator.exception( "Failed enabled Component", m_componentMetadata, ex );
+    		Activator.exception( "Failed enabling Component", m_componentMetadata, ex );
 
             // ensure we get back to DISABLED state 
-            disable();
-
-            return false;
+            // immediately disable, no need to schedule again
+            disableInternal();
     	}
     }
 
@@ -176,7 +293,7 @@
      *   4. Call the activate method, if present
      *   [5. Register provided services]
      */
-     synchronized void activate()
+     private void activateInternal()
      {
          // CONCURRENCY NOTE: This method is called either by the enable()
          //     method or by the dependency managers or the reconfigure() method
@@ -190,6 +307,8 @@
          // go to the activating state
          setState(STATE_ACTIVATING);
 
+         Activator.trace("Activating component", m_componentMetadata);
+
          // Before creating the implementation object, we are going to
          // test if all the mandatory dependencies are satisfied
          Iterator it = m_dependencyManagers.iterator();
@@ -218,9 +337,100 @@
          
          // 5. Register provided services
          m_serviceRegistration = registerComponentService();
+         
+         Activator.trace("Component activated", m_componentMetadata);
      }
 
      /**
+      * This method deactivates the manager, performing the following steps
+      * 
+      * [0. Remove published services from the registry]
+      * 1. Call the deactivate() method, if present
+      * 2. Unbind any bound services
+      * 3. Release references to the component instance and component context 
+     **/
+     private void deactivateInternal()
+     {
+         // CONCURRENCY NOTE: This method may be called either from application
+         // code or by the dependency managers or reconfiguration
+         if ((getState() & (STATE_ACTIVATING|STATE_ACTIVE|STATE_REGISTERED|STATE_FACTORY)) == 0)
+         {
+             // This state can only be entered from the ACTIVATING (if activation
+             // fails), ACTIVE, REGISTERED or FACTORY states
+             return;
+         }
+
+         // start deactivation by resetting the state
+         setState( STATE_DEACTIVATING );
+         
+         Activator.trace("Deactivating component", m_componentMetadata);
+
+         // 0.- Remove published services from the registry
+         unregisterComponentService();
+
+         // 1.- Call the deactivate method, if present       
+         // 2. Unbind any bound services
+         // 3. Release references to the component instance and component context
+         deleteComponent();
+
+         //Activator.trace("InstanceManager from bundle ["+ m_activator.getBundleContext().getBundle().getBundleId() + "] was invalidated.");
+
+         // reset to state UNSATISFIED
+         setState( STATE_UNSATISFIED );
+         
+         Activator.trace("Component deactivated", m_componentMetadata);
+     }
+
+     private void disableInternal()
+     {
+         // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
+         // but not by the dependency managers
+
+         // deactivate first, this does nothing if not active/registered/factory
+         deactivateInternal();
+         
+         Activator.trace("Disabling component", m_componentMetadata);
+
+         // close all service listeners now, they are recreated on enable
+         // Stop the dependency managers to listen to events...
+         Iterator it = m_dependencyManagers.iterator();
+         while (it.hasNext())
+         {
+             DependencyManager dm = (DependencyManager)it.next();
+             dm.close();
+         }
+         m_dependencyManagers.clear();
+
+         // we are now disabled, ready for re-enablement or complete destroyal
+         setState( STATE_DISABLED );
+         
+         Activator.trace("Component disabled", m_componentMetadata);
+     }
+     
+     /**
+      * 
+      */
+     private void disposeInternal()
+     {
+         // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
+        // but not by the dependency managers
+
+         // disable first to clean up correctly
+         disableInternal();
+         
+         // this component must not be used any more
+         setState( STATE_DESTROYED );
+
+         // release references (except component metadata for logging purposes)
+         m_activator = null;
+         m_dependencyManagers = null;
+
+         Activator.trace("Component disposed", m_componentMetadata);
+     }
+
+     //---------- Component handling methods ----------------------------------
+     
+     /**
       * Method is called by {@link #activate()} in STATE_ACTIVATING or by
       * {@link DelayedComponentManager#getService(Bundle, ServiceRegistration)}
       * in STATE_REGISTERED.
@@ -234,6 +444,16 @@
      protected abstract void deleteComponent();
      
      /**
+      * Returns the service object to be registered if the service element is
+      * specified.
+      * <p>
+      * Extensions of this class may overwrite this method to return a
+      * ServiceFactory to register in the case of a delayed or a service
+      * factory component. 
+      */
+     protected abstract Object getService();
+     
+     /**
       * Returns the state value to set, when the component is satisfied. The
       * return value depends on the kind of the component:
       * <dl>
@@ -259,17 +479,6 @@
          }
      }
      
-     /**
-      * Returns the service object to be registered if the service element is
-      * specified.
-      * <p>
-      * Extensions of this class may overwrite this method to return a
-      * ServiceFactory to register in the case of a delayed or a service
-      * factory component. 
-      */
-     protected abstract Object getService();
-     
-
      // 5. Register provided services
      protected ServiceRegistration registerComponentService()
      {
@@ -298,106 +507,6 @@
          }
      }
      
-    /**
-     * Reconfigures this component by deactivating and activating it. During
-     * activation the new configuration data is retrieved from the Configuration
-     * Admin Service.
-     */
-    public void reconfigure()
-    {
-        Activator.trace( "Deactivating and Activating to reconfigure", m_componentMetadata );
-        reactivate();
-    }
-    
-    /**
-     * Deactivates and activates this component instance.
-     */
-    void reactivate() {
-        deactivate();
-        Activator.trace( "Dependency Manager: RECREATING", m_componentMetadata ); 
-        activate();
-    }
-    
-    /**
-     * This method deactivates the manager, performing the following steps
-     * 
-     * [0. Remove published services from the registry]
-     * 1. Call the deactivate() method, if present
-     * 2. Unbind any bound services
-     * 3. Release references to the component instance and component context 
-    **/
-    synchronized void deactivate()
-    {
-        // CONCURRENCY NOTE: This method may be called either from application
-        // code or by the dependency managers or reconfiguration
-        if ((getState() & (STATE_ACTIVATING|STATE_ACTIVE|STATE_REGISTERED|STATE_FACTORY)) == 0)
-        {
-            // This state can only be entered from the ACTIVATING (if activation
-            // fails), ACTIVE, REGISTERED or FACTORY states
-            return;
-        }
-//        if (m_state != INSTANCE_VALID && m_state != INSTANCE_VALIDATING && m_state != INSTANCE_DESTROYING) {
-//            return;
-//        }
-
-        // start deactivation by resetting the state
-        setState( STATE_DEACTIVATING );
-        
-        // 0.- Remove published services from the registry
-        unregisterComponentService();
-
-        // 1.- Call the deactivate method, if present       
-        // 2. Unbind any bound services
-        // 3. Release references to the component instance and component context
-        deleteComponent();
-
-        //Activator.trace("InstanceManager from bundle ["+ m_activator.getBundleContext().getBundle().getBundleId() + "] was invalidated.");
-
-        // reset to state UNSATISFIED
-        setState( STATE_UNSATISFIED );
-    }
-
-    public synchronized void disable()
-    {
-        // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
-        // but not by the dependency managers
-
-        // deactivate first, this does nothing if not active/registered/factory
-        deactivate();
-        
-        // close all service listeners now, they are recreated on enable
-        // Stop the dependency managers to listen to events...
-        Iterator it = m_dependencyManagers.iterator();
-        while (it.hasNext())
-        {
-            DependencyManager dm = (DependencyManager)it.next();
-            dm.close();
-        }
-        m_dependencyManagers.clear();
-
-        // we are now disabled, ready for re-enablement or complete destroyal
-        setState( STATE_DISABLED );
-    }
-    
-    /**
-     * 
-     */
-    public synchronized void dispose()
-    {
-        // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
-    	// but not by the dependency managers
-
-        // disable first to clean up correctly
-        disable();
-        
-        // this component must not be used any more
-        setState( STATE_DISABLED );
-
-        // release references (except component metadata for logging purposes)
-        m_activator = null;
-        m_dependencyManagers = null;
-    }
-
     //**********************************************************************************************************
     
     BundleComponentActivator getActivator() {
@@ -491,7 +600,7 @@
         m_state = newState;
     }
 
-    private String stateToString(int state) {
+    public String stateToString(int state) {
         switch (state) {
             case STATE_DESTROYED:
                 return "Destroyed";
diff --git a/scr/src/main/java/org/apache/felix/scr/Activator.java b/scr/src/main/java/org/apache/felix/scr/Activator.java
index 69b3d0e..aaeddf5 100644
--- a/scr/src/main/java/org/apache/felix/scr/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/Activator.java
@@ -18,12 +18,12 @@
  */
 package org.apache.felix.scr;
 
+import java.io.PrintStream;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.logging.Logger;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -41,8 +41,8 @@
  */
 public class Activator implements BundleActivator, SynchronousBundleListener
 {
-    // name of the LogService class
-    private static final String LOGSERVICE_CLASS = LogService.class.getName();
+    //  name of the LogService class (this is a string to not create a reference to the class)
+    private static final String LOGSERVICE_CLASS = "org.osgi.service.log.LogService";    
     
     // Flag that sets tracing messages
     private static boolean m_trace = true;
@@ -50,9 +50,6 @@
     // Flag that sets error messages
     private static boolean m_error = true;
 
-    // A string containing the version number
-    private static String m_version = "1.0.0 (20070320)";
-
     // this bundle's context
     private BundleContext m_context;
     
@@ -66,6 +63,9 @@
     // registry of managed component
     private ComponentRegistry m_componentRegistry;
 
+    //  thread acting upon configurations
+    private ComponentActorThread m_componentActor;
+    
     /**
      * Registers this instance as a (synchronous) bundle listener and loads the
      * components of already registered bundles.
@@ -92,6 +92,10 @@
                 + context.getBundle().getHeaders().get( Constants.BUNDLE_VERSION ) + " ]", null );
         }
 
+        // create and start the component actor 
+        m_componentActor = new ComponentActorThread();
+        m_componentActor.start();
+
         // register for bundle updates
         context.addBundleListener(this);
 
@@ -107,16 +111,33 @@
      * @param context The <code>BundleContext</code> of the SCR implementation
      *      bundle.
      */
-    public void stop(BundleContext context) throws Exception
+    public void stop( BundleContext context ) throws Exception
     {
         // unregister as bundle listener
-        context.removeBundleListener(this);
+        context.removeBundleListener( this );
 
         // 112.8.2 dispose off all active components
         disposeAllComponents();
 
         // dispose off the component registry
         m_componentRegistry.dispose();
+
+        // terminate the actor thread and wait for it for a limited time
+        if ( m_componentActor != null )
+        {
+            // terminate asynchrounous updates
+            m_componentActor.terminate();
+
+            // wait for all updates to terminate
+            try
+            {
+                m_componentActor.join( 5000 );
+            }
+            catch ( InterruptedException ie )
+            {
+                // don't really care
+            }
+        }
     }
 
     // ---------- BundleListener Interface -------------------------------------
@@ -184,7 +205,7 @@
 
         try
         {
-            BundleComponentActivator ga = new BundleComponentActivator( m_componentRegistry, context );
+            BundleComponentActivator ga = new BundleComponentActivator( m_componentRegistry, m_componentActor, context );
             m_componentBundles.put(bundle.getSymbolicName(), ga);
         }
         catch (Exception e)
@@ -312,86 +333,93 @@
      *
      * @param message a string to be displayed
      * @param metadata ComponentMetadata associated to the message (can be null)
-    **/
-    static void trace(String message, ComponentMetadata metadata)
+     **/
+    static void trace( String message, ComponentMetadata metadata )
     {
-        if(m_trace)
+        if ( m_trace )
         {
-            StringBuffer msg = new StringBuffer("--- ");
-            if(metadata != null) {
-                msg.append("[").append(metadata.getName()).append("] ");
+            StringBuffer msg = new StringBuffer( "--- " );
+            if ( metadata != null )
+            {
+                msg.append( "[" ).append( metadata.getName() ).append( "] " );
             }
-            msg.append(message);
+            msg.append( message );
 
-            LogService log = (LogService) m_logService.getService();
-            if (log == null)
-            {
-                System.out.println(msg);
-            }
-            else
-            {
-                log.log(LogService.LOG_DEBUG, msg.toString());
-            }
+            log( LogService.LOG_DEBUG, msg.toString(), null );
         }
     }
 
+
     /**
      * Method to display errors
      *
      * @param message a string to be displayed
      * @param metadata optional metadata providing more information to log
      **/
-    static void error(String message, ComponentMetadata metadata)
+    static void error( String message, ComponentMetadata metadata )
     {
-        if(m_error)
+        if ( m_error )
         {
-            StringBuffer msg = new StringBuffer("### ");
-            if(metadata != null) {
-                msg.append("[").append(metadata.getName()).append("] ");
+            StringBuffer msg = new StringBuffer( "### " );
+            if ( metadata != null )
+            {
+                msg.append( "[" ).append( metadata.getName() ).append( "] " );
             }
-            msg.append(message);
+            msg.append( message );
 
-            LogService log = (LogService) m_logService.getService();
-            if (log == null)
-            {
-                System.err.println(msg);
-            }
-            else
-            {
-                log.log(LogService.LOG_ERROR, msg.toString());
-            }
+            log( LogService.LOG_ERROR, msg.toString(), null );
         }
     }
 
+
     /**
      * Method to display exceptions
      *
      * @param ex an exception
-     **/   
-    static void exception(String message, ComponentMetadata metadata, Throwable ex)
+     **/
+    static void exception( String message, ComponentMetadata metadata, Throwable ex )
     {
-         if(m_error)
-         {
-             StringBuffer msg = new StringBuffer("--- ");
-             if(metadata != null) {
-                 msg.append("[").append(metadata.getName()).append("] ");
-             }
-             msg.append("Exception with component : ");
-             msg.append(message).append(" ---");
-             
-             LogService log = (LogService) m_logService.getService();
-             if (log == null)
-             {
-                 System.err.println(msg);
-                 if (ex != null)
-                 {
-                     ex.printStackTrace(System.err);
-                 }
-             }
-             else
-             {
-                 log.log(LogService.LOG_ERROR, msg.toString(), ex);
-             }
-         }      
+        if ( m_error )
+        {
+            StringBuffer msg = new StringBuffer( "--- " );
+            if ( metadata != null )
+            {
+                msg.append( "[" ).append( metadata.getName() ).append( "] " );
+            }
+            msg.append( "Exception with component : " );
+            msg.append( message ).append( " ---" );
+
+            log( LogService.LOG_ERROR, msg.toString(), ex );
+        }
+    }
+
+
+    /**
+     * Method to actually emit the log message. If the LogService is available,
+     * the message will be logged through the LogService. Otherwise the message
+     * is logged to stdout (or stderr in case of LOG_ERROR level messages),
+     * 
+     * @param level The log level to log the message at
+     * @param message The message to log
+     * @param ex An optional <code>Throwable</code> whose stack trace is written,
+     *      or <code>null</code> to not log a stack trace.
+     */
+    static void log( int level, String message, Throwable ex )
+    {
+
+        Object logger = m_logService.getService();
+        if ( logger == null )
+        {
+            PrintStream out = ( level == LogService.LOG_ERROR ) ? System.err : System.out;
+            out.println( message );
+            if ( ex != null )
+            {
+                ex.printStackTrace( out );
+            }
+        }
+        else
+        {
+            ( ( LogService ) logger ).log( level, message, ex );
+        }
     }
 }
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
index ac8c9cb..7dde6fd 100644
--- a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
@@ -24,20 +24,15 @@
 import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.StringTokenizer;
 
-import javax.naming.ConfigurationException;
-
 import org.apache.felix.scr.parser.KXml2SAXParser;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.component.ComponentException;
+import org.osgi.service.log.LogService;
 import org.osgi.util.tracker.ServiceTracker;
 
 /**
@@ -59,6 +54,9 @@
     // The Configuration Admin tracker providing configuration for components
     private ServiceTracker m_configurationAdmin;
 
+    // thread acting upon configurations
+    private ComponentActorThread m_componentActor;
+    
     /**
      * Called upon starting of the bundle. This method invokes initialize() which
      * parses the metadata and creates the instance managers
@@ -70,27 +68,26 @@
      * 
      * @throws ComponentException if any error occurrs initializing this class
      */
-    BundleComponentActivator(ComponentRegistry componentRegistry, BundleContext context) throws ComponentException
+    BundleComponentActivator( ComponentRegistry componentRegistry, ComponentActorThread componentActor,
+        BundleContext context ) throws ComponentException
     {
-        // The global "Component" registry
-        this.m_componentRegistry = componentRegistry;
-        
-    	// Stores the context
+        // keep the parameters for later
+        m_componentRegistry = componentRegistry;
+        m_componentActor = componentActor;
         m_context = context;
-        
+
         // have the Configuration Admin Service handy (if available)
-        m_configurationAdmin = new ServiceTracker(context, ConfigurationAdmin.class.getName(), null);
+        m_configurationAdmin = new ServiceTracker( context, ConfigurationAdmin.class.getName(), null );
         m_configurationAdmin.open();
-        
+
         // Get the Metadata-Location value from the manifest
-        String descriptorLocations =
-            (String) m_context.getBundle().getHeaders().get("Service-Component");
-        if (descriptorLocations == null)
+        String descriptorLocations = ( String ) m_context.getBundle().getHeaders().get( "Service-Component" );
+        if ( descriptorLocations == null )
         {
-            throw new ComponentException("Service-Component entry not found in the manifest");
+            throw new ComponentException( "Service-Component entry not found in the manifest" );
         }
 
-        initialize(descriptorLocations);
+        initialize( descriptorLocations );
     }
 
     /**
@@ -138,39 +135,46 @@
                     ComponentMetadata metadata = (ComponentMetadata) i.next();
                 	try
                     {
+                        // check and reserve the component name
+                        m_componentRegistry.checkComponentName( metadata.getName() );
+                        
                         // validate the component metadata
-    		            validate(metadata);
+                        metadata.validate();
     		        	
     	                // Request creation of the component manager
     	                ComponentManager manager;
-                        
-                        if (metadata.isFactory()) {
-                            // 112.2.4 SCR must register a Component Factory service on behalf ot the component
+                        if ( metadata.isFactory() )
+                        {
+                            // 112.2.4 SCR must register a Component Factory
+                            // service on behalf ot the component
                             // as soon as the component factory is satisfied
-                            manager = new ComponentFactoryImpl(this, metadata, m_componentRegistry);
-                        } else {
+                            manager = new ComponentFactoryImpl( this, metadata, m_componentRegistry );
+                        }
+                        else
+                        {
                             manager = ManagerFactory.createManager( this, metadata, m_componentRegistry
-                            .createComponentId() );
+                                .createComponentId() );
                         }
                 		
                         // register the component after validation
                         m_componentRegistry.registerComponent( metadata.getName(), manager );
+                        m_managers.add( manager );
                         
                         // enable the component
-                		if(metadata.isEnabled())
+                        if ( metadata.isEnabled() )
                         {
-		                	manager.enable();
-		                }
-
-                		// register the manager
-                		m_managers.add(manager);
+                            manager.enable();
+                        }
                     }
-                    catch (Exception e)
+                    catch (Throwable t)
                     {
 						// There is a problem with this particular component, we'll log the error
 	                	// and proceed to the next one
-                        Activator.exception("Cannot register Component", metadata, e);
-					} 
+                        Activator.exception("Cannot register Component", metadata, t);
+                        
+                        // make sure the name is not reserved any more
+                        m_componentRegistry.unregisterComponent( metadata.getName() );
+					}
 		        }
 			}
 			catch ( IOException ex )
@@ -295,25 +299,18 @@
         {
             return;
         }
-        
-        Thread enabler = new Thread("Component Enabling") 
+
+        for ( int i = 0; i < cm.length; i++ )
         {
-            public void run()
+            try
             {
-                for (int i=0; i < cm.length; i++)
-                {
-                    try
-                    {
-                        cm[i].enable();
-                    }
-                    catch (Throwable t) 
-                    {
-                        Activator.exception( "Cannot enable component", cm[i].getComponentMetadata(), t );
-                    }
-                }
+                cm[i].enable();
             }
-        };
-        enabler.start();
+            catch ( Throwable t )
+            {
+                Activator.exception( "Cannot enable component", cm[i].getComponentMetadata(), t );
+            }
+        }
     }
     
     /**
@@ -335,25 +332,17 @@
             return;
         }
         
-        Thread disabler = new Thread("Component Disabling")
+        for ( int i = 0; i < cm.length; i++ )
         {
-            public void run()
+            try
             {
-                for (int i=0; i < cm.length; i++)
-                {
-                    try
-                    {
-                        cm[i].disable();
-                    }
-                    catch (Throwable t)
-                    {
-                        Activator.exception("Cannot disable component",
-                            cm[i].getComponentMetadata(), t);
-                    }
-                }
+                cm[i].disable();
             }
-        };
-        disabler.start();
+            catch ( Throwable t )
+            {
+                Activator.exception( "Cannot disable component", cm[i].getComponentMetadata(), t );
+            }
+        }
     }
     
     /**
@@ -395,34 +384,36 @@
         return null;
     }
 
+    //---------- Asynchronous Component Handling ------------------------------
+
     /**
-     * This method is used to validate that the component. This method verifies multiple things:
+     * Schedules the given <code>task</code> for asynchrounous execution or
+     * synchronously runs the task if the thread is not running.
      * 
-     * 1.- That the name attribute is set and is globally unique
-     * 2.- That an implementation class name has been set 
-     * 3.- That a delayed component provides a service and is not specified to be a factory
-     * - That the serviceFactory attribute for the provided service is not true if the component is a factory or immediate
-     * 
-     * If the component is valid, its name is registered
-     * 
-     * @throws A ComponentException if something is not right
+     * @param task The component task to execute
      */
-    void validate(ComponentMetadata component) throws ComponentException
+    void schedule( Runnable task )
     {
-
-        m_componentRegistry.checkComponentName( component.getName() );
-    	
-        try
+        ComponentActorThread cat = m_componentActor;
+        if ( cat != null )
         {
-            component.validate();
+            cat.schedule( task );
         }
-        catch ( ComponentException ce )
+        else
         {
-            // remove the reservation before leaving
-            m_componentRegistry.unregisterComponent( component.getName() );
-            throw ce;
+            Activator.log( LogService.LOG_INFO, "Component Actor Thread not running, calling synchronously", null );
+            try
+            {
+                synchronized ( this )
+                {
+                    task.run();
+                }
+            }
+            catch ( Throwable t )
+            {
+                Activator.log( LogService.LOG_INFO, "Unexpected problem executing task", t );
+            }
         }
-
-        Activator.trace( "Validated and registered component", component );
     }
+
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentActorThread.java b/scr/src/main/java/org/apache/felix/scr/ComponentActorThread.java
new file mode 100644
index 0000000..4327008
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentActorThread.java
@@ -0,0 +1,111 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr;
+
+
+import java.util.LinkedList;
+
+
+/**
+ * The <code>ComponentActorThread</code> is the thread used to act upon registered
+ * components of the service component runtime.
+ *
+ * @author fmeschbe
+ */
+class ComponentActorThread extends Thread
+{
+
+    // the queue of Runnable instances  to be run
+    private LinkedList tasks;
+
+
+    ComponentActorThread()
+    {
+        super( "SCR Component Actor" );
+        this.tasks = new LinkedList();
+    }
+
+
+    // waits on Runnable instances coming into the queue. As instances come
+    // in, this method calls the Runnable.run method, logs any exception
+    // happening and keeps on waiting for the next Runnable. If the Runnable
+    // taken from the queue is this thread instance itself, the thread
+    // terminates.
+    public void run()
+    {
+        for ( ;; )
+        {
+            Runnable task;
+            synchronized ( tasks )
+            {
+                while ( tasks.isEmpty() )
+                {
+                    try
+                    {
+                        tasks.wait();
+                    }
+                    catch ( InterruptedException ie )
+                    {
+                        // don't care
+                    }
+                }
+
+                task = ( Runnable ) tasks.removeFirst();
+            }
+
+            // return if the task is this thread itself
+            if ( task == this )
+            {
+                return;
+            }
+
+            // otherwise execute the task, log any issues
+            try
+            {
+                task.run();
+            }
+            catch ( Throwable t )
+            {
+                Activator.exception( "Unexpected problem executing task", null, t );
+            }
+        }
+    }
+
+
+    // cause this thread to terminate by adding this thread to the end
+    // of the queue
+    void terminate()
+    {
+        schedule( this );
+    }
+
+
+    // queue the given runnable to be run as soon as possible
+    void schedule( Runnable task )
+    {
+        synchronized ( tasks )
+        {
+            // append to the task queue
+            tasks.add( task );
+
+            // notify the waiting thread
+            tasks.notifyAll();
+        }
+    }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java
index 8631883..a6f3c9f 100644
--- a/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java
@@ -79,11 +79,6 @@
         // not component to create, newInstance must be used instead
     }
 
-    public void reconfigure()
-    {
-        super.reconfigure();
-    }
-
     protected void deleteComponent()
     {
         // nothing to delete
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
index c3fea75..5ae0c7a 100644
--- a/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
@@ -29,10 +29,8 @@
 	

 	/**

 	 * Enable the component

-	 * 

-	 * @return true if it was succesfully enabled, false otherwise

 	 */

-	public boolean enable();

+	public void enable();

 	

     /**

      * Reconfigure the component with configuration data newly retrieved from

diff --git a/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java
index 70f7e24..b073bb2 100644
--- a/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java
@@ -47,6 +47,14 @@
         // nothing to do here for a delayed component, will be done in the
         // getService method for the first bundle acquiring the component
     }
+
+    protected void deleteComponent()
+    {
+        // only have to delete, if there is actually an instance
+        if (getInstance() != null) {
+            super.deleteComponent();
+        }
+    }
     
     protected Object getService()
     {
diff --git a/scr/src/main/java/org/apache/felix/scr/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
index daf64c3..4f55702 100644
--- a/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
@@ -613,7 +613,7 @@
             m_tracked.put( reference, service );
         }
 
-        // forward the event if in event hanlding state
+        // forward the event if in event handling state
         if ( handleServiceEvent() )
         {
 
diff --git a/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
index 48b739f..a4db355 100644
--- a/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
@@ -87,21 +87,23 @@
     // 2. Create the component instance and component context
     // 3. Bind the target services
     // 4. Call the activate method, if present
+    // if this method is overwritten, the deleteComponent method should
+    // also be overwritten
     protected void createComponent()
     {
         ComponentContext tmpContext = new ComponentContextImpl( this );
-        Object tmpObject = createImplementationObject( tmpContext );
+        Object tmpComponent = createImplementationObject( tmpContext );
         
         // if something failed craeating the object, we fell back to
         // unsatisfied !!
-        if (tmpObject != null) {
+        if (tmpComponent != null) {
             m_componentContext = tmpContext;
-            m_implementationObject = tmpObject;
+            m_implementationObject = tmpComponent;
         }
     }
     
     protected void deleteComponent() {
-        deactivateImplementationObject( m_implementationObject, m_componentContext );
+        disposeImplementationObject( m_implementationObject, m_componentContext );
         m_implementationObject = null;
         m_componentContext = null;
         m_properties = null;
@@ -189,7 +191,7 @@
         return implementationObject;
     }
 
-    protected void deactivateImplementationObject( Object implementationObject, ComponentContext componentContext )
+    protected void disposeImplementationObject( Object implementationObject, ComponentContext componentContext )
     {
         // 1. Call the deactivate method, if present
         // Search for the activate method
diff --git a/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
index 9e476dd..6c9cba1 100644
--- a/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
@@ -30,20 +30,13 @@
 
 /**
  * The <code>ServiceFactoryComponentManager</code> TODO
- *
- * @author fmeschbe
- * @version $Rev$, $Date$
  */
 public class ServiceFactoryComponentManager extends ImmediateComponentManager implements ServiceFactory
 {
 
-    // we do not have to maintain references to the actual service
-    // instances as those are handled by the ServiceManager and given
-    // to the ungetService method when the bundle releases the service
-
-    // maintain the map of componentContext objects created for the
+    // maintain the map of ComponentContext objects created for the
     // service instances
-    private IdentityHashMap componentContexts = new IdentityHashMap();
+    private IdentityHashMap serviceContexts = new IdentityHashMap();
 
 
     /**
@@ -101,13 +94,13 @@
         // When the getServiceMethod is called, the implementation object must be created
 
         // private ComponentContext and implementation instances
-        BundleComponentContext componentContext = new BundleComponentContext( this, bundle );
-        Object implementationObject = createImplementationObject( componentContext );
+        BundleComponentContext serviceContext = new BundleComponentContext( this, bundle );
+        Object service = createImplementationObject( serviceContext );
 
         // register the components component context if successfull
-        if (implementationObject != null) {
-            componentContext.setImplementationObject( implementationObject );
-            componentContexts.put( implementationObject, componentContext );
+        if (service != null) {
+            serviceContext.setImplementationObject( service );
+            serviceContexts.put( service, serviceContext );
 
             // if this is the first use of this component, switch to ACTIVE state
             if (getState() == STATE_REGISTERED)
@@ -116,7 +109,7 @@
             }
         }
         
-        return implementationObject;
+        return service;
     }
 
 
@@ -129,11 +122,11 @@
         // When the ungetServiceMethod is called, the implementation object must be deactivated
 
         // private ComponentContext and implementation instances
-        ComponentContext componentContext = ( ComponentContext ) componentContexts.remove( service );
-        deactivateImplementationObject( service, componentContext );
+        ComponentContext serviceContext = ( ComponentContext ) serviceContexts.remove( service );
+        disposeImplementationObject( service, serviceContext );
         
         // if this was the last use of the component, go back to REGISTERED state
-        if ( componentContexts.isEmpty() && getState() == STATE_ACTIVE )
+        if ( serviceContexts.isEmpty() && getState() == STATE_ACTIVE )
         {
             setState( STATE_REGISTERED );
         }