You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2009/07/29 21:36:21 UTC

svn commit: r799031 - /felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java

Author: fmeschbe
Date: Wed Jul 29 19:36:21 2009
New Revision: 799031

URL: http://svn.apache.org/viewvc?rev=799031&view=rev
Log:
FELIX-1416 ComponentFactoryImpl was not correctly implemented correctly
for the standard use case (components as per newInstance()) and the
non-standard backwards compatible use case (components as per factory
configuration). Clearly separating the lifecycle management the use
cases are now correctly handled.

Modified:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java?rev=799031&r1=799030&r2=799031&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java Wed Jul 29 19:36:21 2009
@@ -35,33 +35,62 @@
 import org.osgi.service.log.LogService;
 
 /**
- * The <code>ComponentFactoryImpl</code> TODO
+ * The <code>ComponentFactoryImpl</code> extends the {@link AbstractComponentManager}
+ * class to implement the component factory functionality. As such the
+ * OSGi Declarative Services <code>ComponentFactory</code> interface is
+ * implemented.
+ * <p>
+ * In addition the {@link ComponentHolder} interface is implemented to use this
+ * class directly as the holder for component instances created by the
+ * {@link #newInstance(Dictionary)} method.
+ * <p>
+ * Finally, if the <code>ds.factory.enabled</code> bundle context property is
+ * set to <code>true</code>, component instances can be created by factory
+ * configurations. This functionality is present for backwards compatibility
+ * with earlier releases of the Apache Felix Declarative Services implementation.
+ * But keep in mind, that this is non-standard behaviour.
  */
 public class ComponentFactoryImpl extends AbstractComponentManager implements ComponentFactory, ComponentHolder
 {
 
-    // The map of components created from Configuration objects
-    // maps PID to ImmediateComponentManager for configuration updating
-    // this map is lazily created
-    private Map m_configuredServices;
-
-    // Actually we only use the identity key stuff, but there is
-    // no IdentityHashSet and HashSet internally uses a HashMap anyway
-    private final Map m_createdComponents;
+    /**
+     * Contains the component instances created by calling the
+     * {@link #newInstance(Dictionary)} method. These component instances are
+     * provided with updated configuration (or deleted configuration) if
+     * such modifications for the component factory takes place.
+     * <p>
+     * The map is keyed by the component manager instances. The value of each
+     * entry is the same as the entry's key.
+     */
+    private final Map m_componentInstances;
 
-    // configuration of the component factory
+    /**
+     * The configuration for the component factory. This configuration is
+     * supplied as the base configuration for each component instance created
+     * by the {@link #newInstance(Dictionary)} method.
+     */
     private Dictionary m_configuration;
 
-    // whether this instance supports creating component instances for factory
-    // configuration instances. This is backwards compatibility behaviour and
-    // contradicts the specification (Section 112.7)
+    /**
+     * The map of components created from Configuration objects maps PID to
+     * {@link ImmediateComponentManager} for configuration updating this map is
+     * lazily created. This map is only used if the {@link #m_isConfigurationFactory}
+     * field is <code>true</code>.
+     */
+    private Map m_configuredServices;
+
+    /**
+     * Whether this instance supports creating component instances for factory
+     * configuration instances. This is backwards compatibility behaviour and
+     * contradicts the specification (Section 112.7)
+     */
     private final boolean m_isConfigurationFactory;
 
 
     public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
     {
         super( activator, metadata );
-        m_createdComponents = new IdentityHashMap();
+        m_componentInstances = new IdentityHashMap();
         m_isConfigurationFactory = "true".equals( activator.getBundleContext().getProperty( "ds.factory.enabled" ) );
     }
 
@@ -71,24 +100,53 @@
      */
     public ComponentInstance newInstance( Dictionary dictionary )
     {
-        return createComponentManager( dictionary, true );
+        ImmediateComponentManager cm = createComponentManager();
+
+        // register with the internal set of created components
+        m_componentInstances.put( cm, cm );
+
+        cm.setFactoryProperties( dictionary );
+        cm.reconfigure( m_configuration );
+        // enable synchronously
+        cm.enableInternal();
+        cm.activateInternal();
+
+        return cm;
     }
 
 
+    /**
+     * The component factory does not have a component to create.
+     * <p>
+     * But in the backwards compatible case any instances created for factory
+     * configuration instances are to enabled as a consequence of activating
+     * the component factory.
+     */
     protected boolean createComponent()
     {
-        // not component to create, newInstance must be used instead
+        ImmediateComponentManager[] cms = getComponentManagers( m_configuredServices );
+        for ( int i = 0; i < cms.length; i++ )
+        {
+            cms[i].enable();
+        }
+
         return true;
     }
 
 
+    /**
+     * The component factory does not have a component to delete.
+     * <p>
+     * But in the backwards compatible case any instances created for factory
+     * configuration instances are to disabled as a consequence of deactivating
+     * the component factory.
+     */
     protected void deleteComponent( int reason )
     {
-        // though we have nothing to delete really, we have to remove all
-        // references to the components created for configuration
-        m_createdComponents.clear();
-        if (m_configuredServices != null) {
-            m_configuredServices = null;
+        ImmediateComponentManager[] cms = getComponentManagers( m_configuredServices );
+        for ( int i = 0; i < cms.length; i++ )
+        {
+            cms[i].disable();
         }
     }
 
@@ -157,7 +215,7 @@
             m_configuration = null;
             reconfigureComponents( null );
         }
-        else if ( m_isConfigurationFactory && getState() == STATE_FACTORY && m_configuredServices != null )
+        else if ( m_isConfigurationFactory && m_configuredServices != null )
         {
             ImmediateComponentManager cm = ( ImmediateComponentManager ) m_configuredServices.remove( pid );
             if ( cm != null )
@@ -165,7 +223,7 @@
                 log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", getComponentMetadata(),
                     null );
 
-                disposeComponentManager( cm, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
+                cm.dispose();
             }
         }
     }
@@ -180,34 +238,40 @@
         }
         else if ( m_isConfigurationFactory )
         {
-            if ( getState() == STATE_FACTORY )
+            ImmediateComponentManager cm;
+            if ( m_configuredServices != null )
+            {
+                cm = ( ImmediateComponentManager ) m_configuredServices.get( pid );
+            }
+            else
             {
-                // configuration for factory configuration instances
+                m_configuredServices = new HashMap();
+                cm = null;
+            }
 
-                ImmediateComponentManager cm;
-                if ( m_configuredServices != null )
-                {
-                    cm = ( ImmediateComponentManager ) m_configuredServices.get( pid );
-                }
-                else
-                {
-                    m_configuredServices = new HashMap();
-                    cm = null;
-                }
+            if ( cm == null )
+            {
+                // create a new instance with the current configuration
+                cm = createComponentManager();
 
-                if ( cm == null )
-                {
-                    // create a new instance with the current configuration
-                    cm = createComponentManager( configuration, false );
+                // this should not call component reactivation because it is
+                // not active yet
+                cm.reconfigure( configuration );
 
-                    // keep a reference for future updates
-                    m_configuredServices.put( pid, cm );
-                }
-                else
+                // enable asynchronously if components are already enabled
+                if ( getState() == STATE_FACTORY )
                 {
-                    // update the configuration as if called as ManagedService
-                    cm.reconfigure( configuration );
+                    cm.enable();
                 }
+
+                // keep a reference for future updates
+                m_configuredServices.put( pid, cm );
+
+            }
+            else
+            {
+                // update the configuration as if called as ManagedService
+                cm.reconfigure( configuration );
             }
         }
         else
@@ -219,21 +283,31 @@
     }
 
 
-    // TODO: correct ???
+    /**
+     * A component factory component holder enables the held components by
+     * enabling itself.
+     */
     public void enableComponents()
     {
-        ImmediateComponentManager[] cms = getComponentManagers( false );
-        for ( int i = 0; i < cms.length; i++ )
-        {
-            cms[i].enable();
-        }
+        enable();
     }
 
 
-    // update components with this configuration
+    /**
+     * Reconfigure all components created calling the
+     * {@link #newInstance(Dictionary)} method to update them with the new
+     * configuration from the configuration admin.
+     * <p>
+     * This method is not used to reconfigure components created as part of
+     * backwards compatible support for configuration factories since they
+     * are reconfigured directly by {@link #configurationUpdated(String, Dictionary)}
+     * and {@link #configurationDeleted(String)}
+     *
+     * @param configuration the new configuration
+     */
     private void reconfigureComponents( Dictionary configuration )
     {
-        ImmediateComponentManager[] cms = getComponentManagers( false );
+        ImmediateComponentManager[] cms = getComponentManagers( m_componentInstances );
         for ( int i = 0; i < cms.length; i++ )
         {
             cms[i].reconfigure( configuration );
@@ -241,97 +315,71 @@
     }
 
 
-    // TODO: correct ???
+    /**
+     * A component factory component holder disables the held components by
+     * disabling itself.
+     */
     public void disableComponents()
     {
-        ImmediateComponentManager[] cms = getComponentManagers( false );
-        for ( int i = 0; i < cms.length; i++ )
-        {
-            cms[i].disable();
-        }
+        disable();
     }
 
 
-    // TODO: correct ???
+    /**
+     * Disposes off all components ever created by this component holder. This
+     * method is called if either the Declarative Services runtime is stopping
+     * or if the owning bundle is stopped. In both cases all components created
+     * by this holder must be disposed off.
+     */
     public void disposeComponents( int reason )
     {
-        ImmediateComponentManager[] cms = getComponentManagers( true );
+        ImmediateComponentManager[] cms = getComponentManagers( m_componentInstances );
         for ( int i = 0; i < cms.length; i++ )
         {
             cms[i].dispose( reason );
         }
-    }
-
 
-    //---------- internal
+        m_componentInstances.clear();
 
-    /**
-     * ComponentManager instances created by this method are not registered
-     * with the ComponentRegistry. Therefore, any configuration update to these
-     * components must be effected by this class !
-     *
-     * @param configuration The (initial) configuration for the new
-     *      component manager
-     * @param isNewInstance <code>true</code> if this component manager is
-     *      created as per {@link #newInstance(Dictionary)}. In this case the
-     *      given configuration is used as the factory configuration and the
-     *      component is immediately enabled (synchronously). Otherwise the
-     *      component is created because a new configuration instance of
-     *      this factory has been created. In this case the configuration is
-     *      used as the normal configuration from configuration admin (not the
-     *      factory configuration) and the component is enabled asynchronously.
-     */
-    private ImmediateComponentManager createComponentManager( Dictionary configuration, boolean isNewInstance )
-    {
-        ImmediateComponentManager cm = new ImmediateComponentManager( getActivator(), getComponentMetadata() );
-
-        // register with the internal set of created components
-        m_createdComponents.put( cm, cm );
-
-        // inject configuration
-        if ( isNewInstance )
-        {
-            cm.setFactoryProperties( configuration );
-            cm.reconfigure( m_configuration );
-            // enable synchronously
-            cm.enableInternal();
-            cm.activateInternal();
-        }
-        else
+        cms = getComponentManagers( m_configuredServices );
+        for ( int i = 0; i < cms.length; i++ )
         {
-            // this should not call component reactivation because it is
-            // not active yet
-            cm.reconfigure( configuration );
-            // enable asynchronously
-            cm.enable();
+            cms[i].dispose( reason );
         }
 
-        return cm;
+        m_configuredServices = null;
+
+        // finally dispose the component factory itself
+        dispose( reason );
     }
 
-    private void disposeComponentManager( ImmediateComponentManager cm, int reason )
-    {
-        // remove from created components
-        m_createdComponents.remove( cm );
 
-        // finally dispose it
-        cm.dispose( reason );
+    //---------- internal
+
+    /**
+     * Creates an {@link ImmediateComponentManager} instance with the
+     * {@link BundleComponentActivator} and {@link ComponentMetadata} of this
+     * instance. The component manager is kept in the internal set of created
+     * components. The component is neither configured nor enabled.
+     */
+    private ImmediateComponentManager createComponentManager()
+    {
+        return new ImmediateComponentManager( getActivator(), getComponentMetadata() );
     }
 
 
-    private ImmediateComponentManager[] getComponentManagers( boolean clear )
+    private ImmediateComponentManager[] getComponentManagers( Map componentMap )
     {
-        synchronized ( m_createdComponents )
+        if ( componentMap != null )
         {
-            ImmediateComponentManager[] cm = new ImmediateComponentManager[m_createdComponents.size()];
-            m_createdComponents.keySet().toArray( cm );
-
-            if ( clear )
+            synchronized ( componentMap )
             {
-                m_createdComponents.clear();
+                ImmediateComponentManager[] cm = new ImmediateComponentManager[componentMap.size()];
+                componentMap.values().toArray( cm );
+                return cm;
             }
-
-            return cm;
         }
+
+        return new ImmediateComponentManager[0];
     }
 }