Fixes for bundle adapters. Added missing methods to DAB.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@910568 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 a4004a5..4b07c24 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
@@ -23,6 +23,7 @@
 
 import org.apache.felix.dm.dependencies.BundleDependency;
 import org.apache.felix.dm.dependencies.ConfigurationDependency;
+import org.apache.felix.dm.dependencies.ResourceDependency;
 import org.apache.felix.dm.dependencies.ServiceDependency;
 import org.apache.felix.dm.dependencies.TemporalServiceDependency;
 import org.apache.felix.dm.impl.Logger;
@@ -142,10 +143,26 @@
     public BundleDependency createBundleDependency() {
         return m_manager.createBundleDependency();
     }
+    
+    public ResourceDependency createResourceDependency() {
+        return m_manager.createResourceDependency();
+    }
 
     public Service createAspectService(Class serviceInterface, String serviceFilter, Object aspectImplementation, Dictionary properties) {
         return m_manager.createAspectService(serviceInterface, serviceFilter, aspectImplementation, properties);
     }
+    
+    public Service createAdapterService(Class serviceInterface, String serviceFilter, Class adapterInterface, Object adapterImplementation, Dictionary adapterProperties) {
+        return m_manager.createAdapterService(serviceInterface, serviceFilter, adapterInterface, adapterImplementation, adapterProperties);
+    }
+    
+    public Service createResourceAdapter(String resourceFilter, Class adapterInterface, Dictionary adapterProperties, Object adapterImplementation, boolean propagate) {
+        return m_manager.createResourceAdapterService(resourceFilter, adapterInterface, adapterProperties, adapterImplementation, propagate);
+    }
+    
+    public Service createBundleAdapterService(int bundleStateMask, String bundleFilter, Object adapterImplementation, String adapterInterface, Dictionary adapterProperties, boolean propagate) {
+        return m_manager.createBundleAdapterService(bundleStateMask, bundleFilter, adapterImplementation, adapterInterface, adapterProperties, propagate);
+    }
 
     /**
      * Cleans up all services and their dependencies.
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 b5e1868..f608e16 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
@@ -186,7 +186,7 @@
      * It will also inherit all dependencies, and if you declare the original
      * service as a member it will be injected.
      * 
-     * @param serviceInterface the service interface to apply the aspect to
+     * @param serviceInterface the service interface to apply the adapter to
      * @param serviceFilter the filter condition to use with the service interface
      * @param adapterInterface the interface to use when registering adapters
      * @param adapterImplementation the implementation of the adapter
@@ -244,11 +244,13 @@
      * @param bundleFilter the filter to apply to the bundle manifest
      * @param adapterImplementation the implementation of the adapter
      * @param adapterInterface the interface to use when registering adapters
+     * @param adapterProperties additional properties to use with the service registration
+     * @param propagate <code>true</code> if properties from the bundle should be propagated to the service
      * @return a service that acts as a factory for generating bundle adapters
      */
-    public Service createBundleAdapterService(int bundleStateMask, String bundleFilter, Object adapterImplementation, Class adapterInterface) {
+    public Service createBundleAdapterService(int bundleStateMask, String bundleFilter, Object adapterImplementation, String adapterInterface, Dictionary adapterProperties, boolean propagate) {
         return createService()
-            .setImplementation(new BundleAdapterImpl(bundleStateMask, bundleFilter, adapterImplementation, adapterInterface))
+            .setImplementation(new BundleAdapterImpl(bundleStateMask, bundleFilter, adapterImplementation, adapterInterface, adapterProperties, propagate))
             .add(createBundleDependency()
                 .setFilter(bundleFilter)
                 .setStateMask(bundleStateMask)
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/BundleDependency.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/BundleDependency.java
index 3466606..87474b6 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/BundleDependency.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/dependencies/BundleDependency.java
@@ -75,4 +75,6 @@
   BundleDependency setFilter(String filter) throws IllegalArgumentException;
 
   BundleDependency setStateMask(int mask);
+  
+  BundleDependency setPropagate(boolean propagate);
 }
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
index 218d2e7..7cf3478 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java
@@ -25,6 +25,7 @@
 import org.apache.felix.dm.DependencyManager;
 import org.apache.felix.dm.resources.Resource;
 import org.apache.felix.dm.service.Service;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
 
 public abstract class AbstractDecorator {
@@ -69,6 +70,24 @@
         }
     }
     
+    // callbacks for bundles
+    public void added(Bundle bundle) {
+        Service newService = createService(new Object[] { bundle });
+        m_services.put(bundle, newService);
+        m_manager.add(newService);
+    }
+    
+    public void removed(Bundle bundle) {
+        Service newService = (Service) m_services.remove(bundle);
+        if (newService == null) {
+            System.out.println("Service should not be null here, dumping stack.");
+            Thread.dumpStack();
+        }
+        else {
+            m_manager.remove(newService);
+        }
+    }
+    
     public void stop() { 
         Iterator i = m_services.values().iterator();
         while (i.hasNext()) {
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterImpl.java
index 6fc4897..2f9a9dc 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterImpl.java
@@ -18,36 +18,80 @@
  */
 package org.apache.felix.dm.impl;
 
-import org.apache.felix.dm.DependencyManager;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.dm.service.Service;
 import org.osgi.framework.Bundle;
 
-public class BundleAdapterImpl {
-	private final int m_stateMask;
-	private final String m_filter;
-	private final Object m_impl;
-	private volatile DependencyManager m_manager;
-	private final Class m_iface;
+public class BundleAdapterImpl extends AbstractDecorator {
+    private volatile Service m_service;
+    private final String m_resourceFilter;
+    private final Object m_adapterImplementation;
+    private final Object m_adapterInterface;
+    private final Dictionary m_adapterProperties;
+    private final boolean m_propagate;
+    private final int m_bundleStateMask;
 
-	public BundleAdapterImpl(int stateMask, String filter, Object impl, Class iface) {
-		m_stateMask = stateMask;
-		m_filter = filter;
-		m_impl = impl;
-		m_iface = iface;
-	}
+    public BundleAdapterImpl(int bundleStateMask, String bundleFilter, Object adapterImplementation, String adapterInterface, Dictionary adapterProperties, boolean propagate) {
+        m_bundleStateMask = bundleStateMask;
+        m_resourceFilter = bundleFilter;
+        m_adapterImplementation = adapterImplementation;
+        m_adapterInterface = adapterInterface;
+        m_adapterProperties = adapterProperties;
+        m_propagate = propagate;
+    }
+
+    public BundleAdapterImpl(int bundleStateMask, String bundleFilter, Object adapterImplementation, String[] adapterInterfaces, Dictionary adapterProperties, boolean propagate) {
+        m_bundleStateMask = bundleStateMask;
+        m_resourceFilter = bundleFilter;
+        m_adapterImplementation = adapterImplementation;
+        m_adapterInterface = adapterInterfaces;
+        m_adapterProperties = adapterProperties;
+        m_propagate = propagate;
+    }       
 	
-	public void added(Bundle bundle) {
-		// TODO decorator be smarter:
-		m_manager.add(m_manager.createService()
-			.setInterface(m_iface.getName(), null)
-			.setImplementation(m_impl)
-			.add(m_manager.createBundleDependency()
-				.setBundle(bundle)
-				.setStateMask(m_stateMask)
-				.setRequired(true)
-				)
-			);
-	}
-
-	public void removed(Bundle bundle) {
+	public Service createService(Object[] properties) {
+	    Bundle bundle = (Bundle) properties[0];
+	    Properties props = new Properties();
+        if (m_adapterProperties != null) {
+            Enumeration e = m_adapterProperties.keys();
+            while (e.hasMoreElements()) {
+                Object key = e.nextElement();
+                props.put(key, m_adapterProperties.get(key));
+            }
+        }
+        List dependencies = m_service.getDependencies();
+        // the first dependency is always the dependency on the bundle, which
+        // will be replaced with a more specific dependency below
+        dependencies.remove(0);
+        if (m_adapterInterface instanceof String) {
+            return m_manager.createService()
+                .setInterface((String) m_adapterInterface, props)
+                .setImplementation(m_adapterImplementation)
+                .add(dependencies)
+                .add(m_manager.createBundleDependency()
+                    .setBundle(bundle)
+                    .setPropagate(m_propagate)
+                    .setCallbacks(null, "changed", null)
+                    .setAutoConfig(true)
+                    .setRequired(true)
+                );
+        }
+        else {
+            return m_manager.createService()
+                .setInterface((String[]) m_adapterInterface, props)
+                .setImplementation(m_adapterImplementation)
+                .add(dependencies)
+                .add(m_manager.createBundleDependency()
+                    .setBundle(bundle)
+                    .setPropagate(m_propagate)
+                    .setCallbacks(null, "changed", null)
+                    .setAutoConfig(true)
+                    .setRequired(true)
+                );
+        }
 	}
 }
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 ab748a7..8bb09b9 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,11 +18,13 @@
  */
 package org.apache.felix.dm.impl.dependencies;
 
+import java.lang.reflect.Proxy;
 import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.List;
 
 import org.apache.felix.dm.dependencies.BundleDependency;
+import org.apache.felix.dm.impl.DefaultNullObject;
 import org.apache.felix.dm.impl.Logger;
 import org.apache.felix.dm.impl.tracker.BundleTracker;
 import org.apache.felix.dm.impl.tracker.BundleTrackerCustomizer;
@@ -49,6 +51,11 @@
 	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;
+
     
     public BundleDependencyImpl(BundleContext context, Logger logger) {
         super(logger);
@@ -297,7 +304,7 @@
     public synchronized BundleDependency setCallbacks(Object instance, String added, String changed, String removed) {
         ensureNotActive();
         // if at least one valid callback is specified, we turn off auto configuration
-        if (added != null || removed != null || changed != null) {
+        if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
             setAutoConfig(false);
         }
         m_callbackInstance = instance;
@@ -315,6 +322,15 @@
     public synchronized BundleDependency setAutoConfig(boolean autoConfig) {
         ensureNotActive();
         m_autoConfig = autoConfig;
+        m_autoConfigInvoked = true;
+        return this;
+    }
+
+    public synchronized BundleDependency setAutoConfig(String instanceName) {
+        ensureNotActive();
+        m_autoConfig = (instanceName != null);
+        m_autoConfigInstance = instanceName;
+        m_autoConfigInvoked = true;
         return this;
     }
     
@@ -323,7 +339,13 @@
         setIsRequired(required);
         return this;
     }
-
+    
+    public BundleDependency setPropagate(boolean propagate) {
+        ensureNotActive();
+        m_propagate = propagate;
+        return this;
+    }
+    
 	public BundleDependency setBundle(Bundle bundle) {
 		m_bundleId = bundle.getBundleId();
 		return this;
@@ -359,18 +381,53 @@
     }
 
     public Object getAutoConfigInstance() {
-        // TODO Auto-generated method stub
-        return null;
+        return lookupBundle();
     }
 
+    public Object lookupBundle() {
+        Object service = null;
+        if (m_isStarted) {
+            service = getBundle();
+        }
+        else {
+            Bundle[] bundles = m_context.getBundles();
+            for (int i = 0; i < bundles.length; i++) {
+                if ((bundles[i].getState() & m_stateMask) > 0) {
+                    if (m_filter.match(bundles[i].getHeaders())) {
+                        service = bundles[i];
+                        break;
+                    }
+                }
+            }
+        }
+        if (service == null && isAutoConfig()) {
+            // TODO does it make sense to add support for custom bundle impls?
+//            service = getDefaultImplementation();
+            if (service == null) {
+                service = getNullObject();
+            }
+        }
+        return service;
+    }
+
+    private Object getNullObject() {
+        if (m_nullObject == null) {
+            try {
+                m_nullObject = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Bundle.class }, new DefaultNullObject()); 
+            }
+            catch (Exception e) {
+                m_logger.log(Logger.LOG_ERROR, "Could not create null object for Bundle.", e);
+            }
+        }
+        return m_nullObject;
+    }
+    
     public String getAutoConfigName() {
-        // TODO Auto-generated method stub
-        return null;
+        return m_autoConfigInstance;
     }
 
     public Class getAutoConfigType() {
-        // TODO Auto-generated method stub
-        return null;
+        return Bundle.class;
     }
 
     public void invokeAdded(DependencyService service) {
@@ -396,7 +453,6 @@
     }
 
     public boolean isPropagated() {
-        // TODO Auto-generated method stub
-        return false;
+        return m_propagate;
     }
 }