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/28 16:03:02 UTC

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

Author: fmeschbe
Date: Tue Jul 28 14:03:02 2009
New Revision: 798529

URL: http://svn.apache.org/viewvc?rev=798529&view=rev
Log:
FELIX-1284 Add support to call a modified method for dynamic configuration update
FELIX-1416 Adapt to new ComponentHolder setup

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

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java?rev=798529&r1=798528&r2=798529&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java Tue Jul 28 14:03:02 2009
@@ -26,11 +26,10 @@
 import java.util.List;
 
 import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.ComponentRegistry;
 import org.apache.felix.scr.impl.helper.ReflectionHelper;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
-import org.osgi.service.cm.Configuration;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentConstants;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.log.LogService;
@@ -55,6 +54,9 @@
     // the deactivate method
     private Method deactivateMethod = ReflectionHelper.SENTINEL;
 
+    // the modify method
+    private Method modifyMethod = ReflectionHelper.SENTINEL;
+
     // optional properties provided in the ComponentFactory.newInstance method
     private Dictionary m_factoryProperties;
 
@@ -72,22 +74,9 @@
      * @param activator
      * @param metadata
      */
-    public ImmediateComponentManager( BundleComponentActivator activator, ComponentMetadata metadata,
-        ComponentRegistry componentRegistry )
+    public ImmediateComponentManager( BundleComponentActivator activator, ComponentMetadata metadata )
     {
-        super( activator, metadata, componentRegistry );
-
-        // only ask for configuration if not created by a Component Factory, in
-        // which case the configuration is provided by the Component Factory
-        if ( !getComponentMetadata().isFactory() )
-        {
-            Configuration cfg = componentRegistry.getConfiguration( activator.getBundleContext(),
-                getComponentMetadata().getName() );
-            if ( cfg != null )
-            {
-                m_configurationProperties = cfg.getProperties();
-            }
-        }
+        super( activator, metadata );
     }
 
 
@@ -278,6 +267,12 @@
     }
 
 
+    public boolean hasConfiguration()
+    {
+        return m_configurationProperties != null;
+    }
+
+
     /**
      * Returns the (private copy) of the Component properties to be used
      * for the ComponentContext as well as eventual service registration.
@@ -357,18 +352,135 @@
         // clear the current properties to force using the configuration data
         m_properties = null;
 
+        if ( getState() == STATE_UNSATISFIED && configuration != null
+            && getComponentMetadata().isConfigurationRequired() )
+        {
+            activateInternal();
+            return;
+        }
+
         // reactivate the component to ensure it is provided with the
         // configuration data
-        if ( ( getState() & ( STATE_ACTIVE | STATE_FACTORY | STATE_REGISTERED ) ) != 0 )
+        if ( ( getState() & ( STATE_ACTIVE | STATE_FACTORY | STATE_REGISTERED ) ) == 0 )
+        {
+            // nothing to do for inactive components, leave this method
+            return;
+        }
+
+        // if the configuration has been deleted but configuration is required
+        // this component must be deactivated
+        if ( configuration == null && getComponentMetadata().isConfigurationRequired() )
+        {
+            deactivateInternal( ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
+        }
+        else if ( !modify() )
         {
             log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure from configuration",
                 getComponentMetadata(), null );
             int reason = ( configuration == null ) ? ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED
-                : ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED;
+                : ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_MODIFIED;
             reactivate( reason );
         }
     }
 
+    private boolean modify() {
+        // 1. no live update if there is no declared method
+        if ( getComponentMetadata().getModified() == null )
+        {
+            return false;
+        }
+        // invariant: we have a modified method name
+
+        // 2. get and check configured method
+        Method modifyMethod = getModifyMethod();
+        if ( modifyMethod == null )
+        {
+            // log an error if the declared method cannot be found
+            log( LogService.LOG_ERROR, "Declared modify method '" + getComponentMetadata().getModified()
+                + "' cannot be found, configuring by reactivation", getComponentMetadata(), null );
+            return false;
+        }
+        // invariant: modify method is configured and found
+
+        // 3. check whether we can dynamically apply the configuration if
+        // any target filters influence the bound services
+        final Dictionary props = getProperties();
+        Iterator it = getDependencyManagers();
+        while ( it.hasNext() )
+        {
+            DependencyManager dm = ( DependencyManager ) it.next();
+            if ( !dm.canUpdateDynamically( props ) )
+            {
+                log( LogService.LOG_INFO,
+                    "Cannot dynamically update the configuration due to dependency changes induced on dependency "
+                        + dm.getName(), getComponentMetadata(), null );
+                return false;
+            }
+        }
+        // invariant: modify method existing and no static bound service changes
+
+        // 4. call method (nothing to do when failed, since it has already been logged)
+        invokeMethod( modifyMethod, m_implementationObject, m_componentContext, -1 );
+
+        // 5. update the target filter on the services now, this may still
+        // result in unsatisfied dependencies, in which case we abort
+        // this dynamic update and have the component be deactivated
+        if ( !verifyDependencyManagers( props ) )
+        {
+            log(
+                LogService.LOG_ERROR,
+                "Updating the service references caused at least on reference to become unsatisifed, deactivating component",
+                getComponentMetadata(), null );
+            return false;
+        }
+
+        // 6. update service registration properties
+        ServiceRegistration sr = getServiceRegistration();
+        if ( sr != null )
+        {
+            try
+            {
+                final Dictionary regProps = copyTo( null, props );
+                sr.setProperties( regProps );
+            }
+            catch ( IllegalStateException ise )
+            {
+                // service has been unregistered asynchronously, ignore
+            }
+            catch ( IllegalArgumentException iae )
+            {
+                log( LogService.LOG_ERROR,
+                    "Unexpected configuration property problem when updating service registration",
+                    getComponentMetadata(), iae );
+            }
+            catch ( Throwable t )
+            {
+                log( LogService.LOG_ERROR, "Unexpected problem when updating service registration",
+                    getComponentMetadata(), t );
+            }
+        }
+
+        // 7. everything set and done, the component has been udpated
+        return true;
+    }
+
+
+    /**
+     * Returns the configured modify method or <code>null</code> if the
+     * configured method cannot be found.
+     */
+    private Method getModifyMethod()
+    {
+        // ensure the method object is known
+        if ( modifyMethod == ReflectionHelper.SENTINEL )
+        {
+            modifyMethod = getMethod( m_implementationObject, getComponentMetadata().getModified(),
+                ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
+        }
+
+        return modifyMethod;
+    }
+
 
     /**
      * Find the method with the given name in the class hierarchy of the
@@ -448,7 +560,7 @@
                 }
                 else if ( paramTypes[i] == ReflectionHelper.MAP_CLASS )
                 {
-                    // note: getProperties() returns a Hashtable which is a Map
+                    // note: getProperties() returns a ReadOnlyDictionary which is a Map
                     param[i] = componentContext.getProperties();
                 }
                 else if ( paramTypes[i] == ReflectionHelper.INTEGER_CLASS || paramTypes[i] == Integer.TYPE)