Replaced the publisher/unpublisher Service attributes by a new LifecycelControler annotation, which can apply to any kind of Services
(service, adapters, or aspect).
A Service can now take control of its component activation/deactivation like this:
@AspectService(ranking=10)
public class MyServiceImpl implements MyService {
@LifecycleController
Runnable m_componentActivator;
@LifecycleController(start=false)
Runnable m_componentDeactivator;
void activateMyComponentWheneverIWant() {
m_componentActivator.run();
}
void deactivateMyComponentWheneverIWant() {
m_componentDeactivator.run();
}
}
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@987871 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleAdapterService.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleAdapterService.java
index d0c25f8..bf7d93c 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleAdapterService.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleAdapterService.java
@@ -60,7 +60,7 @@
int stateMask() default Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
/**
- * Specifies if properties from the bundle should be propagated to the service.
+ * Specifies if manifest headers from the bundle should be propagated to the service.
*/
boolean propagate() default true;
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleDependency.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleDependency.java
index 50eeada..c9911fa 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleDependency.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/BundleDependency.java
@@ -58,7 +58,8 @@
int stateMask() default Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
/**
- * @TODO
+ * Specifies if the manifest headers from the bundle should be propagated to
+ * the service properties.
*/
boolean propagate() default false;
}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
index 473e240..0c90c9c 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
@@ -173,81 +173,5 @@
/**
* Sets the static method used to create the Service implementation instance.
*/
- String factoryMethod() default "";
-
- /**
- * Injects a <code>Runnable</code> object to invoke for manually registering the Service into the OSGi registry.
- * By default, a Service is implicitly registered into the OSGi registry when the service's bundle is
- * started and when all required dependencies are satisfied. However, it is sometimes required to programatically
- * take control of when the service is registered. In this case, this attribute can be used and provides a
- * </code>Runnable</code> object that can be invoked in order to register a Service at any time.
- * <p>
- * <h3>Usage Examples</h3>
- * <blockquote>
- *
- * <pre>
- * /**
- * * This Service will be registered programatically into the OSGi registry, using the publisher attribute.
- * */
- * @Service(publisher="m_publisher")
- * class X implements Z {
- * Runnable m_publisher;
- *
- * @Start
- * void start() {
- * // Our Z Service is started but won't be registered into the OSGi registry once this method returns,
- * // because we are using the publisher attribute. The service will be registered only when we
- * // decide to invoke the Runnable injected by the publisher attribute.
- * }
- *
- * public void registerServiceWheneverIWant() {
- * m_publisher.run(); // register our service into the osgi registry.
- * }
- * }
- * </pre>
- * </blockquote>
- */
- String publisher() default "";
-
- /**
- * Injects a <code>Runnable</code> object for manually unregistering the Service from the OSGi registry.
- * By default, a Service is implicitly unregistered from the OSGi registry when the service's bundle is
- * stopped, or when the Service has lost one of its required dependencies. However, it is sometimes required to programatically
- * take control of when the service is unregistered. In this case, this attribute can be used and provides a
- * </code>Runnable</code> object that can be invoked in order to unregister a Service at any time.
- *
- * <p> Notice that this attribute is generally used with the {@link #publisher()} attribute.
- * <p>
- * <h3>Usage Examples</h3>
- * <blockquote>
- *
- * <pre>
- * /**
- * * This Service will be registered programatically into the OSGi registry, using the publisher attribute.
- * * It will also be unregistered unsing the Runnable injected by the unpublisher attribute.
- * */
- * @Service(publisher="m_publisher", unpublisher="m_unpublisher")
- * class X implements Z {
- * Runnable m_publisher;
- * Runnable m_unpublisher;
- *
- * @Start
- * void start() {
- * // Our Z Service is started but won't be registered into the OSGi registry once this method returns,
- * // because we are using the publisher attribute. The service will be registered only when we
- * // decide to invoke the Runnable injected by the publisher attribute.
- * }
- *
- * public void registerServiceWheneverIWant() {
- * m_publisher.run(); // register our service into the OSGi registry.
- * }
- *
- * public void unregisterServiceWheneverIWant() {
- * m_unpublisher.run(); // unregister our Z service from the OSGi registry.
- * }
- * }
- * </pre>
- * </blockquote>
- */
- String unpublisher() default "";
+ String factoryMethod() default "";
}
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 08bda25..bdcb4e5 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
@@ -36,6 +36,7 @@
import org.apache.felix.dm.annotation.api.Destroy;
import org.apache.felix.dm.annotation.api.FactoryConfigurationAdapterService;
import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.LifecycleController;
import org.apache.felix.dm.annotation.api.ResourceAdapterService;
import org.apache.felix.dm.annotation.api.ResourceDependency;
import org.apache.felix.dm.annotation.api.Service;
@@ -60,27 +61,19 @@
private final static String A_START = "L" + Start.class.getName().replace('.', '/') + ";";
private final static String A_STOP = "L" + Stop.class.getName().replace('.', '/') + ";";
private final static String A_DESTROY = "L" + Destroy.class.getName().replace('.', '/') + ";";
- private final static String A_COMPOSITION = "L" + Composition.class.getName().replace('.', '/')
- + ";";
+ private final static String A_COMPOSITION = "L" + Composition.class.getName().replace('.', '/') + ";";
+ private final static String A_LIFCLE_CTRL = "L" + LifecycleController.class.getName().replace('.', '/')+ ";";
+
private final static String A_SERVICE = "L" + Service.class.getName().replace('.', '/') + ";";
- private final static String A_SERVICE_DEP = "L"
- + ServiceDependency.class.getName().replace('.', '/') + ";";
- private final static String A_CONFIGURATION_DEPENDENCY = "L"
- + ConfigurationDependency.class.getName().replace('.', '/') + ";";
- private final static String A_BUNDLE_DEPENDENCY = "L"
- + BundleDependency.class.getName().replace('.', '/') + ";";
- private final static String A_RESOURCE_DEPENDENCY = "L"
- + ResourceDependency.class.getName().replace('.', '/') + ";";
- private final static String A_ASPECT_SERVICE = "L"
- + AspectService.class.getName().replace('.', '/') + ";";
- private final static String A_ADAPTER_SERVICE = "L"
- + AdapterService.class.getName().replace('.', '/') + ";";
- private final static String A_BUNDLE_ADAPTER_SERVICE = "L"
- + BundleAdapterService.class.getName().replace('.', '/') + ";";
- private final static String A_RESOURCE_ADAPTER_SERVICE = "L"
- + ResourceAdapterService.class.getName().replace('.', '/') + ";";
- private final static String A_FACTORYCONFIG_ADAPTER_SERVICE = "L"
- + FactoryConfigurationAdapterService.class.getName().replace('.', '/') + ";";
+ private final static String A_SERVICE_DEP = "L" + ServiceDependency.class.getName().replace('.', '/') + ";";
+ private final static String A_CONFIGURATION_DEPENDENCY = "L" + ConfigurationDependency.class.getName().replace('.', '/') + ";";
+ private final static String A_BUNDLE_DEPENDENCY = "L" + BundleDependency.class.getName().replace('.', '/') + ";";
+ private final static String A_RESOURCE_DEPENDENCY = "L" + ResourceDependency.class.getName().replace('.', '/') + ";";
+ private final static String A_ASPECT_SERVICE = "L"+ AspectService.class.getName().replace('.', '/') + ";";
+ private final static String A_ADAPTER_SERVICE = "L" + AdapterService.class.getName().replace('.', '/') + ";";
+ private final static String A_BUNDLE_ADAPTER_SERVICE = "L" + BundleAdapterService.class.getName().replace('.', '/') + ";";
+ private final static String A_RESOURCE_ADAPTER_SERVICE = "L" + ResourceAdapterService.class.getName().replace('.', '/') + ";";
+ private final static String A_FACTORYCONFIG_ADAPTER_SERVICE = "L" + FactoryConfigurationAdapterService.class.getName().replace('.', '/') + ";";
private Reporter m_reporter;
private String m_className;
@@ -98,6 +91,8 @@
private String m_initMethod;
private String m_destroyMethod;
private String m_compositionMethod;
+ private String m_starter;
+ private String m_stopper;
/**
* This class represents a DependencyManager component descriptor entry.
@@ -226,6 +221,9 @@
{
Patterns.parseMethod(m_method, m_descriptor, Patterns.COMPOSITION);
m_compositionMethod = m_method;
+ } else if (annotation.getName().equals(A_LIFCLE_CTRL))
+ {
+ parseLifecycleAnnotation(annotation);
}
else if (annotation.getName().equals(A_SERVICE_DEP))
{
@@ -274,10 +272,6 @@
// factoryMethod attribute
writer.putString(annotation, EntryParam.factoryMethod, null);
-
- // Parse publisher/unpublisher attributes.
- writer.putString(annotation, EntryParam.publisher, null);
- writer.putString(annotation, EntryParam.unpublisher, null);
}
private void addCommonServiceParams(EntryWriter writer)
@@ -305,7 +299,22 @@
if (m_compositionMethod != null)
{
writer.put(EntryParam.composition, m_compositionMethod);
- }
+ }
+
+ if (m_starter != null)
+ {
+ writer.put(EntryParam.starter, m_starter);
+ }
+
+ if (m_stopper != null)
+ {
+ writer.put(EntryParam.stopper, m_stopper);
+ if (m_starter == null)
+ {
+ throw new IllegalArgumentException("Can't use a @LifecycleController annotation for stopping a service without declaring a " +
+ "@LifecycleController that starts the component in class " + m_className);
+ }
+ }
}
/**
@@ -652,6 +661,25 @@
writer.putString(annotation, EntryParam.factoryMethod, null);
}
+ private void parseLifecycleAnnotation(Annotation annotation)
+ {
+ Patterns.parseField(m_field, m_descriptor, Patterns.Runnable);
+ if ("true".equals(get(annotation,EntryParam.start.name(), "true")))
+ {
+ if (m_starter != null) {
+ throw new IllegalStateException("Lifecycle annotation already defined on field " +
+ m_starter + " in class " + m_className);
+ }
+ m_starter = m_field;
+ } else {
+ if (m_stopper != null) {
+ throw new IllegalStateException("Lifecycle annotation already defined on field " +
+ m_stopper + " in class " + m_className);
+ }
+ m_stopper = m_field;
+ }
+ }
+
/**
* Parse optional meta types annotation attributes
* @param annotation
@@ -809,11 +837,11 @@
return false;
}
- // We must have at least a Service or an AspectService annotation.
+ // We must have at least a Service annotation.
checkServiceDeclared(EntryType.Service, EntryType.AspectService, EntryType.AdapterService,
EntryType.BundleAdapterService,
EntryType.ResourceAdapterService, EntryType.FactoryConfigurationAdapterService);
-
+
StringBuilder sb = new StringBuilder();
sb.append("Parsed annotation for class ");
sb.append(m_className);
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
index 5f295ec..43d8a10 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
@@ -34,7 +34,7 @@
factoryConfigure,
factoryMethod,
field,
- name,
- publisher,
- unpublisher
+ name,
+ starter,
+ stopper,
}
diff --git a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
index c976d7e..2bc3660 100644
--- a/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
+++ b/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
@@ -18,7 +18,7 @@
public final static Pattern CLASS = Pattern.compile("L([^;]+);");
// Pattern used to parse the field on which a Publisher annotation may be applied on
- public final static Pattern PUBLISHER = Pattern.compile("Ljava/lang/Runnable;");
+ public final static Pattern Runnable = Pattern.compile("Ljava/lang/Runnable;");
/**
* Parses a class.
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AdapterServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AdapterServiceBuilder.java
index e20144f..ef85a85 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AdapterServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AdapterServiceBuilder.java
@@ -48,8 +48,9 @@
Dictionary<String, Object> adapterProperties = srvMeta.getDictionary(Params.properties, null);
Class<?> adapteeService = b.loadClass(srvMeta.getString(Params.adapteeService));
String adapteeFilter = srvMeta.getString(Params.adapteeFilter, null);
- Service service = dm.createAdapterService(adapteeService, adapteeFilter)
- .setInterface(provides, adapterProperties);
+ Service service = dm.createAdapterService(adapteeService, adapteeFilter);
+ service.setInterface(provides, adapterProperties);
+
String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
if (factoryMethod == null)
{
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/BundleAdapterServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/BundleAdapterServiceBuilder.java
index d00c9b6..5b247ab 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/BundleAdapterServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/BundleAdapterServiceBuilder.java
@@ -45,8 +45,8 @@
String[] provides = srvMeta.getStrings(Params.provides, null);
Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
boolean propagate = "true".equals(srvMeta.getString(Params.propagate, "false"));
- Service srv = dm.createBundleAdapterService(stateMask, filter, propagate)
- .setInterface(provides, properties);
+ Service srv = dm.createBundleAdapterService(stateMask, filter, propagate);
+ srv.setInterface(provides, properties);
String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
if (factoryMethod == null)
{
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
index 5937577..34a380f 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactoryConfigurationAdapterServiceBuilder.java
@@ -45,8 +45,8 @@
String[] provides = srvMeta.getStrings(Params.provides, null);
Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
boolean propagate = "true".equals(srvMeta.getString(Params.propagate, "false"));
- Service srv = dm.createFactoryConfigurationAdapterService(factoryPid, updated, propagate)
- .setInterface(provides, properties);
+ Service srv = dm.createFactoryConfigurationAdapterService(factoryPid, updated, propagate);
+ srv.setInterface(provides, properties);
String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
if (factoryMethod == null)
{
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 7c77893..12e8059 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
@@ -367,28 +367,7 @@
{
// Merge service properties with the configuration provided by the factory.
Dictionary serviceProperties = mergeSettings(m_serviceProperties, configuration);
-
- // Set the exposed service, unless a Publisher field is present.
- // If present, the publisher field means that we have to inject
- // a Runnable that will be called back by the service for firing a service
- // registration.
-
- String publisherField = m_srvMeta.getString(Params.publisher, null);
- String unpublisherField = m_srvMeta.getString(Params.unpublisher, null);
- if (publisherField == null)
- {
- s.setInterface(m_provide, serviceProperties);
- } else
- {
- // Services will be manually provided by the service itself.
- ServicePublisher publisher = new ServicePublisher(publisherField,
- unpublisherField,
- s,
- m_bundle.getBundleContext(),
- m_provide,
- serviceProperties);
- publisher.register(m_dm);
- }
+ s.setInterface(m_provide, serviceProperties);
}
s.setComposition(m_srvMeta.getString(Params.composition, null));
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java
index d2efcc8..59d08a0 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java
@@ -54,6 +54,6 @@
factoryMethod,
name,
field,
- publisher,
- unpublisher
+ starter,
+ stopper
}
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ResourceAdapterServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ResourceAdapterServiceBuilder.java
index 6c74481..5d2da3c 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ResourceAdapterServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ResourceAdapterServiceBuilder.java
@@ -45,8 +45,8 @@
Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
boolean propagate = "true".equals(srvMeta.getString(Params.propagate, "false"));
String changed = srvMeta.getString(Params.changed, null /* no change callback if not specified explicitly */);
- Service srv = dm.createResourceAdapterService(filter, propagate, null, changed)
- .setInterface(provides, properties);
+ Service srv = dm.createResourceAdapterService(filter, propagate, null, changed);
+ srv.setInterface(provides, properties);
String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
if (factoryMethod == null)
{
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java
index aae44da..066356b 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java
@@ -74,23 +74,7 @@
// Set the provided services
Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
String[] services = srvMeta.getStrings(Params.provides, null);
- String publisherField = srvMeta.getString(Params.publisher, null);
- String unpublisherField = srvMeta.getString(Params.unpublisher, null);
- if (publisherField == null)
- {
- service.setInterface(services, properties);
- }
- else if (services != null)
- {
- // Services will be manually provided by the service itself.
- ServicePublisher publisher = new ServicePublisher(publisherField,
- unpublisherField,
- service,
- b.getBundleContext(),
- services,
- properties);
- publisher.register(dm);
- }
+ service.setInterface(services, properties);
}
else
{
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
index 3a6356d..6b6fed8 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
@@ -18,7 +18,9 @@
*/
package org.apache.felix.dm.runtime;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
@@ -26,11 +28,14 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.Service;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.service.log.LogService;
/**
@@ -93,6 +98,9 @@
private List<MetaData> m_depsMeta;
private List<Dependency> m_namedDeps = new ArrayList<Dependency>();
private Bundle m_bundle;
+ private final AtomicBoolean m_started = new AtomicBoolean(false);
+ private ToggleServiceDependency m_toggle;
+ private final static Object SYNC = new Object();
/**
* Makes a new ServiceLifecycleHandler object. This objects allows to decorate the "init" service callback, in
@@ -119,7 +127,8 @@
/**
* Handles an "init" lifecycle service callback. We just catch the "init" method, and callback
* 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
*/
@SuppressWarnings("unchecked")
@@ -127,15 +136,34 @@
throws Exception
{
Object serviceInstance = service.getService();
- DependencyManager dm = service.getDependencyManager();
-
+ DependencyManager dm = service.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
+ // the component ...
+ String starter = m_srvMeta.getString(Params.starter, null);
+ String stopper = m_srvMeta.getString(Params.stopper, null);
+
+ if (starter != null)
+ {
+ Log.instance().log(LogService.LOG_DEBUG, "Setting up a lifecycle controller for service %s", serviceInstance);
+ String componentName = serviceInstance.getClass().getName();
+ m_toggle = new ToggleServiceDependency();
+ service.add(m_toggle);
+ setField(serviceInstance, starter, Runnable.class, new ComponentStarter(componentName));
+
+ if (stopper != null) {
+ setField(serviceInstance, stopper, Runnable.class, new ComponentStopper(componentName));
+ }
+ }
+
// Invoke 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();
- for (Object composite : composites)
+ for (Object composite: composites)
{
Object o = invokeMethod(composite, m_init, dm, service);
if (o != null && Map.class.isAssignableFrom(o.getClass()))
@@ -143,18 +171,19 @@
customization.putAll((Map) o);
}
}
-
+
Log.instance().log(LogService.LOG_DEBUG,
"ServiceLifecycleHandler.init: invoked init method from service %s " +
- ", returned map: %s", serviceInstance, customization);
-
- for (MetaData dependency : m_depsMeta)
+ ", returned map: %s", serviceInstance, customization);
+
+ for (MetaData dependency: m_depsMeta)
{
// Check if this dependency has a name, and if we find the name from the
// customization map, then apply filters and required flag from the map into it.
-
+
String name = dependency.getString(Params.name, null);
- if (name != null) {
+ if (name != null)
+ {
String filter = customization.get(name + ".filter");
String required = customization.get(name + ".required");
@@ -179,9 +208,9 @@
m_namedDeps.add(d);
service.add(d);
}
- }
+ }
}
-
+
/**
* Handles the Service's start lifecycle callback. We just invoke the service "start" service callback on
* the service instance, as well as on all eventual service composites.
@@ -251,7 +280,7 @@
/**
* Invoke a callback on all Service compositions.
*/
- private void callbackComposites(Service service, String callback)
+ private void callbackComposites(Service service, String callback)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
Object serviceInstance = service.getService();
@@ -268,25 +297,102 @@
private Object invokeMethod(Object serviceInstance, String method, DependencyManager dm, Service service)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
- if (method != null) {
- try
+ if (method != null)
+ {
+ try
{
return InvocationUtil.invokeCallbackMethod(
- serviceInstance, method,
- new Class[][] { { Service.class }, {} },
- new Object[][] { { service }, {} }
+ serviceInstance, method,
+ new Class[][] { { Service.class }, {} },
+ new Object[][] { { service }, {} }
);
- }
-
- catch (NoSuchMethodException e)
+ }
+
+ catch (NoSuchMethodException e)
{
// ignore this
}
-
+
// Other exception will be thrown up to the ServiceImpl.invokeCallbackMethod(), which is
// currently invoking our method. So, no need to log something here, since the invokeCallbackMethod
// method is already logging any thrown exception.
}
return null;
}
+
+ /**
+ * Sets a field of an object by reflexion.
+ */
+ private void setField(Object instance, String fieldName, Class fieldClass, Object fieldValue)
+ {
+ Object serviceInstance = instance;
+ Class serviceClazz = serviceInstance.getClass();
+ if (Proxy.isProxyClass(serviceClazz))
+ {
+ serviceInstance = Proxy.getInvocationHandler(serviceInstance);
+ serviceClazz = serviceInstance.getClass();
+ }
+ while (serviceClazz != null)
+ {
+ Field[] fields = serviceClazz.getDeclaredFields();
+ for (int j = 0; j < fields.length; j++)
+ {
+ Field field = fields[j];
+ Class type = field.getType();
+ if (field.getName().equals(fieldName) && type.isAssignableFrom(fieldClass))
+ {
+ try
+ {
+ field.setAccessible(true);
+ // synchronized makes sure the field is actually written to immediately
+ synchronized (SYNC)
+ {
+ field.set(serviceInstance, fieldValue);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Could not set field " + field, e);
+ }
+ }
+ }
+ serviceClazz = serviceClazz.getSuperclass();
+ }
+ }
+
+ private class ComponentStarter implements Runnable {
+ private String m_componentName;
+
+ public ComponentStarter(String name)
+ {
+ m_componentName = name;
+ }
+
+ public void run()
+ {
+ if (m_started.compareAndSet(false, true)) {
+ Log.instance().log(LogService.LOG_DEBUG, "Lifecycle controller is activating the component %s",
+ m_componentName);
+ m_toggle.setAvailable(true);
+ }
+ }
+ }
+
+ private class ComponentStopper implements Runnable {
+ private Object m_componentName;
+
+ public ComponentStopper(String componentName)
+ {
+ m_componentName = componentName;
+ }
+
+ public void run()
+ {
+ if (m_started.compareAndSet(true, false)) {
+ Log.instance().log(LogService.LOG_DEBUG, "Lifecycle controller is deactivating the component %s",
+ m_componentName);
+ m_toggle.setAvailable(false);
+ }
+ }
+ }
}
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java
deleted file mode 100644
index 94a3b49..0000000
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.dm.runtime;
-
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.Service;
-import org.apache.felix.dm.ServiceStateListener;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.log.LogService;
-
-/**
- * This class is injected in Service's Runnable fields which are annotated with the Publisher annotation.
- * This Runnable acts as a Service publisher, allowing the Service to take control of when the Service
- * is actually exposed from the OSGi registry.
- */
-public class ServicePublisher
-{
- private final AtomicBoolean m_published = new AtomicBoolean(false);
- private Service m_srv;
- private BundleContext m_bc;
- private String[] m_services;
- private Dictionary<String, Object> m_properties;
- private volatile ServiceRegistration m_registration;
- private String m_publisherField;
- private String m_unpublisherField;
-
- /**
- * Class constructor.
- * @param publisherField The Service field name annotated with the Publisher annotation
- * @param unpublisherField the Servicel field where to inject a Runnable for unregistering the Service
- * @param srv the Service object where to inject the Runnables (we'll use defaultImplementation ...)
- * @param bc the Service bundle context
- * @param services the list of provided services which will be registered once our Runnable is invoked
- * @param props the published service properties.
- */
- public ServicePublisher(String publisherField, String unpublisherField, Service srv, BundleContext bc, String[] services, Dictionary<String, Object> props)
- {
- m_publisherField = publisherField;
- m_unpublisherField = unpublisherField;
- m_srv = srv;
- m_bc = bc;
- m_services = services;
- m_properties = props;
- }
-
- public void register(DependencyManager dm)
- {
- Log.instance().log(LogService.LOG_DEBUG, "registering Publisher for services %s",
- Arrays.toString(m_services));
-
- // First, store the service properties in the service itself. We do this because when
- // our lifecycle handler will invoke the service's start callback, it will eventually
- // append the eventual properties returned by the start() method into our current service
- // properties.
- m_srv.setServiceProperties(m_properties);
-
- Publisher publisher = new Publisher();
- m_srv.add(dm.createServiceDependency()
- .setService(Runnable.class, "(dm.publisher=" + System.identityHashCode(this) + ")")
- .setRequired(false)
- .setAutoConfig(m_publisherField)
- .setDefaultImplementation(publisher));
- m_srv.addStateListener(publisher);
-
- if (m_unpublisherField != null)
- {
- Unpublisher unpublisher = new Unpublisher();
- m_srv.add(dm.createServiceDependency()
- .setService(Runnable.class, "(dm.unpublisher=" + System.identityHashCode(this) + ")")
- .setRequired(false)
- .setAutoConfig(m_unpublisherField)
- .setDefaultImplementation(unpublisher));
- }
- }
-
- private void publish()
- {
- if (m_published.compareAndSet(false, true))
- {
- try
- {
- Log.instance().log(LogService.LOG_DEBUG, "publishing services %s",
- Arrays.toString(m_services));
- m_registration = m_bc.registerService(m_services, m_srv.getService(), m_srv.getServiceProperties());
- }
- catch (Throwable t)
- {
- if (t instanceof RuntimeException)
- {
- throw (RuntimeException) t;
- }
- else
- {
- throw new RuntimeException("Could not register services", t);
- }
- }
- }
- }
-
- private void unpublish()
- {
- if (m_published.compareAndSet(true, false))
- {
- try
- {
- if (m_registration != null)
- {
- Log.instance().log(LogService.LOG_DEBUG, "unpublishing services %s",
- Arrays.toString(m_services));
- m_registration.unregister();
- m_registration = null;
- }
- }
- catch (Throwable t)
- {
- if (t instanceof RuntimeException)
- {
- throw (RuntimeException) t;
- }
- else
- {
- throw new RuntimeException("Could not unregister services", t);
- }
- }
- }
- }
-
- private class Publisher implements Runnable, ServiceStateListener
- {
- // true if the service has started
- private boolean m_started;
- // flag used to delay early publisher until we are really started.
- public boolean m_publishDelayed;
-
- public void run()
- {
- // Only register the service if it has been started. Otherwise delay the registration
- // until the service start callback has been invoked.
- synchronized (this) {
- if (! m_started)
- {
- Log.instance().log(LogService.LOG_DEBUG, "Delaying service publication for services %s (service not yet started)",
- Arrays.toString(m_services));
-
- m_publishDelayed = true;
- return;
- }
- }
- publish();
- }
-
- public void starting(Service service)
- {
- }
-
- public void started(Service service)
- {
- boolean publishDelayed = false;
- synchronized (this)
- {
- m_started = true;
- if (m_publishDelayed)
- {
- publishDelayed = true;
- }
- }
- if (publishDelayed)
- {
- // Our runnable has been invoked before the service start callback has been called:
- // Now that we are started, we fire the service registration.
- publish();
- }
- }
-
- public void stopping(Service service)
- {
- synchronized (this)
- {
- m_started = false;
- m_publishDelayed = false;
- }
- unpublish();
- }
-
- public void stopped(Service service)
- {
- }
- }
-
- private class Unpublisher implements Runnable
- {
- public void run()
- {
- unpublish();
- }
- }
-}
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ToggleServiceDependency.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ToggleServiceDependency.java
new file mode 100644
index 0000000..880dc49
--- /dev/null
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ToggleServiceDependency.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.runtime;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyActivation;
+import org.apache.felix.dm.DependencyService;
+
+/**
+ * This is a custom DependencyManager Dependency, allowing to take control of when the dependency
+ * is available or not. It's used in the context of the LifecycleController class, in order to
+ * activate/deactivate a Component on demand.
+ */
+public class ToggleServiceDependency implements Dependency, DependencyActivation {
+ private final List m_services = new ArrayList();
+ private boolean m_isAvailable;
+ private boolean m_stopped;
+
+ public ToggleServiceDependency()
+ {
+ }
+
+ public ToggleServiceDependency(boolean mIsAvailable)
+ {
+ m_isAvailable = mIsAvailable;
+ }
+
+ public void setAvailable(boolean isAvailable) {
+ if (m_stopped) {
+ return;
+ }
+ boolean changed = m_isAvailable != isAvailable;
+ m_isAvailable = isAvailable;
+ // invoked on every change
+ if (m_isAvailable) {
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ ds.dependencyAvailable(this);
+ if (!isRequired()) {
+ invokeAdded(ds);
+ }
+ }
+ }
+ else {
+ Object[] services = m_services.toArray();
+ for (int i = 0; i < services.length; i++) {
+ DependencyService ds = (DependencyService) services[i];
+ ds.dependencyUnavailable(this);
+ if (!isRequired()) {
+ invokeRemoved(ds);
+ }
+ }
+ }
+ }
+
+ public Dependency createCopy() {
+ return new ToggleServiceDependency(m_isAvailable);
+ }
+
+ public Object getAutoConfigInstance() {
+ return "" + m_isAvailable;
+ }
+
+ public String getAutoConfigName() {
+ return null;
+ }
+
+ public Class getAutoConfigType() {
+ return String.class;
+ }
+
+ public Dictionary getProperties() {
+ return null;
+ }
+
+ public void invokeAdded(DependencyService service) {
+ invoke(service, "added");
+ }
+
+ public void invokeRemoved(DependencyService service) {
+ invoke(service, "removed");
+ }
+
+ public void invoke(DependencyService dependencyService, String name) {
+ if (name != null) {
+ dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
+ new Class[][] {{String.class}, {Object.class}, {}},
+ new Object[][] {{getAutoConfigInstance()}, {getAutoConfigInstance()}, {}}
+ );
+ }
+ }
+
+ private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
+ return dependencyService.getCompositionInstances();
+ }
+
+ public boolean isAutoConfig() {
+ return true;
+ }
+
+ public boolean isAvailable() {
+ return m_isAvailable;
+ }
+
+ public boolean isInstanceBound() {
+ return true;
+ }
+
+ public boolean isPropagated() {
+ return false;
+ }
+
+ public boolean isRequired() {
+ return true;
+ }
+
+ public void start(DependencyService service) {
+ synchronized (this) {
+ m_services.add(service);
+ }
+ }
+
+ public void stop(DependencyService service) {
+ synchronized (this) {
+ m_services.remove(service);
+ }
+ m_stopped = true;
+ }
+}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/AdapterServiceTestWithPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/AdapterServiceTestWithPublisher.java
new file mode 100644
index 0000000..2c00691
--- /dev/null
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/AdapterServiceTestWithPublisher.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.test.bundle.annotation.publisher;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.AdapterService;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.Property;
+import org.apache.felix.dm.annotation.api.LifecycleController;
+import org.apache.felix.dm.annotation.api.Service;
+import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.apache.felix.dm.annotation.api.Start;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+
+/**
+ * Test an AdapterService which provides its interface using a @ServiceLifecycle.
+ */
+public class AdapterServiceTestWithPublisher
+{
+ public interface Provider
+ {
+ }
+
+ public interface Provider2
+ {
+ }
+
+ @Service
+ public static class Consumer
+ {
+ @ServiceDependency(filter="(test=AdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @ServiceDependency(required=false, removed = "unbind")
+ void bind(Map properties, Provider2 provider)
+ {
+ m_sequencer.step(1);
+ // check ProviderImpl properties
+ if ("bar".equals(properties.get("foo")))
+ {
+ m_sequencer.step(2);
+ }
+ // check extra ProviderImpl properties (returned by start method)
+ if ("bar2".equals(properties.get("foo2")))
+ {
+ m_sequencer.step(3);
+ }
+ // check Provider2Impl properties
+ if ("bar3".equals(properties.get("foo3")))
+ {
+ m_sequencer.step(4);
+ }
+ // check extra Provider2Impl properties (returned by start method)
+ if ("bar4".equals(properties.get("foo4")))
+ {
+ m_sequencer.step(5);
+ }
+
+ }
+
+ void unbind(Provider2 provider)
+ {
+ m_sequencer.step(6);
+ }
+ }
+
+ @Service(properties={@Property(name="foo", value="bar")})
+ public static class ProviderImpl implements Provider
+ {
+ @Start
+ Map start()
+ {
+ // Add some extra service properties ... they will be appended to the one we have defined
+ // in the @Service annotation.
+ return new HashMap() {{ put("foo2", "bar2"); }};
+ }
+ }
+
+ @AdapterService(properties={@Property(name="foo3", value="bar3")}, adapteeService=Provider.class)
+ public static class Provider2Impl implements Provider2
+ {
+ @LifecycleController
+ Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
+ Runnable m_unpublisher; // injected and used to unregister our service
+
+ @ServiceDependency(filter="(test=AdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
+ @Start
+ Map start()
+ {
+ // Add some extra service properties ... they will be appended to the one we have defined
+ // in the @Service annotation.
+ return new HashMap() {{ put("foo4", "bar4"); }};
+ }
+ }
+}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/BundleAdapterServiceTestWithPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/BundleAdapterServiceTestWithPublisher.java
new file mode 100644
index 0000000..07f4036
--- /dev/null
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/BundleAdapterServiceTestWithPublisher.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.test.bundle.annotation.publisher;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.BundleAdapterService;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.Property;
+import org.apache.felix.dm.annotation.api.LifecycleController;
+import org.apache.felix.dm.annotation.api.Service;
+import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.apache.felix.dm.annotation.api.Start;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.osgi.framework.Bundle;
+
+/**
+ * Test a BundleAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+public class BundleAdapterServiceTestWithPublisher
+{
+ public interface Provider
+ {
+ }
+
+ @Service
+ public static class Consumer
+ {
+ @ServiceDependency(filter="(test=BundleAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @ServiceDependency(required=false, removed = "unbind")
+ void bind(Map properties, Provider provider)
+ {
+ m_sequencer.step(1);
+ // check ProviderImpl properties
+ if ("bar".equals(properties.get("foo")))
+ {
+ m_sequencer.step(2);
+ }
+ // check extra ProviderImpl properties (returned by start method)
+ if ("bar2".equals(properties.get("foo2")))
+ {
+ m_sequencer.step(3);
+ }
+ // check properties propagated from bundle
+ if ("org.apache.felix.dependencymanager".equals(properties.get("Bundle-SymbolicName")))
+ {
+ m_sequencer.step(4);
+ } else {
+ Thread.dumpStack();
+ System.out.println(properties);
+ }
+ }
+
+ void unbind(Provider provider)
+ {
+ m_sequencer.step(5);
+ }
+ }
+
+ @BundleAdapterService(properties={@Property(name="foo", value="bar")},
+ filter = "(Bundle-SymbolicName=org.apache.felix.dependencymanager)",
+ stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE,
+ propagate = true)
+ public static class ProviderImpl implements Provider
+ {
+ @LifecycleController
+ Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
+ Runnable m_unpublisher; // injected and used to unregister our service
+
+ @ServiceDependency(filter="(test=BundleAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
+ @Start
+ Map start()
+ {
+ // Add some extra service properties ... they will be appended to the one we have defined
+ // in the @Service annotation.
+ return new HashMap() {{ put("foo2", "bar2"); }};
+ }
+ }
+}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryConfigurationAdapterServiceTestWithPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryConfigurationAdapterServiceTestWithPublisher.java
new file mode 100644
index 0000000..78bba0e
--- /dev/null
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryConfigurationAdapterServiceTestWithPublisher.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.test.bundle.annotation.publisher;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.FactoryConfigurationAdapterService;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.LifecycleController;
+import org.apache.felix.dm.annotation.api.Property;
+import org.apache.felix.dm.annotation.api.Service;
+import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.apache.felix.dm.annotation.api.Start;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Test a FactoryConfigurationAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+public class FactoryConfigurationAdapterServiceTestWithPublisher
+{
+ public interface Provider
+ {
+ }
+
+ @Service
+ public static class Consumer
+ {
+ @ServiceDependency(filter="(test=FactoryConfigurationAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @ServiceDependency(required=false, removed = "unbind")
+ void bind(Map properties, Provider provider)
+ {
+ m_sequencer.step(1);
+ // check ProviderImpl properties
+ if ("bar".equals(properties.get("foo")))
+ {
+ m_sequencer.step(2);
+ }
+ // check extra ProviderImpl properties (returned by start method)
+ if ("bar2".equals(properties.get("foo2")))
+ {
+ m_sequencer.step(3);
+ }
+ // check Factory Configuration properties
+ if ("bar3".equals(properties.get("foo3")))
+ {
+ m_sequencer.step(4);
+ }
+ }
+
+ void unbind(Provider provider)
+ {
+ m_sequencer.step(5);
+ }
+ }
+
+ @Service
+ public static class Configurator
+ {
+ @ServiceDependency
+ void bind(ConfigurationAdmin cm) throws IOException
+ {
+ Configuration cf = cm.createFactoryConfiguration("MyPid", null);
+ cf.update(new Hashtable() {{ put("foo3", "bar3"); }});
+ }
+ }
+
+ @FactoryConfigurationAdapterService(propagate=true, properties={@Property(name="foo", value="bar")}, factoryPid="MyPid", updated="updated")
+ public static class ProviderImpl implements Provider
+ {
+ @LifecycleController
+ Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
+ Runnable m_unpublisher; // injected and used to unregister our service
+
+ @ServiceDependency(filter="(test=FactoryConfigurationAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ void updated(Dictionary conf) {
+ }
+
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
+ @Start
+ Map start()
+ {
+ // Add some extra service properties ... they will be appended to the one we have defined
+ // in the @Service annotation.
+ return new HashMap() {{ put("foo2", "bar2"); }};
+ }
+
+ }
+}
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 dc9ca46..a55d578 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
@@ -24,22 +24,28 @@
import java.util.Map;
import java.util.Set;
+import org.apache.felix.dm.annotation.api.Init;
import org.apache.felix.dm.annotation.api.Property;
+import org.apache.felix.dm.annotation.api.LifecycleController;
import org.apache.felix.dm.annotation.api.Service;
import org.apache.felix.dm.annotation.api.ServiceDependency;
import org.apache.felix.dm.annotation.api.Start;
import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
/**
- * This test validates that a basic "ProviderImpl" which is instantiated from a FactorySet can register/unregister its
- * service using the Publisher annotation.
+ * A Service instantiated from a FactorySet, and which registers/unregisters its service,
+ * using the @ServiceLifecycle annotation.
*/
public class FactoryServiceTestWthPublisher
{
+ public interface Provider
+ {
+ }
+
@Service
public static class Consumer
{
- @ServiceDependency(filter="(test=testFactoryService)")
+ @ServiceDependency(filter="(test=FactoryServiceTestWthPublisher)")
Sequencer m_sequencer;
@ServiceDependency(required=false, removed = "unbind")
@@ -66,46 +72,34 @@
}
}
- @Service(publisher="m_publisher", unpublisher="m_unpublisher", factorySet="MyFactory", properties={@Property(name="foo", value="bar")})
+ @Service(factorySet="MyFactory", properties={@Property(name="foo", value="bar")})
public static class ProviderImpl implements Provider
{
+ @LifecycleController
Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
Runnable m_unpublisher; // injected and used to unregister our service
- @ServiceDependency(filter="(test=testFactoryService)")
+ @ServiceDependency(filter="(test=FactoryServiceTestWthPublisher)")
Sequencer m_sequencer;
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
@Start
Map start()
{
- // register service in 1 second
- schedule(m_publisher, 1000);
- // unregister the service in 2 seconds
- schedule(m_unpublisher, 2000);
// At this point, our service properties are the one specified in our @Service annotation + the one specified by our Factory.
// We also append an extra service property here:
return new HashMap() {{ put("foo3", "bar3"); }};
}
-
- private void schedule(final Runnable task, final long n)
- {
- Thread t = new Thread() {
- public void run()
- {
- try
- {
- sleep(n);
- }
- catch (InterruptedException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- task.run();
- }
- };
- t.start();
- }
}
@Service
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ResourceAdapterServiceTestWithPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ResourceAdapterServiceTestWithPublisher.java
new file mode 100644
index 0000000..328ce93
--- /dev/null
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ResourceAdapterServiceTestWithPublisher.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.test.bundle.annotation.publisher;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.ResourceHandler;
+import org.apache.felix.dm.ResourceUtil;
+import org.apache.felix.dm.annotation.api.Destroy;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.LifecycleController;
+import org.apache.felix.dm.annotation.api.Property;
+import org.apache.felix.dm.annotation.api.ResourceAdapterService;
+import org.apache.felix.dm.annotation.api.Service;
+import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.apache.felix.dm.annotation.api.Start;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * Test a ResourceAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+public class ResourceAdapterServiceTestWithPublisher
+{
+ public interface Provider
+ {
+ }
+
+ @Service
+ public static class Consumer
+ {
+ @ServiceDependency(filter="(test=ResourceAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ @ServiceDependency(required=false, removed = "unbind")
+ void bind(Map properties, Provider provider)
+ {
+ m_sequencer.step(1);
+ // check ProviderImpl properties
+ if ("bar".equals(properties.get("foo")))
+ {
+ m_sequencer.step(2);
+ }
+ // check extra ProviderImpl properties (returned by start method)
+ if ("bar2".equals(properties.get("foo2")))
+ {
+ m_sequencer.step(3);
+ }
+ // check properties propagated by the resource adapter
+ if ("/path/to/test1.txt".equals(properties.get(ResourceHandler.PATH)))
+ {
+ m_sequencer.step(4);
+ }
+ if ("localhost".equals(properties.get(ResourceHandler.HOST)))
+ {
+ m_sequencer.step(5);
+ }
+ }
+
+ void unbind(Provider provider)
+ {
+ m_sequencer.step(6);
+ }
+ }
+
+ @Service
+ public static class ResourceProvider
+ {
+ private volatile BundleContext m_context;
+ private final Map m_handlers = new HashMap();
+ private URL[] m_resources;
+
+ public ResourceProvider() throws Exception {
+ m_resources = new URL[] {
+ new URL("file://localhost/path/to/test1.txt"),
+ new URL("file://localhost/path/to/test2.txt"),
+ new URL("file://localhost/path/to/README.doc")
+ };
+ }
+
+ /**
+ * Handles a new Resource consumer
+ * @param serviceProperties
+ * @param handler
+ */
+ @ServiceDependency(removed = "remove", required=false)
+ public void add(Map serviceProperties, ResourceHandler handler)
+ {
+ String filterString = (String) serviceProperties.get("filter");
+ Filter filter = null;
+ if (filterString != null) {
+ try
+ {
+ filter = m_context.createFilter(filterString);
+ }
+ catch (InvalidSyntaxException e)
+ {
+ Assert.fail("Could not create filter for resource handler: " + e);
+ return;
+ }
+ }
+ synchronized (m_handlers)
+ {
+ m_handlers.put(handler, filter);
+ }
+ for (int i = 0; i < m_resources.length; i++)
+ {
+ if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i])))
+ {
+ handler.added(m_resources[i]);
+ }
+ }
+ }
+
+ /**
+ * Remove a Resource consumer.bar
+ * @param handler
+ */
+ public void remove(ResourceHandler handler)
+ {
+ Filter filter;
+ synchronized (m_handlers)
+ {
+ filter = (Filter) m_handlers.remove(handler);
+ }
+ removeResources(handler, filter);
+ }
+
+ private void removeResources(ResourceHandler handler, Filter filter)
+ {
+ for (int i = 0; i < m_resources.length; i++)
+ {
+ if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i])))
+ {
+ handler.removed(m_resources[i]);
+ }
+ }
+ }
+
+ /**
+ * Our component is being destroyed: notify all our registered Resource consumers that we don't
+ * provide our Resources anymore.
+ */
+ @Destroy
+ public void destroy()
+ {
+ Entry[] handlers;
+ synchronized (m_handlers)
+ {
+ handlers = (Entry[]) m_handlers.entrySet().toArray(new Entry[m_handlers.size()]);
+ }
+ for (int i = 0; i < handlers.length; i++)
+ {
+ removeResources((ResourceHandler) handlers[i].getKey(), (Filter) handlers[i].getValue());
+ }
+ }
+ }
+
+ @ResourceAdapterService(filter = "(&(path=/path/to/test1.txt)(host=localhost))",
+ properties = {@Property(name="foo", value="bar")},
+ propagate = true)
+ public static class ProviderImpl implements Provider
+ {
+ @LifecycleController
+ Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
+ Runnable m_unpublisher; // injected and used to unregister our service
+
+ @ServiceDependency(filter="(test=ResourceAdapterServiceTestWithPublisher)")
+ Sequencer m_sequencer;
+
+ // Injected by reflection
+ URL m_resource;
+
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
+ @Start
+ Map start()
+ {
+ // Add some extra service properties ... they will be appended to the one we have defined
+ // in the @Service annotation.
+ return new HashMap() {{ put("foo2", "bar2"); }};
+ }
+ }
+}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthEarlyPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthEarlyPublisher.java
deleted file mode 100644
index edae9e2..0000000
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthEarlyPublisher.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.dm.test.bundle.annotation.publisher;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.felix.dm.annotation.api.Init;
-import org.apache.felix.dm.annotation.api.Property;
-import org.apache.felix.dm.annotation.api.Service;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
-import org.apache.felix.dm.annotation.api.Start;
-import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
-
-/**
- * This test validates that when a provider publishes its service early (before the
- * start callback method is invoked), then the runtime bundle must delay the service
- * registration until the service is fully started.
- */
-public class ServiceTestWthEarlyPublisher
-{
- @Service
- public static class Consumer
- {
- @ServiceDependency(filter="(test=testEarlyService)")
- Sequencer m_sequencer;
-
- @ServiceDependency(required=false, removed = "unbind")
- void bind(Provider provider)
- {
- m_sequencer.step(3);
- }
-
- void unbind(Provider provider)
- {
- m_sequencer.step(5);
- }
- }
-
- @Service(publisher="m_publisher", unpublisher="m_unpublisher")
- public static class ProviderImpl implements Provider
- {
- Runnable m_publisher; // injected and used to register our service
- Runnable m_unpublisher; // injected and used to unregister our service
-
- @ServiceDependency(filter="(test=testEarlyService)")
- Sequencer m_sequencer;
-
- @Init
- void init()
- {
- // invoking the publisher before the start() method has been called
- // does not make sense, but this testcase just ensure that the
- // runtime will defer the service registration until the start
- // method is invoked.
- m_sequencer.step(1);
- m_publisher.run();
- }
-
- @Start
- void start()
- {
- m_sequencer.step(2);
- // unregister the service in 2 seconds
- schedule(m_unpublisher, 2000, 4);
- }
-
- private void schedule(final Runnable task, final long n, final int step)
- {
- Thread t = new Thread() {
- public void run()
- {
- try
- {
- sleep(n);
- }
- catch (InterruptedException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- m_sequencer.step(step);
- task.run();
- }
- };
- t.start();
- }
- }
-}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java
index 965960e..573dc9d 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java
@@ -21,7 +21,8 @@
import java.util.HashMap;
import java.util.Map;
-import org.apache.felix.dm.annotation.api.Destroy;
+import org.apache.felix.dm.annotation.api.Init;
+import org.apache.felix.dm.annotation.api.LifecycleController;
import org.apache.felix.dm.annotation.api.Property;
import org.apache.felix.dm.annotation.api.Service;
import org.apache.felix.dm.annotation.api.ServiceDependency;
@@ -29,15 +30,18 @@
import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
/**
- * This test validates that a basic "ProviderImpl" services can register/unregister its
- * service using the Publisher annotation.
+ * A Service that just registers/unregisters its service, using the @ServiceLifecycle annotation.
*/
public class ServiceTestWthPublisher
{
+ public interface Provider
+ {
+ }
+
@Service
public static class Consumer
{
- @ServiceDependency(filter="(test=testService)")
+ @ServiceDependency(filter="(test=ServiceTestWthPublisher)")
Sequencer m_sequencer;
@ServiceDependency(required=false, removed = "unbind")
@@ -60,46 +64,33 @@
}
}
- @Service(publisher="m_publisher", unpublisher="m_unpublisher", properties={@Property(name="foo", value="bar")})
+ @Service(properties={@Property(name="foo", value="bar")})
public static class ProviderImpl implements Provider
{
+ @LifecycleController
Runnable m_publisher; // injected and used to register our service
+
+ @LifecycleController(start=false)
Runnable m_unpublisher; // injected and used to unregister our service
- @ServiceDependency(filter="(test=testService)")
+ @ServiceDependency(filter="(test=ServiceTestWthPublisher)")
Sequencer m_sequencer;
+ @Init
+ void init()
+ {
+ // register service in 1 second
+ Utils.schedule(m_publisher, 1000);
+ // unregister the service in 2 seconds
+ Utils.schedule(m_unpublisher, 2000);
+ }
+
@Start
Map start()
{
- // register service in 1 second
- schedule(m_publisher, 1000);
- // unregister the service in 2 seconds
- schedule(m_unpublisher, 2000);
-
// Add some extra service properties ... they will be appended to the one we have defined
// in the @Service annotation.
return new HashMap() {{ put("foo2", "bar2"); }};
}
-
- private void schedule(final Runnable task, final long n)
- {
- Thread t = new Thread() {
- public void run()
- {
- try
- {
- sleep(n);
- }
- catch (InterruptedException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- task.run();
- }
- };
- t.start();
- }
}
}
diff --git a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Utils.java
similarity index 63%
rename from dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java
rename to dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Utils.java
index 8606b80..0ec0cfb 100644
--- a/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java
+++ b/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Utils.java
@@ -18,6 +18,25 @@
*/
package org.apache.felix.dm.test.bundle.annotation.publisher;
-public interface Provider
+public class Utils
{
+ public static void schedule(final Runnable task, final long n)
+ {
+ Thread t = new Thread() {
+ public void run()
+ {
+ try
+ {
+ sleep(n);
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ task.run();
+ }
+ };
+ t.start();
+ }
}
diff --git a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java
index 39f59b3..137b326 100644
--- a/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java
+++ b/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java
@@ -37,8 +37,7 @@
import org.osgi.framework.Constants;
/**
- * Use case: Verify the Publisher annotation, which allows a component to register/unregister
- * its service programatically.
+ * Use case: Verify the @ServiceLifecycle annotation, which allows a component to activate/deactivate itself programatically.
*/
@RunWith(JUnit4TestRunner.class)
public class PublisherAnnotationTest extends AnnotationBase
@@ -51,6 +50,7 @@
provision(
mavenBundle().groupId("org.osgi").artifactId("org.osgi.compendium").version("4.1.0"),
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager").versionAsInProject(),
+ mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.configadmin").version("1.2.4"),
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager.runtime").versionAsInProject()),
provision(
new BundleGenerator()
@@ -63,43 +63,81 @@
}
/**
- * A Provider that just registers/unregisters its service, using the Publisher annotation.
+ * Registers the Sequencer interface, for activating a given testcase
+ */
+ private void registerSequencer(DependencyManager m, final String testName)
+ {
+ m.add(m.createService()
+ .setImplementation(this)
+ .setInterface(Sequencer.class.getName(),new Hashtable() {{
+ put("test", testName);
+ }}));
+ }
+
+ /**
+ * A Service that just registers/unregisters its service, using the @ServiceLifecycle annotation.
*/
@Test
public void testServiceWithPublisher(BundleContext context)
{
DependencyManager m = new DependencyManager(context);
- // Provide the Sequencer service to the "Component" service.
- m.add(m.createService().setImplementation(this).setInterface(Sequencer.class.getName(),
- new Hashtable() {{ put("test", "testService"); }}));
+ registerSequencer(m, "ServiceTestWthPublisher");
m_ensure.waitForStep(4, 10000);
}
/**
- * A Provider instantiated from a FactorySet, and which registers/unregisters its service, using the Publisher annotation.
+ * A Service instantiated from a FactorySet, and which registers/unregisters its service,
+ * using the @ServiceLifecycle annotation.
*/
@Test
public void testFactoryServiceWithPublisher(BundleContext context)
{
DependencyManager m = new DependencyManager(context);
- // Provide the Sequencer service to the "Component" service.
- m.add(m.createService().setImplementation(this).setInterface(Sequencer.class.getName(),
- new Hashtable() {{ put("test", "testFactoryService"); }}));
+ registerSequencer(m, "FactoryServiceTestWthPublisher");
m_ensure.waitForStep(5, 10000);
}
-
+
/**
- * A Provider that registers its service, using the Publisher annotation, but very early: before
- * the start callback is invoked ! In this case, we must verify that the runtime will delay the
- * service registration until the service is fully started.
+ * Test an AdapterService which provides its interface using a @ServiceLifecycle.
*/
@Test
- public void testServiceWithEarlyPublisher(BundleContext context)
+ public void testAdapterServiceWithPublisher(BundleContext context)
{
DependencyManager m = new DependencyManager(context);
- // Provide the Sequencer service to the "Component" service.
- m.add(m.createService().setImplementation(this).setInterface(Sequencer.class.getName(),
- new Hashtable() {{ put("test", "testEarlyService"); }}));
+ registerSequencer(m, "AdapterServiceTestWithPublisher");
+ m_ensure.waitForStep(6, 10000);
+ }
+
+ /**
+ * Test a BundleAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+ @Test
+ public void testBundleAdapterServiceWithPublisher(BundleContext context)
+ {
+ DependencyManager m = new DependencyManager(context);
+ registerSequencer(m, "BundleAdapterServiceTestWithPublisher");
+ m_ensure.waitForStep(5, 10000);
+ }
+
+ /**
+ * Test a ResourceAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+ @Test
+ public void TestResourceAdapterServiceWithPublisher(BundleContext context)
+ {
+ DependencyManager m = new DependencyManager(context);
+ registerSequencer(m, "ResourceAdapterServiceTestWithPublisher");
+ m_ensure.waitForStep(5, 10000);
+ }
+
+ /**
+ * Test a FactoryConfigurationAdapterService which provides its interface using a @ServiceLifecycle.
+ */
+ @Test
+ public void testFactoryAdapterServiceWithPublisher(BundleContext context)
+ {
+ DependencyManager m = new DependencyManager(context);
+ registerSequencer(m, "FactoryConfigurationAdapterServiceTestWithPublisher");
m_ensure.waitForStep(5, 10000);
}
}