FELIX-2954 (annotated component factory does not allow to provide a component instance explicitly)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1124168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/doc/changelog.txt b/dependencymanager/annotation/doc/changelog.txt
index 13f10c0..cff358b 100644
--- a/dependencymanager/annotation/doc/changelog.txt
+++ b/dependencymanager/annotation/doc/changelog.txt
@@ -1,5 +1,5 @@
-Initial Release 3.0.0
----------------------
+Changes from 3.0.0 to 3.0.1
+---------------------------
** Bug
@@ -7,3 +7,11 @@
* removed LICENSE.json
* removed changelog.txt from root of project
+ * [FELIX-2954 ] - annotated component factory does not allow to provide a component instance explicitly
+
+Initial Release 3.0.0
+---------------------
+
+** Bug
+
+** Improvement
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Component.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Component.java
index 9619863..780b8f4 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Component.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Component.java
@@ -122,10 +122,15 @@
* // Update the first X component instance
* x1.put("foo", "bar1_modified");
* _XFactory.add(x1);
+ *
+ * // Instantiate a third X instance, by explicitly providing the implementation object
+ * Dictionary x3 = new Hashtable() {{ put(Component.FACTORY_INSTANCE, new X()); }};
+ * _XFactory.add(x3);
*
- * // Destroy x1/x2 components (Notice that invoking XFactory.clear() will destroy all X component instances).
+ * // Destroy x1/x2/x3 components (Notice that invoking XFactory.clear() will destroy all X component instances).
* _XFactory.remove(x1);
* _XFactory.remove(x2);
+ * _XFactory.remove(x3);
* }
* }
* </pre>
@@ -164,6 +169,9 @@
* <p>The dictionary registered in the Set will be provided to the created component instance using a callback method that you can
* optionally specify in the {@link Component#factoryConfigure()} attribute. Each public properties from that dictionary
* (which don't start with a dot) will be propagated along with the annotated component service properties.
+ *
+ * <p>Optionally, the dictionary registered into the factory set may provide an implementation instance for the component to be created,
+ * using the {@value #FACTORY_INSTANCE} key.
*/
String factorySet() default "";
@@ -179,4 +187,16 @@
* Sets the static method used to create the components implementation instance.
*/
String factoryMethod() default "";
+
+ /**
+ * Service property name used to match a given Factory Set.
+ * @see #factorySet() for more information about factory sets.
+ */
+ final static String FACTORY_NAME = "dm.factory.name";
+
+ /**
+ * Key used when providing an implementation in a factory Set dictionary configuration.
+ * @see #factorySet()
+ */
+ final static String FACTORY_INSTANCE = "dm.factory.instance";
}
diff --git a/dependencymanager/runtime/doc/changelog.txt b/dependencymanager/runtime/doc/changelog.txt
index 81bbf9e..7f3eb61 100644
--- a/dependencymanager/runtime/doc/changelog.txt
+++ b/dependencymanager/runtime/doc/changelog.txt
@@ -1,7 +1,15 @@
+Changes from 3.0.0 to 3.0.1
+---------------------------
+
+** Bug
+
+** Improvement
+ * Removed root changelog.txt
+ * [FELIX-2954 ] - annotated component factory does not allow to provide a component instance explicitly
+
Initial Release 3.0.0
---------------------
** Bug
** Improvement
- * Removed root changelog.txt
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java
index 15cc1be..a035c1e 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java
@@ -108,6 +108,13 @@
private final static Object SERVICE_CREATING = new Object();
/**
+ * When a Dictionary is registered in a factory Set, we use this special
+ * property key, whose value may provide the instance to use when
+ * creating a service.
+ */
+ private final static String DM_FACTORY_INSTANCE = "dm.factory.instance";
+
+ /**
* This class wraps <tt>Dictionary</tt>, allowing to store the dictionary into a Map, using
* reference-equality in place of object-equality when getting the Dictionary from the Map.
*/
@@ -344,19 +351,28 @@
{
try
{
- // Create the Service / impl
+ // Create the Service / impl, unless it is explicitly provided from the
+ // configuration (using the specific key "dm.factory.instance").
Component s = m_dm.createComponent();
Class implClass = m_bundle.loadClass(m_srvMeta.getString(Params.impl));
- String factoryMethod = m_srvMeta.getString(Params.factoryMethod, null);
- if (factoryMethod == null)
+ Object impl = configuration.get(DM_FACTORY_INSTANCE);
+ if (impl == null)
{
- m_impl = implClass.newInstance();
+ String factoryMethod = m_srvMeta.getString(Params.factoryMethod, null);
+ if (factoryMethod == null)
+ {
+ m_impl = implClass.newInstance();
+ }
+ else
+ {
+ Method m = implClass.getDeclaredMethod(factoryMethod);
+ m.setAccessible(true);
+ m_impl = m.invoke(null);
+ }
}
else
{
- Method m = implClass.getDeclaredMethod(factoryMethod);
- m.setAccessible(true);
- m_impl = m.invoke(null);
+ m_impl = impl;
}
// Invoke "configure" callback
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/factory/MyServiceFactory.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/factory/MyServiceFactory.java
index e7fbdec..71c1ef9 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/factory/MyServiceFactory.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/factory/MyServiceFactory.java
@@ -34,7 +34,7 @@
@Component
public class MyServiceFactory
{
- @ServiceDependency(filter = "(dm.factory.name=MyServiceFactory)")
+ @ServiceDependency(filter = "(" + Component.FACTORY_NAME + "=MyServiceFactory)")
Set<Dictionary> m_myServiceFactory;
@ServiceDependency
@@ -50,6 +50,7 @@
m_conf = new Hashtable();
m_conf.put("instance.id", "instance");
m_conf.put(".private.param", "private");
+ m_conf.put(Component.FACTORY_INSTANCE, new MyService()); // we explicitly provide the instance
Assert.assertTrue(m_myServiceFactory.add(m_conf));
}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java
index c63c5e2..488c425 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java
@@ -105,7 +105,7 @@
@Component
public static class ProviderImplFactory
{
- @ServiceDependency(filter="(dm.factory.name=MyFactory)")
+ @ServiceDependency(filter="(" + Component.FACTORY_NAME + "=MyFactory)")
void bind(Set<Dictionary> m_providerImplFactory)
{
m_providerImplFactory.add(new Hashtable() {{ put("foo2", "bar2"); }});