You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2013/05/24 19:37:03 UTC
svn commit: r1486131 - in
/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime:
AbstractBuilder.java ServiceLifecycleHandler.java
Author: pderop
Date: Fri May 24 17:37:02 2013
New Revision: 1486131
URL: http://svn.apache.org/r1486131
Log:
FELIX-4050: Avoid messing up component state calculation when an init method adds
available dependencies using the API and also returns a Map for configuring
other named annotated dependencies.
Modified:
felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java
felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java?rev=1486131&r1=1486130&r2=1486131&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java Fri May 24 17:37:02 2013
@@ -115,7 +115,7 @@ public abstract class AbstractBuilder
String name = dependency.getString(Params.name, null);
if (name == null) {
DependencyBuilder depBuilder = new DependencyBuilder(dependency);
- Log.instance().info("ServiceLifecycleHandler.init: adding dependency %s into service %s",
+ Log.instance().info("adding dependency %s into service %s",
dependency, srvMeta);
Dependency d = depBuilder.build(b, dm, false);
s.add(d);
Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java?rev=1486131&r1=1486130&r2=1486131&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java Fri May 24 17:37:02 2013
@@ -90,15 +90,15 @@ import org.osgi.framework.Bundle;
*/
public class ServiceLifecycleHandler
{
- private String m_init;
- private String m_start;
- private String m_stop;
- private String m_destroy;
- private MetaData m_srvMeta;
- private List<MetaData> m_depsMeta;
- private List<Dependency> m_namedDeps = new ArrayList<Dependency>();
- private Bundle m_bundle;
- private ToggleServiceDependency m_toggle;
+ private final String m_init;
+ private final String m_start;
+ private final String m_stop;
+ private final String m_destroy;
+ private final MetaData m_srvMeta;
+ private final List<MetaData> m_depsMeta;
+ private final List<Dependency> m_namedDeps = new ArrayList<Dependency>();
+ private final Bundle m_bundle;
+ private volatile ToggleServiceDependency m_toggle;
private final static Object SYNC = new Object();
/**
@@ -128,14 +128,17 @@ public class ServiceLifecycleHandler
* the actual Service' init method, to see if a dependency customization map is returned.
* We also check if a Lifecycle Controller is used. In this case, we add a hidden custom dependency,
* allowing to take control of when the component is actually started/stopped.
- * @param service The Annotated Service
+ * We also handle an edge case described in FELIX-4050, where component state calculation
+ * may mess up if some dependencies are added using the API from the init method.
+ *
+ * @param c The Annotated Component
*/
- @SuppressWarnings("unchecked")
- public void init(Component service)
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void init(Component c)
throws Exception
{
- Object serviceInstance = service.getService();
- DependencyManager dm = service.getDependencyManager();
+ Object serviceInstance = c.getService();
+ DependencyManager dm = c.getDependencyManager();
// Check if a lifecycle controller is defined for this service. If true, then
// We'll use the ToggleServiceDependency in order to manually activate/deactivate
@@ -154,7 +157,7 @@ public class ServiceLifecycleHandler
m_toggle = new ToggleServiceDependency();
AtomicBoolean startFlag = new AtomicBoolean(false);
// Add the toggle to the service (we'll remove it from our destroy emthod).
- service.add(m_toggle);
+ c.add(m_toggle);
// Inject the runnable that will start our service, when invoked.
setField(serviceInstance, starter, Runnable.class, new ComponentStarter(componentName, m_toggle, startFlag));
if (stopper != null) {
@@ -163,15 +166,27 @@ public class ServiceLifecycleHandler
}
}
- // Invoke all composites' init methods, and for each one, check if a dependency
+ // Before invoking an optional init method, we have to handle an edge case (FELIX-4050), where
+ // init may add dependencies using the API and also return a map for configuring some
+ // named dependencies. We have to add a hidden toggle dependency in the component, which we'll
+ // active *after* the init method is called, and possibly *after* named dependencies are configured.
+
+ ToggleServiceDependency initToggle = null;
+ if (m_init != null)
+ {
+ initToggle = new ToggleServiceDependency();
+ c.add(initToggle);
+ }
+
+ // Invoke component and all composites init methods, and for each one, check if a dependency
// customization map is returned by the method. This map will be used to configure
// some dependency filters (or required flag).
Map<String, String> customization = new HashMap<String, String>();
- Object[] composites = service.getCompositionInstances();
+ Object[] composites = c.getCompositionInstances();
for (Object composite: composites)
{
- Object o = invokeMethod(composite, m_init, dm, service);
+ Object o = invokeMethod(composite, m_init, dm, c);
if (o != null && Map.class.isAssignableFrom(o.getClass()))
{
customization.putAll((Map) o);
@@ -180,7 +195,9 @@ public class ServiceLifecycleHandler
Log.instance().debug("ServiceLifecycleHandler.init: invoked init method from service %s " +
", returned map: %s", serviceInstance, customization);
-
+
+ // Apply name dependency filters possibly returned by the init() method.
+
for (MetaData dependency: m_depsMeta)
{
// Check if this dependency has a name, and if we find the name from the
@@ -214,10 +231,19 @@ public class ServiceLifecycleHandler
}
// Add all extra dependencies in one shot, in order to calculate state changes for all dependencies at a time.
- if (m_namedDeps.size() > 0) {
+ if (m_namedDeps.size() > 0)
+ {
Log.instance().info("ServiceLifecycleHandler.init: adding extra/named dependencies %s",
m_namedDeps);
- service.add(m_namedDeps);
+ c.add(m_namedDeps);
+ }
+
+ // init method fully handled, and all possible named dependencies have been configured. Now, activate the
+ // hidden toggle, and then remove it from the component, because we don't need it anymore.
+ if (initToggle != null)
+ {
+ initToggle.setAvailable(true);
+ c.remove(initToggle);
}
}
@@ -228,7 +254,7 @@ public class ServiceLifecycleHandler
* some additional properties which must be appended to existing service properties.
* Such extra properties takes precedence over existing service properties.
*/
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public void start(Component service)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
{