FELIX-3869: Fragment support for DependencyManager-Component.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1441505 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/runtime/doc/changelog.txt b/dependencymanager/runtime/doc/changelog.txt
index b4aa109..2bb4add 100644
--- a/dependencymanager/runtime/doc/changelog.txt
+++ b/dependencymanager/runtime/doc/changelog.txt
@@ -1,11 +1,19 @@
-Changes from 3.0.0 to 3.0.1
----------------------------
+Trunk
+------
+
+** Bug
+
+** Improvement
+ * [FELIX-3869] - Fragment support for DependencyManager-Component
+
+Release 3.1.0
+-------------
** Bug
** Improvement
* Removed root changelog.txt
- * [FELIX-2954 ] - annotated component factory does not allow to provide a component instance explicitly
+ * [FELIX-2954] - annotated component factory does not allow to provide a component instance explicitly
* [FELIX-2966] - Annotations should automatically generate Import-Service/Export-Service headers
* [FELIX-2965] - Annotations should allow to enable or disable auto-configuration mode.
* [FELIX-3866] - Added support for swap attribute in AspectService and AdpaterService annotations.
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Activator.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Activator.java
index b551302..18a3499 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Activator.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Activator.java
@@ -18,12 +18,17 @@
*/
package org.apache.felix.dm.runtime;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyActivatorBase;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.ServiceDependency;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.log.LogService;
+import org.osgi.service.packageadmin.PackageAdmin;
/*
* This is the Activator for our DependencyManager Component Runtime.
@@ -42,6 +47,12 @@
final static String CONF_LOG = "dm.runtime.log";
/**
+ * Name of bundle context property telling if PackageAdmin service is required or not.
+ * (default = false)
+ */
+ private final static String CONF_PACKAGE_ADMIN = "dm.runtime.packageAdmin";
+
+ /**
* Name of bundle context property telling if Components must be auto configured
* with BundleContext/ServiceRegistration etc .. (default = false)
*/
@@ -52,32 +63,42 @@
*
* We depend on the OSGi LogService, and we track all started bundles which do have a
* "DependencyManager-Component" Manifest header.
- * If the "dm.runtime.log=true" parameter is configured in the Felix config.properties
- * then we'll use a required/temporal service dependency over the log service.
- * This temporal dependency allows to not being restarted if the log service is temporarily
- * unavailable (that is: when the log service is updated).
- * if the "dm.runtime.log" is not configured or it it is set to false, then we'll use
- * an optional dependency over the log service, in order to use a NullObject in case
- * the log service is not available.
+ * If the "dm.runtime.log=true" or "dm.runtime.packageAdmin=true" parameter is configured in the Felix config.properties
+ * then we'll use a required/temporal service dependency over the respective service.
+ * These temporal dependencies avoid us to be restarted if the respective service is temporarily
+ * unavailable (that is: when the service is updating).
+ * if the "dm.runtime.log" or "dm.runtime.packageAdmin" is not configured or it it is set to false, then we'll use
+ * an optional dependency over the respective service, in order to use a NullObject in case
+ * the service is not available.
*/
@Override
public void init(BundleContext context, DependencyManager dm) throws Exception
{
- boolean logActive = "true".equalsIgnoreCase(context.getProperty(CONF_LOG));
- ServiceDependency logDep = logActive ?
- createTemporalServiceDependency() : createServiceDependency().setRequired(false);
- logDep.setService(LogService.class).setAutoConfig(true);
-
- dm.add(createComponent()
- .setImplementation(DependencyManagerRuntime.class)
- .setComposition("getComposition")
- .add(logDep)
- .add(createBundleDependency()
- .setRequired(false)
- .setAutoConfig(false)
- .setStateMask(Bundle.ACTIVE)
- .setFilter("(DependencyManager-Component=*)")
- .setCallbacks("bundleStarted", "bundleStopped")));
+ Component component = createComponent()
+ .setImplementation( DependencyManagerRuntime.class )
+ .setComposition( "getComposition" )
+ .add(createBundleDependency()
+ .setRequired( false )
+ .setAutoConfig( false )
+ .setStateMask( Bundle.ACTIVE )
+ .setFilter( "(DependencyManager-Component=*)" )
+ .setCallbacks( "bundleStarted", "bundleStopped" ) );
+
+ Map<String, Class<?>> services = new HashMap<String, Class<?>>( 2 );
+ services.put( CONF_LOG, LogService.class );
+ services.put( CONF_PACKAGE_ADMIN, PackageAdmin.class );
+ for (Map.Entry<String, Class<?>> entry : services.entrySet())
+ {
+ String serviceProperty = entry.getKey();
+ Class<?> service = entry.getValue();
+ boolean serviceActive = "true".equalsIgnoreCase(context.getProperty(serviceProperty));
+ ServiceDependency serviceDep =
+ serviceActive ? createTemporalServiceDependency()
+ : createServiceDependency().setRequired(false);
+ serviceDep.setService(service).setAutoConfig(true);
+ component.add(serviceDep);
+ }
+ dm.add( component );
}
/**
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyManagerRuntime.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyManagerRuntime.java
index 9022064..2bd6aa7 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyManagerRuntime.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/DependencyManagerRuntime.java
@@ -29,6 +29,7 @@
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.PackageAdmin;
/**
* This class parses service descriptors generated by the annotation bnd processor.
@@ -42,6 +43,7 @@
private ConcurrentHashMap<Bundle, DependencyManager> m_managers =
new ConcurrentHashMap<Bundle, DependencyManager>();
private DescriptorParser m_parser;
+ private PackageAdmin m_packageAdmin; // Possibly a NullObject
/**
* Our constructor. We'll initialize here our DM component builders.
@@ -96,31 +98,26 @@
}
/**
- * Checks if a started bundle have some DependencyManager descriptors
- * referenced in the "DependencyManager-Component" OSGi header.
- * @param b the started bundle.
+ * Load the DM descriptors from the started bundle. We also check possible fragments
+ * attached to the bundle, which might also contain some DM descriptors.
+ * @param bundle the started bundle which contains a DependencyManager-Component header
*/
- protected void bundleStarted(Bundle b)
+ protected void bundleStarted(Bundle bundle)
{
- String descriptorPaths = (String) b.getHeaders().get("DependencyManager-Component");
- if (descriptorPaths == null)
- {
- return;
- }
-
- for (String descriptorPath : descriptorPaths.split(","))
- {
- URL descriptorURL = b.getEntry(descriptorPath);
- if (descriptorURL == null)
- {
- Log.instance().error("Runtime: " + "DependencyManager component descriptor not found: %s",
- descriptorPath);
- continue;
+ Log.instance().info("Scanning started bundle %s", bundle.getSymbolicName());
+ List<URL> descriptorURLs = new ArrayList<URL>();
+ collectDescriptors(bundle, descriptorURLs);
+ Bundle[] fragments = m_packageAdmin.getFragments(bundle);
+ if (fragments != null) {
+ for (Bundle fragment : fragments) {
+ collectDescriptors(fragment, descriptorURLs);
}
- loadDescriptor(b, descriptorURL);
+ }
+ for (URL descriptorURL: descriptorURLs) {
+ loadDescriptor(bundle, descriptorURL);
}
}
-
+
/**
* Unregisters all services for a stopping bundle.
* @param b
@@ -132,7 +129,7 @@
DependencyManager dm = m_managers.remove(b);
if (dm != null)
{
- List<Component> services = new ArrayList(dm.getComponents());
+ List<Component> services = new ArrayList<Component>(dm.getComponents());
for (Component service : services)
{
Log.instance().info("Runtime: Removing service: %s", service);
@@ -142,15 +139,40 @@
}
/**
+ * Collect all descriptors found from a given bundle, including its possible attached fragments.
+ * @param bundle a started bundle containing some DM descriptors
+ * @param out the list of descriptors' URLS found from the started bundle, as well as from possibly
+ * attached fragments.
+ */
+ private void collectDescriptors(Bundle bundle, List<URL> out) {
+ String descriptorPaths = (String) bundle.getHeaders().get("DependencyManager-Component");
+ if (descriptorPaths == null)
+ {
+ return;
+ }
+
+ for (String descriptorPath : descriptorPaths.split(","))
+ {
+ URL descriptorURL = bundle.getEntry(descriptorPath);
+ if (descriptorURL == null)
+ {
+ Log.instance()
+ .error("Runtime: " + "DependencyManager component descriptor not found: %s",
+ descriptorPath);
+ continue;
+ }
+ out.add(descriptorURL);
+ }
+ }
+
+ /**
* Load a DependencyManager component descriptor from a given bundle.
* @param b
* @param descriptorURL
*/
private void loadDescriptor(Bundle b, URL descriptorURL)
{
- Log.instance().debug("Runtime: ++++ Parsing descriptor %s from bundle %s",
- descriptorURL,
- b.getSymbolicName());
+ Log.instance().debug("Parsing descriptor %s from bundle %s", descriptorURL, b.getSymbolicName());
BufferedReader in = null;
try
@@ -164,7 +186,6 @@
}
m_parser.parse(in, b, dm);
- m_managers.put(b, dm);
}
catch (Throwable t)