You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2010/08/10 23:19:45 UTC

svn commit: r984213 - in /felix/trunk/dependencymanager: annotation/src/main/java/org/apache/felix/dm/annotation/api/ annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/ runtime/src/main/java/org/apache/felix/dm/runtime/ test/src/main/j...

Author: pderop
Date: Tue Aug 10 21:19:44 2010
New Revision: 984213

URL: http://svn.apache.org/viewvc?rev=984213&view=rev
Log:
Added two new publisher/unpublisher attributes in the Service annotation in order to allow a Service to take control over service exposition. Allow Start annotation to return an optional Map of properties which can be appended into the provided service properties

Added:
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAdapterServiceProperties.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAspectServiceProperties.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraFactoryServiceProperties.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraServiceProperties.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java
    felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java
    felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/ExtraServicePropertiesTest.java
    felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java
Modified:
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ServiceDependency.java
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Start.java
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
    felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Log.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceComponentBuilder.java
    felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Service.java Tue Aug 10 21:19:44 2010
@@ -174,4 +174,80 @@ public @interface Service
      * 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 "";
 }

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ServiceDependency.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ServiceDependency.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ServiceDependency.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/ServiceDependency.java Tue Aug 10 21:19:44 2010
@@ -110,8 +110,8 @@ public @interface ServiceDependency
      * The name used when dynamically configuring this dependency from the init method.
      * Specifying this attribute allows to dynamically configure the dependency 
      * <code>filter</code> and <code>required</code> flag from the Service's init method.
-     * All unamed dependencies will be injected before the init() method; so from the init() method, you can
-     * then pick up whatever information needed from already injected (unamed) dependencies, and configure dynamically
+     * All unnamed dependencies will be injected before the init() method; so from the init() method, you can
+     * then pick up whatever information needed from already injected (unnamed) dependencies, and configure dynamically
      * your named dependencies, which will then be calculated once the init() method returns.
      * 
      * <p> Usage example of a Service whose dependency filter is configured from ConfigAdmin:

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Start.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Start.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Start.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/api/Start.java Tue Aug 10 21:19:44 2010
@@ -25,7 +25,31 @@ import java.lang.annotation.Target;
 
 /**
  * Annotates a method which will be invoked when the Service is started.
- * If you don't supply this annotation, then no "start" method will be invoked.
+ * The annotated method will be called when all required dependencies have been injected, and
+ * just before registering the service into the OSGi registry (if the service provides an interface).
+ * Notice that the start method may optionally return a Map which will be propagated to the provided
+ * service properties.
+ *      
+ * <p>
+ * <h3>Usage Examples</h3>
+ * <blockquote>
+ * 
+ * <pre>
+ * &#64;Service(properties={&#64;Property(name="foo", value="bar")})
+ * class X implements Z {
+ *     &#64;ServiceDependency
+ *     OtherService m_dependency;
+ *   
+ *     &#64;Start
+ *     Map start() {
+ *         // Our Z Service is ready (all required dependencies have been satisfied), and is about to be 
+ *         // registered into the OSGi registry. We return here an optional Map containing some extra-properties
+ *         // which will be appended to the properties supplied in the Service annotation.
+ *         return new HashMap() {{ put("foo2", "bar2"); }};
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
  */
 @Retention(RetentionPolicy.CLASS)
 @Target(ElementType.METHOD)

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/AnnotationCollector.java Tue Aug 10 21:19:44 2010
@@ -208,26 +208,18 @@ public class AnnotationCollector extends
         }
         else if (annotation.getName().equals(A_INIT))
         {
-            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
-            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_initMethod = m_method;
         } 
         else if (annotation.getName().equals(A_START))
         {
-            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
-            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_startMethod = m_method;
         } 
         else if (annotation.getName().equals(A_STOP))
         {
-            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
-            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_stopMethod = m_method;
         }
         else if (annotation.getName().equals(A_DESTROY))
         {
-            //Patterns.parseMethod(m_method, m_descriptor, Patterns.VOID);
-            // TODO check if method takes optional params like Service, DependencyManager, etc ...
             m_destroyMethod = m_method;
         }
         else if (annotation.getName().equals(A_COMPOSITION))
@@ -282,6 +274,10 @@ public class AnnotationCollector extends
         
         // 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)
@@ -306,11 +302,10 @@ public class AnnotationCollector extends
             writer.put(EntryParam.destroy, m_destroyMethod);
         }
 
-        // Register Composition method
         if (m_compositionMethod != null)
         {
             writer.put(EntryParam.composition, m_compositionMethod);
-        }
+        }        
     }
 
     /**

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/EntryParam.java Tue Aug 10 21:19:44 2010
@@ -36,5 +36,7 @@ public enum EntryParam
     factoryConfigure,
     factoryMethod,
     field,
-    name
+    name,
+    publisher,
+    unpublisher
 }

Modified: felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java (original)
+++ felix/trunk/dependencymanager/annotation/src/main/java/org/apache/felix/dm/annotation/plugin/bnd/Patterns.java Tue Aug 10 21:19:44 2010
@@ -11,11 +11,14 @@ public class Patterns
     // Pattern used to check if a method returns an array of Objects
     public final static Pattern COMPOSITION = Pattern.compile("\\(\\)\\[Ljava/lang/Object;");
 
-   // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)" or "bind(BundleContext, Type)"
+    // Pattern used to parse the class parameter from the bind methods ("bind(Type)" or "bind(Map, Type)" or "bind(BundleContext, Type)"
     public final static Pattern BIND_CLASS = Pattern.compile("\\((L[^;]+;)?L([^;]+);\\)V");
 
     // Pattern used to parse classes from class descriptors;
     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;");
 
     /**
      * Parses a class.
@@ -39,6 +42,7 @@ public class Patterns
     
     /**
      * Checks if a method descriptor matches a given pattern. 
+     * @param the method whose signature descriptor is checked
      * @param pattern the pattern used to check the method signature descriptor
      * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern.
      */
@@ -51,4 +55,20 @@ public class Patterns
                 + descriptor);
         }
     }
+    
+    /**
+     * Checks if a field descriptor matches a given pattern.
+     * @param field the field whose type descriptor is checked
+     * @param descriptor the field descriptor to be checked
+     * @param pattern the pattern to use
+     * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern.
+     */
+    public static void parseField(String field, String descriptor, Pattern pattern) {
+        Matcher matcher = pattern.matcher(descriptor);
+        if (!matcher.matches())
+        {
+            throw new IllegalArgumentException("Invalid field " + field + ", wrong signature: "
+                + descriptor);
+        }
+    }
 }

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/FactorySet.java Tue Aug 10 21:19:44 2010
@@ -365,9 +365,30 @@ public class FactorySet extends Abstract
                 s.setImplementation(m_impl);
                 if (m_provide != null)
                 {
-                    // Merge service properties with the configuration provided by the factory.
+                     // Merge service properties with the configuration provided by the factory.
                     Dictionary serviceProperties = mergeSettings(m_serviceProperties, configuration);
-                    s.setInterface(m_provide, serviceProperties);
+                    
+                    // 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.setComposition(m_srvMeta.getString(Params.composition, null));

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Log.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Log.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Log.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Log.java Tue Aug 10 21:19:44 2010
@@ -26,7 +26,7 @@ import org.osgi.service.log.LogService;
 public class Log
 {
     /** The log service */
-    private LogService m_logService;
+    private volatile LogService m_logService;
     
     /** Our sole instance */
     private static Log m_instance = new Log();

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/Params.java Tue Aug 10 21:19:44 2010
@@ -55,5 +55,7 @@ public enum Params
     factoryConfigure,
     factoryMethod,
     name,
-    field
+    field,
+    publisher,
+    unpublisher
 }

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceBuilder.java Tue Aug 10 21:19:44 2010
@@ -55,8 +55,6 @@ public class ServiceBuilder extends Serv
 
             String impl = srvMeta.getString(Params.impl);
             String composition = srvMeta.getString(Params.composition, null);
-            Dictionary<String, Object> serviceProperties = srvMeta.getDictionary(Params.properties, null);
-            String[] provide = srvMeta.getStrings(Params.provide, null);
             String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
             if (factoryMethod == null)
             {
@@ -66,12 +64,33 @@ public class ServiceBuilder extends Serv
                 service.setFactory(b.loadClass(impl), factoryMethod);
             }
             service.setComposition(composition);
-            service.setInterface(provide, serviceProperties);
+            
             // Adds dependencies (except named dependencies, which are managed by the lifecycle handler).
             addUnamedDependencies(b, dm, service, srvMeta, depsMeta);
             // Creates a ServiceHandler, which will filter all service lifecycle callbacks.
             ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(service, b, dm, srvMeta, depsMeta);
             service.setCallbacks(lfcleHandler, "init", "start", "stop", "destroy");
+            
+            // Set the provided services
+            Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
+            String[] services = srvMeta.getStrings(Params.provide, 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);
+            }
         }
         else
         {

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceComponentBuilder.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceComponentBuilder.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceComponentBuilder.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceComponentBuilder.java Tue Aug 10 21:19:44 2010
@@ -18,12 +18,15 @@
  */
 package org.apache.felix.dm.runtime;
 
+import java.util.Arrays;
+import java.util.Dictionary;
 import java.util.List;
 
 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.service.log.LogService;
 
 /**
@@ -64,7 +67,7 @@ public abstract class ServiceComponentBu
     }
     
     /**
-     * Registers all unamed dependencies into a given service. Named dependencies are
+     * Registers all unnamed dependencies into a given service. Named dependencies are
      * handled differently, and are managed by the ServiceLifecycleHandler class.
      * @throws Exception 
      */
@@ -84,6 +87,5 @@ public abstract class ServiceComponentBu
                 s.add(d);
             }
         }
-
     }
 }

Modified: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java?rev=984213&r1=984212&r2=984213&view=diff
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java (original)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceLifecycleHandler.java Tue Aug 10 21:19:44 2010
@@ -20,7 +20,10 @@ package org.apache.felix.dm.runtime;
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
@@ -182,11 +185,47 @@ public class ServiceLifecycleHandler
     /**
      * 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.
+     * We take care to check if a start callback returns a Map, which is meant to contain
+     * some additional properties which must be appended to existing service properties.
+     * Such extra properties takes precedence over existing service properties.
      */
+    @SuppressWarnings("unchecked")
     public void start(Service service)
         throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
     {
-        callbackComposites(service, m_start);
+        DependencyManager dm = service.getDependencyManager();
+        Map<String, String> extraProperties = new HashMap<String, String>();
+        Object[] composites = service.getCompositionInstances();
+        for (Object composite: composites)
+        {
+            Object o = invokeMethod(composite, m_start, dm, service);
+            if (o != null && Map.class.isAssignableFrom(o.getClass()))
+            {
+                extraProperties.putAll((Map) o);
+            }
+        }
+
+        if (extraProperties.size() > 0)
+        {
+            // Store extra properties returned by start callbacks into existing service properties
+            Dictionary existingProperties = service.getServiceProperties();
+            if (existingProperties != null)
+            {
+                Hashtable props = new Hashtable();
+                Enumeration e = existingProperties.keys();
+                while (e.hasMoreElements())
+                {
+                    Object key = e.nextElement();
+                    props.put(key, existingProperties.get(key));
+                }
+                props.putAll(extraProperties);
+                service.setServiceProperties(props);
+            }
+            else
+            {
+                service.setServiceProperties(new Hashtable(extraProperties));
+            }
+        }
     }
 
     /**

Added: felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java (added)
+++ felix/trunk/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServicePublisher.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,165 @@
+/*
+ * 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));
+        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 class Publisher implements Runnable, ServiceStateListener
+    {
+        public void run()
+        {
+            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_properties);
+                }
+                catch (Throwable t)
+                {
+                    m_published.set(false);
+                    if (t instanceof RuntimeException)
+                    {
+                        throw (RuntimeException) t;
+                    }
+                    else
+                    {
+                        throw new RuntimeException("Could not register services", t);
+                    }
+                }
+            }
+        }
+
+        public void starting(Service service)
+        {
+        }
+
+        public void started(Service service)
+        {
+            // TODO Auto-generated method stub
+
+        }
+
+        public void stopping(Service service)
+        {
+            if (m_published.compareAndSet(true, false))
+            {
+                if (m_registration != null)
+                {
+                    Log.instance().log(LogService.LOG_DEBUG, "unpublishing services %s (service is stopping)",
+                                       Arrays.toString(m_services));
+
+                    m_registration.unregister();
+                    m_registration = null;
+                }
+            }
+        }
+
+        public void stopped(Service service)
+        {
+        }
+    }
+
+    private class Unpublisher implements Runnable
+    {
+        public void run()
+        {
+            if (m_published.compareAndSet(true, false))
+            {
+                if (m_registration != null)
+                {
+                    Log.instance().log(LogService.LOG_DEBUG, "unpublishing services %s",
+                                       Arrays.toString(m_services));
+
+                    m_registration.unregister();
+                    m_registration = null;
+                }
+            }
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAdapterServiceProperties.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAdapterServiceProperties.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAdapterServiceProperties.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAdapterServiceProperties.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,97 @@
+/*
+ * 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.extraproperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.AdapterService;
+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 an adapter Service may specify some extra service properties
+ * from it's start callback
+ */
+public class ExtraAdapterServiceProperties
+{
+    public interface Provider
+    {
+    }
+    
+    public interface Provider2
+    {
+    }
+
+
+    @Service(properties={@Property(name="foo", value="bar")})
+    public static class ProviderImpl implements Provider
+    {
+    }
+    
+    @AdapterService(adapteeService=Provider.class, adapterProperties={@Property(name="foo2", value="bar2")})
+    public static class Provider2Impl implements Provider2
+    {
+        protected Provider m_adaptee;
+        
+        @Start
+        Map<String, String> start()
+        {
+            return new HashMap<String, String>() {{ put("foo3", "bar3"); }};
+        }
+    }
+    
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=ExtraAdapterServiceProperties)")
+        Sequencer m_sequencer;
+
+        private Map m_properties;
+
+        @ServiceDependency
+        void bind(Map properties, Provider2 provider2)
+        {
+            m_properties = properties;
+        }
+        
+        @Start
+        void start() 
+        {
+            System.out.println("provider2 service properties: " + m_properties);
+            if ("bar".equals(m_properties.get("foo"))) 
+            {
+                m_sequencer.step(1);
+            }
+            
+            if ("bar2".equals(m_properties.get("foo2"))) 
+            {
+                m_sequencer.step(2);
+            }         
+            
+            if ("bar3".equals(m_properties.get("foo3"))) 
+            {
+                m_sequencer.step(3);
+            }            
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAspectServiceProperties.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAspectServiceProperties.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAspectServiceProperties.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraAspectServiceProperties.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,90 @@
+/*
+ * 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.extraproperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.AspectService;
+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 an adapter Service may specify some extra service properties
+ * from it's start callback
+ */
+public class ExtraAspectServiceProperties
+{
+    public interface Provider
+    {
+    }
+    
+    @Service(properties={@Property(name="foo", value="bar")})
+    public static class ProviderImpl implements Provider
+    {
+    }
+    
+    @AspectService(ranking=10, properties={@Property(name="foo2", value="bar2")})
+    public static class ProviderAspectImpl implements Provider
+    {        
+        @Start
+        Map<String, String> start()
+        {
+            return new HashMap<String, String>() {{ put("foo3", "aspect"); }};
+        }
+    }
+    
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=ExtraAspectServiceProperties)")
+        Sequencer m_sequencer;
+
+        private Map m_properties;
+
+        @ServiceDependency
+        void bind(Map properties, Provider provider)
+        {
+            m_properties = properties;
+        }
+        
+        @Start
+        void start() 
+        {
+            System.out.println("provider aspect service properties: " + m_properties);
+            if ("bar".equals(m_properties.get("foo"))) 
+            {
+                m_sequencer.step(1);
+            }
+            
+            if ("bar2".equals(m_properties.get("foo2"))) 
+            {
+                m_sequencer.step(2);
+            }         
+            
+            if ("aspect".equals(m_properties.get("foo3"))) 
+            {
+                m_sequencer.step(3);
+            }            
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraFactoryServiceProperties.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraFactoryServiceProperties.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraFactoryServiceProperties.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraFactoryServiceProperties.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,96 @@
+/*
+ * 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.extraproperties;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+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;
+
+public class ExtraFactoryServiceProperties
+{
+    public interface Provider
+    {
+    }
+
+    @Service(properties={@Property(name="foo", value="bar")}, factorySet="MyFactory")
+    public static class ProviderImpl implements Provider
+    {
+        @Start
+        Map<String, String> start()
+        {
+            return new HashMap<String, String>() {{ put("foo2", "bar2"); }};
+        }
+    }
+    
+    @Service
+    public static class ProviderImplFactory
+    {
+        @ServiceDependency
+        Set<Dictionary> m_factory;
+        
+        @Start
+        void start()
+        {
+            m_factory.add(new Hashtable() {{ put("foo3", "bar3"); }});
+        }
+    }
+    
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=ExtraFactoryServiceProperties)")
+        Sequencer m_sequencer;
+        
+        private Map m_properties;
+        
+        @ServiceDependency
+        void bindProvider(Map properties, Provider m_provider)
+        {
+            m_properties = properties;
+        }
+        
+        @Start
+        void start() 
+        {
+            System.out.println("provider service properties: " + m_properties);
+            if ("bar".equals(m_properties.get("foo"))) 
+            {
+                m_sequencer.step(1);
+            }
+            
+            if ("bar2".equals(m_properties.get("foo2"))) 
+            {
+                m_sequencer.step(2);
+            }
+            
+            if ("bar3".equals(m_properties.get("foo3"))) 
+            {
+                m_sequencer.step(3);
+            }
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraServiceProperties.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraServiceProperties.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraServiceProperties.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/extraproperties/ExtraServiceProperties.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,79 @@
+/*
+ * 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.extraproperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.annotation.api.Service;
+import org.apache.felix.dm.annotation.api.Property;
+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 Service may specify some extra service properties
+ * from it's start callback
+ */
+public class ExtraServiceProperties
+{
+    public interface Provider
+    {
+    }
+
+    @Service(properties={@Property(name="foo", value="bar")})
+    public static class ProviderImpl implements Provider
+    {
+        @Start
+        Map<String, String> start()
+        {
+            return new HashMap<String, String>() {{ put("foo2", "bar2"); }};
+        }
+    }
+    
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=ExtraServiceProperties)")
+        Sequencer m_sequencer;
+        
+        private Map m_properties;
+        
+        @ServiceDependency
+        void bindProvider(Map properties, Provider m_provider)
+        {
+            m_properties = properties;
+        }
+        
+        @Start
+        void start() 
+        {
+            System.out.println("provider service properties: " + m_properties);
+            if ("bar".equals(m_properties.get("foo"))) 
+            {
+                m_sequencer.step(1);
+            }
+            
+            if ("bar2".equals(m_properties.get("foo2"))) 
+            {
+                m_sequencer.step(2);
+            }            
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/FactoryServiceTestWthPublisher.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,109 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.apache.felix.dm.annotation.api.Destroy;
+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 validate that a basic "ProviderImpl" which is instantiated from a FactorySet can register/unregister its
+ * service using the Publisher annotation.
+ */
+public class FactoryServiceTestWthPublisher
+{
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=testFactoryService)")
+        Sequencer m_sequencer;
+        
+        @ServiceDependency(required=false, removed = "unbind")
+        void bind(Provider provider)
+        {
+            m_sequencer.step(1);
+        }
+
+        void unbind(Provider provider)
+        {
+            m_sequencer.step(2);
+        }
+        
+        @Destroy
+        void destroy() 
+        {
+            m_sequencer.step(3);
+        }
+    }
+   
+    @Service(publisher="m_publisher", unpublisher="m_unpublisher", factorySet="MyFactory")
+    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=testFactoryService)")
+        Sequencer m_sequencer;
+        
+        @Start
+        void start()
+        {
+            // register service in 1 second
+            schedule(m_publisher, 1000);
+            // unregister the service in 2 seconds
+            schedule(m_unpublisher, 2000);
+        }
+
+        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
+    public static class ProviderImplFactory 
+    {
+        @ServiceDependency(filter="(dm.factory.name=MyFactory)")
+        void bind(Set<Dictionary> m_providerImplFactory)
+        {
+            m_providerImplFactory.add(new Hashtable() {{ put("foo", "bar"); }});
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/Provider.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+public interface Provider
+{
+}

Added: felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java (added)
+++ felix/trunk/dependencymanager/test/src/main/java/org/apache/felix/dm/test/bundle/annotation/publisher/ServiceTestWthPublisher.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,95 @@
+/*
+ * 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 org.apache.felix.dm.annotation.api.Destroy;
+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 validate that a basic "ProviderImpl" services can register/unregister its
+ * service using the Publisher annotation.
+ */
+public class ServiceTestWthPublisher
+{
+    @Service
+    public static class Consumer
+    {
+        @ServiceDependency(filter="(test=testService)")
+        Sequencer m_sequencer;
+        
+        @ServiceDependency(required=false, removed = "unbind")
+        void bind(Provider provider)
+        {
+            m_sequencer.step(1);
+        }
+
+        void unbind(Provider provider)
+        {
+            m_sequencer.step(2);
+        }
+        
+        @Destroy
+        void destroy() 
+        {
+            m_sequencer.step(3);
+        }
+    }
+    
+    @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=testService)")
+        Sequencer m_sequencer;
+
+        @Start
+        void start()
+        {
+            // register service in 1 second
+            schedule(m_publisher, 1000);
+            // unregister the service in 2 seconds
+            schedule(m_unpublisher, 2000);
+        }
+
+        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();
+        }
+    }
+}

Added: felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/ExtraServicePropertiesTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/ExtraServicePropertiesTest.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/ExtraServicePropertiesTest.java (added)
+++ felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/ExtraServicePropertiesTest.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,115 @@
+/*
+ * 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.annotation;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.util.Hashtable;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.BundleGenerator;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+/**
+ * Use case: Verify the a Service may provide its service properties dynamically from its start method.
+ */
+@RunWith(JUnit4TestRunner.class)
+public class ExtraServicePropertiesTest extends AnnotationBase
+{
+    @Configuration
+    public static Option[] configuration()
+    {
+        return options(
+            systemProperty(DMLOG_PROPERTY).value( "true" ),
+            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.dependencymanager.runtime").versionAsInProject()),
+            provision(
+                new BundleGenerator()
+                    .set(Constants.BUNDLE_SYMBOLICNAME, "ExtraPropertiesTest")
+                    .set("Export-Package", "org.apache.felix.dm.test.bundle.annotation.sequencer")
+                    .set("Private-Package", "org.apache.felix.dm.test.bundle.annotation.extraproperties")
+                    .set("Import-Package", "*")
+                    .set("-plugin", "org.apache.felix.dm.annotation.plugin.bnd.AnnotationPlugin")
+                    .build()));            
+    }
+
+    /**
+     * Tests if a Service can provide its service properties from its start method.
+     */
+    @Test
+    public void testExtraServiceProperties(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", "ExtraServiceProperties"); }}));
+        m_ensure.waitForStep(2, 10000);
+    }
+    
+    /**
+     * Tests if a Service instantiated by a Factory can provide its service properties from its start method.
+     */
+    @Test
+    public void testExtraFactoryServiceProperties(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", "ExtraFactoryServiceProperties"); }}));
+        m_ensure.waitForStep(3, 10000);
+    }
+
+    /**
+     * Tests if an AdapterService can provide its service properties from its start method.
+     */
+    @Test
+    public void testExtraAdapterServiceProperties(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", "ExtraAdapterServiceProperties"); }}));
+        m_ensure.waitForStep(3, 10000);
+    }
+    
+    /**
+     * Tests if an AspectService can provide its service properties from its start method.
+     */
+    @Test
+    public void testExtraAspectServiceProperties(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", "ExtraAspectServiceProperties"); }}));
+        m_ensure.waitForStep(3, 10000);
+    }
+}

Added: felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java?rev=984213&view=auto
==============================================================================
--- felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java (added)
+++ felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/annotation/PublisherAnnotationTest.java Tue Aug 10 21:19:44 2010
@@ -0,0 +1,100 @@
+/*
+ * 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.annotation;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.util.Hashtable;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.test.BundleGenerator;
+import org.apache.felix.dm.test.bundle.annotation.sequencer.Sequencer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+/**
+ * Use case: Verify the Publisher annotation, which allows a component to register/unregister
+ * its service programatically.
+ */
+@RunWith(JUnit4TestRunner.class)
+public class PublisherAnnotationTest extends AnnotationBase
+{
+    @Configuration
+    public static Option[] configuration()
+    {
+        return options(
+            systemProperty(DMLOG_PROPERTY).value( "true" ),
+            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.dependencymanager.runtime").versionAsInProject()),
+            provision(
+                new BundleGenerator()
+                    .set(Constants.BUNDLE_SYMBOLICNAME, "PublisherAnnotationsTest")
+                    .set("Export-Package", "org.apache.felix.dm.test.bundle.annotation.sequencer")
+                    .set("Private-Package", "org.apache.felix.dm.test.bundle.annotation.publisher")
+                    .set("Import-Package", "*")
+                    .set("-plugin", "org.apache.felix.dm.annotation.plugin.bnd.AnnotationPlugin")
+                    .build()));            
+    }
+
+    /**
+     * A Provider that just registers/unregisters its service, using the Publisher 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"); }}));
+        // Check if the Provider has seen the Provider.
+        m_ensure.waitForStep(2, 10000);
+        // Stop the bundle
+        stopBundle("PublisherAnnotationsTest", context);
+        // And check if the Consumer has been destroyed.
+        m_ensure.waitForStep(3, 10000);
+    }
+    
+    /**
+     * A Provider instantiated from a FactorySet, and which registers/unregisters its service, using the Publisher 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"); }}));
+        // Check if the Provider has seen the Provider.
+        m_ensure.waitForStep(2, 10000);
+        // Stop the bundle
+        stopBundle("PublisherAnnotationsTest", context);
+        // And check if the Consumer has been destroyed.
+        m_ensure.waitForStep(3, 10000);
+    }
+}