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>
-     * &#47;**
-     *   * This Service will be registered programatically into the OSGi registry, using the publisher attribute.
-     *   *&#47;
-     * &#64;Service(publisher="m_publisher")
-     * class X implements Z {
-     *     Runnable m_publisher;
-     *   
-     *     &#64;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>
-     * &#47;**
-     *   * 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.
-     *   *&#47;
-     * &#64;Service(publisher="m_publisher", unpublisher="m_unpublisher")
-     * class X implements Z {
-     *     Runnable m_publisher;
-     *     Runnable m_unpublisher;
-     *   
-     *     &#64;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);
     }
 }