Allow to define an Aspect Service implemented with a DynamicProxy.
Added factoryMethod attribute in all services.
Don't turn off anymore "instance bound" flag in extra (init) service dependencies.
Renamed Service factory attribute into factorySet attribute.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@957379 13f79535-47bb-0310-9956-ffa450edef68
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 3446192..87c085a 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
@@ -43,14 +43,22 @@
     public void buildService(MetaData srvMeta, List<MetaData> depsMeta, Bundle b, DependencyManager dm)
         throws Exception
     {
-        Class<?> adapterImpl = b.loadClass(srvMeta.getString(Params.impl));
+        Class<?> adapterImplClass = b.loadClass(srvMeta.getString(Params.impl));
         String[] adapterService = srvMeta.getStrings(Params.adapterService, null);
         Dictionary<String, Object> adapterProperties = srvMeta.getDictionary(Params.adapterProperties, null);
         Class<?> adapteeService = b.loadClass(srvMeta.getString(Params.adapteeService));
         String adapteeFilter = srvMeta.getString(Params.adapteeFilter, null);     
         Service service = dm.createAdapterService(adapteeService, adapteeFilter)
-                            .setInterface(adapterService, adapterProperties)
-                            .setImplementation(adapterImpl);
+                            .setInterface(adapterService, adapterProperties);
+        String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
+        if (factoryMethod == null)
+        {
+            service.setImplementation(adapterImplClass);
+        } 
+        else
+        {
+            service.setFactory(adapterImplClass, factoryMethod);
+        }
         service.setComposition(srvMeta.getString(Params.composition, null));
         ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(service, b, dm, srvMeta, depsMeta);
         // The dependencies will be plugged by our lifecycle handler.
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AspectServiceBuilder.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AspectServiceBuilder.java
index 4130cb8..f14ca18 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AspectServiceBuilder.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/AspectServiceBuilder.java
@@ -48,12 +48,21 @@
         String serviceFilter = srvMeta.getString(Params.filter, null);
         Dictionary<String, Object> aspectProperties = srvMeta.getDictionary(Params.properties, null);
         int ranking = srvMeta.getInt(Params.ranking, 1);
-        String implClass = srvMeta.getString(Params.impl);
-        Object impl = b.loadClass(implClass);        
-        String field = srvMeta.getString(Params.field, null);        
+        String implClassName = srvMeta.getString(Params.impl);
+        Object implClass = b.loadClass(implClassName);        
+        String field = srvMeta.getString(Params.field, null);  
+        String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
         Service service = dm.createAspectService(serviceInterface, serviceFilter, ranking, field)
-                            .setImplementation(impl)
                             .setServiceProperties(aspectProperties);
+        if (factoryMethod == null)
+        {
+            service.setImplementation(implClass);
+        } 
+        else
+        {
+            service.setFactory(implClass, factoryMethod);
+        }
+        
         service.setComposition(srvMeta.getString(Params.composition, null));
         ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(service, b, dm, srvMeta, depsMeta);
         // The dependencies will be plugged by our lifecycle handler.
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 4b40ba2..6eb41ef 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
@@ -41,13 +41,22 @@
     {
         int stateMask = srvMeta.getInt(Params.stateMask, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE);
         String filter = srvMeta.getString(Params.filter, null);
-        Class<?> adapterImpl = b.loadClass(srvMeta.getString(Params.impl));
+        Class<?> adapterImplClass = b.loadClass(srvMeta.getString(Params.impl));
         String[] service = srvMeta.getStrings(Params.service, 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(service, properties)
-                            .setImplementation(adapterImpl);
+                            .setInterface(service, properties);
+        String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
+        if (factoryMethod == null)
+        {
+            srv.setImplementation(adapterImplClass);
+        } 
+        else
+        {
+            srv.setFactory(adapterImplClass, factoryMethod);
+        }
+
         srv.setComposition(srvMeta.getString(Params.composition, null));
         ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(srv, b, dm, srvMeta, depsMeta);
         // The dependencies will be plugged by our lifecycle handler.
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 13301eb..1f049ed 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
@@ -39,15 +39,23 @@
     public void buildService(MetaData srvMeta, List<MetaData> depsMeta, Bundle b, DependencyManager dm) 
         throws Exception
     {
-        Class<?> impl = b.loadClass(srvMeta.getString(Params.impl));
+        Class<?> implClass = b.loadClass(srvMeta.getString(Params.impl));
         String factoryPid = srvMeta.getString(Params.factoryPid);
         String updated = srvMeta.getString(Params.updated);
         String[] services = srvMeta.getStrings(Params.service, 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(services, properties)
-                        .setImplementation(impl);
+                        .setInterface(services, properties);
+        String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
+        if (factoryMethod == null)
+        {
+            srv.setImplementation(implClass);
+        } 
+        else
+        {
+            srv.setFactory(implClass, factoryMethod);
+        }
         srv.setComposition(srvMeta.getString(Params.composition, null));
         ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(srv, b, dm, srvMeta, depsMeta);
         // The dependencies will be plugged by our lifecycle handler.
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/InvocationUtil.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/InvocationUtil.java
new file mode 100644
index 0000000..39d5555
--- /dev/null
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/InvocationUtil.java
@@ -0,0 +1,76 @@
+package org.apache.felix.dm.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+
+/**
+ * Class copied from DM core (but, ultimately, the core should export this class so we could then 
+ * import/reuse it).
+ */
+public class InvocationUtil
+{
+    public static Object invokeCallbackMethod(Object instance, String methodName, Class[][] signatures,
+                                            Object[][] parameters) 
+        throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
+    {
+        Class currentClazz = instance.getClass();
+        while (currentClazz != null)
+        {
+            try
+            {
+                return invokeMethod(instance, currentClazz, methodName, signatures, parameters, false);
+            }
+            catch (NoSuchMethodException nsme)
+            {
+                // ignore
+            }
+            currentClazz = currentClazz.getSuperclass();
+        }
+        throw new NoSuchMethodException(methodName);
+    }
+
+    public static Object invokeMethod(Object object, Class clazz, String name, Class[][] signatures,
+                                      Object[][] parameters, boolean isSuper) 
+        throws NoSuchMethodException, InvocationTargetException, IllegalArgumentException, IllegalAccessException
+    {
+        if (object == null)
+        {
+            throw new IllegalArgumentException("Instance cannot be null");
+        }
+        if (clazz == null)
+        {
+            throw new IllegalArgumentException("Class cannot be null");
+        }
+
+        // If we're talking to a proxy here, dig one level deeper to expose the
+        // underlying invocation handler ...
+        
+        if (Proxy.isProxyClass(clazz))
+        {
+            object = Proxy.getInvocationHandler(object);
+            clazz = object.getClass();
+        }
+
+        Method m = null;
+        for (int i = 0; i < signatures.length; i++)
+        {
+            Class[] signature = signatures[i];
+            try
+            {
+                m = clazz.getDeclaredMethod(name, signature);
+                if (!(isSuper && Modifier.isPrivate(m.getModifiers())))
+                {
+                    m.setAccessible(true);
+                    return m.invoke(object, parameters[i]);
+                }
+            }
+            catch (NoSuchMethodException e)
+            {
+                // ignore this and keep looking
+            }
+        }
+        throw new NoSuchMethodException(name);
+    }
+}
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 fa0ffb7..445b5d4 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
@@ -51,8 +51,9 @@
     stateMask,
     ranking,
     factoryPid,    
-    factory,
+    factorySet,
     factoryConfigure,
+    factoryMethod,
     name,
     field
 }
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 ede3c53..ac89efe 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
@@ -40,13 +40,21 @@
         throws Exception
     {
         String filter = srvMeta.getString(Params.filter, null);
-        Class<?> impl = b.loadClass(srvMeta.getString(Params.impl));
+        Class<?> implClass = b.loadClass(srvMeta.getString(Params.impl));
         String[] service = srvMeta.getStrings(Params.service, null);
         Dictionary<String, Object> properties = srvMeta.getDictionary(Params.properties, null);
         boolean propagate = "true".equals(srvMeta.getString(Params.propagate, "false"));
         Service srv = dm.createResourceAdapterService(filter, propagate)
-                        .setInterface(service, properties)
-                        .setImplementation(impl);
+                        .setInterface(service, properties);       
+        String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
+        if (factoryMethod == null)
+        {
+            srv.setImplementation(implClass);
+        } 
+        else
+        {
+            srv.setFactory(implClass, factoryMethod);
+        }
         srv.setComposition(srvMeta.getString(Params.composition, null));
         ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(srv, b, dm, srvMeta, depsMeta);
         // The dependencies will be plugged by our lifecycle handler.
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 bd435c6..b8213e1 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
@@ -44,7 +44,7 @@
         throws Exception
     {
         Service service = dm.createService();
-        String factory = srvMeta.getString(Params.factory, null);
+        String factory = srvMeta.getString(Params.factorySet, null);
 
         // Check if we must provide a Set Factory.
         if (factory == null)
@@ -57,7 +57,14 @@
             String composition = srvMeta.getString(Params.composition, null);
             Dictionary<String, Object> serviceProperties = srvMeta.getDictionary(Params.properties, null);
             String[] provide = srvMeta.getStrings(Params.provide, null);
-            service.setImplementation(b.loadClass(impl));
+            String factoryMethod = srvMeta.getString(Params.factoryMethod, null);
+            if (factoryMethod == null)
+            {
+                service.setImplementation(b.loadClass(impl));
+            } else
+            {
+                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).
diff --git a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceFactory.java b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceFactory.java
index 98dd03d..f1697e1 100644
--- a/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceFactory.java
+++ b/dependencymanager/runtime/src/main/java/org/apache/felix/dm/runtime/ServiceFactory.java
@@ -100,7 +100,7 @@
      * The bundle containing the Service annotated with the factory attribute.
      */
     private Bundle m_bundle;
-    
+
     /**
      * Flag used to check if a service is being created
      */
@@ -154,7 +154,7 @@
      */
     public ServiceFactory(Bundle b, MetaData srvMeta, List<MetaData> depsMeta)
     {
-        m_serviceProperties = srvMeta.getDictionary(Params.properties, null);;
+        m_serviceProperties = srvMeta.getDictionary(Params.properties, null);
         m_provide = srvMeta.getStrings(Params.provide, null);
         m_configure = srvMeta.getString(Params.factoryConfigure, null);
         m_bundle = b;
@@ -343,7 +343,17 @@
                 // Create the Service / impl
                 Service s = m_dm.createService();
                 Class implClass = m_bundle.loadClass(m_srvMeta.getString(Params.impl));
-                m_impl = implClass.newInstance();
+                String factoryMethod = m_srvMeta.getString(Params.factoryMethod, null);
+                if (factoryMethod == null)
+                {
+                    m_impl = implClass.newInstance();
+                }
+                else
+                {
+                    Method m = implClass.getDeclaredMethod(factoryMethod);
+                    m.setAccessible(true);
+                    m_impl = m.invoke(null);
+                }
 
                 // Invoke "configure" callback
                 if (m_configure != null)
@@ -359,26 +369,29 @@
                     Dictionary serviceProperties = mergeSettings(m_serviceProperties, configuration);
                     s.setInterface(m_provide, serviceProperties);
                 }
-                
+
                 s.setComposition(m_srvMeta.getString(Params.composition, null));
-                ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(s, m_bundle, m_dm, m_srvMeta, m_depsMeta);
+                ServiceLifecycleHandler lfcleHandler = new ServiceLifecycleHandler(s, m_bundle, m_dm,
+                    m_srvMeta, m_depsMeta);
                 // The dependencies will be plugged by our lifecycle handler.
                 s.setCallbacks(lfcleHandler, "init", "start", "stop", "destroy");
 
                 // Adds dependencies (except named dependencies, which are managed by the lifecycle handler).
-                for (MetaData dependency : m_depsMeta) 
+                for (MetaData dependency: m_depsMeta)
                 {
                     String name = dependency.getString(Params.name, null);
-                    if (name == null) {
+                    if (name == null)
+                    {
                         DependencyBuilder depBuilder = new DependencyBuilder(dependency);
-                        Log.instance().log(LogService.LOG_INFO, 
+                        Log.instance().log(
+                                           LogService.LOG_INFO,
                                            "ServiceLifecycleHandler.init: adding dependency %s into service %s",
                                            dependency, m_srvMeta);
                         Dependency d = depBuilder.build(m_bundle, m_dm, false);
                         s.add(d);
                     }
                 }
-                
+
                 // Register the Service instance, and keep track of it.
                 Log.instance().log(LogService.LOG_INFO, "ServiceFactory: created service %s", m_srvMeta);
                 m_dm.add(s);
@@ -388,7 +401,8 @@
             {
                 // Make sure the SERVICE_CREATING flag is also removed
                 m_services.remove(serviceKey);
-                Log.instance().log(LogService.LOG_ERROR, "ServiceFactory: could not instantiate service %s", t, m_srvMeta);
+                Log.instance().log(LogService.LOG_ERROR, "ServiceFactory: could not instantiate service %s",
+                                   t, m_srvMeta);
             }
         }
         else
@@ -424,7 +438,7 @@
     {
         try
         {
-            for (Object service : m_services.values())
+            for (Object service: m_services.values())
             {
                 if (service instanceof Service)
                 {
@@ -458,7 +472,7 @@
                 Object key = keys.nextElement();
                 Object val = serviceProperties.get(key);
                 props.put(key, val);
-            }        
+            }
         }
 
         Enumeration keys = factoryConfiguration.keys();
@@ -478,16 +492,16 @@
     /**
      * Invokes the configure callback method on the service instance implemenatation.
      * @param impl
-     * @param factoryConfige
+     * @param configure
      * @param config
      */
-    private void invokeConfigure(Object impl, String factoryConfige, Dictionary config)
+    private void invokeConfigure(Object impl, String configure, Dictionary config)
     {
         try
         {
-            Method m = impl.getClass().getMethod(factoryConfige, Dictionary.class);
-            m.setAccessible(true);
-            m.invoke(impl, new Object[] { config });
+            InvocationUtil.invokeCallbackMethod(impl, configure,
+                                                new Class[][] { { Dictionary.class } },
+                                                new Object[][] { { config } });
         }
 
         catch (Throwable t)
@@ -498,8 +512,8 @@
             }
             else
             {
-                throw new RuntimeException("Could not invoke method " + factoryConfige
-                    + " on object " + impl);
+                throw new RuntimeException("Could not invoke method " + configure
+                                           + " on object " + impl);
             }
         }
     }
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 89c1a33..9afc47f 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
@@ -164,28 +164,6 @@
     public void start(Object serviceInstance, DependencyManager dm, Service service)
         throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
     {
-        // Remove "instance bound" flag from all dependencies, because we want to be deactivated
-        // once we lose one of the deps ...
-        Iterator it = m_namedDeps.iterator();
-        while (it.hasNext())
-        {
-            Dependency d = (Dependency) it.next();
-            if (d instanceof ServiceDependency) {
-                ((ServiceDependency)d).setInstanceBound(false);
-            } else if (d instanceof BundleDependency)
-            {
-                ((BundleDependency)d).setInstanceBound(false);
-            } else  if (d instanceof ResourceDependency) 
-            {
-                ((ResourceDependency) d).setInstanceBound(false);
-            } else if (d instanceof ConfigurationDependency) 
-            {
-                ((ConfigurationDependency) d).setInstanceBound(false);
-            } else if (d instanceof TemporalServiceDependency) 
-            {
-                ((TemporalServiceDependency) d).setInstanceBound(false);
-            }
-        }
         invokeMethod(serviceInstance, m_start, dm, service);
     }
 
@@ -228,29 +206,16 @@
             // The annotated class did not provide an annotation for this lifecycle callback.
             return null;
         }
-
-        Class clazz = instance.getClass();
-
-        while (clazz != null)
+        
+        try 
         {
-            for (int i = 0; i < signatures.length; i++)
-            {
-                Class<?>[] signature = signatures[i];
-                try
-                {
-                    // Don't use getMethod because getMethod only look for public methods !
-                    Method m = instance.getClass().getDeclaredMethod(method, signature);
-                    m.setAccessible(true);
-                    return m.invoke(instance, params[i]);
-                }
-                catch (NoSuchMethodException e)
-                {
-                    // ignore this and keep looking
-                }
-            }
-            clazz = clazz.getSuperclass();
+            return InvocationUtil.invokeCallbackMethod(instance, method, signatures, params);
+        } 
+        
+        catch (NoSuchMethodException e) 
+        {
+            // ignore this
+            return null;
         }
-
-        return null;
     }
 }