Added the notion of ranking to aspects so they can dynamically be chained. Fixed a bug in bundle dependencies.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@918508 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/pom.xml b/dependencymanager/core/pom.xml
index 12725dc..6acd83c 100644
--- a/dependencymanager/core/pom.xml
+++ b/dependencymanager/core/pom.xml
@@ -55,9 +55,9 @@
             <Export-Package>org.apache.felix.dm;version="3.0.0",org.apache.felix.dm.service;version="3.0.0",org.apache.felix.dm.management;version="3.0.0",org.apache.felix.dm.dependencies;version="3.0.0",org.apache.felix.dm.resources;version="3.0.0"</Export-Package>
             <Import-Package>!org.apache.felix.dm,!org.apache.felix.dm.service,!org.apache.felix.dm.management,!org.apache.felix.dm.dependencies,!org.apache.felix.dm.resources,*</Import-Package>
 	        <Private-Package>org.apache.felix.dm.impl,org.apache.felix.dm.impl.dependencies,org.apache.felix.dm.impl.tracker</Private-Package>
-	        <!-- Uncomment this line to include source code in the bundle.
+	        <!-- Uncomment this line to include source code in the bundle.-->
             <Include-Resource>src/main/java</Include-Resource>
-            -->
+            <!-- -->
           </instructions>
         </configuration>
       </plugin>
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 4b07c24..03c5738 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
@@ -148,8 +148,11 @@
         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 createAspectService(Class serviceInterface, String serviceFilter, int ranking, Object aspectImplementation, Dictionary properties) {
+        return m_manager.createAspectService(serviceInterface, serviceFilter, ranking, aspectImplementation, properties);
+    }
+    public Service createAspectService(Class serviceInterface, String serviceFilter, int ranking, Object factory, String factoryCreateMethod, Dictionary properties) {
+        return m_manager.createAspectService(serviceInterface, serviceFilter, ranking, factory, factoryCreateMethod, properties);
     }
     
     public Service createAdapterService(Class serviceInterface, String serviceFilter, Class adapterInterface, Object adapterImplementation, Dictionary adapterProperties) {
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 f608e16..65b97b7 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
@@ -54,6 +54,7 @@
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class DependencyManager {
+    public static final String ASPECT = "org.apache.felix.dependencymanager.aspect";
     private final BundleContext m_context;
     private final Logger m_logger;
     private List m_services = Collections.synchronizedList(new ArrayList());
@@ -167,15 +168,33 @@
      * @param aspectProperties additional properties to use with the aspect service registration
      * @return a service that acts as a factory for generating aspects
      */
-    public Service createAspectService(Class serviceInterface, String serviceFilter, Object aspectImplementation, Dictionary aspectProperties) {
+    public Service createAspectService(Class serviceInterface, String serviceFilter, int ranking, Object aspectImplementation, Dictionary aspectProperties) {
         return createService()
-            .setImplementation(new AspectImpl(serviceInterface, serviceFilter, aspectImplementation, aspectProperties))
+            .setImplementation(new AspectImpl(serviceInterface, serviceFilter, ranking, aspectImplementation, aspectProperties))
             .add(createServiceDependency()
-                .setService(serviceInterface, serviceFilter)
+                .setService(serviceInterface, createAspectFilter(serviceFilter))
                 .setAutoConfig(false)
                 .setCallbacks("added", "removed")
             );
     }
+    public Service createAspectService(Class serviceInterface, String serviceFilter, int ranking, Object factory, String factoryCreateMethod, Dictionary aspectProperties) {
+        return createService()
+            .setImplementation(new AspectImpl(serviceInterface, serviceFilter, ranking, factory, factoryCreateMethod, aspectProperties))
+            .add(createServiceDependency()
+                .setService(serviceInterface, createAspectFilter(serviceFilter))
+                .setAutoConfig(false)
+                .setCallbacks("added", "removed")
+            );
+    }
+    private String createAspectFilter(String filter) {
+        // we only want to match services which are not themselves aspects
+        if (filter == null || filter.length() == 0) {
+            return "(!(" + ASPECT + "=*))";
+        }
+        else {
+            return "(&(!(" + ASPECT + "=*))" + filter + ")";
+        }        
+    }
     
     /**
      * Creates a new adapter. The adapter will be applied to any service that
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
index 29fa6b3..31c7a20 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
@@ -23,7 +23,9 @@
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.felix.dm.DependencyManager;
 import org.apache.felix.dm.service.Service;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
 public class AspectImpl extends AbstractDecorator {
@@ -32,18 +34,38 @@
 	private final String m_serviceFilter;
 	private final Object m_aspectImplementation;
     private final Dictionary m_aspectProperties;
+    private final Object m_factory;
+    private final String m_factoryCreateMethod;
+    private final int m_ranking;
 	
-	public AspectImpl(Class serviceInterface, String serviceFilter, Object aspectImplementation, Dictionary properties) {
+	public AspectImpl(Class serviceInterface, String serviceFilter, int ranking, Object aspectImplementation, Dictionary properties) {
 		m_serviceInterface = serviceInterface;
 		m_serviceFilter = serviceFilter;
 		m_aspectImplementation = aspectImplementation;
 		m_aspectProperties = properties;
+		m_factory = null;
+		m_factoryCreateMethod = null;
+		m_ranking = ranking;
 	}
+	
+    public AspectImpl(Class serviceInterface, String serviceFilter, int ranking, Object factory, String factoryCreateMethod, Dictionary properties) {
+        m_serviceInterface = serviceInterface;
+        m_serviceFilter = serviceFilter;
+        m_factory = factory;
+        m_factoryCreateMethod = factoryCreateMethod;
+        m_aspectProperties = properties;
+        m_aspectImplementation = null;
+        m_ranking = ranking;
+    }
 
     public Service createService(Object[] properties) {
         ServiceReference ref = (ServiceReference) properties[0]; 
         Object service = properties[1];
         Properties props = new Properties();
+        // first add our aspect property
+        props.put(DependencyManager.ASPECT, "true");
+        // and the ranking
+        props.put(Constants.SERVICE_RANKING, Integer.valueOf(m_ranking));
         String[] keys = ref.getPropertyKeys();
         for (int i = 0; i < keys.length; i++) {
             props.put(keys[i], ref.getProperty(keys[i]));
@@ -57,12 +79,31 @@
         }
         List dependencies = m_service.getDependencies();
         dependencies.remove(0);
-        return m_manager.createService()
+        if (m_aspectImplementation == null) {
+            return m_manager.createService()
             .setInterface(m_serviceInterface.getName(), props)
-            .setImplementation(m_aspectImplementation)
+            .setFactory(m_factory, m_factoryCreateMethod)
             .add(dependencies)
             .add(m_manager.createServiceDependency()
-                .setService(m_serviceInterface, ref)
+                .setService(m_serviceInterface, createAspectFilter(m_serviceFilter))
                 .setRequired(true));
+        }
+        else {
+            return m_manager.createService()
+                .setInterface(m_serviceInterface.getName(), props)
+                .setImplementation(m_aspectImplementation)
+                .add(dependencies)
+                .add(m_manager.createServiceDependency()
+                    .setService(m_serviceInterface, createAspectFilter(m_serviceFilter))
+                    .setRequired(true));
+        }
+    }
+    private String createAspectFilter(String filter) {
+        if (filter == null || filter.length() == 0) {
+            return "(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=" + (m_ranking - 1) + "))";
+        }
+        else {
+            return "(&(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=" + (m_ranking - 1) + "))" + filter + ")";
+        }
     }
 }
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
index 0422fc7..51a42cd 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
@@ -828,6 +828,10 @@
 	    	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++) {
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 12b6332..a97d054 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
@@ -384,8 +384,8 @@
         return lookupBundle();
     }
 
-    public Object lookupBundle() {
-        Object service = null;
+    public Bundle lookupBundle() {
+        Bundle service = null;
         if (m_isStarted) {
             service = getBundle();
         }
@@ -415,7 +415,7 @@
         return service;
     }
 
-    private Object getNullObject() {
+    private Bundle getNullObject() {
         if (m_nullObject == null) {
             try {
                 m_nullObject = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Bundle.class }, new DefaultNullObject()); 
@@ -424,7 +424,7 @@
                 m_logger.log(Logger.LOG_ERROR, "Could not create null object for Bundle.", e);
             }
         }
-        return m_nullObject;
+        return (Bundle) m_nullObject;
     }
     
     public String getAutoConfigName() {
@@ -437,13 +437,7 @@
 
     public void invokeAdded(DependencyService service) {
         // we remember these for future reference, needed for required service callbacks
-        if (m_isStarted) {
-            // use the tracker
-        }
-        else {
-            // do a manual lookup
-        }
-        m_bundleInstance = null; // TODO save what we looked up here
+        m_bundleInstance = lookupBundle();
         invokeAdded(service, m_bundleInstance);
     }
 
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
index 9eeff70..89f68d4 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ServiceDependencyImpl.java
@@ -336,7 +336,7 @@
                             m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
                         }
                         catch (InvalidSyntaxException e) {
-                            throw new IllegalStateException("Invalid filter definition for dependency.");
+                            throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
                         }
                     }
                     else if (m_trackedServiceReference != null) {