Added a feature to use an external instance/method to provide properties to propagate. Implemented it for all dependencies plus the resource adapter. Other adapters still under consideration.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@963265 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
index 0584721..2e6b07d 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
@@ -161,6 +161,10 @@
         return m_manager.createResourceAdapterService(resourceFilter, propagate, callbackInstance, callbackChanged);
     }
     
+    public Service createResourceAdapter(String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackChanged) {
+        return m_manager.createResourceAdapterService(resourceFilter, propagateCallbackInstance, propagateCallbackMethod, callbackInstance, callbackChanged);
+    }
+    
     public Service createBundleAdapterService(int bundleStateMask, String bundleFilter, boolean propagate) {
         return m_manager.createBundleAdapterService(bundleStateMask, bundleFilter, propagate);
     }
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 6f78610..afcf517 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -238,6 +238,10 @@
         return new ResourceAdapterServiceImpl(this, resourceFilter, propagate, callbackInstance, callbackChanged);
     }
     
+    public Service createResourceAdapterService(String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackChanged) {
+        return new ResourceAdapterServiceImpl(this, resourceFilter, propagateCallbackInstance, propagateCallbackMethod, callbackInstance, callbackChanged);
+    }
+    
     /**
      * Creates a new bundle adapter. The adapter will be applied to any bundle that
      * matches the specified bundle state mask and filter condition. For each matching
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/ResourceDependency.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/ResourceDependency.java
index 333d66f..aa76552 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/ResourceDependency.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/ResourceDependency.java
@@ -102,5 +102,7 @@
      
      public ResourceDependency setPropagate(boolean propagate);
      
+     public ResourceDependency setPropagate(Object instance, String method);
+     
      public ResourceDependency setInstanceBound(boolean isInstanceBound);
 }
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
index fba52fa..73a5bfb 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
@@ -6,12 +6,11 @@
 import java.lang.reflect.Proxy;
 
 public class InvocationUtil {
-    public static void invokeCallbackMethod(Object instance, String methodName, Class[][] signatures, Object[][] parameters) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+    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 {
-                invokeMethod(instance, currentClazz, methodName, signatures, parameters, false);
-                return;
+                return invokeMethod(instance, currentClazz, methodName, signatures, parameters, false);
             }
             catch (NoSuchMethodException nsme) {
                 // ignore
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java
index 7406f44..1082317 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java
@@ -25,6 +25,7 @@
 
 import org.apache.felix.dm.Dependency;
 import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceDependency;
 import org.apache.felix.dm.Service;
 import org.apache.felix.dm.ServiceStateListener;
 
@@ -51,13 +52,36 @@
                  .setCallbacks("added", "removed"));
     }
 
+    public ResourceAdapterServiceImpl(DependencyManager dm, String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackChanged) {
+        super(dm.createService()); // This service will be filtered by our super class, allowing us to take control.
+        m_callbackInstance = callbackInstance;
+        m_callbackChanged = callbackChanged;
+        m_service.setImplementation(new ResourceAdapterImpl(resourceFilter, propagateCallbackInstance, propagateCallbackMethod))
+            .add(dm.createResourceDependency()
+                 .setFilter(resourceFilter)
+                 .setAutoConfig(false)
+                 .setCallbacks("added", "removed"));
+    }
+
     public class ResourceAdapterImpl extends AbstractDecorator {
         private final String m_resourceFilter;
         private final boolean m_propagate;
+        private final Object m_propagateCallbackInstance;
+        private final String m_propagateCallbackMethod;
 
         public ResourceAdapterImpl(String resourceFilter, boolean propagate) {
+            this(resourceFilter, propagate, null, null);
+        }
+
+        public ResourceAdapterImpl(String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod) {
+            this(resourceFilter, true, propagateCallbackInstance, propagateCallbackMethod);
+        }
+        
+        private ResourceAdapterImpl(String resourceFilter, boolean propagate, Object propagateCallbackInstance, String propagateCallbackMethod) {
             m_resourceFilter = resourceFilter;
             m_propagate = propagate;
+            m_propagateCallbackInstance = propagateCallbackInstance;
+            m_propagateCallbackMethod = propagateCallbackMethod;
         }
 
         public Service createService(Object[] properties) {
@@ -74,18 +98,21 @@
             // the first dependency is always the dependency on the resource, which
             // will be replaced with a more specific dependency below
             dependencies.remove(0);
+            ResourceDependency resourceDependency = m_manager.createResourceDependency()
+                 .setResource(resource)
+                 .setPropagate(m_propagate)
+                 .setCallbacks(m_callbackInstance, null, m_callbackChanged, null)
+                 .setAutoConfig(true)
+                 .setRequired(true);
+            resourceDependency.setPropagate(m_propagate);
+            resourceDependency.setPropagate(m_propagateCallbackInstance, m_propagateCallbackMethod);
             Service service = m_manager.createService()
                 .setInterface(m_serviceInterfaces, props)
                 .setImplementation(m_serviceImpl)
                 .setFactory(m_factory, m_factoryCreateMethod) // if not set, no effect
                 .setComposition(m_compositionInstance, m_compositionMethod) // if not set, no effect
                 .setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy) // if not set, no effect
-                .add(m_manager.createResourceDependency()
-                     .setResource(resource)
-                     .setPropagate(m_propagate)
-                     .setCallbacks(m_callbackInstance, null, m_callbackChanged, null)
-                     .setAutoConfig(true)
-                     .setRequired(true));
+                .add(resourceDependency);
             
             for (int i = 0; i < dependencies.size(); i++) {
                 service.add(((Dependency) dependencies.get(i)).createCopy());
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java
index 380300e..0482cec 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm.impl.dependencies;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -27,6 +28,7 @@
 import org.apache.felix.dm.Dependency;
 import org.apache.felix.dm.ServiceComponentDependency;
 import org.apache.felix.dm.impl.DefaultNullObject;
+import org.apache.felix.dm.impl.InvocationUtil;
 import org.apache.felix.dm.impl.Logger;
 import org.apache.felix.dm.impl.tracker.BundleTracker;
 import org.apache.felix.dm.impl.tracker.BundleTrackerCustomizer;
@@ -35,6 +37,7 @@
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.Filter;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
 
 public class BundleDependencyImpl extends DependencyBase implements BundleDependency, BundleTrackerCustomizer, ServiceComponentDependency {
 	private final BundleContext m_context;
@@ -43,7 +46,6 @@
 	private int m_stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
 	private List m_services = new ArrayList();
 	private boolean m_isAvailable;
-	
     private Object m_callbackInstance;
     private String m_callbackAdded;
     private String m_callbackChanged;
@@ -52,12 +54,13 @@
 	private Bundle m_bundleInstance;
 	private Filter m_filter;
 	private long m_bundleId = -1;
-	private boolean m_propagate;
 	private String m_autoConfigInstance;
     private Object m_nullObject;
     private boolean m_autoConfigInvoked;
+    private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
 
-    
     public BundleDependencyImpl(BundleContext context, Logger logger) {
         super(logger);
 		m_context = context;
@@ -356,12 +359,6 @@
         return this;
     }
     
-    public BundleDependency setPropagate(boolean propagate) {
-        ensureNotActive();
-        m_propagate = propagate;
-        return this;
-    }
-    
 	public BundleDependency setBundle(Bundle bundle) {
 		m_bundleId = bundle.getBundleId();
 		return this;
@@ -461,10 +458,42 @@
         invokeRemoved(service, m_bundleInstance);
         m_bundleInstance = null;
     }
-
+    
+    public BundleDependency setPropagate(boolean propagate) {
+        ensureNotActive();
+        m_propagate = propagate;
+        return this;
+    }
+    
+    public BundleDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
+    }
+    
     public Dictionary getProperties() {
-        // TODO Auto-generated method stub
-        return null;
+        Bundle bundle = lookupBundle();
+        if (bundle != null) {
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Bundle.class }}, new Object[][] {{ bundle }});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                return bundle.getHeaders();
+            }
+        }
+        else {
+            throw new IllegalStateException("cannot find bundle");
+        }
     }
 
     public boolean isPropagated() {
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
index e55665e..267cd85 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
@@ -38,6 +38,7 @@
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
 
 /**
  * Configuration dependency that can track the availability of a (valid) configuration.
@@ -65,11 +66,13 @@
 	private ServiceRegistration m_registration;
     protected List m_services = new ArrayList();
 	private Dictionary m_settings;
-	private boolean m_propagate;
     private String m_callback;
     private boolean m_isStarted;
 	private final Set m_updateInvokedCache = new HashSet();
     private MetaTypeProviderImpl m_metaType;
+    private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
 	
 	public ConfigurationDependencyImpl(BundleContext context, Logger logger) {
 	    super(logger);
@@ -324,8 +327,35 @@
         return false;
     }
 
+    public ConfigurationDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
+    }
+    
     public Dictionary getProperties() {
-        return getConfiguration();
+        Dictionary config = getConfiguration();
+        if (config != null) {
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Dictionary.class }, {}}, new Object[][] {{ config }, {}});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                return config;
+            }
+        }
+        else {
+            throw new IllegalStateException("cannot find configuration");
+        }
     }
     
     public BundleContext getBundleContext() {
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java
index 428e1fb..df09ddc 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ResourceDependencyImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm.impl.dependencies;
 
+import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -29,9 +30,11 @@
 import org.apache.felix.dm.ResourceHandler;
 import org.apache.felix.dm.Service;
 import org.apache.felix.dm.ServiceComponentDependency;
+import org.apache.felix.dm.impl.InvocationUtil;
 import org.apache.felix.dm.impl.Logger;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
 
 public class ResourceDependencyImpl extends DependencyBase implements ResourceDependency, ResourceHandler, DependencyActivation, ServiceComponentDependency {
 	private volatile BundleContext m_context;
@@ -51,6 +54,8 @@
     private List m_resources = new ArrayList();
     private URL m_resourceInstance;
     private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
 	
     public ResourceDependencyImpl(BundleContext context, Logger logger) {
         super(logger);
@@ -430,15 +435,36 @@
         return this;
     }
     
+    public ResourceDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
+    }
+    
     public Dictionary getProperties() {
         URL resource = lookupResource();
         if (resource != null) {
-            Properties props = new Properties();
-            props.setProperty(ResourceHandler.HOST, resource.getHost());
-            props.setProperty(ResourceHandler.PATH, resource.getPath());
-            props.setProperty(ResourceHandler.PROTOCOL, resource.getProtocol());
-            props.setProperty(ResourceHandler.PORT, Integer.toString(resource.getPort()));
-            return props;
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ URL.class }}, new Object[][] {{ resource }});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                Properties props = new Properties();
+                props.setProperty(ResourceHandler.HOST, resource.getHost());
+                props.setProperty(ResourceHandler.PATH, resource.getPath());
+                props.setProperty(ResourceHandler.PROTOCOL, resource.getProtocol());
+                props.setProperty(ResourceHandler.PORT, Integer.toString(resource.getPort()));
+                return props;
+            }
         }
         else {
             throw new IllegalStateException("cannot find resource");
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
index 86e1043..76a3306 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.dm.impl.dependencies;
 
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Proxy;
 import java.util.AbstractMap;
 import java.util.ArrayList;
@@ -27,12 +28,14 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 
 import org.apache.felix.dm.Dependency;
 import org.apache.felix.dm.ServiceComponentDependency;
 import org.apache.felix.dm.ServiceDependency;
 import org.apache.felix.dm.impl.DefaultNullObject;
+import org.apache.felix.dm.impl.InvocationUtil;
 import org.apache.felix.dm.impl.Logger;
 import org.apache.felix.dm.impl.tracker.ServiceTracker;
 import org.apache.felix.dm.impl.tracker.ServiceTrackerCustomizer;
@@ -40,6 +43,7 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
 
 /**
  * Service dependency that can track an OSGi service.
@@ -69,6 +73,9 @@
     private Object m_defaultImplementationInstance;
     private boolean m_isAvailable;
     private ServiceReference[] m_references;
+    private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
     
     private static final Comparator COMPARATOR = new Comparator() {
         public int getRank(ServiceReference ref) {
@@ -805,12 +812,51 @@
     }
 
     public Dictionary getProperties() {
-        // TODO Auto-generated method stub
-        return null;
+        ServiceReference reference = lookupServiceReference();
+        Object service = lookupService();
+        if (reference != null) {
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ ServiceReference.class, Object.class }, { ServiceReference.class }}, new Object[][] {{ reference, service }, { reference }});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                Properties props = new Properties();
+                String[] keys = reference.getPropertyKeys();
+                for (int i = 0; i < keys.length; i++) {
+                    if (!(keys[i].equals(Constants.SERVICE_ID) || keys[i].equals(Constants.SERVICE_PID))) {
+                        props.put(keys[i], reference.getProperty(keys[i]));
+                    }
+                }
+                return props;
+            }
+        }
+        else {
+            throw new IllegalStateException("cannot find service reference");
+        }
     }
 
     public boolean isPropagated() {
-        // TODO Auto-generated method stub
-        return false;
+        return m_propagate;
+    }
+    
+    public ServiceDependency setPropagate(boolean propagate) {
+        ensureNotActive();
+        m_propagate = propagate;
+        return this;
+    }
+    
+    public ServiceDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
     }
 }