FELIX-987 implemented the request as documented, FELIX-992 merged the patch, resolved some issues findbugs found in the code.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@759760 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/pom.xml b/dependencymanager/pom.xml
index 17fdefb..4e6ea3d 100644
--- a/dependencymanager/pom.xml
+++ b/dependencymanager/pom.xml
@@ -58,7 +58,6 @@
             <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
             <Export-Package>org.apache.felix.dependencymanager</Export-Package>
             <Import-Package>!org.apache.felix.dependencymanager,*</Import-Package>
-            <Include-Resource>META-INF/LICENSE=LICENSE,META-INF/NOTICE=NOTICE,org/osgi/util/tracker/=target/classes/org/osgi/util/tracker</Include-Resource>
           </instructions>
         </configuration>
       </plugin>
diff --git a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/Logger.java b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/Logger.java
index f7409d3..ab85366 100644
--- a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/Logger.java
+++ b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/Logger.java
@@ -143,7 +143,7 @@
      * there will never be a log service present since the system bundle is
      * started before every other bundle.
      */
-    private void startListeningForLogService() {
+    private synchronized void startListeningForLogService() {
         // Add a service listener for log services.
         try {
             m_context.addServiceListener(this, "(objectClass=org.osgi.service.log.LogService)");
diff --git a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java
index 43946ff..b7d40d3 100644
--- a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java
+++ b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java
@@ -22,15 +22,17 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.util.AbstractMap;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 /**
  * Service dependency that can track an OSGi service.
@@ -40,14 +42,14 @@
 public class ServiceDependency implements Dependency, ServiceTrackerCustomizer, ServiceComponentDependency {
     private boolean m_isRequired;
     private Service m_service;
-    private ServiceTracker m_tracker;
+    private volatile ServiceTracker m_tracker;
     private BundleContext m_context;
     private boolean m_isAvailable;
-    private Class m_trackedServiceName;
+    private volatile Class m_trackedServiceName;
     private Object m_nullObject;
-    private String m_trackedServiceFilter;
-    private ServiceReference m_trackedServiceReference;
-    private boolean m_isStarted;
+    private volatile String m_trackedServiceFilter;
+    private volatile ServiceReference m_trackedServiceReference;
+    private volatile boolean m_isStarted;
     private Object m_callbackInstance;
     private String m_callbackAdded;
     private String m_callbackChanged;
@@ -83,6 +85,78 @@
         }
     };
     
+    // Class used to wrap service properties behing a Map
+    private final static class ServicePropertiesMapEntry implements Map.Entry {
+        private final String m_key;
+        private Object m_value;
+
+        public ServicePropertiesMapEntry(String key, Object value) {
+            m_key = key;
+            m_value = value;
+        }
+
+        public Object getKey() {
+            return m_key;
+        }
+
+        public Object getValue() {
+            return m_value;
+        }
+
+        public String toString() {
+            return m_key + "=" + m_value;
+        }
+
+        public Object setValue(Object value) {
+            Object oldValue = m_value;
+            m_value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry)) {
+                return false;
+            }
+            Map.Entry e = (Map.Entry) o;
+            return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
+        }
+
+        public int hashCode() {
+            return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
+        }
+
+        private static final boolean eq(Object o1, Object o2) {
+            return (o1 == null ? o2 == null : o1.equals(o2));
+        }
+    }
+
+    // Class used to wrap service properties behing a Map
+    private final static class ServicePropertiesMap extends AbstractMap {
+        private final ServiceReference m_ref;
+
+        public ServicePropertiesMap(ServiceReference ref) {
+            m_ref = ref;
+        }
+
+        public Object get(Object key) {
+            return m_ref.getProperty(key.toString());
+        }
+
+        public int size() {
+            return m_ref.getPropertyKeys().length;
+        }
+
+        public Set entrySet() {
+            Set set = new HashSet();
+            String[] keys = m_ref.getPropertyKeys();
+            for (int i = 0; i < keys.length; i++) {
+                set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
+            }
+            return set;
+        }
+    }
+    
+    
     /**
      * Creates a new service dependency.
      * 
@@ -377,8 +451,8 @@
                 trackedServiceName = m_trackedServiceName;
             }
             done = invokeMethod(instance, currentClazz, methodName,
-                new Class[][] {{ServiceReference.class, trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {trackedServiceName}, {Object.class}, {}},
-                new Object[][] {{reference, service}, {reference, service}, {reference}, {service}, {service}, {}},
+                new Class[][] {{ServiceReference.class, trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {trackedServiceName}, {Object.class}, {}, {Map.class}},
+                new Object[][] {{reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference)}},
                 false);
             if (!done) {
                 currentClazz = currentClazz.getSuperclass();
diff --git a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
index a50dfac..3b8204d 100644
--- a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
+++ b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
@@ -26,9 +26,11 @@
 import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import org.osgi.framework.BundleContext;
@@ -86,6 +88,8 @@
 	// internal logging
     private final Logger m_logger;
     private ServiceRegistration m_serviceRegistration;
+    private Map m_autoConfig = new HashMap();
+    private Map m_autoConfigInstance = new HashMap();
 
     public ServiceImpl(BundleContext context, DependencyManager manager, Logger logger) {
     	m_logger = logger;
@@ -97,6 +101,9 @@
         m_callbackStop = "stop";
         m_callbackDestroy = "destroy";
         m_implementation = null;
+        m_autoConfig.put(BundleContext.class, Boolean.TRUE);
+        m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
+        m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
     }
 
     private void calculateStateChanges(final State oldState, final State newState) {
@@ -575,13 +582,15 @@
 		        	if (factory == null) {
                         m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
 		        	}
-		        	try {
-						Method m = factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
-						m_serviceInstance = m.invoke(factory, null);
-					}
-		        	catch (Exception e) {
-	                    m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
-					}
+		        	else {
+    		        	try {
+    						Method m = factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
+    						m_serviceInstance = m.invoke(factory, null);
+    					}
+    		        	catch (Exception e) {
+    	                    m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
+    					}
+		        	}
 	        	}
 	        	if (m_implementation == null) {
                     m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
@@ -591,12 +600,27 @@
 	        	}
 	        }
 	        // configure the bundle context
-	        configureImplementation(BundleContext.class, m_context);
-	        configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
-	        configureImplementation(DependencyManager.class, m_manager);
+	        if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
+	            configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
+	        }
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
+                configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
+            }
     	}
     }
 
+    public void setAutoConfig(Class clazz, boolean autoConfig) {
+        m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
+    }
+    
+    public void setAutoConfig(Class clazz, String instanceName) {
+        m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
+        m_autoConfigInstance.put(clazz, instanceName);
+    }
+    
     private void configureService(State state) {
         // configure all services (the optional dependencies might be configured
         // as null objects but that's what we want at this point)
@@ -612,7 +636,10 @@
         if (m_serviceName != null) {
             ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
             m_registration = wrapper;
-            configureImplementation(ServiceRegistration.class, wrapper);
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            
             // service name can either be a string or an array of strings
             ServiceRegistration registration;
 
diff --git a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java
index c79257d..83c4b4b 100644
--- a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java
+++ b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java
@@ -162,7 +162,7 @@
         this.trackReference = null;
         this.trackClass = clazz;
         this.customizer = (customizer == null) ? this : customizer;
-        this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
         try {
             this.filter = context.createFilter(listenerFilter);
         }