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 );
}