[FELIX-2965] - Apply @Registered/@Unregistered annotation on composition instances.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1126383 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
index 958e16a..981c4ba 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
@@ -335,8 +335,13 @@
// properties attribute
parseProperties(annotation, EntryParam.properties, writer);
- // provides attribute
- writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService);
+ // provides attribute.
+ if (writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService) == 0)
+ {
+ // no service provided: check if @Registered/@Unregistered annotation are used
+ // and raise an error if true.
+ checkRegisteredUnregisteredNotPresent();
+ }
// factorySet attribute
String factorySetName = writer.putString(annotation, EntryParam.factorySet, null);
@@ -644,7 +649,10 @@
parseProperties(annotation, EntryParam.properties, writer);
// Parse the provided adapter service (use directly implemented interface by default).
- writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService);
+ if (writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService) == 0)
+ {
+ checkRegisteredUnregisteredNotPresent();
+ }
// Parse factoryMethod attribute
writer.putString(annotation, EntryParam.factoryMethod, null);
@@ -684,7 +692,10 @@
parseProperties(annotation, EntryParam.properties, writer);
// Parse the optional adapter service (use directly implemented interface by default).
- writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService);
+ if (writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService) == 0)
+ {
+ checkRegisteredUnregisteredNotPresent();
+ }
// Parse propagate attribute
writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
@@ -720,7 +731,10 @@
parseProperties(annotation, EntryParam.properties, writer);
// Parse the provided adapter service (use directly implemented interface by default).
- writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService);
+ if (writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService) == 0)
+ {
+ checkRegisteredUnregisteredNotPresent();
+ }
// Parse propagate attribute
writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
@@ -754,7 +768,10 @@
writer.putString(annotation, EntryParam.propagate, Boolean.FALSE.toString());
// Parse the provided adapter service (use directly implemented interface by default).
- writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService);
+ if (writer.putClassArray(annotation, EntryParam.provides, m_interfaces, m_exportService) == 0)
+ {
+ checkRegisteredUnregisteredNotPresent();
+ }
// Parse Adapter properties.
parseProperties(annotation, EntryParam.properties, writer);
@@ -1008,6 +1025,27 @@
}
/**
+ * This method checks if the @Registered and/or @Unregistered annotations have been defined
+ * while they should not, because the component does not provide a service.
+ */
+ private void checkRegisteredUnregisteredNotPresent()
+ {
+ if (m_registeredMethod != null)
+ {
+ throw new IllegalStateException("@Registered annotation can't be used on a Component " +
+ " which does not provide a service (class=" + m_className + ")");
+
+ }
+
+ if (m_unregisteredMethod != null)
+ {
+ throw new IllegalStateException("@Unregistered annotation can't be used on a Component " +
+ " which does not provide a service (class=" + m_className + ")");
+
+ }
+ }
+
+ /**
* Get an annotation attribute, and return a default value if its not present.
* @param <T> the type of the variable which is assigned to the return value of this method.
* @param annotation The annotation we are parsing
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java
index 2a02076..ed40158 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryWriter.java
@@ -221,8 +221,9 @@
/**
* Get a class array attribute value from an annotation and write it into this descriptor entry.
* Also collect classes found from the array into a given Set.
+ * @return the class array size.
*/
- public void putClassArray(Annotation annotation, EntryParam param, Object def, Set<String> collect)
+ public int putClassArray(Annotation annotation, EntryParam param, Object def, Set<String> collect)
{
checkType(param.toString());
@@ -258,7 +259,11 @@
+ value.toString(), e);
}
}
+
+ return ((Object[]) value).length;
}
+
+ return 0;
}
/**
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java
index 2127c8e..c8e23b6 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AbstractBuilder.java
@@ -144,18 +144,23 @@
{
if (m_registered != null)
{
- Object instance = c.getService();
- try
+ // The component has registered a service: notify all component instances
+ Object[] componentInstances = c.getCompositionInstances();
+ for (Object instance : componentInstances)
{
- InvocationUtil
- .invokeCallbackMethod(instance,
- m_registered,
- new Class[][] {{ ServiceRegistration.class }, {}},
- new Object[][] {{ c.getServiceRegistration() }, {}});
- }
- catch (Throwable t)
- {
- Log.instance().error("Exception caught while invoking method %s on component %s", t, m_registered, instance);
+ try
+ {
+ Class[][] signatures = new Class[][] { { ServiceRegistration.class }, {} };
+ Object[][] params = new Object[][] { { c.getServiceRegistration() }, {} };
+ InvocationUtil.invokeCallbackMethod(instance, m_registered, signatures, params);
+ }
+ catch (Throwable t)
+ {
+ Log.instance().error("Exception caught while invoking method %s on component %s",
+ t,
+ m_registered,
+ instance);
+ }
}
}
}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/CompositeService.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1.java
similarity index 87%
rename from dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/CompositeService.java
rename to dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1.java
index 418ee4d..5496f15 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/CompositeService.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1.java
@@ -18,26 +18,28 @@
import org.apache.felix.dm.annotation.api.Composition;
import org.apache.felix.dm.annotation.api.Destroy;
import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.Registered;
import org.apache.felix.dm.annotation.api.ServiceDependency;
import org.apache.felix.dm.annotation.api.Start;
import org.apache.felix.dm.annotation.api.Stop;
import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.osgi.framework.ServiceRegistration;
/**
* This service is also composed of the Component object.
*/
@Component
-public class CompositeService
+public class C1 implements C1Service
{
/* We are composed of this object, which will also be injected with our dependencies */
- private Composite m_composite = new Composite();
+ private C2 m_c2 = new C2();
/* This dependency filter will be configured from our init method */
@ServiceDependency(name = "D")
public volatile Runnable m_runnable;
/* Object used to check that methods are called in the proper sequence */
- @ServiceDependency(filter="(name=CompositeService)")
+ @ServiceDependency(filter="(name=C1)")
private volatile Sequencer m_sequencer;
/**
@@ -60,7 +62,7 @@
@Composition
Object[] getComposition()
{
- return new Object[] { this, m_composite };
+ return new Object[] { this, m_c2 };
}
/**
@@ -76,12 +78,21 @@
}
/**
+ * Our provided service has been registered into the OSGi service registry.
+ */
+ @Registered
+ void registered(ServiceRegistration sr)
+ {
+ m_sequencer.step(7);
+ }
+
+ /**
* Our Service is stopping, and our Composites will also be
*/
@Stop
void stop()
{
- m_sequencer.step(7);
+ m_sequencer.step(9);
// Our Component.stop() method should be called once this method returns.
}
@@ -91,7 +102,7 @@
@Destroy
void destroy()
{
- m_sequencer.step(9);
+ m_sequencer.step(11);
// Our Component.destroy() method should be called once this method returns.
}
}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1Service.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1Service.java
new file mode 100644
index 0000000..a4ce49c
--- /dev/null
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C1Service.java
@@ -0,0 +1,5 @@
+package org.apache.felix.dm.test.bundle.annotation.composite;
+
+public interface C1Service
+{
+}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/Composite.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C2.java
similarity index 86%
rename from dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/Composite.java
rename to dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C2.java
index 3366735..9d486d0 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/Composite.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/composite/C2.java
@@ -12,11 +12,12 @@
package org.apache.felix.dm.test.bundle.annotation.composite;
import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.osgi.framework.ServiceRegistration;
/**
* The CompositeService is also made up of this Class.
*/
-public class Composite
+public class C2
{
// Injected dependency (from CompositeService)
private volatile Sequencer m_sequencer;
@@ -37,15 +38,24 @@
m_runnable.run(); /* step 6 */
}
+ void registered(ServiceRegistration sr)
+ {
+ if (sr == null)
+ {
+ m_sequencer.throwable(new Exception("null service registration"));
+ }
+ m_sequencer.step(8);
+ }
+
// lifecycle callback (same method as the one from CompositeService)
void stop()
{
- m_sequencer.step(8);
+ m_sequencer.step(10);
}
// lifecycle callback (same method as the one from CompositeService)
void destroy()
{
- m_sequencer.step(10);
+ m_sequencer.step(12);
}
}
diff --git a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/CompositeAnnotationsTest.java b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/CompositeAnnotationsTest.java
index 6301e4f..6f89054 100644
--- a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/CompositeAnnotationsTest.java
+++ b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/CompositeAnnotationsTest.java
@@ -64,7 +64,7 @@
{
DependencyManager m = new DependencyManager(context);
// Provide the Sequencer service to the "Component" service.
- m.add(makeSequencer(m, "CompositeService"));
+ m.add(makeSequencer(m, "C1"));
m.add(makeSequencer(m, "Dependency1"));
m.add(makeSequencer(m, "Dependency2"));
// Check if the components have been initialized orderly
@@ -72,6 +72,6 @@
// Stop the bundle
stopBundle("CompositeAnnotationsTest", context);
// And check if the components lifecycle callbacks are called orderly
- m_ensure.waitForStep(10, 10000);
+ m_ensure.waitForStep(12, 10000);
}
}