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 2014/09/30 22:30:23 UTC

svn commit: r1628547 [2/2] - in /felix/sandbox/pderop/dependencymanager-prototype: cnf/ org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/ org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests...

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -21,6 +21,7 @@ package org.apache.felix.dm.impl;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Proxy;
 import java.util.Dictionary;
+import java.util.Set;
 
 import org.apache.felix.dm.BundleDependency;
 import org.apache.felix.dm.ComponentDependencyDeclaration;
@@ -74,23 +75,15 @@ public class BundleDependencyImpl extend
     }
     
     @Override
-    public void start() {
-        boolean wasStarted = isStarted();
-        super.start();
-        if (!wasStarted) {
-            m_tracker = new BundleTracker(m_context, m_stateMask, this);
-            m_tracker.open();
-        }
+    protected void startTracking() {
+        m_tracker = new BundleTracker(m_context, m_stateMask, this);
+        m_tracker.open();
     }
 
     @Override
-    public void stop() {
-        boolean wasStarted = isStarted();
-        super.stop();
-        if (wasStarted) {
-            m_tracker.close();
-            m_tracker = null;
-        }            
+    protected void stopTracking() {
+        m_tracker.close();
+        m_tracker = null;
     }
 
     @Override
@@ -179,19 +172,15 @@ public class BundleDependencyImpl extend
     }
     
     @Override
-    public Object getAutoConfigInstance() {
-        return getService();
-    }
-
-    @Override
     public Class<?> getAutoConfigType() {
         return Bundle.class;
     }
-    
+        
     @Override
     public Dictionary<?,?> getProperties() {
-        Bundle bundle = (Bundle) getService();
-        if (bundle != null) {
+        Event event = getService();
+        if (event != null) {
+            Bundle bundle = (Bundle) event.getEvent();
             if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
                 try {
                     return (Dictionary<?,?>) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Bundle.class }}, new Object[][] {{ bundle }});
@@ -214,29 +203,9 @@ public class BundleDependencyImpl extend
     }
     
     @Override
-    protected Object getService() {
-        Bundle service = null;
-        if (isStarted()) {
-            BundleEventImpl be = (BundleEventImpl) m_component.getDependencyEvent(this);
-            return be != null ? be.getBundle() : null;
-        }
-        else {
-            Bundle[] bundles = m_context.getBundles();
-            for (int i = 0; i < bundles.length; i++) {
-                if ((bundles[i].getState() & m_stateMask) > 0) {
-                    Filter filter = m_filter;
-                    if (filter == null) {
-                        service = bundles[i];
-                        break;
-                    }
-                    else if (filter.match(bundles[i].getHeaders())) {
-                        service = bundles[i];
-                        break;
-                    }
-                }
-            }
-        }
-        if (service == null && isAutoConfig()) {
+    public Object getDefaultService() {
+        Object service = null;
+        if (isAutoConfig()) {
             // TODO does it make sense to add support for custom bundle impls?
 //            service = getDefaultImplementation();
             if (service == null) {
@@ -245,7 +214,7 @@ public class BundleDependencyImpl extend
         }
         return service;
     }
-    
+
     private Bundle getNullObject() {
         if (m_nullObject == null) {
             try {

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Dictionary;
+
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleEvent;
 
@@ -30,6 +32,16 @@ public class BundleEventImpl extends Eve
         m_event = event;
     }
     
+    @Override
+    public Object getEvent() {
+        return getBundle();
+    }
+    
+    @Override
+    public Dictionary getProperties() {
+        return m_bundle.getHeaders();
+    }
+    
     public Bundle getBundle() {
         return m_bundle;
     }

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java Tue Sep 30 20:30:21 2014
@@ -29,6 +29,7 @@ import java.lang.reflect.InvocationTarge
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -71,8 +72,7 @@ public class ComponentImpl implements Co
     private final Logger m_logger;
     private final BundleContext m_context;
     private final DependencyManager m_manager;
-    private final Object SYNC = new Object();
-	private Object m_componentDefinition;
+    private Object m_componentDefinition;
 	private Object m_componentInstance;
     private volatile Object m_serviceName;
     private volatile Dictionary m_serviceProperties;
@@ -81,6 +81,7 @@ public class ComponentImpl implements Co
     private final Map m_autoConfigInstance = new ConcurrentHashMap();
     private final long m_id;
     private static AtomicLong m_idGenerator = new AtomicLong();
+    // Holds all the services of a given dependency context. Caution: the last entry in the skiplist is the highest ranked service.
     private final Map<DependencyContext, ConcurrentSkipListSet<Event>> m_dependencyEvents = new HashMap<>();
     private volatile boolean m_active;
     
@@ -248,87 +249,110 @@ public class ComponentImpl implements Co
 		if (debug) {
 			System.out.println("*" + debugKey + " T" + Thread.currentThread().getId() + " handleAdded " + e);
 		}
-
-	    Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
-	    dependencyEvents.add(e);
-	    dc.setAvailable(true);
-	    
-        switch (m_state) {
-        case WAITING_FOR_REQUIRED:
-            if (dc.isRequired())
-                handleChange();
-            break;
-        case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
-            if (!dc.isInstanceBound()) {
-                if (dc.isRequired()) {
-                    dc.invokeAdd(e);
-                }
-                updateInstance(dc);
-            }
-            else {
+		
+		Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
+		dependencyEvents.add(e);		
+		dc.setAvailable(true);
+		
+		// Recalculate state changes. We only do this if the dependency is started. If the dependency is not started,
+		// it means it is actually starting. And in this case, we don't recalculate state changes now. We'll do it 
+		// once all currently available services are found, and then after, we'll recalculate state change 
+		// (see the startDependencies method).
+		// All this is done for two reasons:
+		// 1- optimization: it is preferable to recalculate state changes once we know about all currently available dependency services
+		//    (after the tracker has returned from its open method).
+		// 2- This also allows to determine the list of currently available dependency services from within the component start method callback
+		//    (this will be extremely useful when porting the Felix SCR on top of DM4).
+		
+		if (dc.isStarted()) {
+            switch (m_state) {
+            case WAITING_FOR_REQUIRED:
                 if (dc.isRequired())
                     handleChange();
+                break;
+            case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+                if (!dc.isInstanceBound()) {
+                    if (dc.isRequired()) {
+                        dc.invokeAdd(e);
+                    }
+                    updateInstance(dc, e, false, true);
+                }
+                else {
+                    if (dc.isRequired())
+                        handleChange();
+                }
+                break;
+            case TRACKING_OPTIONAL:
+                dc.invokeAdd(e);
+                updateInstance(dc, e, false, true);
+                break;
+            default:
             }
-            break;
-        case TRACKING_OPTIONAL:
-            dc.invokeAdd(e);
-            updateInstance(dc);
-            break;
-        default:
-        }
+		}
 	}
-	
+		
     @Override
     public void handleChanged(DependencyContext dc, Event e) {
         Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
         dependencyEvents.remove(e);
         dependencyEvents.add(e);
         
-        switch (m_state) {
-        case TRACKING_OPTIONAL:
-            dc.invokeChange(e);
-            updateInstance(dc);
-            break;
-
-        case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
-            if (!dc.isInstanceBound()) {
+        if (dc.isStarted()) {
+            switch (m_state) {
+            case TRACKING_OPTIONAL:
                 dc.invokeChange(e);
-                updateInstance(dc);
+                updateInstance(dc, e, true, false);
+                break;
+
+            case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+                if (!dc.isInstanceBound()) {
+                    dc.invokeChange(e);
+                    updateInstance(dc, e, true, false);
+                }
+                break;
             }
-            break;
         }
     }
 
     @Override
     public void handleRemoved(DependencyContext dc, Event e) {
+        // Check if the dependency is still available.
         Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
         int size = dependencyEvents.size();
         if (dependencyEvents.contains(e)) {
             size --; // the dependency is currently registered and is about to be removed.
         }
         dc.setAvailable(size > 0);
-        handleChange();
         
-        // Now, really remove the dependency event, because next, we'll possibly invoke updateInstance, which will
-        // trigger getAutoConfigInstance, and at this point, we don't want to return the removed service, which might
-        // be the highest ranked service.
-        dependencyEvents.remove(e);
+        // If the dependency is now unavailable, we have to recalculate state change. This will result in invoking the
+        // "removed" callback with the removed dependency (which we have not yet removed from our dependency events list.).
+        // But we don't recalculate the state if the dependency is not started (if not started, it means that it is currently starting,
+        // and the tracker is detecting a removed service).
+        if (size == 0 && dc.isStarted()) {
+            handleChange();
+        }
+        
+        // Now, really remove the dependency event.
+        dependencyEvents.remove(e);    
         
-        // Depending on the state, we possible have to invoke the callbacks and update the component instance.        
-        switch (m_state) {
-        case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
-            if (! dc.isInstanceBound()) {
-                if (dc.isRequired()) {            
-                    dc.invokeRemove(e);
-                }
-                updateInstance(dc);
-            }
-            break;
-        case TRACKING_OPTIONAL:
-            dc.invokeRemove(e);
-            updateInstance(dc);
-            break;
-        default:
+        // Only check if the component instance has to be updated if the dependency is really started.
+        if (dc.isStarted()) {
+            // Depending on the state, we possible have to invoke the callbacks and update the component instance.        
+            switch (m_state) {
+            case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+                if (!dc.isInstanceBound()) {
+                    if (dc.isRequired()) {
+                        dc.invokeRemove(e);
+                    }
+                    updateInstance(dc, e, false, false);
+                }
+                break;
+            case TRACKING_OPTIONAL:
+                dc.invokeRemove(e);
+                updateInstance(dc, e, false, false);
+                break;
+            default:
+            }
         }
     }
 
@@ -337,23 +361,25 @@ public class ComponentImpl implements Co
         dependencyEvents.remove(event);
         dependencyEvents.add(newEvent);
                 
-        // Depending on the state, we possible have to invoke the callbacks and update the component instance.        
-        switch (m_state) {
-        case WAITING_FOR_REQUIRED:
-            // No need to swap, we don't have yet injected anything
-            break;
-        case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
-            // Only swap *non* instance-bound dependencies
-            if (!dc.isInstanceBound()) {
-                if (dc.isRequired()) {
-                    dc.invokeSwap(event, newEvent);
-                }
-            }
-            break;
-        case TRACKING_OPTIONAL:
-            dc.invokeSwap(event, newEvent);
-            break;
-        default:
+        if (dc.isStarted()) {
+            // Depending on the state, we possible have to invoke the callbacks and update the component instance.        
+            switch (m_state) {
+            case WAITING_FOR_REQUIRED:
+                // No need to swap, we don't have yet injected anything
+                break;
+            case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+                // Only swap *non* instance-bound dependencies
+                if (!dc.isInstanceBound()) {
+                    if (dc.isRequired()) {
+                        dc.invokeSwap(event, newEvent);
+                    }
+                }
+                break;
+            case TRACKING_OPTIONAL:
+                dc.invokeSwap(event, newEvent);
+                break;
+            default:
+            }
         }
     }
     
@@ -363,6 +389,11 @@ public class ComponentImpl implements Co
         return events.size() > 0 ? events.last() : null;
     }
     
+    @Override
+    public Set<Event> getDependencyEvents(DependencyContext dc) {
+        return m_dependencyEvents.get(dc);
+    }
+
     public Component setAutoConfig(Class clazz, boolean autoConfig) {
         m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
         return this;
@@ -530,12 +561,21 @@ public class ComponentImpl implements Co
         }
         return false;
     }
-
-    private void updateInstance(DependencyContext d) {
-        if (d.isAutoConfig()) {
-            configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+    
+    /**
+     * Updates the component instance(s).
+     * @param dc the dependency context for the updating dependency service
+     * @param event the event holding the updating service (service + properties)
+     * @param update true if dependency service properties are updating, false if not. If false, it means
+     *        that a dependency service is being added or removed. (see the "add" flag).
+     * @param add true if the dependency service has been added, false if it has been removed. This flag is 
+     *        ignored if the "update" flag is true (because the dependency properties are just being updated).
+     */
+    private void updateInstance(DependencyContext dc, Event event, boolean update, boolean add) {
+        if (dc.isAutoConfig()) {
+            updateImplementation(dc.getAutoConfigType(), dc, dc.getAutoConfigName(), event, update, add);
         }
-        if (d.isPropagated() && m_registration != null) {
+        if (dc.isPropagated() && m_registration != null) {
             m_registration.setProperties(calculateServiceProperties());
         }
     }
@@ -563,6 +603,8 @@ public class ComponentImpl implements Co
             }
             d.start();
         }
+        // The started dependencies has probably called our handleAdded method: we now have to run our state machine.
+        handleChange();
     }
     
     private void stopDependencies() {
@@ -740,7 +782,7 @@ public class ComponentImpl implements Co
     private void invokeAutoConfigDependencies() {
         for (DependencyContext d : m_dependencies) {
             if (d.isAutoConfig() && !d.isInstanceBound()) {
-                configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+                configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
             }
         }
     }
@@ -748,7 +790,7 @@ public class ComponentImpl implements Co
     private void invokeAutoConfigInstanceBoundDependencies() {
         for (DependencyContext d : m_dependencies) {
             if (d.isAutoConfig() && d.isInstanceBound()) {
-                configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+                configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
             }
         }
     }
@@ -890,46 +932,39 @@ public class ComponentImpl implements Co
      * and for each of these fields, the specified instance is filled in.
      *
      * @param clazz the class to search for
-     * @param instance the instance to fill in
+     * @param inject the object to fill in the implementation class(es) field
      * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
      */
-    private void configureImplementation(Class clazz, Object instance, String instanceName) {
-        Object[] instances = getInstances();
-        if (instances != null && instance != null && clazz != null) {
-            for (int i = 0; i < instances.length; i++) {
-                Object serviceInstance = instances[i];
-                Class serviceClazz = serviceInstance.getClass();
-                if (Proxy.isProxyClass(serviceClazz)) {
-                    serviceInstance = Proxy.getInvocationHandler(serviceInstance);
-                    serviceClazz = serviceInstance.getClass();
-                }
-                while (serviceClazz != null) {
-                    Field[] fields = serviceClazz.getDeclaredFields();
-                    for (int j = 0; j < fields.length; j++) {
-                        Field field = fields[j];
-                        Class type = field.getType();
-                        if ((instanceName == null && type.equals(clazz)) 
-                            || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
-                            try {
-                                field.setAccessible(true);
-                                // synchronized makes sure the field is actually written to immediately
-                                synchronized (SYNC) {
-                                    field.set(serviceInstance, instance);
-                                }
-                            }
-                            catch (Exception e) {
-                                m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
-                                return;
-                            }
-                        }
-                    }
-                    serviceClazz = serviceClazz.getSuperclass();
-                }
-            }
-        }
+    private void configureImplementation(Class clazz, Object inject, String fieldName) {
+        Object[] targets = getInstances();
+        FieldUtil.injectField(targets, fieldName, clazz, inject, m_logger);
     }
 
-	@Override
+    private void configureImplementation(Class clazz, DependencyContext dc, String fieldName) {
+        Object[] targets = getInstances();
+        FieldUtil.injectDependencyField(targets, fieldName, clazz, dc, m_logger);
+    }
+
+    /**
+     * Update the component instances.
+     *
+     * @param clazz the class of the dependency service to inject in the component instances
+     * @param dc the dependency context for the updating dependency service
+     * @param fieldName the component instances fieldname to fill in with the updated dependency service
+     * @param event the event holding the updating service (service + properties)
+     * @param update true if dependency service properties are updating, false if not. If false, it means
+     *        that a dependency service is being added or removed. (see the "add" flag).
+     * @param add true if the dependency service has been added, false if it has been removed. This flag is 
+     *        ignored if the "update" flag is true (because the dependency properties are just being updated).
+     */
+    private void updateImplementation(Class clazz, DependencyContext dc, String fieldName, Event event, boolean update,
+        boolean add)
+    {
+        Object[] targets = getInstances();
+        FieldUtil.updateDependencyField(targets, fieldName, update, add, clazz, event, dc, m_logger);
+    }
+
+    @Override
 	public ServiceRegistration getServiceRegistration() {
         return m_registration;
 	}

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -21,6 +21,7 @@ package org.apache.felix.dm.impl;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Dictionary;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.felix.dm.ConfigurationDependency;
@@ -77,8 +78,7 @@ public class ConfigurationDependencyImpl
     }
 
     @Override
-    public void start() {
-        super.start();
+    protected void startTracking() {
         if (m_context != null) { // If null, we are in a test environment
 	        Properties props = new Properties();
 	        props.put(Constants.SERVICE_PID, m_pid);
@@ -91,8 +91,7 @@ public class ConfigurationDependencyImpl
     }
 
     @Override
-    public void stop() {
-        super.stop();
+    protected void stopTracking() {
         if (m_registration != null) {
             try {
                 m_registration.unregister();
@@ -118,12 +117,7 @@ public class ConfigurationDependencyImpl
     public String getType() {
         return "configuration";
     }
-
-    @Override
-    protected Object getService() {
-        return m_settings;
-    }
-        
+            
     public ConfigurationDependency add(PropertyMetaData properties)
     {
         createMetaTypeImpl();
@@ -190,17 +184,17 @@ public class ConfigurationDependencyImpl
 
         if ((oldSettings == null) && (settings != null)) {
             // Notify the component that our dependency is available.
-            add(new EventImpl());
+            add(new ConfigurationEventImpl(m_pid, settings));
         }
         else if ((oldSettings != null) && (settings != null)) {
             // Notify the component that our dependency has changed.
-            change(new EventImpl());
+            change(new ConfigurationEventImpl(m_pid, settings));
         }
         else if ((oldSettings != null) && (settings == null)) {
             // Notify the component that our dependency has been removed.
             // Notice that the component will be stopped, and then all required dependencies will be unbound
             // (including our configuration dependency).
-            remove(new EventImpl());
+            remove(new ConfigurationEventImpl(m_pid, oldSettings));
         }
     }
 

Added: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java?rev=1628547&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java Tue Sep 30 20:30:21 2014
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.impl;
+
+import java.util.Dictionary;
+
+public class ConfigurationEventImpl extends EventImpl {
+    private final Dictionary<?,?> m_conf;
+    private final String m_pid;
+    
+    public ConfigurationEventImpl(String pid, Dictionary<?,?> conf) {
+        m_pid = pid;
+        m_conf = conf;
+    }
+    
+    public String getPid() {
+        return m_pid;
+    }
+    
+    public Dictionary<?,?> getConf() {
+        return m_conf;
+    }
+    
+    @Override
+    public Object getEvent() {
+        return m_conf;
+    }
+}

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -18,7 +18,11 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Collection;
 import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.felix.dm.ComponentDependencyDeclaration;
 import org.apache.felix.dm.Dependency;
@@ -143,14 +147,18 @@ public class DependencyImpl<T extends De
 
 	@Override
 	public void start() {
-        m_isStarted = true;
-		// you would normally start tracking this dependency here, so for example
-		// for a service dependency you might start a service tracker here
+	    if (! m_isStarted) {
+	        startTracking();
+	        m_isStarted = true;
+	    }
 	}
 
 	@Override
 	public void stop() {
-		m_isStarted = false;
+	    if (m_isStarted) {
+	        stopTracking();
+	        m_isStarted = false;
+	    }
 	}
 
 	@Override
@@ -272,11 +280,6 @@ public class DependencyImpl<T extends De
     }
     
     @Override
-    public Object getAutoConfigInstance() {
-        return getService();
-    }
-    
-    @Override
     public boolean isAutoConfig() {
         return m_autoConfig;
     }
@@ -313,11 +316,49 @@ public class DependencyImpl<T extends De
     	}
     }
    
-    protected Object getService() {
-        // only real dependencies can return actual service.
-        return null;
+    @Override
+    public Event getService() {
+        Event event = m_component.getDependencyEvent(this);
+        if (event == null) {
+            Object defaultService = getDefaultService();
+            if (defaultService != null) {
+                event = new EventImpl(0, defaultService);
+            }
+        }
+        return event;
+    }
+    
+    @Override
+    public void copyToCollection(Collection<Object> services) {
+        Set<Event> events = m_component.getDependencyEvents(this);
+        if (events.size() > 0) {
+            for (Event e : events) {
+                services.add(e.getEvent());
+            }
+        } else {
+            Object defaultService = getDefaultService();
+            if (defaultService != null) {
+                services.add(defaultService);
+            }
+        }
     }
     
+    @Override
+    public void copyToMap(Map<Object, Dictionary> map) {
+        Set<Event> events = m_component.getDependencyEvents(this);
+        if (events.size() > 0) {
+            for (Event e : events) {
+                map.put(e.getEvent(), e.getProperties());
+            }
+        } else {
+            Object defaultService = getDefaultService();
+            if (defaultService != null) {
+                map.put(defaultService, new Hashtable());
+            }
+        }
+    }
+    
+    @Override
     public boolean isStarted() {
     	return m_isStarted;
     }
@@ -337,9 +378,19 @@ public class DependencyImpl<T extends De
 		return m_component;
 	}
 	
+    protected Object getDefaultService() {
+        return null;
+    }
+        
     protected void ensureNotActive() {
         if (isStarted()) {
             throw new IllegalStateException("Cannot modify state while active.");
         }
     }
+    
+    protected void startTracking() {
+    }
+    
+    protected void stopTracking() {
+    }
 }

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,23 +18,32 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
+
 import org.apache.felix.dm.context.Event;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 
 /* in real life, this event might contain a service reference and service instance
  * or something similar
  */
 public class EventImpl implements Event {
 	private final int m_id;
+	private final Object m_event;    // the actual event object (a Service, a Bundle, a Configuration, etc ...)
+	private final static Dictionary m_emptyProperties = new Hashtable();
 
 	public EventImpl() {
 		this(1);
 	}
 	/** By constructing events with different IDs, we can simulate different unique instances. */
 	public EventImpl(int id) {
-		m_id = id;
+		this (id, null);
+	}
+	
+	public EventImpl(int id, Object event) {
+	    m_id = id;
+	    m_event = event;
 	}
+	
 
 	@Override
 	public int hashCode() {
@@ -66,4 +75,14 @@ public class EventImpl implements Event 
     @Override
     public void close() {
     }
+    
+    @Override
+    public Object getEvent() {
+        return m_event;
+    }
+    
+    @Override
+    public Dictionary getProperties() {
+        return m_emptyProperties;
+    }
 }

Added: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java?rev=1628547&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java Tue Sep 30 20:30:21 2014
@@ -0,0 +1,285 @@
+package org.apache.felix.dm.impl;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Map;
+
+import org.apache.felix.dm.context.DependencyContext;
+import org.apache.felix.dm.context.Event;
+
+/**
+ * Reflection Helper methods, used to inject autoconfig fields in component instances.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldUtil {
+    /**
+     * Callbacks for fields to be injected
+     */
+    private interface FieldFunction {
+        // Inject an updated service in the given field for the the given target component instance.
+        void injectField(Field f, Object target);
+
+        // Inject a Collection field  in the given field for the the given target component instance.
+        void injectCollectionField(Field f, Object target);
+
+        // Inject a Map field (key = dependency service, value = Dictionary with dependency service properties).
+        void injectMapField(Field f, Object target);
+    }
+
+    /**
+     * Injects some component instances (on a given field, if provided), with an object of a given class.
+     * @param targets the component instances to fill in
+     * @param fieldName the fieldname, or null. If null, the field must exaclty match the injected service classname.
+     * @param clazz the injected service class
+     * @param service the injected service
+     * @param logger the component logger.
+     */
+    public static void injectField(Object[] targets, String fieldName, Class<?> clazz, final Object service,
+        final Logger logger)
+    {
+        if (service == null) {
+            return;
+        }
+        mapField(true, clazz, targets, fieldName, logger, new FieldFunction() {
+            public void injectField(Field f, Object target) {
+                try {
+                    f.setAccessible(true);
+                    f.set(target, service);
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+
+            public void injectCollectionField(Field f, Object target) { // never called
+            }
+
+            public void injectMapField(Field f, Object target) { // never called
+            }
+        });
+    }
+
+    /**
+     * Injects a dependency service in some component instances.
+     * Here, we'll inject the dependency services in the component if the field is of the same type of the injected services,
+     * or if the field is a Collection of the injected service, or if the field is a Map<Injected Service class, Dictionary).
+     * @param targets the component instances to fill in
+     * @param fieldName the fieldname, or null. If null, the field must exaclty match the injected service classname.
+     * @param clazz the injected service class
+     * @param service the injected service
+     * @param logger the component logger.
+     */
+    public static void injectDependencyField(Object[] targets, String fieldName, Class<?> clazz,
+        final DependencyContext dc, final Logger logger)
+    {
+        final Event event = dc.getService();
+        if (event == null) {
+            return;
+        }
+        mapField(false, clazz, targets, fieldName, logger, new FieldFunction() {
+            public void injectField(Field f, Object target) {
+                try {
+                    f.setAccessible(true);
+                    f.set(target, event.getEvent());
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+
+            public void injectCollectionField(Field f, Object target) {
+                f.setAccessible(true);
+                Class<?> type = f.getType();
+
+                try {
+                    Collection<Object> coll = (Collection) type.newInstance();
+                    dc.copyToCollection(coll);
+                    f.set(target, coll);
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+
+            @Override
+            public void injectMapField(Field f, Object target) {
+                f.setAccessible(true);
+                Class<?> type = f.getType();
+
+                try {
+                    Map map = (Map) type.newInstance();
+                    dc.copyToMap(map);
+                    f.set(target, map);
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Adds, or removes, or update some component instances with an updated dependency service
+     * @param targets the component instances to fill in with the updated service
+     * @param fieldName the component instance fieldname 
+     * @param update true if it's a dependency service update, false if the dependency service is added or removed
+     * @param add true if the dependency service has been added, false the dependency service has been removed. 
+     * This flag is ignored if the "update" parameter is "true". 
+     * @param clazz the clazz of the dependency service
+     * @param event the event holding the dependency service
+     * @param dc the dependency service context
+     * @param logger the logger used when problems occure.
+     */
+    public static void updateDependencyField(Object[] targets, String fieldName, final boolean update,
+        final boolean add, Class<?> clazz, final Event event, final DependencyContext dc, final Logger logger)
+    {
+        mapField(false, clazz, targets, fieldName, logger, new FieldFunction() {
+            public void injectField(Field f, Object target) {
+                try {
+                    f.setAccessible(true);
+                    f.set(target, dc.getService().getEvent());
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+
+            public void injectCollectionField(Field f, Object target) {
+                if (update) {
+                    return;
+                }
+
+                f.setAccessible(true);
+                Class<?> type = f.getType();
+
+                try {
+                    Collection coll = (Collection) f.get(target);
+                    if (add) {
+                        coll.add(event.getEvent());
+                    } else {
+                        coll.remove(event.getEvent());
+                    }
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+
+            @Override
+            public void injectMapField(Field f, Object target) {
+                f.setAccessible(true);
+                Class<?> type = f.getType();
+
+                try {
+                    Map<Object, Dictionary> map = (Map) f.get(target);
+                    if (add) {
+                        map.put(event.getEvent(), event.getProperties());
+                    } else {
+                        map.remove(event.getEvent());
+                    }
+                } catch (Throwable e) {
+                    logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+                        + target.getClass().getName(), e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Scans component instances for fields having either the same dependency service type, or being a 
+     * Collection of the dependency service, or being a Map<Dependency Service class, Dictionary> (the Dictionary
+     * corresponds to the dependency service properties).
+     * @param strict true if we are only looking for fields having exactly the same type as the dependency service. 
+     * In other words, if strict = true, we don't lookup for fields of "Collection" or "Map" types.
+     * @param clazz the dependency service class
+     * @param targets the component instances
+     * @param fieldName the component instances field name or null
+     * @param logger a logger used when exceptions are occuring
+     * @param func the callback used to notify when we find either a field with the same dependency service type, or
+     * with a "Collection" type, or with a "Map" type.
+     */
+    private static void mapField(boolean strict, Class<?> clazz, Object[] targets, String fieldName, Logger logger,
+        FieldFunction func)
+    {
+        if (targets != null && clazz != null) {
+            for (int i = 0; i < targets.length; i++) {
+                Object target = targets[i];
+                Class<?> targetClass = target.getClass();
+                if (Proxy.isProxyClass(targetClass)) {
+                    target = Proxy.getInvocationHandler(target);
+                    targetClass = target.getClass();
+                }
+                while (targetClass != null) {
+                    Field[] fields = targetClass.getDeclaredFields();
+                    for (int j = 0; j < fields.length; j++) {
+                        Field field = fields[j];
+                        Class<?> fieldType = field.getType();
+
+                        if (fieldName == null) {
+                            // Field type class must match injected service type
+                            if (fieldType.equals(clazz)) {
+                                func.injectField(field, target);
+                            } else if (!strict && mayInjectToCollection(clazz, field, true)) {
+                                func.injectCollectionField(field, target);
+                            } else if (!strict && mayInjectToMap(clazz, field, true)) {
+                                func.injectMapField(field, target);
+                            }
+                        } else if (field.getName().equals(fieldName)) {
+                            // Field type may be a superclass of the service type
+                            if (fieldType.isAssignableFrom(clazz)) {
+                                func.injectField(field, target);
+                            } else if (!strict && mayInjectToCollection(clazz, field, false)) {
+                                func.injectCollectionField(field, target);
+                            } else if (!strict && mayInjectToMap(clazz, field, false)) {
+                                func.injectMapField(field, target);
+                            } else {
+                                logger.log(
+                                    Logger.LOG_ERROR,
+                                    "Could not set field " + field + " in class " + target.getClass().getName()
+                                        + ": the type of the field type should be either assignable from "
+                                        + clazz.getName() + " or Collection, or Map");
+                            }
+                        }
+                    }
+                    targetClass = targetClass.getSuperclass();
+                }
+            }
+        }
+    }
+
+    private static boolean mayInjectToCollection(Class<?> clazz, Field field, boolean strictClassEquality) {
+        Class<?> fieldType = field.getType();
+        if (Collection.class.isAssignableFrom(fieldType)) {
+            ParameterizedType parameterType = (ParameterizedType) field.getGenericType();
+            if (parameterType == null) {
+                return false;
+            }
+            Class<?> parameterizedTypeClass = (Class<?>) parameterType.getActualTypeArguments()[0];
+            return strictClassEquality ? parameterizedTypeClass.equals(clazz)
+                : parameterizedTypeClass.isAssignableFrom(clazz);
+        }
+        return false;
+    }
+
+    private static boolean mayInjectToMap(Class<?> clazz, Field field, boolean strictClassEquality) {
+        Class<?> fieldType = field.getType();
+        if (Map.class.isAssignableFrom(fieldType)) {
+            ParameterizedType parameterType = (ParameterizedType) field.getGenericType();
+            if (parameterType == null) {
+                return false;
+            }
+            Class<?> K = (Class<?>) parameterType.getActualTypeArguments()[0];
+            Class<?> V = (Class<?>) parameterType.getActualTypeArguments()[1];
+
+            if (!V.equals(Dictionary.class)) {
+                return false;
+            }
+            return strictClassEquality ? K.equals(clazz) : K.isAssignableFrom(clazz);
+        }
+        return false;
+    }
+}

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java Tue Sep 30 20:30:21 2014
@@ -20,6 +20,7 @@ package org.apache.felix.dm.impl;
 
 import java.util.Dictionary;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
@@ -311,10 +312,16 @@ public class FilterComponent implements 
         return m_component.getInstances();
     }
     
+    @Override
     public Event getDependencyEvent(DependencyContext dc) {
         return m_component.getDependencyEvent(dc);
     }
     
+    @Override
+    public Set<Event> getDependencyEvents(DependencyContext dc) {
+        return m_component.getDependencyEvents(dc);
+    }
+    
     public ComponentDeclaration getComponentDeclaration() {
         return this;
     }

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -23,6 +23,7 @@ import java.net.URL;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Properties;
+import java.util.Set;
 
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.ComponentDependencyDeclaration;
@@ -61,33 +62,24 @@ public class ResourceDependencyImpl exte
     }
     
     @Override
-    public void start() {
-        boolean wasStarted = isStarted();
-        super.start();
-        if (!wasStarted) {
-            Dictionary props = null;
-            if (m_trackedResource != null) {
+    protected void startTracking() {
+        Dictionary props = null;
+        if (m_trackedResource != null) {
+            props = new Properties();
+            props.put(ResourceHandler.URL, m_trackedResource);
+        } else {
+            if (m_resourceFilter != null) {
                 props = new Properties();
-                props.put(ResourceHandler.URL, m_trackedResource);
-            }
-            else { 
-                if (m_resourceFilter != null) {
-                    props = new Properties();
-                    props.put(ResourceHandler.FILTER, m_resourceFilter);
-                }
+                props.put(ResourceHandler.FILTER, m_resourceFilter);
             }
-            m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
         }
+        m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
     }
 
     @Override
-    public void stop() {
-        boolean wasStarted = isStarted();
-        super.stop();
-        if (wasStarted) {
-            m_registration.unregister();
-            m_registration = null;
-        }
+    protected void stopTracking() {
+        m_registration.unregister();
+        m_registration = null;
     }
 
     public void added(URL resource) {
@@ -130,7 +122,7 @@ public class ResourceDependencyImpl exte
     public void invoke(String method, Event e) {
         ResourceEventImpl re = (ResourceEventImpl) e;
         URL serviceInstance = re.getResource();
-        Dictionary<?,?> resourceProperties = re.getResourceProperties();
+        Dictionary<?,?> resourceProperties = re.getProperties();
        
         m_component.invokeCallbackMethod(getInstances(), method,
             new Class[][] {
@@ -171,12 +163,6 @@ public class ResourceDependencyImpl exte
     }
     
     @Override
-    protected Object getService() {
-        ResourceEventImpl re = (ResourceEventImpl) m_component.getDependencyEvent(this);
-        return re != null ? re.getResource() : null;
-    }
-            
-    @Override
     public Class<?> getAutoConfigType() {
         return URL.class;
     }
@@ -185,7 +171,7 @@ public class ResourceDependencyImpl exte
         ResourceEventImpl re = (ResourceEventImpl) m_component.getDependencyEvent(this);
         if (re != null) {
             URL resource = re.getResource();
-            Dictionary<?,?> resourceProperties = re.getResourceProperties();
+            Dictionary<?,?> resourceProperties = re.getProperties();
             if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
                 try {
                     return (Dictionary<?,?>) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ URL.class }}, new Object[][] {{ resource }});

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java Tue Sep 30 20:30:21 2014
@@ -30,14 +30,20 @@ public class ResourceEventImpl extends E
         m_resourceProperties = resourceProperties;
     }
     
-    public URL getResource() {
-        return m_resource;
+    @Override
+    public Object getEvent() {
+        return getResource();
     }
-    
-    public Dictionary<?, ?> getResourceProperties() {
+
+    @Override
+    public Dictionary getProperties() {
         return m_resourceProperties;
     }
-    
+
+    public URL getResource() {
+        return m_resource;
+    }
+        
     @Override
     public boolean equals(Object obj) {
         if (obj instanceof ResourceEventImpl) {
@@ -45,8 +51,8 @@ public class ResourceEventImpl extends E
             ResourceEventImpl r2 = (ResourceEventImpl) obj;
             boolean match = r1.getResource().equals(r2.getResource());
             if (match) {
-                Dictionary<?,?> d1 = getResourceProperties();
-                Dictionary<?,?> d2 = r2.getResourceProperties();
+                Dictionary<?,?> d1 = getProperties();
+                Dictionary<?,?> d2 = r2.getProperties();
                 
                 if (d1 == null) {
                 	return d2 == null ? match : false;
@@ -64,7 +70,7 @@ public class ResourceEventImpl extends E
         final int prime = 31;
         int result = 1;
         result = prime * result + getResource().hashCode();
-        result = prime * result + ((getResourceProperties() == null) ? 0 : getResourceProperties().hashCode());
+        result = prime * result + ((getProperties() == null) ? 0 : getProperties().hashCode());
         return result;
     }
 

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -23,7 +23,9 @@ import java.lang.reflect.Proxy;
 import java.util.AbstractMap;
 import java.util.Arrays;
 import java.util.Dictionary;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -200,41 +202,33 @@ public class ServiceDependencyImpl exten
     }
 
 	@Override
-	public void start() {
-		boolean wasStarted = isStarted();
-		super.start();
-
-        if (!wasStarted) {
-            if (m_trackedServiceName != null) {
-                if (m_trackedServiceFilter != null) {
-                    try {
-                        m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
-                    } catch (InvalidSyntaxException e) {
-                        throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
-                    }
-                } else if (m_trackedServiceReference != null) {
-                    m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
-                } else {
-                    m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
+	protected void startTracking() {
+        if (m_trackedServiceName != null) {
+            if (m_trackedServiceFilter != null) {
+                try {
+                    m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
+                } catch (InvalidSyntaxException e) {
+                    throw new IllegalStateException("Invalid filter definition for dependency: "
+                        + m_trackedServiceFilter);
                 }
+            } else if (m_trackedServiceReference != null) {
+                m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
             } else {
-                throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
-            }
-            if (debug) {
-            	m_tracker.setDebug(debugKey);
+                m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
             }
-            m_tracker.open();
+        } else {
+            throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
+        }
+        if (debug) {
+            m_tracker.setDebug(debugKey);
         }
+        m_tracker.open();
 	}
 	
 	@Override
-	public void stop() {
-		boolean wasStarted = isStarted();
-		super.stop();
-		if (wasStarted) {
-			m_tracker.close();
-			m_tracker = null;
-		}
+	protected void stopTracking() {
+	    m_tracker.close();
+	    m_tracker = null;
 	}
 
 	@Override
@@ -245,7 +239,7 @@ public class ServiceDependencyImpl exten
 	@Override
 	public void addedService(ServiceReference reference, Object service) {
 		if (debug) {
-			System.out.println(debugKey + " addedService");
+			System.out.println(debugKey + " addedService: ref=" + reference + ", service=" + service);
 		}
 		add(new ServiceEventImpl(m_bundle, m_context, reference, service));
 	}
@@ -281,20 +275,20 @@ public class ServiceDependencyImpl exten
             {Map.class, m_trackedServiceName}}, 
             
             new Object[][]{
-		    {m_component, se.getReference(), se.getService()},
-            {m_component, se.getReference(), se.getService()}, 
+		    {m_component, se.getReference(), se.getEvent()},
+            {m_component, se.getReference(), se.getEvent()}, 
             {m_component, se.getReference()}, 
-            {m_component, se.getService()},
-            {m_component, se.getService()},
+            {m_component, se.getEvent()},
+            {m_component, se.getEvent()},
             {m_component},
-            {m_component, new ServicePropertiesMap(se.getReference()), se.getService()},
-            {se.getReference(), se.getService()},
-            {se.getReference(), se.getService()}, 
+            {m_component, new ServicePropertiesMap(se.getReference()), se.getEvent()},
+            {se.getReference(), se.getEvent()},
+            {se.getReference(), se.getEvent()}, 
             {se.getReference()}, 
-            {se.getService()}, 
-            {se.getService()}, 
+            {se.getEvent()}, 
+            {se.getEvent()}, 
             {},
-            {new ServicePropertiesMap(se.getReference()), se.getService()}}
+            {new ServicePropertiesMap(se.getReference()), se.getEvent()}}
 		);
 	}
 	
@@ -347,7 +341,7 @@ public class ServiceDependencyImpl exten
                 try {
                     return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod,
                             new Class[][]{{ServiceReference.class, Object.class}, {ServiceReference.class}}, new Object[][]{
-                                    {se.getReference(), se.getService()}, {se.getReference()}});
+                                    {se.getReference(), se.getEvent()}, {se.getReference()}});
                 } catch (InvocationTargetException e) {
                     m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
                 } catch (Exception e) {
@@ -369,11 +363,6 @@ public class ServiceDependencyImpl exten
         }
     }	
 
-    @Override
-    public boolean isPropagated() {
-        return m_propagate;
-    }
-
     private BundleContext getBundleContext() {
         return m_context;
     }
@@ -413,12 +402,9 @@ public class ServiceDependencyImpl exten
     }
     
     @Override
-    protected Object getService() {
+    public Object getDefaultService() {
         Object service = null;
-        ServiceEventImpl se = (ServiceEventImpl) m_component.getDependencyEvent(this);
-        if (se != null) {
-            service = se.getService();
-        } else if (isAutoConfig()) {
+        if (isAutoConfig()) {
             service = getDefaultImplementation();
             if (service == null) {
                 service = getNullObject();
@@ -426,7 +412,7 @@ public class ServiceDependencyImpl exten
         }
         return service;
     }
-    
+        
     private Object getNullObject() {
         if (m_nullObject == null) {
             Class trackedServiceName;
@@ -466,7 +452,7 @@ public class ServiceDependencyImpl exten
     public void invokeSwap(Event event, Event newEvent) {
         ServiceEventImpl oldE = (ServiceEventImpl) event;
         ServiceEventImpl newE = (ServiceEventImpl) newEvent;
-        invokeSwap(m_swap, oldE.getReference(), oldE.getService(), newE.getReference(), newE.getService(), getInstances());
+        invokeSwap(m_swap, oldE.getReference(), oldE.getEvent(), newE.getReference(), newE.getEvent(), getInstances());
     }
 
     public void invokeSwap(String swapMethod, ServiceReference previousReference, Object previous,
@@ -512,5 +498,5 @@ public class ServiceDependencyImpl exten
 			addedService(newReference, newService);
 			removedService(reference, service);
 		}
-	}
+	}	
 }

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Dictionary;
+
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -78,12 +80,15 @@ public class ServiceEventImpl extends Ev
 		return m_reference;
 	}
 	
-	/**
-	 * Returns the service dependency instance.
-	 */
-	public Object getService() {
-		return m_service;
-	}
+    @Override
+    public Object getEvent() {
+        return m_service;
+    }
+    
+    @Override
+    public Dictionary getProperties() {
+        return ServiceUtil.propertiesToDictionary(m_reference);
+    }
 	
 	@Override
 	public boolean equals(Object obj) {

Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java Tue Sep 30 20:30:21 2014
@@ -18,7 +18,12 @@
  */
 package org.apache.felix.dm.impl;
 
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.felix.dm.DependencyManager;
 import org.osgi.framework.Bundle;
@@ -173,4 +178,66 @@ public class ServiceUtil {
         }
         return buf.toString();
     }
+    
+    /**
+     * Wraps ServiceReference properties behind a Dictionary object.
+     * @param ref the ServiceReference to wrap
+     * @return a new Dictionary used to wrap the ServiceReference properties
+     */
+    public static Dictionary<String, ?> propertiesToDictionary(final ServiceReference ref) {
+        return new Dictionary<String, Object>() {
+            private Dictionary<String, Object> m_wrapper;
+            
+            @Override
+            public int size() {
+                return getWrapper().size();
+            }
+
+            @Override
+            public boolean isEmpty() {
+                return getWrapper().isEmpty();
+            }
+
+            @Override
+            public Enumeration<String> keys() {
+                return getWrapper().keys();
+            }
+
+            @Override
+            public Enumeration<Object> elements() {
+                return getWrapper().elements();
+            }
+
+            @Override
+            public Object get(Object key) {
+                return ref.getProperty(key.toString());
+            }
+
+            @Override
+            public Object put(String key, Object value) {
+                throw new UnsupportedOperationException("Unmodified Dictionary.");
+            }
+
+            @Override
+            public Object remove(Object key) {
+                throw new UnsupportedOperationException("Unmodified Dictionary.");
+            }
+            
+            @Override
+            public String toString() {
+                return getWrapper().toString();
+            }
+            
+            private synchronized Dictionary<String, Object> getWrapper() {
+                if (m_wrapper == null) {
+                    m_wrapper = new Hashtable<String, Object>();
+                    String[] keys = ref.getPropertyKeys();
+                    for (String key : keys) {
+                        m_wrapper.put(key, ref.getProperty(key));
+                    }                    
+                }
+                return m_wrapper;
+            }
+        };
+    }
 }