felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1727487 [3/7] - in /felix/sandbox/pderop/dependencymanager-lambda: org.apache.felix.dependencymanager.lambda.itest/ org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/builder/ org.apache.felix.dependencymanager.lambda....
Date Fri, 29 Jan 2016 06:50:11 GMT
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AspectWithPropagationTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AspectWithPropagationTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AspectWithPropagationTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AspectWithPropagationTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,716 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.adapter;
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.aspect;
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Test for aspects with service properties propagations.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"rawtypes", "unchecked", "unused"})
+public class AspectWithPropagationTest extends TestBase {
+    private final static int ASPECTS = 3;
+    private final Set<Integer> _randoms = new HashSet<Integer>();
+    private final Random _rnd = new Random();
+    private static Ensure m_invokeStep;
+    private static Ensure m_changeStep;
+    
+    /**
+     * This test does the following:
+     * 
+     * - Create S service with property "p=s"
+     * - Create SA (aspect of S) with property "p=aspect"
+     * - Create Client, depending on S (actually, on SA).
+     * - Client should see SA with properties p=aspect
+     * - Change S service property with "p=smodified": the Client should be changed with SA(p=aspect)
+     * - Change aspect service property with "p=aspectmodified": The client should be changed with SA(p=aspectmodified)
+     */
+    public void testAspectsWithPropagationNotOverriding() {
+        System.out.println("----------- Running testAspectsWithPropagationNotOverriding ...");
+        DependencyManager m = getDM();
+        m_invokeStep = new Ensure(); 
+        
+        // Create our original "S" service.
+        S s = new S() {
+			public void invoke() {
+			}
+        };
+		Component sComp = component(m).impl(s).provides(S.class, p -> "s").build();
+
+        // Create SA (aspect of S)
+        S sa = new S() {
+        	volatile S m_s;
+			public void invoke() {
+			}
+        };
+        Component saComp = aspect(m, S.class).rank(1).impl(sa).properties(p -> "aspect").build();
+                
+        // Create client depending on S
+        Object client = new Object() {
+        	int m_changeCount;
+        	void add(Map props, S s) {
+        		Assert.assertEquals("aspect", props.get("p"));
+        		m_invokeStep.step(1);
+        	}
+        	
+            void change(Map props, S s) {
+        		switch (++m_changeCount) {
+        		case 1:
+        			Assert.assertEquals("aspect", props.get("p"));
+            		m_invokeStep.step(2);
+            		break;
+        		case 2:
+        			Assert.assertEquals("aspectmodified", props.get("p"));
+            		m_invokeStep.step(3);
+        		}
+        	}
+        };
+        Component clientComp = component(m).impl(client).withSrv(S.class, srv->srv.cb("add", "change", null)).build();
+        
+        // Add components in dependency manager
+        m.add(sComp);
+        m.add(saComp);
+        m.add(clientComp);
+        
+        // client should have been added with SA aspect
+        m_invokeStep.waitForStep(1, 5000);
+        
+        // now change s "p=s" to "p=smodified": client should not see it
+        Hashtable props = new Hashtable();
+        props.put("p", "smodified");
+        sComp.setServiceProperties(props);
+        m_invokeStep.waitForStep(2, 5000);
+        
+        // now change sa aspect "p=aspect" to "p=aspectmodified": client should see it
+        props = new Hashtable();
+        props.put("p", "aspectmodified");
+        saComp.setServiceProperties(props);
+        m_invokeStep.waitForStep(3, 5000);    
+        
+        // remove components
+        m.remove(clientComp);
+        m.remove(saComp);
+        m.remove(sComp);
+    }
+            
+    /**
+     * This test does the following:
+     * 
+     * - Create S service
+     * - Create some S Aspects
+     * - Create a Client, depending on S (actually, on the top-level S aspect)
+     * - Client has a "change" callback in order to track S service properties modifications.
+     * - First, invoke Client.invoke(): all S aspects, and finally original S service must be invoked orderly.
+     * - Modify S original service properties, and check if all aspects, and the client has been orderly called in their "change" callback.
+     * - Modify the First lowest ranked aspect (rank=1), and check if all aspects, and client have been orderly called in their "change" callback.
+     */
+    public void testAspectsWithPropagation() {
+        System.out.println("----------- Running testAspectsWithPropagation ...");
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        m_invokeStep = new Ensure(); 
+        
+        // Create our original "S" service.
+        Dictionary props = new Hashtable();
+        props.put("foo", "bar");
+        Component s = component(m).impl(new SImpl()).provides(S.class, props).build();
+                
+        // Create an aspect aware client, depending on "S" service.
+        Client clientImpl;
+        Component client = component(m).impl((clientImpl = new Client())).withSrv(S.class, srv -> srv.cb("add", "change", "remove", "swap")).build();     
+
+        // Create some "S" aspects
+        Component[] aspects = new Component[ASPECTS];
+        for (int rank = 1; rank <= ASPECTS; rank ++) {
+            aspects[rank-1] = aspect(m, S.class).rank(rank).impl(new A("A" + rank, rank)).cb("add", "change", "remove", "swap").build();
+            props = new Hashtable();
+            props.put("a" + rank, "v" + rank);
+            aspects[rank-1].setServiceProperties(props);
+        }                                    
+              
+        // Register client
+        m.add(client);
+        
+        // Randomly register aspects and original service
+        boolean originalServiceAdded = false;
+        for (int i = 0; i < ASPECTS; i ++) {
+            int index = getRandomAspect();
+            m.add(aspects[index]);
+            if (! originalServiceAdded && _rnd.nextBoolean()) {
+                m.add(s);
+                originalServiceAdded = true;
+            }
+        }
+        if (! originalServiceAdded) {
+            m.add(s);
+        }
+              
+        // All set, check if client has inherited from top level aspect properties + original service properties
+        Map check = new HashMap();
+        check.put("foo", "bar");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS);
+        checkServiceProperties(check, clientImpl.getServiceProperties());
+
+        // Now invoke client, which orderly calls all aspects in the chain, and finally the original service "S".
+        System.out.println("-------------------------- Invoking client.");
+        clientImpl.invoke();
+        m_invokeStep.waitForStep(ASPECTS+1, 5000);
+        
+        // Now, change original service "S" properties: this will orderly trigger "change" callbacks on aspects, and on client. 
+        System.out.println("-------------------------- Modifying original service properties.");
+        m_changeStep = new Ensure();
+        props = new Hashtable();
+        props.put("foo", "barModified");
+        s.setServiceProperties(props);
+        
+        // Check if aspects and client have been orderly called in their "changed" callback
+        m_changeStep.waitForStep(ASPECTS+1, 5000);
+        
+        // Check if modified "foo" original service property has been propagated
+        check = new HashMap();
+        check.put("foo", "barModified");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS); // we only see top-level aspect service properties
+        checkServiceProperties(check, clientImpl.getServiceProperties());
+        
+        // Now, change the top-level ranked aspect: it must propagate to all upper aspects, as well as to the client
+        System.out.println("-------------------------- Modifying top-level aspect service properties.");
+
+        m_changeStep = new Ensure();
+        for (int i = 1; i <= ASPECTS; i ++) {
+            m_changeStep.step(i); // only client has to be changed.
+        }
+        props = new Hashtable();
+        props.put("a" + ASPECTS, "v" + ASPECTS + "-Modified");
+        aspects[ASPECTS-1].setServiceProperties(props); // That triggers change callbacks for upper aspects (with rank >= 2)
+        m_changeStep.waitForStep(ASPECTS+1, 5000); // check if client have been changed.
+        
+        // Check if top level aspect service properties have been propagated up to the client.
+        check = new HashMap();
+        check.put("foo", "barModified");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS + "-Modified");
+        checkServiceProperties(check, clientImpl.getServiceProperties());
+
+        // Clear all components.
+        m_changeStep = null;
+        m.clear();
+    }    
+    
+    /**
+     * This test does the following:
+     * 
+     * - Create S service
+     * - Create some S Aspects without any callbacks (add/change/remove/swap)
+     * - Create a Client, depending on S (actually, on the top-level S aspect)
+     * - Client has a "change" callack in order to track S service properties modifications.
+     * - First, invoke Client.invoke(): all S aspects, and finally original S service must be invoked orderly.
+     * - Modify S original service properties, and check if the client has been called in its "change" callback.
+     */
+    public void testAspectsWithPropagationAndNoCallbacks() {
+        System.out.println("----------- Running testAspectsWithPropagation ...");
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        m_invokeStep = new Ensure(); 
+        
+        // Create our original "S" service.
+        Dictionary props = new Hashtable();
+        props.put("foo", "bar");
+        Component s = component(m).impl(new SImpl()).provides(S.class, props).build();
+        
+        // Create an aspect aware client, depending on "S" service.
+        Client clientImpl;
+        Component client = component(m).impl((clientImpl = new Client())).withSrv(S.class, srv->srv.cb("add", "change", "remove")).build();            
+
+        // Create some "S" aspects
+        Component[] aspects = new Component[ASPECTS];
+        for (int rank = 1; rank <= ASPECTS; rank ++) {
+            aspects[rank-1] = aspect(m, S.class).rank(rank).impl(new A("A" + rank, rank)).build();
+            props = new Hashtable();
+            props.put("a" + rank, "v" + rank);
+            aspects[rank-1].setServiceProperties(props);
+        }                                    
+              
+        // Register client
+        m.add(client);
+        
+        // Randomly register aspects and original service
+        boolean originalServiceAdded = false;
+        for (int i = 0; i < ASPECTS; i ++) {
+            int index = getRandomAspect();
+            m.add(aspects[index]);
+            if (! originalServiceAdded && _rnd.nextBoolean()) {
+                m.add(s);
+                originalServiceAdded = true;
+            }
+        }
+        if (! originalServiceAdded) {
+            m.add(s);
+        }
+              
+        // All set, check if client has inherited from top level aspect properties + original service properties
+        Map check = new HashMap();
+        check.put("foo", "bar");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS);
+        checkServiceProperties(check, clientImpl.getServiceProperties());
+
+        // Now invoke client, which orderly calls all aspects in the chain, and finally the original service "S".
+        System.out.println("-------------------------- Invoking client.");
+        clientImpl.invoke();
+        m_invokeStep.waitForStep(ASPECTS+1, 5000);
+        
+        // Now, change original service "S" properties: this will orderly trigger "change" callbacks on aspects, and on client. 
+        System.out.println("-------------------------- Modifying original service properties.");
+        m_changeStep = new Ensure();
+        for (int i = 1; i <= ASPECTS; i ++) {
+            m_changeStep.step(i); // skip aspects, which have no "change" callbacks.
+        }
+        props = new Hashtable();
+        props.put("foo", "barModified");
+        s.setServiceProperties(props);
+        
+        // Check if aspects and client have been orderly called in their "changed" callback
+        m_changeStep.waitForStep(ASPECTS+1, 5000);
+        
+        // Check if modified "foo" original service property has been propagated
+        check = new HashMap();
+        check.put("foo", "barModified");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS); // we only see top-level aspect service properties
+        checkServiceProperties(check, clientImpl.getServiceProperties());
+        
+        // Clear all components.
+        m_changeStep = null;
+        m.clear();
+    }    
+    
+    /**
+     * This test does the following:
+     * 
+     * - Create S service
+     * - Create some S Aspects
+     * - Create S2 Adapter, which adapts S to S2
+     * - Create Client2, which depends on S2. Client2 listens to S2 property change events.
+     * - Now, invoke Client2.invoke(): all S aspects, and finally original S service must be invoked orderly.
+     * - Modify S original service properties, and check if all aspects, S2 Adapter, and Client2 have been orderly called in their "change" callback.
+     */
+    public void testAdapterWithAspectsAndPropagation() {
+        System.out.println("----------- Running testAdapterWithAspectsAndPropagation ...");
+
+        DependencyManager m = getDM();
+        m_invokeStep = new Ensure(); 
+        
+        // Create our original "S" service.
+        Dictionary props = new Hashtable();
+        props.put("foo", "bar");
+        Component s = component(m).impl(new SImpl()).provides(S.class, props).build();
+        
+        // Create some "S" aspects
+        Component[] aspects = new Component[ASPECTS];
+        for (int rank = 1; rank <= ASPECTS; rank ++) {
+            aspects[rank-1] = aspect(m, S.class).rank(rank).impl(new A("A" + rank, rank)).cb("add", "change", "remove", "swap").build();
+            props = new Hashtable();
+            props.put("a" + rank, "v" + rank);
+            aspects[rank-1].setServiceProperties(props);
+        } 
+        
+        // Create S2 adapter (which adapts S1 to S2 interface)
+        Component adapter = adapter(m, S.class).cb("add", "change", "remove", "swap").provides(S2.class).impl(new S2Impl()).build();
+        
+        // Create Client2, which depends on "S2" service.
+        Client2 client2Impl;
+        Component client2 = component(m).impl((client2Impl = new Client2())).withSrv(S2.class, srv -> srv.cb("add", "change", null)).build();
+              
+        // Register client2
+        m.add(client2);
+        
+        // Register S2 adapter
+        m.add(adapter);
+        
+        // Randomly register aspects, original service
+        boolean originalServiceAdded = false;
+        for (int i = 0; i < ASPECTS; i ++) {
+            int index = getRandomAspect();
+            m.add(aspects[index]);
+            if (! originalServiceAdded && _rnd.nextBoolean()) {
+                m.add(s);
+                originalServiceAdded = true;
+            }
+        }
+        if (! originalServiceAdded) {
+            m.add(s);
+        }
+             
+        // Now invoke client2, which orderly calls all S1 aspects, then S1Impl, and finally S2 service
+        System.out.println("-------------------------- Invoking client2.");
+        client2Impl.invoke2();
+        m_invokeStep.waitForStep(ASPECTS+2, 5000);
+        
+        // Now, change original service "S" properties: this will orderly trigger "change" callbacks on aspects, S2Impl, and Client2.
+        System.out.println("-------------------------- Modifying original service properties.");
+        m_changeStep = new Ensure();
+        props = new Hashtable();
+        props.put("foo", "barModified");
+        s.setServiceProperties(props);
+        
+        // Check if aspects and Client2 have been orderly called in their "changed" callback
+        m_changeStep.waitForStep(ASPECTS+2, 5000);
+        
+        // Check if modified "foo" original service property has been propagated to Client2
+        Map check = new HashMap();
+        check.put("foo", "barModified");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS);
+        checkServiceProperties(check, client2Impl.getServiceProperties());
+        
+        // Clear all components.
+        m_changeStep = null;
+        m.clear();
+    }    
+    
+    /**
+     * This test does the following:
+     * 
+     * - Create S service
+     * - Create some S Aspects without any callbacks (add/change/remove)
+     * - Create S2 Adapter, which adapts S to S2 (but does not have any add/change/remove callbacks)
+     * - Create Client2, which depends on S2. Client2 listens to S2 property change events.
+     * - Now, invoke Client2.invoke(): all S aspects, and finally original S service must be invoked orderly.
+     * - Modify S original service properties, and check if all aspects, S2 Adapter, and Client2 have been orderly called in their "change" callback.
+     */
+    public void testAdapterWithAspectsAndPropagationNoCallbacks() {
+        System.out.println("----------- Running testAdapterWithAspectsAndPropagationNoCallbacks ...");
+
+        DependencyManager m = getDM();
+        m_invokeStep = new Ensure(); 
+        
+        // Create our original "S" service.
+        Dictionary props = new Hashtable();
+        props.put("foo", "bar");
+        Component s = component(m).impl(new SImpl()).provides(S.class, props).build();
+        
+        // Create some "S" aspects
+        Component[] aspects = new Component[ASPECTS];
+        for (int rank = 1; rank <= ASPECTS; rank ++) {
+            aspects[rank-1] = aspect(m, S.class).rank(rank).impl(new A("A" + rank, rank)).build();
+            props = new Hashtable();
+            props.put("a" + rank, "v" + rank);
+            aspects[rank-1].setServiceProperties(props);
+        } 
+        
+        // Create S2 adapter (which adapts S1 to S2 interface)
+        Component adapter = adapter(m, S.class).provides(S2.class).impl(new S2Impl()).build();                                
+        
+        // Create Client2, which depends on "S2" service.
+        Client2 client2Impl;
+        Component client2 = component(m).impl((client2Impl = new Client2())).withSrv(S2.class, srv->srv.cb("add", "change", null)).build();
+              
+        // Register client2
+        m.add(client2);
+        
+        // Register S2 adapter
+        m.add(adapter);
+        
+        // Randomly register aspects, original service
+        boolean originalServiceAdded = false;
+        for (int i = 0; i < ASPECTS; i ++) {
+            int index = getRandomAspect();
+            m.add(aspects[index]);
+            if (! originalServiceAdded && _rnd.nextBoolean()) {
+                m.add(s);
+                originalServiceAdded = true;
+            }
+        }
+        if (! originalServiceAdded) {
+            m.add(s);
+        }
+             
+        // Now invoke client2, which orderly calls all S1 aspects, then S1Impl, and finally S2 service
+        System.out.println("-------------------------- Invoking client2.");
+        client2Impl.invoke2();
+        m_invokeStep.waitForStep(ASPECTS+2, 5000);
+        
+        // Now, change original service "S" properties: this will orderly trigger "change" callbacks on aspects, S2Impl, and Client2.
+        System.out.println("-------------------------- Modifying original service properties.");
+        m_changeStep = new Ensure();
+        for (int i = 1; i <= ASPECTS+1; i ++) {
+            m_changeStep.step(i); // skip all aspects and the adapter
+        }
+        props = new Hashtable();
+        props.put("foo", "barModified");
+        s.setServiceProperties(props);
+        
+        // Check if Client2 has been called in its "changed" callback
+        m_changeStep.waitForStep(ASPECTS+2, 5000);
+        
+        // Check if modified "foo" original service property has been propagated to Client2
+        Map check = new HashMap();
+        check.put("foo", "barModified");
+        for (int i = 1; i < (ASPECTS - 1); i ++) {
+            check.put("a" + i, null); // we must not inherit from lower ranks, only from the top-level aspect.
+        }
+        check.put("a" + ASPECTS, "v" + ASPECTS);
+        checkServiceProperties(check, client2Impl.getServiceProperties());
+        
+        // Clear all components.
+        m_changeStep = null;
+        m.clear();
+    }    
+    
+   private void checkServiceProperties(Map<?, ?> check, Dictionary properties) {
+        for (Object key : check.keySet()) {
+            Object val = check.get(key);   
+            if (val == null) {
+                Assert.assertNull(properties.get(key));
+            } else {
+                Assert.assertEquals(val, properties.get(key));
+            }
+        }
+    }
+    
+    private int getRandomAspect() {
+        int index = 0;  
+        do {
+            index = _rnd.nextInt(ASPECTS);            
+        } while (_randoms.contains(new Integer(index)));
+        _randoms.add(new Integer(index));
+        return index;
+    }
+
+    // S Service
+    public static interface S {
+        public void invoke();
+    }
+    
+    // S ServiceImpl
+    static class SImpl implements S {
+        public SImpl() {
+        }
+        
+        public String toString() {
+            return "S";
+        }
+        
+        public void invoke() {
+             m_invokeStep.step(ASPECTS+1);
+        }
+    }
+    
+    // S Aspect
+    static class A implements S {
+        private final String m_name;
+        private volatile ServiceRegistration m_registration;
+        private volatile S m_next;
+        private final int m_rank;
+
+        public A(String name, int rank) {
+            m_name = name;
+            m_rank = rank;
+        }
+        
+        public String toString() {
+            return m_name;
+        }
+        
+        public void invoke() {
+            int rank = ServiceUtil.getRanking(m_registration.getReference());
+            m_invokeStep.step(ASPECTS - rank + 1);
+            m_next.invoke();
+        }
+               
+        public void add(ServiceReference ref, S s) {
+            System.out.println("+++ A" + m_rank + ".add:" + s + "/" + ServiceUtil.toString(ref));   
+            m_next = s;
+        }
+
+        public void swap(ServiceReference oldSRef, S oldS, ServiceReference newSRef, S newS) {
+            System.out.println("+++ A" + m_rank + ".swap: new=" + newS + ", props=" + ServiceUtil.toString(newSRef));
+            Assert.assertTrue(m_next == oldS);
+            m_next = newS;
+        }
+
+        public void change(ServiceReference props, S s) {   
+            System.out.println("+++ A" + m_rank + ".change: s=" + s + ", props=" + ServiceUtil.toString(props));
+            if (m_changeStep != null) {
+                int rank = ServiceUtil.getRanking(m_registration.getReference());
+                m_changeStep.step(rank);
+            }
+        }
+        
+        public void remove(ServiceReference props, S s) {
+            System.out.println("+++ A" + m_rank + ".remove: " + s + ", props=" + ServiceUtil.toString(props));
+        }
+    }
+    
+    // Aspect aware client, depending of "S" service aspects.
+    static class Client {
+        private volatile S m_s;
+        private volatile ServiceReference m_sRef;
+
+        public Client() {
+        }
+        
+        public Dictionary getServiceProperties() {
+            Dictionary props = new Hashtable();
+            for (String key : m_sRef.getPropertyKeys()) {
+                props.put(key, m_sRef.getProperty(key));
+            }
+            return props;
+        }
+
+        public void invoke() {
+            m_s.invoke();           
+        }
+
+        public String toString() {
+            return "Client";
+        }
+        
+        public void add(ServiceReference ref, S s) {
+            System.out.println("+++ Client.add: " + s + "/" + ServiceUtil.toString(ref));
+            m_s = s;
+            m_sRef = ref;
+        }
+              
+        public void swap(ServiceReference oldSRef, S oldS, ServiceReference newSRef, S newS) {
+            System.out.println("+++ Client.swap: m_s = " + m_s + ", old=" + oldS + ", oldProps=" + ServiceUtil.toString(oldSRef) + ", new=" + newS + ", props=" + ServiceUtil.toString(newSRef));
+            Assert.assertTrue(m_s == oldS);
+            m_s = newS;
+            m_sRef = newSRef;
+        }
+
+        public void change(ServiceReference properties, S s) {
+            System.out.println("+++ Client.change: s=" + s + ", props=" + ServiceUtil.toString(properties));
+            if (m_changeStep != null) {
+                m_changeStep.step(ASPECTS+1);
+            }
+        }
+        
+        public void remove(ServiceReference props, S s) {
+            System.out.println("+++ Client.remove: " + s + ", props=" + ServiceUtil.toString(props));
+        }
+    }
+    
+    // S2 Service
+    public static interface S2 {
+        public void invoke2();
+    }
+
+    // S2 impl, which adapts S1 interface to S2 interface
+    static class S2Impl implements S2 {
+        private volatile S m_s; // we shall see top-level aspect on S service
+        
+        public void add(ServiceReference ref, S s) {
+            System.out.println("+++ S2Impl.add: " + s + "/" + ServiceUtil.toString(ref));
+            m_s = s;
+        }
+              
+        public void swap(ServiceReference oldSRef, S oldS, ServiceReference newSRef, S newS) {
+            System.out.println("+++ S2Impl.swap: new=" + newS + ", props=" + ServiceUtil.toString(newSRef));
+            m_s = newS;
+        }
+
+        public void change(ServiceReference properties, S s) {
+            System.out.println("+++ S2Impl.change: s=" + s + ", props=" + ServiceUtil.toString(properties));
+            if (m_changeStep != null) {
+                m_changeStep.step(ASPECTS+1);
+            }
+        }
+        
+        public void remove(ServiceReference props, S s) {
+            System.out.println("+++ S2Impl.remove: " + s + ", props=" + ServiceUtil.toString(props));
+        }
+        
+        public void invoke2() {
+            m_s.invoke();
+            m_invokeStep.step(ASPECTS + 2); // All aspects, and S1Impl have been invoked
+        }
+
+        public String toString() {
+            return "S2";
+        }        
+    }
+    
+    // Client2 depending on S2.
+    static class Client2 {
+        private volatile S2 m_s2;
+        private volatile ServiceReference m_s2Ref;
+
+        public Dictionary getServiceProperties() {
+            Dictionary props = new Hashtable();
+            for (String key : m_s2Ref.getPropertyKeys()) {
+                props.put(key, m_s2Ref.getProperty(key));
+            }
+            return props;
+        }
+
+        public void invoke2() {
+            m_s2.invoke2();           
+        }
+
+        public String toString() {
+            return "Client2";
+        }  
+                
+        public void add(ServiceReference ref, S2 s2) {
+            System.out.println("+++ Client2.add: " + s2 + "/" + ServiceUtil.toString(ref));
+            m_s2 = s2;
+            m_s2Ref = ref;
+        }
+
+        public void change(ServiceReference props, S2 s2) {   
+            System.out.println("+++ Client2.change: s2=" + s2 + ", props=" + ServiceUtil.toString(props));
+            if (m_changeStep != null) {
+                m_changeStep.step(ASPECTS + 2); // S1Impl, all aspects, and S2 adapters have been changed before us.
+            }
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AutoConfigTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AutoConfigTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AutoConfigTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/AutoConfigTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Constants;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class AutoConfigTest extends TestBase {
+    private final Ensure m_ensure = new Ensure();
+
+    public void testField() throws Exception {
+        final DependencyManager dm = getDM();
+        // Create a consumer, depending on some providers (autoconfig field).
+        ConsumeWithProviderField consumer = new ConsumeWithProviderField();
+        Component c = createConsumer(dm, consumer);
+        // Create two providers
+        Component p1 = createProvider(dm, 10, new Provider() {
+            public String toString() { return "provider1"; }
+            public void run() { m_ensure.step(); }
+        });
+        Component p2 = createProvider(dm, 20, new Provider() {
+            public String toString() { return "provider2"; }
+            public void run() { m_ensure.step(); }
+        });
+
+        // add the two providers
+        dm.add(p2);
+        dm.add(p1);
+        // add the consumer, which should have been injected with provider2 (highest rank)
+        dm.add(c);
+        m_ensure.waitForStep(1, 5000);
+        // remove the provider2, the consumer should now be injected with provider1
+        dm.remove(p2);
+        Assert.assertNotNull(consumer.getProvider());
+        Assert.assertEquals("provider1", consumer.getProvider().toString());
+        // remove the provider1, the consumer should have been stopped
+        dm.remove(p1);
+        m_ensure.waitForStep(2, 5000);
+        dm.clear();
+    }
+    
+    public void testIterableField() throws Exception {
+        final DependencyManager dm = getDM();
+        ConsumerWithIterableField consumer = new ConsumerWithIterableField();
+        Component c = createConsumer(dm, consumer);
+        Component p1 = createProvider(dm, 10, new Provider() {
+            public void run() { m_ensure.step(); }
+            public String toString() { return "provider1"; }
+        });
+        Component p2 = createProvider(dm, 20, new Provider() {
+            public void run() { m_ensure.step();}
+            public String toString() { return "provider2"; }
+        });
+
+        dm.add(p2);
+        dm.add(p1);
+        dm.add(c);
+        // the consumer should have been injected with all providers.
+        m_ensure.waitForStep(3, 5000);
+        
+        // check if all providers are there
+        Assert.assertNotNull(consumer.getProvider("provider1"));
+        Assert.assertNotNull(consumer.getProvider("provider2"));
+        
+        // remove provider1
+        dm.remove(p1);
+        
+        // check if provider1 has been removed and if provider2 is still there
+        Assert.assertNull(consumer.getProvider("provider1"));
+        Assert.assertNotNull(consumer.getProvider("provider2"));
+
+        // remove provider2, the consumer should be stopped
+        dm.remove(p2);
+        m_ensure.waitForStep(4, 5000);
+        dm.clear();
+    }   
+    
+    public void testMapField() throws Exception {
+        final DependencyManager dm = getDM();
+        ConsumerWithMapField consumer = new ConsumerWithMapField();
+        Component c = createConsumer(dm, consumer);
+        Component p1 = createProvider(dm, 10, new Provider() {
+            public void run() { m_ensure.step(); }
+            public String toString() { return "provider1"; }
+        });
+        Component p2 = createProvider(dm, 20, new Provider() {
+            public void run() { m_ensure.step();}
+            public String toString() { return "provider2"; }
+        });
+
+        dm.add(p2);
+        dm.add(p1);
+        dm.add(c);
+        // the consumer should have been injected with all providers.
+        m_ensure.waitForStep(3, 5000);
+        
+        // check if all providers are there
+        Assert.assertNotNull(consumer.getProvider("provider1"));
+        Assert.assertNotNull(consumer.getProvider("provider2"));
+        
+        // remove provider1
+        dm.remove(p1);
+        
+        // check if provider1 has been removed and if provider2 is still there
+        Assert.assertNull(consumer.getProvider("provider1"));
+        Assert.assertNotNull(consumer.getProvider("provider2"));
+
+        // remove provider2, the consumer should be stopped
+        dm.remove(p2);
+        m_ensure.waitForStep(4, 5000);
+        dm.clear();
+    }
+
+    private Component createProvider(DependencyManager dm, int rank, Provider provider) {
+        return component(dm).impl(provider).provides(Provider.class, Constants.SERVICE_RANKING, new Integer(rank)).build();
+    }
+
+    private Component createConsumer(DependencyManager dm, Object consumer) {
+        return component(dm).impl(consumer).withSrv(Provider.class).build();
+    }
+
+    public static interface Provider extends Runnable {      
+    }
+    
+    public class ConsumeWithProviderField {
+        volatile Provider m_provider;
+        
+        void start() {
+            Assert.assertNotNull(m_provider);
+            Assert.assertEquals("provider2", m_provider.toString());
+            m_ensure.step(1);
+        }
+        
+        public Provider getProvider() {
+            return m_provider;
+        }
+
+        void stop() {
+            m_ensure.step(2);
+        }
+    }
+    
+    public class ConsumerWithIterableField {
+        final Iterable<Provider> m_providers = new ConcurrentLinkedQueue<>();
+        final List m_notInjectMe = new ArrayList();
+        
+        void start() {
+            Assert.assertNotNull(m_providers);
+            int found = 0;
+            for (Provider provider : m_providers) {
+                provider.run();
+                found ++;
+            }
+            Assert.assertTrue(found == 2);
+            // The "m_notInjectMe" should not be injected with anything
+            Assert.assertEquals(m_notInjectMe.size(), 0);
+            m_ensure.step(3);
+        }
+        
+        public Provider getProvider(String name) {
+            System.out.println("getProvider(" + name + ") : proviers=" + m_providers);
+            for (Provider provider : m_providers) {
+                if (provider.toString().equals(name)) {
+                    return provider;
+                }
+            }
+            return null;
+        }
+        
+        void stop() {
+            m_ensure.step(4);
+        }
+    }    
+    
+    public class ConsumerWithMapField {
+        final Map<Provider, Dictionary> m_providers = new ConcurrentHashMap<>();
+        final Map m_notInjectMe = new HashMap<>();
+        
+        void start() {
+            Assert.assertNotNull(m_providers);
+            System.out.println("ConsumerMap.start: injected providers=" + m_providers);
+            Assert.assertTrue(m_providers.size() == 2);
+            Assert.assertEquals(0, m_notInjectMe.size());
+            for (Map.Entry<Provider, Dictionary> e : m_providers.entrySet()) {
+                Provider provider = e.getKey();
+                Dictionary props = e.getValue();
+                
+                provider.run();
+                if (provider.toString().equals("provider1")) {
+                    Assert.assertEquals(props.get(Constants.SERVICE_RANKING), 10);
+                } else if (provider.toString().equals("provider2")) {
+                    Assert.assertEquals(props.get(Constants.SERVICE_RANKING), 20);
+                } else {
+                    Assert.fail("Did not find any properties for provider " + provider);
+                }
+            }
+            
+            m_ensure.step(3);
+        }
+        
+        public Provider getProvider(String name) {
+            System.out.println("getProvider(" + name + ") : providers=" + m_providers);
+            for (Provider provider : m_providers.keySet()) {
+                if (provider.toString().equals(name)) {
+                    return provider;
+                }
+            }
+            return null;
+        }
+
+        Map<Provider, Dictionary> getProviders() {
+            return m_providers;
+        }
+        
+        void stop() {
+            m_ensure.step(4);
+        }
+    }    
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.bundleAdapter;
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleAdapterTest extends TestBase {    
+    public void testBundleAdapter() {
+        DependencyManager m = getDM();
+        // create a bundle adapter service (one is created for each bundle)
+        Component adapter = bundleAdapter(m)
+            .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+            .impl(BundleAdapter.class)
+            .provides(BundleAdapter.class)
+            .build();
+
+        // create a service provider and consumer
+        Consumer c = new Consumer();
+        Component consumer = m.createComponent().setImplementation(c)
+            .add(m.createServiceDependency().setService(BundleAdapter.class).setCallbacks("add", "remove"));
+        
+        // add the bundle adapter
+        m.add(adapter);
+        // add the service consumer
+        m.add(consumer);
+        // check if at least one bundle was found
+        c.check();
+        // remove the consumer again
+        m.remove(consumer);
+        // check if all bundles were removed correctly
+        c.doubleCheck();
+        // remove the bundle adapter
+        m.remove(adapter);
+    }
+    
+    public void testBundleAdapterWithCallbackInstance() {
+        DependencyManager m = getDM();
+        // create a bundle adapter service (one is created for each bundle)
+        BundleAdapterWithCallback baWithCb = new BundleAdapterWithCallback();
+        BundleAdapterCallbackInstance cbInstance = new BundleAdapterCallbackInstance(baWithCb);
+        
+        Component adapter = bundleAdapter(m)
+            .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+            .cbi(cbInstance, "add", "remove")
+            .impl(baWithCb)
+            .provides(BundleAdapter.class.getName())
+            .build();
+
+        // create a service provider and consumer
+        Consumer c = new Consumer();
+        Component consumer = component(m)
+            .impl(c)
+            .withSrv(BundleAdapter.class, s->s.cb("add", "remove"))
+            .build();
+        
+        // add the bundle adapter
+        m.add(adapter);
+        // add the service consumer
+        m.add(consumer);
+        // check if at least one bundle was found
+        c.check();
+        // remove the consumer again
+        m.remove(consumer);
+        // check if all bundles were removed correctly
+        c.doubleCheck();
+        // remove the bundle adapter
+        m.remove(adapter);
+    }
+        
+    public void testBundleAdapterWithCallbackInstanceRef() {
+        DependencyManager m = getDM();
+        // create a bundle adapter service (one is created for each bundle)
+        BundleAdapterWithCallback baWithCb = new BundleAdapterWithCallback();
+        BundleAdapterCallbackInstance cbInstance = new BundleAdapterCallbackInstance(baWithCb);
+        
+        Component adapter = bundleAdapter(m)
+            .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+            .cbi(cbInstance::add, cbInstance::remove)
+            .impl(baWithCb)
+            .provides(BundleAdapter.class.getName())
+            .build();
+
+        // create a service provider and consumer
+        Consumer c = new Consumer();
+        Component consumer = component(m)
+            .impl(c)
+            .withSrv(BundleAdapter.class, s->s.cb("add", "remove"))
+            .build();
+        
+        // add the bundle adapter
+        m.add(adapter);
+        // add the service consumer
+        m.add(consumer);
+        // check if at least one bundle was found
+        c.check();
+        // remove the consumer again
+        m.remove(consumer);
+        // check if all bundles were removed correctly
+        c.doubleCheck();
+        // remove the bundle adapter
+        m.remove(adapter);
+    }
+        
+    public static class BundleAdapter {
+        volatile Bundle m_bundle;
+        
+        Bundle getBundle() {
+            return m_bundle;
+        }
+    }
+    
+    public static class BundleAdapterWithCallback extends BundleAdapter {
+        void add(Bundle b) {
+        	m_bundle = b;        	
+        }
+        
+        void remove(Bundle b) {
+        	m_bundle = null;
+        }
+    }
+    
+    public static class BundleAdapterCallbackInstance {
+    	final BundleAdapterWithCallback m_ba;
+    	
+    	BundleAdapterCallbackInstance(BundleAdapterWithCallback ba) {
+    		m_ba = ba;
+    	}
+    	
+        void add(Component c, Bundle b) {
+        	m_ba.add(b);	
+        }
+        
+        void remove(Component c, Bundle b) {
+        	m_ba.remove(b);
+        }
+    }
+    
+    static class Consumer {
+        private volatile int m_count = 0;
+
+        public void add(BundleAdapter ba) {
+            Bundle b = ba.getBundle();
+            System.out.println("Consumer.add(" + b.getSymbolicName() + ")");
+            Assert.assertNotNull("bundle instance must not be null", b);
+            m_count++;
+        }
+        
+        public void check() {
+            Assert.assertTrue("we should have found at least one bundle", m_count > 0);
+        }
+        
+        public void remove(BundleAdapter ba) {
+            Bundle b = ba.getBundle();
+            System.out.println("Consumer.remove(" + b.getSymbolicName() + ")");
+            m_count--;
+        }
+        
+        public void doubleCheck() {
+            Assert.assertEquals("all bundles we found should have been removed again", 0, m_count);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterWithCallbacksNotAutoConfiguredTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterWithCallbacksNotAutoConfiguredTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterWithCallbacksNotAutoConfiguredTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleAdapterWithCallbacksNotAutoConfiguredTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.bundleAdapter;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleAdapterWithCallbacksNotAutoConfiguredTest extends TestBase {  
+    final Ensure m_e = new Ensure();
+    
+    public void testBundleAdapterWithCallbacksNotAutoConfigured() {
+        DependencyManager m = getDM();
+        // create a bundle adapter service (one is created for each bundle)
+        BundleAdapterWithCallback baWithCb = new BundleAdapterWithCallback();
+        String bsn = "org.apache.felix.dependencymanager";
+        String filter = "(Bundle-SymbolicName=" + bsn + ")";
+
+        Component adapter = bundleAdapter(m)
+            .mask(Bundle.ACTIVE).filter(filter).cb("add")        												 
+            .impl(baWithCb)
+            .build();
+        
+        // add the bundle adapter
+        m.add(adapter);
+        
+        // Check if adapter has not been auto configured (because it has callbacks defined).
+        m_e.waitForStep(1, 3000);
+        Assert.assertNull("bundle adapter must not be auto configured", baWithCb.getBundle());
+        
+        // remove the bundle adapters
+        m.remove(adapter);
+    }
+                
+    class BundleAdapterWithCallback {
+        volatile Bundle m_bundle; // must not be auto configured because we are using callbacks.
+        
+        Bundle getBundle() {
+            return m_bundle;
+        }
+        
+        void add(Bundle b) {
+            Assert.assertNotNull(b);
+            Assert.assertEquals("org.apache.felix.dependencymanager", b.getSymbolicName());
+            m_e.step(1);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/BundleDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleDependencyTest extends TestBase {
+    private final static String BSN = "org.apache.felix.metatype";
+    
+    public void testBundleDependencies() {
+        DependencyManager m = getDM();
+        // create a service provider and consumer
+        MyConsumer c = new MyConsumer();        
+        Component consumer = component(m, comp -> comp.impl(c).withBundle(bundle -> bundle.cb("add", "remove")));
+        
+        // check if at least one bundle was found
+        c.check();
+        // remove the consumer again
+        m.remove(consumer);
+        // check if all bundles were removed correctly
+        c.doubleCheck();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        String filter = "(Bundle-SymbolicName=" + BSN + ")";
+        Component consumerWithFilter = component(m, comp -> comp.impl(new FilteredConsumer(e))
+            .withBundle(bundle-> bundle.filter(filter).cb("add", "remove")));
+        e.step(2);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.step(4);
+    }
+
+    public void testBundleDependenciesRef() {
+        DependencyManager m = getDM();
+        // create a service provider and consumer
+        MyConsumer c = new MyConsumer();        
+        Component consumer = component(m, comp -> comp.impl(c).withBundle(bundle -> bundle.cb(MyConsumer::add, MyConsumer::remove)));
+        
+        // check if at least one bundle was found
+        c.check();
+        // remove the consumer again
+        m.remove(consumer);
+        // check if all bundles were removed correctly
+        c.doubleCheck();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        String filter = "(Bundle-SymbolicName=" + BSN + ")";
+        Component consumerWithFilter = component(m, comp -> comp.impl(new FilteredConsumer(e))
+            .withBundle(bundle-> bundle.filter(filter).cb(FilteredConsumer::add, FilteredConsumer::remove)));
+        e.step(2);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.step(4);
+    }
+    
+    public void testRequiredBundleDependency() {
+        DependencyManager m = getDM();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        Component consumerWithFilter = component(m, c -> c.impl(new FilteredConsumerRequired(e))
+            .withBundle(b -> b.filter("(Bundle-SymbolicName=" + BSN + ")").cb("add", "remove")));
+        e.waitForStep(1, 5000);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.waitForStep(2, 5000);
+    }
+    
+    public void testRequiredBundleDependencyRef() {
+        DependencyManager m = getDM();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        FilteredConsumerRequired impl = new FilteredConsumerRequired(e);
+        Component consumerWithFilter = component(m, c -> c.impl(impl)
+            .withBundle(b -> b.filter("(Bundle-SymbolicName=" + BSN + ")").cbi(impl::add, impl::remove)));
+        e.waitForStep(1, 5000);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.waitForStep(2, 5000);
+    }
+        
+    public void testRequiredBundleDependencyWithComponentArgInCallbackMethod() {
+        DependencyManager m = getDM();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // add a consumer with a filter
+        FilteredConsumerRequiredWithComponentArg impl = new FilteredConsumerRequiredWithComponentArg(e);
+        Component consumerWithFilter = component(m, c -> c.impl(impl)
+            .withBundle(b -> b.filter("(Bundle-SymbolicName=" + BSN + ")").cb("add", "remove")));
+        e.waitForStep(1, 5000);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.waitForStep(2, 5000);
+    }
+    
+    public void testRequiredBundleDependencyWithComponentArgInCallbackMethodRef() {
+        DependencyManager m = getDM();
+        
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        FilteredConsumerRequiredWithComponentArg impl = new FilteredConsumerRequiredWithComponentArg(e);
+        Component consumerWithFilter = component(m).impl(impl)
+        		.withBundle(b -> b.filter("(Bundle-SymbolicName=" + BSN + ")").cbi(impl::add, impl::remove)).build();
+        // add a consumer with a filter
+        m.add(consumerWithFilter);
+        e.waitForStep(1, 5000);
+        // remove the consumer again
+        m.remove(consumerWithFilter);
+        e.waitForStep(2, 5000);
+    }
+    
+    static class MyConsumer {
+        private volatile int m_count = 0;
+
+        public void add(Bundle b) {
+            System.out.println("Consumer.add(" + b.getSymbolicName() + ")");
+            Assert.assertNotNull("bundle instance must not be null", b);
+            m_count++;
+        }
+        
+        public void check() {
+            Assert.assertTrue("we should have found at least one bundle", m_count > 0);
+        }
+        
+        public void remove(Bundle b) {
+            System.out.println("Consumer.remove(" + b.getSymbolicName() + ")");
+            m_count--;
+        }
+        
+        public void doubleCheck() {
+            Assert.assertEquals("all bundles we found should have been removed again", 0, m_count);
+        }
+    }
+    
+    static class FilteredConsumer {
+        private final Ensure m_ensure;
+
+        public FilteredConsumer(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void add(Bundle b) {
+            m_ensure.step(1);
+        }
+        
+        public void remove(Bundle b) {
+            m_ensure.step(3);
+        }
+    }
+    
+    static class FilteredConsumerRequired {
+        private final Ensure m_ensure;
+
+        public FilteredConsumerRequired(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void add(Bundle b) {
+            System.out.println("Bundle is " + b);
+//            Assert.assertNotNull(b);
+            if (b.getSymbolicName().equals(BSN)) {
+                m_ensure.step(1);
+            }
+        }
+        
+        public void remove(Bundle b) {
+            Assert.assertNotNull(b);
+            if (b.getSymbolicName().equals(BSN)) {
+                m_ensure.step(2);
+            }
+        }
+    }
+
+    static class FilteredConsumerRequiredWithComponentArg {
+        private final Ensure m_ensure;
+
+        public FilteredConsumerRequiredWithComponentArg(Ensure e) {
+            m_ensure = e;
+        }
+                
+        public void add(Component component, Bundle b) {
+        	Assert.assertNotNull(component);
+            if (b.getSymbolicName().equals(BSN)) {
+                m_ensure.step(1);
+            }
+        }
+        
+        public void remove(Component component, Bundle b) {
+        	Assert.assertNotNull(component);
+            Assert.assertNotNull(b);
+            if (b.getSymbolicName().equals(BSN)) {
+                m_ensure.step(2);
+            }
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ComponentTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ComponentTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ComponentTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ComponentTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import java.util.Dictionary;
+
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentTest extends TestBase {
+    private final Ensure m_ensure = new Ensure();
+    
+    public void testSimple() throws Exception {
+        final DependencyManager dm = getDM();
+
+        // Create consumer (dependency is required by default using builder api).
+        component(dm, comp -> comp
+        		.factory(Consumer::new)
+        		.withSrv(Provider.class, srv -> srv.filter("(name=provider2)").cb(Consumer::add, Consumer::remove))
+        		.withSrv(Provider.class, srv -> srv.filter("(name=provider1)").autoConfig("m_autoConfiguredProvider")));
+                
+        // Create providers (auto added to dependency manager)
+        component(dm, comp -> comp
+        		.impl(new Provider() { public String toString() { return "provider1";}})
+        		.provides(Provider.class).properties("name", "provider1"));
+        		
+        component(dm, comp -> comp
+        		.impl(new Provider() { public String toString() { return "provider2";}})
+        		.provides(Provider.class).properties("name", "provider2"));
+        		
+        m_ensure.waitForStep(2, 5000);
+        dm.clear();
+        m_ensure.waitForStep(5, 5000);
+    }
+    
+    public static interface Provider {    	
+    }
+    
+    public class Consumer {
+        Provider m_provider;
+        Provider m_autoConfiguredProvider;
+                
+		void add(Provider provider, Dictionary<String, Object> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("provider2", props.get("name"));
+            m_provider = provider;
+            m_ensure.step(1);
+        }
+        
+        void start() {
+            Assert.assertNotNull(m_autoConfiguredProvider);
+            Assert.assertEquals("provider1", m_autoConfiguredProvider.toString());
+            m_ensure.step(2);
+        }
+        
+        void stop() {
+            m_ensure.step(3);
+        }
+        
+        void destroy() {
+            m_ensure.step(4);
+        }
+        
+        void remove(Provider provider, Dictionary<String, Object> props) {
+            Assert.assertEquals(m_provider, provider);
+            m_ensure.step(5);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/CompositionTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/CompositionTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/CompositionTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/CompositionTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositionTest extends TestBase {
+    public void testComposition() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a service provider and consumer
+        Component sp = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
+        Component sc = component(m).impl(new ServiceConsumer(e)).composition("getComposition")
+            .withSrv(ServiceInterface.class, sb->sb.cb("add")).build();
+        m.add(sp);
+        m.add(sc);
+        // ensure we executed all steps inside the component instance
+        e.step(6);
+        m.clear();
+    }
+    
+    public void testCompositionRef() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a service provider and consumer
+        Component sp = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
+        ServiceConsumer scimpl = new ServiceConsumer(e);
+        Component sc = component(m).impl(scimpl).composition(scimpl::getComposition)
+            .withSrv(ServiceInterface.class, sb->sb.cb("add")).build();
+        m.add(sp);
+        m.add(sc);
+        // ensure we executed all steps inside the component instance
+        e.step(6);
+        m.clear();
+    }
+    
+    static interface ServiceInterface {
+        public void invoke();
+    }
+
+    static class ServiceProvider implements ServiceInterface {
+        private final Ensure m_ensure;
+        public ServiceProvider(Ensure e) {
+            m_ensure = e;
+        }
+        public void invoke() {
+            m_ensure.step(4);
+        }
+    }
+
+    static class ServiceConsumer {
+        private final Ensure m_ensure;
+        private ServiceConsumerComposite m_composite;
+        @SuppressWarnings("unused")
+        private ServiceInterface m_service;
+
+        public ServiceConsumer(Ensure e) {
+            m_ensure = e;
+            m_composite = new ServiceConsumerComposite(m_ensure);
+        }
+        
+        public Object[] getComposition() {
+            return new Object[] { this, m_composite };
+        }
+        
+        void add(ServiceInterface service) {
+            m_ensure.step(1);
+            m_service = service; // This method seems to not being called anymore 
+        }
+        
+        void start() {
+            m_composite.invoke();
+            m_ensure.step(5); 
+        }
+    }
+    
+    static class ServiceConsumerComposite {
+        ServiceInterface m_service;
+        private Ensure m_ensure;
+        
+        ServiceConsumerComposite(Ensure ensure)
+        {
+            m_ensure = ensure;
+        }
+
+        void add(ServiceInterface service) {
+
+            m_ensure.step(2);
+            m_service = service;
+        }
+
+        void invoke()
+        {
+            m_ensure.step(3);
+            m_service.invoke();
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/DynamicProxyAspectTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/DynamicProxyAspectTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/DynamicProxyAspectTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/DynamicProxyAspectTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,254 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.aspect;
+import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"rawtypes"})
+public class DynamicProxyAspectTest extends TestBase {
+    public void testImplementGenericAspectWithDynamicProxyAndFactory() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        
+        DynamicProxyHandler.resetCounter();
+        
+        // create two service providers, each providing a different service interface
+        Component sp1 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
+        Component sp2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface2.class).build();
+        
+        // create a dynamic proxy based aspect and hook it up to both services
+        Component a1 = aspect(m, ServiceInterface.class)
+            .rank(10)
+            .autoConfig("m_service")
+            .factory(new Factory(e, ServiceInterface.class, "ServiceInterfaceProxy"), "create")
+            .build();
+        
+        Component a2 = aspect(m, ServiceInterface2.class)
+            .rank(10)
+            .autoConfig("m_service")
+            .factory(new Factory(e, ServiceInterface2.class, "ServiceInterfaceProxy2"), "create")
+            .build();
+
+        // create a client that invokes a method on boths services, validate that it goes
+        // through the proxy twice
+        Component sc = component(m)
+            .impl(new ServiceConsumer(e))
+            .withSrv(ServiceInterface.class, ServiceInterface2.class).build();
+        
+        // register both producers, validate that both services are started
+        m.add(sp1);
+        e.waitForStep(1, 2000);
+        m.add(sp2);
+        e.waitForStep(2, 2000);
+        
+        // add both aspects, and validate that both instances have been created
+        m.add(a1);
+        m.add(a2);
+        e.waitForStep(4, 4000);
+        
+        // add the client, which will automatically invoke both services
+        m.add(sc);
+        
+        // wait until both services have been invoked
+        e.waitForStep(6, 4000);
+        
+        // make sure the proxy has been called twice
+        Assert.assertEquals("Proxy should have been invoked this many times.", 2, DynamicProxyHandler.getCounter());
+        
+        m.remove(sc);
+        m.remove(a2);
+        m.remove(a1);
+        m.remove(sp2);
+        m.remove(sp1);
+        m.remove(a2);
+        m.remove(a1);
+    }
+
+    public void testImplementGenericAspectWithDynamicProxyAndFactoryRef() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        
+        DynamicProxyHandler.resetCounter();
+
+        // create two service providers, each providing a different service interface
+        Component sp1 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class).build();
+        Component sp2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface2.class).build();
+        
+        // create a dynamic proxy based aspect and hook it up to both services
+        Component a1 = aspect(m, ServiceInterface.class).rank(10).autoConfig("m_service")
+            .factory(() -> new Factory(e, ServiceInterface.class, "ServiceInterfaceProxy"), Factory::create).build();
+        Component a2 = aspect(m, ServiceInterface2.class).rank(10).autoConfig("m_service")
+            .factory(() -> new Factory(e, ServiceInterface2.class, "ServiceInterfaceProxy2"), Factory::create).build();
+
+        // create a client that invokes a method on boths services, validate that it goes
+        // through the proxy twice
+        Component sc = component(m)
+            .impl(new ServiceConsumer(e))
+            .withSrv(ServiceInterface.class, ServiceInterface2.class).build();
+        
+        // register both producers, validate that both services are started
+        m.add(sp1);
+        e.waitForStep(1, 2000);
+        m.add(sp2);
+        e.waitForStep(2, 2000);
+        
+        // add both aspects, and validate that both instances have been created
+        m.add(a1);
+        m.add(a2);
+        e.waitForStep(4, 4000);
+        
+        // add the client, which will automatically invoke both services
+        m.add(sc);
+        
+        // wait until both services have been invoked
+        e.waitForStep(6, 4000);
+        
+        // make sure the proxy has been called twice
+        Assert.assertEquals("Proxy should have been invoked this many times.", 2, DynamicProxyHandler.getCounter());
+        
+        m.remove(sc);
+        m.remove(a2);
+        m.remove(a1);
+        m.remove(sp2);
+        m.remove(sp1);
+        m.remove(a2);
+        m.remove(a1);        
+    }
+    
+    static interface ServiceInterface {
+        public void invoke(Runnable run);
+    }
+    
+    static interface ServiceInterface2 {
+        public void invoke(Runnable run);
+    }
+    
+    static class ServiceProvider implements ServiceInterface {
+        private final Ensure m_ensure;
+        public ServiceProvider(Ensure e) {
+            m_ensure = e;
+        }
+        public void start() {
+            m_ensure.step(1);
+        }
+        public void invoke(Runnable run) {
+            run.run();
+        }
+    }
+    
+    static class ServiceProvider2 implements ServiceInterface2 {
+        private final Ensure m_ensure;
+        public ServiceProvider2(Ensure ensure) {
+            m_ensure = ensure;
+        }
+        public void start() {
+            m_ensure.step(2);
+        }
+        public void invoke(Runnable run) {
+            run.run();
+        }
+    }
+    
+    static class ServiceConsumer implements Runnable {
+        private volatile ServiceInterface m_service;
+        private volatile ServiceInterface2 m_service2;
+        private final Ensure m_ensure;
+
+        public ServiceConsumer(Ensure e) {
+            m_ensure = e;
+        }
+        
+        public void init() {
+            Thread t = new Thread(this);
+            t.start();
+        }
+        
+        public void run() {
+            m_service.invoke(Ensure.createRunnableStep(m_ensure, 5));
+            m_service2.invoke(Ensure.createRunnableStep(m_ensure, 6));
+        }
+    }
+    
+    static class DynamicProxyHandler implements InvocationHandler {
+        public volatile Object m_service; // ISSUE, we cannot inject into "Object" at the moment
+        private final String m_label;
+        private static volatile int m_counter = 0;
+
+        public DynamicProxyHandler(String label) {
+            m_label = label;
+        }
+
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            System.out.println("IIIIIIINVOKE--------------------------" + method.getName());
+            if (m_service == null) {
+                Assert.fail("No service was injected into dynamic proxy handler " + m_label);
+            }
+            Method m = m_service.getClass().getMethod(method.getName(), method.getParameterTypes());
+            if (m == null) {
+                Assert.fail("No method " + method.getName() + " was found in instance " + m_service + " in dynamic proxy handler " + m_label);
+            }
+            if (method.getName().equals("invoke")) {
+                // only count methods called 'invoke' because those are actually the ones
+                // both interfaces implement (and the dynamic proxy might be invoked for
+                // other methods, such as toString() as well)
+                m_counter++;
+            }
+            return m.invoke(m_service, args);
+        }
+        
+        public static int getCounter() {
+            return m_counter;
+        }
+        
+        public static void resetCounter() {
+            m_counter = 0;
+        }
+    }
+    
+    static class Factory {
+        private final String m_label;
+        private Class m_class;
+        private final Ensure m_ensure;
+        
+        public Factory(Ensure ensure, Class clazz, String label) {
+            m_ensure = ensure;
+            m_class = clazz;
+            m_label = label;
+        }
+        
+        public Object create() {
+            m_ensure.step();
+            return Proxy.newProxyInstance(m_class.getClassLoader(), new Class[] { m_class }, new DynamicProxyHandler(m_label));
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/Ensure.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/Ensure.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/Ensure.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/Ensure.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.lambda.itest;
+
+import java.io.PrintStream;
+
+import org.junit.Assert;
+
+/**
+ * Helper class to make sure that steps in a test happen in the correct order. Instantiate
+ * this class and subsequently invoke <code>step(nr)</code> with steps starting at 1. You
+ * can also have threads wait until you arrive at a certain step.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Ensure {
+    private final boolean DEBUG;
+    private static long INSTANCE = 0;
+    private static final int RESOLUTION = 100;
+    private static PrintStream STREAM = System.out;
+    int step = 0;
+    private Throwable m_throwable;
+    
+    public Ensure() {
+        this(true);
+    }
+    
+    public Ensure(boolean debug) {
+        DEBUG = debug;
+        if (DEBUG) {
+            INSTANCE++;
+        }
+    }
+
+    public void setStream(PrintStream output) {
+        STREAM = output;
+    }
+    
+    /**
+     * Mark this point as step <code>nr</code>.
+     * 
+     * @param nr the step we are in
+     */
+    public synchronized void step(int nr) {
+        step++;
+        Assert.assertEquals(nr, step);
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] step " + step + " [" + currentThread() + "] " + info);
+        }
+        notifyAll();
+    }
+
+    private String getLineInfo(int depth) {
+        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
+        String info = trace[depth].getClassName() + "." + trace[depth].getMethodName() + ":" + trace[depth].getLineNumber();
+        return info;
+    }
+    
+    /**
+     * Mark this point as the next step.
+     */
+    public synchronized void step() {
+        step++;
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] next step " + step + " [" + currentThread() + "] " + info);
+        }
+        notifyAll();
+    }
+
+    /**
+     * Wait until we arrive at least at step <code>nr</code> in the process, or fail if that
+     * takes more than <code>timeout</code> milliseconds. If you invoke wait on a thread,
+     * you are effectively assuming some other thread will invoke the <code>step(nr)</code>
+     * method.
+     * 
+     * @param nr the step to wait for
+     * @param timeout the number of milliseconds to wait
+     */
+    public synchronized void waitForStep(int nr, int timeout) {
+        final int initialTimeout = timeout;
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] waiting for step " + nr + " [" + currentThread() + "] " + info);
+        }
+        while (step < nr && timeout > 0) {
+            try {
+                wait(RESOLUTION);
+                timeout -= RESOLUTION;
+            }
+            catch (InterruptedException e) {}
+        }
+        if (step < nr) {
+            throw new IllegalStateException("Timed out waiting for " + initialTimeout + " ms for step " + nr + ", we are still at step " + step);
+        }
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] arrived at step " + nr + " [" + currentThread() + "] " + info);
+        }
+    }
+    
+    private String currentThread() {
+        Thread thread = Thread.currentThread();
+        return thread.getId() + " " + thread.getName();
+    }
+    
+    public static Runnable createRunnableStep(final Ensure ensure, final int nr) {
+        return new Runnable() { public void run() { ensure.step(nr); }};
+    }
+    
+    public synchronized void steps(Steps steps) {
+        steps.next(this);
+    }
+    
+    /** 
+     * Helper class for naming a list of step numbers. If used with the steps(Steps) method
+     * you can define at which steps in time this point should be passed. That means you can
+     * check methods that will get invoked multiple times during a test.
+     */
+    public static class Steps {
+        private final int[] m_steps;
+        private int m_stepIndex;
+
+        /** 
+         * Create a list of steps and initialize the step counter to zero.
+         */
+        public Steps(int... steps) {
+            m_steps = steps;
+            m_stepIndex = 0;
+        }
+
+        /**
+         * Ensure we're at the right step. Will throw an index out of bounds exception if we enter this step more often than defined.
+         */
+        public void next(Ensure ensure) {
+            ensure.step(m_steps[m_stepIndex++]);
+        }
+    }
+
+    /**
+     * Saves a thrown exception that occurred in a different thread. You can only save one exception
+     * at a time this way.
+     */
+    public synchronized void throwable(Throwable throwable) {
+        m_throwable = throwable;
+    }
+
+    /**
+     * Throws a <code>Throwable</code> if one occurred in a different thread and that thread saved it
+     * using the <code>throwable()</code> method.
+     */
+    public synchronized void ensure() throws Throwable {
+        if (m_throwable != null) {
+            throw m_throwable;
+        }
+    }
+}




Mime
View raw message