felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1727487 [4/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/FactoryConfigurationAdapterTest.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/FactoryConfigurationAdapterTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,227 @@
+/*
+ * 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 static org.apache.felix.dm.lambda.DependencyManagerActivator.factoryPidAdapter;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class FactoryConfigurationAdapterTest extends TestBase
+{
+    private static Ensure m_ensure;
+    
+    public void testFactoryConfigurationAdapter() {
+    	testFactoryConfigurationAdapter(Adapter.class, "updated");
+    }
+    
+    public void testFactoryConfigurationAdapterWithUpdatedCallbackThatTakesComponentAsParameter() {
+    	testFactoryConfigurationAdapter(AdapterWithUpdateMethodThatTakesComponentAsParameter.class, "updatedWithComponent");
+    }
+    
+    public void testFactoryConfigurationAdapter(Class<?> adapterImplClass, String adapterUpdate) {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        m_ensure = new Ensure();
+        
+        // Create a Configuration instance, which will create/update/remove a configuration for factoryPid "MyFactoryPid"
+        ConfigurationCreator configurator = new ConfigurationCreator("MyFactoryPid", "key", "value1");
+        Component s1 = component(m).impl(configurator).withSrv(ConfigurationAdmin.class).build();
+           
+        // Create an Adapter that will be instantiated, once the configuration is created.
+        // This Adapter provides an AdapterService, and depends on an AdapterExtraDependency service.
+        Component s2 = factoryPidAdapter(m)
+            .factoryPid("MyFactoryPid").impl(adapterImplClass).cb(adapterUpdate).propagate().provides(AdapterService.class, "foo", "bar")            
+            .withSrv(AdapterExtraDependency.class)
+            .build();
+                    
+        // Create extra adapter service dependency upon which our adapter depends on.
+        Component s3 = component(m)
+            .impl(new AdapterExtraDependency()).provides(AdapterExtraDependency.class).build();
+        
+        // Create an AdapterService Consumer
+        Component s4 = component(m)
+            .impl(AdapterServiceConsumer.class).withSrv(AdapterService.class, srv -> srv.cb("bind", "change", "remove")).build();
+        
+        // Start services
+        m.add(s1);
+        m.add(s2);
+        m.add(s3);
+        m.add(s4);
+        
+        // Wait for step 8: the AdapterService consumer has been injected with the AdapterService, and has called the doService method.
+        m_ensure.waitForStep(8, 10000);
+        
+        // Modify configuration.
+        configurator.update("key", "value2");
+        
+        // Wait for step 13: the AdapterService has been updated, and the AdapterService consumer has seen the change
+        m_ensure.waitForStep(13, 10000);
+        
+        // Remove the configuration
+        m.remove(s1); // The stop method will remove the configuration
+        m_ensure.waitForStep(16, 10000);
+        m.clear();
+    }
+
+    public static class ConfigurationCreator {
+        private volatile ConfigurationAdmin m_ca;
+        private String m_key;
+        private String m_value;
+        private org.osgi.service.cm.Configuration m_conf;
+        private String m_factoryPid;
+        
+        public ConfigurationCreator(String factoryPid, String key, String value) {
+            m_factoryPid = factoryPid;
+            m_key = key;
+            m_value = value;
+        }
+
+        public void start() {
+            try {
+                m_ensure.step(1);
+                m_conf = m_ca.createFactoryConfiguration(m_factoryPid, null);
+                Hashtable props = new Hashtable();
+                props.put(m_key, m_value);
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not create configuration: " + e.getMessage());
+            }
+        }
+        
+        public void update(String key, String val) {
+            Hashtable props = new Hashtable();
+            props.put(key, val);
+            try {
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not update configuration: " + e.getMessage());
+            }
+        }
+        
+        public void stop() {
+            try
+            {
+                m_conf.delete();
+            }
+            catch (IOException e)
+            {
+                Assert.fail("Could not remove configuration: " + e.toString());
+            }
+        }
+    }
+    
+    public interface AdapterService {
+        public void doService();
+    }
+    
+    public static class AdapterExtraDependency {
+    }
+
+    public static class Adapter implements AdapterService {
+        volatile AdapterExtraDependency m_extraDependency; // extra dependency.
+        private int updateCount;
+        
+        void updated(Dictionary settings) {
+            updateCount ++;
+            if (updateCount == 1) {
+                m_ensure.step(2);
+                Assert.assertEquals(true, "value1".equals(settings.get("key")));
+                m_ensure.step(3);
+            } else if (updateCount == 2) {
+                m_ensure.step(9);
+                Assert.assertEquals(true, "value2".equals(settings.get("key")));
+                m_ensure.step(10);
+            } else {
+                Assert.fail("wrong call to updated method: count=" + updateCount);
+            }
+        }
+
+        public void doService() {   
+            m_ensure.step(8);
+        }
+        
+        public void start() {
+            m_ensure.step(4);
+            Assert.assertNotNull(m_extraDependency);
+            m_ensure.step(5);
+        }
+        
+        public void stop() {
+            m_ensure.step(16);
+        }
+    }
+    
+    public static class AdapterWithUpdateMethodThatTakesComponentAsParameter extends Adapter {
+        void updatedWithComponent(Component component, Dictionary settings) {
+        	Assert.assertNotNull(component);
+        	Assert.assertEquals(this, component.getInstance());
+        	super.updated(settings);
+        }
+    }
+
+    public static class AdapterServiceConsumer {
+        private AdapterService m_adapterService;
+        private Map m_adapterServiceProperties;
+        
+        void bind(Map serviceProperties, AdapterService adapterService) {
+            m_ensure.step(6);
+            m_adapterService = adapterService;
+            m_adapterServiceProperties = serviceProperties;
+        }
+        
+        void change(Map serviceProperties, AdapterService adapterService) {
+            m_ensure.step(11);
+            Assert.assertEquals(true, "value2".equals(m_adapterServiceProperties.get("key")));
+            m_ensure.step(12);
+            Assert.assertEquals(true, "bar".equals(m_adapterServiceProperties.get("foo")));
+            m_ensure.step(13);
+        }
+        
+        public void start() {
+            m_ensure.step(7);
+            Assert.assertNotNull(m_adapterService);
+            Assert.assertEquals(true, "value1".equals(m_adapterServiceProperties.get("key")));
+            Assert.assertEquals(true, "bar".equals(m_adapterServiceProperties.get("foo")));
+            m_adapterService.doService();
+        }
+        
+        public void stop() {
+            m_ensure.step(14);
+        }
+        
+        void remove(AdapterService adapterService) {
+            m_ensure.step(15);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.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/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,132 @@
+/*
+ * 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.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+
+/**
+ * Use case: one component is instantiated using another factory object, and the 
+ * factory object needs the configuration before the factory.create method is called.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FactoryInjectedWithConfigurationBeforeTheCreateMethod extends TestBase {
+    Ensure m_e;
+    
+    public void testServiceInjection() {
+        DependencyManager m = getDM();
+        m_e = new Ensure();
+        
+        // Create the component that creates a configuration.
+        Component configurator = component(m).impl(new Configurator("foobar")).withSrv(ConfigurationAdmin.class).build();
+        
+        // Create the object that has to be injected with the configuration before its create method is called.
+        MyFactory factory = new MyFactory();
+        
+        // Create the Component for the MyComponent class that is created using the factory above.
+        Component myComponent = component(m).factory(factory, "create").withCnf(b->b.pid("foobar").cbi(factory, "updated")).build();
+        
+        // provide the configuration
+        m.add(configurator);
+        
+        m.add(myComponent);
+        m_e.waitForStep(4, 10000);
+        m.remove(myComponent);
+        m.remove(configurator);
+    }
+    
+    public void testServiceInjectionRef() {
+        DependencyManager m = getDM();
+        m_e = new Ensure();
+        
+        // Create the component that creates a configuration.
+        Component configurator = component(m).impl(new Configurator("foobar")).withSrv(ConfigurationAdmin.class).build();
+        
+        // Create the object that has to be injected with the configuration before its create method is called.
+        MyFactory factory = new MyFactory();
+        
+        // Create the Component for the MyComponent class that is created using the factory above.
+        Component myComponent = component(m).factory(factory, "create").withCnf(b->b.pid("foobar").cbi(factory::updated)).build();
+        
+        // provide the configuration
+        m.add(configurator);
+        
+        m.add(myComponent);
+        m_e.waitForStep(4, 10000);
+        m.remove(myComponent);
+        m.remove(configurator);
+    }
+
+    class Configurator {
+        private volatile ConfigurationAdmin m_ca;
+        Configuration m_conf;
+        final String m_pid;
+        
+        public Configurator(String pid) {
+            m_pid = pid;
+        }
+
+        public void init() {
+            try {
+                Assert.assertNotNull(m_ca);
+                m_e.step(1);
+                m_conf = m_ca.getConfiguration(m_pid, null);
+                Hashtable<String, Object> props = new Hashtable<>();
+                props.put("testkey", "testvalue");
+                m_conf.update(props);
+            }
+            catch (IOException e) {
+                Assert.fail("Could not create configuration: " + e.getMessage());
+            }
+        }
+        
+        public void destroy() throws IOException {
+            m_conf.delete();  
+        }
+    }
+
+    public class MyFactory {
+        public void updated(Dictionary<String, Object> conf) {
+            Assert.assertNotNull("configuration is null", conf);
+            m_e.step(2);
+        }
+        
+        public MyComponent create() {
+            m_e.step(3);
+            return new MyComponent();
+        }
+    }
+    
+    public class MyComponent {
+        void start() {
+            m_e.step(4);
+        }        
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.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/InstanceBoundDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,157 @@
+/*
+ * 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.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This test does some injection tests on components being in INSTANTIATED_AND_WAITING_FOR_REQUIRED state.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class InstanceBoundDependencyTest extends TestBase {
+    Ensure m_e;
+    
+    public void testServiceInjection() {
+        DependencyManager m = getDM();
+        m_e = new Ensure();
+        
+        // Create a "C" component: it depends on some S1 services, and on some S2 instance-bound services (declared from C.init() method)        
+        C cimpl = new C();
+        Component c = component(m).impl(cimpl)
+            .withSrv(S1.class, sb->sb.cb("addS1", "changeS1", "removeS1").autoConfig(true)).build();
+        m.add(c);
+        
+        // Add S1 (s1_1): C.add(S1 s1) is called, then init() is called where a dependency is declared on S2
+        Hashtable s1_1_props = new Hashtable();
+        s1_1_props.put("name", "s1_1");
+        s1_1_props.put(Constants.SERVICE_RANKING, new Integer(10));
+        S1Impl s1_1_impl = new S1Impl();
+        Component s1_1 = component(m).impl(s1_1_impl).provides(S1.class.getName(), s1_1_props).build();
+        m.add(s1_1);
+        m_e.waitForStep(1, 5000); // wait until C.init called
+        ServiceReference ref = cimpl.getS1("s1_1");
+        Assert.assertNotNull(ref);
+        Assert.assertNotNull(cimpl.getS1());
+        Assert.assertEquals(s1_1_impl, cimpl.getS1());
+        
+        // At this point, MyComponent is in INSTANTIATED_AND_WAITING_FOR_REQUIRED state. 
+        // add now add another higher ranked S1 (s1_2) instance. C.add(s1_2) method should be called (the S1 dependency 
+        // is not instance bound), and m_s1 autoconfig field should be updated.
+        Hashtable s1_2_props = new Hashtable();
+        s1_2_props.put(Constants.SERVICE_RANKING, new Integer(20));
+        s1_2_props.put("name", "s1_2");
+        S1Impl s1_2_impl = new S1Impl();
+        Component s1_2 = component(m).impl(s1_2_impl).provides(S1.class.getName(), s1_2_props).build();
+        m.add(s1_2);
+        ref = cimpl.getS1("s1_2");
+        Assert.assertNotNull(ref);
+        Assert.assertNotNull(cimpl.getS1()); 
+        Assert.assertEquals(s1_2_impl, cimpl.getS1()); // must return s1_2 with ranking = 20
+
+        // Now, change the s1_1 service properties: C.changed(s1_1) should be called, and C.m_s1AutoConfig should be updated
+        s1_1_props.put(Constants.SERVICE_RANKING, new Integer(30));
+        s1_1.setServiceProperties(s1_1_props);
+        ref = cimpl.getS1("s1_1");
+        Assert.assertNotNull(ref);
+        Assert.assertEquals(new Integer(30), ref.getProperty(Constants.SERVICE_RANKING));
+        Assert.assertNotNull(cimpl.getS1());
+        Assert.assertEquals(s1_1_impl, cimpl.getS1());
+        
+        // Now, remove the s1_1: C.remove(s1_1) should be called, and C.m_s1AutoConfig should be updated
+        m.remove(s1_1);
+        ref = cimpl.getS1("s1_1");
+        Assert.assertNull(cimpl.getS1("s1_1"));
+        Assert.assertNotNull(cimpl.getS1());
+        Assert.assertEquals(s1_2_impl, cimpl.getS1());
+        m.clear();
+    }
+    
+    // C component depends on some S1 required services
+    public interface S1 {
+    }
+    
+    public class S1Impl implements S1 {
+    }
+    
+    public interface S2 {        
+    }
+    
+    public class S2Impl implements S2 {        
+    }
+    
+    // Our "C" component: it depends on S1 (required) and S2 (required/instance bound)
+    class C {        
+        final Map<String, ServiceReference> m_s1Map = new HashMap();
+        final Map<String, ServiceReference> m_s2Map = new HashMap();
+        volatile S1 m_s1; // auto configured
+        
+        S1 getS1() {
+            return m_s1;
+        }
+
+        void addS1(ServiceReference s1) {
+            m_s1Map.put((String) s1.getProperty("name"), s1);
+        }
+        
+        void changeS1(ServiceReference s1) {
+            m_s1Map.put((String) s1.getProperty("name"), s1);
+        }
+        
+        void removeS1(ServiceReference s1) {
+            m_s1Map.remove((String) s1.getProperty("name"));
+        }
+        
+        void addS2(ServiceReference s2) {
+            m_s2Map.put((String) s2.getProperty("name"), s2);
+        }
+        
+        void changeS2(ServiceReference s2) {
+            m_s2Map.put((String) s2.getProperty("name"), s2);
+        }
+        
+        void removeS2(ServiceReference s2) {
+            m_s2Map.remove((String) s2.getProperty("name"));
+        }
+        
+        ServiceReference getS1(String name) {
+            return m_s1Map.get(name);
+        }
+        
+        ServiceReference getS2(String name) {
+            return m_s2Map.get(name);
+        }
+        
+        void init(Component c) {
+            component(c, comp->comp.withSrv(S2.class, srv -> srv.cb(C::addS2, C::changeS2, C::removeS2)));
+            m_e.step(1);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.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/ModifiedBundleDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,168 @@
+/*
+ * 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;
+import org.osgi.framework.BundleException;
+
+/**
+ * Test for FELIX-4334 issue.
+ * 
+ * Two components: A, B
+ * 
+ * - A provided.
+ * - B has a bundle dependency on the dependency manager shell bundle, which is currently stopped.
+ * - B has an instance bound dependency on A.
+ * - Now unregister A.
+ * - As a result of that, B becomes unavailable and is unbound from A. But B is not destroyed, because A dependency 
+ *   is "instance bound". So B is still bound to the bundle dependency.
+ * - Now, someone starts the dependency manager shell bundle: B then shall be called in its "changed" callback.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ModifiedBundleDependencyTest extends TestBase {
+    public static interface A {
+    }
+    
+    static class AImpl implements A {
+    }
+        
+    public static interface B {
+    }
+    
+    static class BImpl implements B {
+        final Ensure m_e;
+        
+        BImpl(Ensure e) {
+            m_e = e;
+        }
+        
+        public void add(Bundle dmTest) {
+            m_e.step(1);
+        }
+
+        void init(Component c) {
+            m_e.step(2);
+            component(c, comp -> comp.withSrv(A.class, srv -> srv.cb("add", "remove")));
+        }
+        
+        public void add(A a) {
+            m_e.step(3);
+        }
+        
+        public void start() {
+            m_e.step(4);            
+        }
+        
+        public void stop() {
+            m_e.step(5);
+        }
+
+        public void remove(A a) {
+            m_e.step(6);
+        }
+
+        public void change(Bundle dmTest) { // called two times: one for STARTING, one for STARTED
+            m_e.step(); 
+        }
+        
+        public void destroy() {
+            m_e.step(9);
+        }
+
+        public void remove(Bundle dmTest) {   
+            m_e.step(10);
+        }                    
+    }
+    
+    public void testAdapterWithChangedInstanceBoundDependencyAndCallbacks() {
+        DependencyManager m = getDM();
+        Ensure e = new Ensure();
+
+        Component a = component(m).impl(new AImpl()).provides(A.class).build();
+        
+        String filter = "(Bundle-SymbolicName=org.apache.felix.metatype)";
+        int mask = Bundle.INSTALLED|Bundle.ACTIVE|Bundle.RESOLVED|Bundle.STARTING;
+        Component b = component(m)
+            .provides(B.class).impl(new BImpl(e)).withBundle(bd -> bd.filter(filter).mask(mask).cb("add", "change", "remove")).build();     	
+        						                    
+        Bundle dmtest = getBundle("org.apache.felix.metatype");
+        try {
+            dmtest.stop();
+        } catch (BundleException e1) {
+            Assert.fail("could not find metatype bundle");
+        }
+        
+        m.add(a);
+        m.add(b);
+        
+        e.waitForStep(4, 5000);        
+        m.remove(a); // B will loose A and will enter into "waiting for required (instantiated)" state.
+        System.out.println("Starting metatype bundle ...");        
+        try {
+            dmtest.start();
+        } catch (BundleException e1) {
+            Assert.fail("could not start metatype bundle");
+        }
+        e.waitForStep(7, 5000);     
+        m.remove(b);        
+        e.waitForStep(10, 5000);                
+    }
+
+    public void testAdapterWithChangedInstanceBoundDependencyRef() {
+        DependencyManager m = getDM();
+        Ensure e = new Ensure();
+
+        Component a = 
+        	component(m, comp -> comp.impl(new AImpl()).provides(A.class).autoAdd(false));
+        
+        BImpl impl = new BImpl(e);
+        String filter = "(Bundle-SymbolicName=org.apache.felix.metatype)";
+        int mask = Bundle.INSTALLED|Bundle.ACTIVE|Bundle.RESOLVED|Bundle.STARTING;
+        Component b = component(m).provides(B.class).impl(impl)
+            .withBundle(bd -> bd.filter(filter).mask(mask).cbi(impl::add, impl::change, impl::remove)).build();        	
+        
+        Bundle dmtest = getBundle("org.apache.felix.metatype");
+        try {
+            dmtest.stop();
+        } catch (BundleException e1) {
+            Assert.fail("could not find metatype bundle");
+        }
+        
+        m.add(a);
+        m.add(b);
+        
+        e.waitForStep(4, 5000);        
+        m.remove(a); // B will loose A and will enter into "waiting for required (instantiated)" state.
+        System.out.println("Starting metatype bundle ...");        
+        try {
+            dmtest.start();
+        } catch (BundleException e1) {
+            Assert.fail("could not start metatype bundle");
+        }
+        e.waitForStep(7, 5000);     
+        m.remove(b);        
+        e.waitForStep(10, 5000);                
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.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/MultipleExtraDependenciesTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class MultipleExtraDependenciesTest extends TestBase {
+    /**
+     * Check that list of extra dependencies (defined from init method) are handled properly.
+     * The extra dependencies are added using a List object (Component.add(List)).
+     * A component c1 will define two extra dependencies over *available* c4/c5 services.
+     */
+     public void testWithTwoAvailableExtraDependency() {   
+         DependencyManager m = getDM();
+         // Helper class that ensures certain steps get executed in sequence
+         Ensure e = new Ensure();
+         Component c1 = component(m).provides(Service1.class).impl(new MyComponent1(e)).withSrv(Service2.class, srv->srv.autoConfig("m_service2")).build();
+         Component c2 = component(m).impl(new MyComponent2(e)).withSrv(Service1.class, srv->srv.required(false).autoConfig(false).cb("added")).build();
+         Component c3 = component(m).provides(Service2.class).impl(Service2Impl.class).build();
+         Component c4 = component(m).impl(Service3Impl1.class).provides(Service3.class, type -> "xx").build();
+         Component c5 = component(m).impl(Service3Impl2.class).provides(Service3.class, type -> "yy").build();
+
+         System.out.println("\n+++ Adding c2 / MyComponent2");
+         m.add(c2);
+         System.out.println("\n+++ Adding c3 / Service2");
+         m.add(c3);
+         System.out.println("\n+++ Adding c4 / Service3(xx)");
+         m.add(c4);
+         System.out.println("\n+++ Adding c5 / Service3(yy)");
+         m.add(c5);
+         System.out.println("\n+++ Adding c1 / MyComponent1");
+         // c1 have declared two extra dependency on Service3 (xx/yy).
+         // both extra dependencies are available, so the c1 component should be started immediately.
+         m.add(c1);
+         e.waitForStep(3, 3000);
+         m.clear();
+     }
+
+    /**
+     * Check that list of extra dependencies (defined from init method) are handled properly.
+     * The extra dependencies are added using a List object (Component.add(List)).
+     * A component c1 will define two extra dependencies over c4/c5. At the point c1.init()
+     * is adding the two extra dependencies from its init method, c4 is available, but not c5.
+     * So, c1 is not yet activated.
+     * Then c5 is added, and it triggers the c1 activation ...
+     */
+    public void testWithOneAvailableExtraDependency() {  
+        DependencyManager m = getDM();
+        // Helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        Component c1 = component(m).provides(Service1.class).impl(new MyComponent1(e)).withSrv(Service2.class, srv->srv.autoConfig("m_service2")).build();
+        Component c2 = component(m).impl(new MyComponent2(e)).withSrv(Service1.class, srv->srv.required(false).autoConfig(false).cb("added")).build();
+        Component c3 = component(m).provides(Service2.class).impl(Service2Impl.class).build();
+        Component c4 = component(m).impl(Service3Impl1.class).provides(Service3.class, type -> "xx").build();
+        Component c5 = component(m).impl(Service3Impl2.class).provides(Service3.class, type -> "yy").build();
+
+        System.out.println("\n+++ Adding c2 / MyComponent2");
+        m.add(c2);
+        System.out.println("\n+++ Adding c3 / Service2");
+        m.add(c3);
+        System.out.println("\n+++ Adding c4 / Service3(xx)");
+        m.add(c4);
+        System.out.println("\n+++ Adding c1 / MyComponent1");
+        m.add(c1);
+
+        // c1 have declared two extra dependency on Service3 (xx/yy).
+        // So, because we have not yet added c5 (yy), c1 should not be started currently.
+        // But, now, we'll add c5 (Service3/yy) and c1 should then be started ...
+        System.out.println("\n+++ Adding c5 / Service3(yy)");
+        m.add(c5);
+        e.waitForStep(3, 3000);
+        m.clear();
+    }
+
+
+    public interface Service1 {}
+    public interface Service2 {}
+    public interface Service3 {}
+
+    public static class Service2Impl implements Service2 {}
+    public static class Service3Impl1 implements Service3 {}
+    public static class Service3Impl2 implements Service3 {}
+
+    public static class MyComponent1 implements Service1 {
+        Service2 m_service2;
+        Service3 m_service3_xx;
+        Service3 m_service3_yy;
+        Ensure m_ensure;
+        
+        public MyComponent1(Ensure e) {
+            m_ensure = e;
+        }
+
+        void init(Component c) {
+            m_ensure.step(1);
+            // Service3/xx currently available
+            // Service3/yy not yet available
+
+            component(c, comp -> comp
+                .withSrv(Service3.class, srv->srv.filter("(type=xx)").autoConfig("m_service3_xx"))
+                .withSrv(Service3.class, srv->srv.filter("(type=yy)").autoConfig("m_service3_yy")));
+        }
+        
+        void start() {
+            System.out.println("MyComponent1.start");
+            Assert.assertNotNull(m_service2);
+            Assert.assertNotNull(m_service3_xx);
+            Assert.assertNotNull(m_service3_yy);
+            m_ensure.step(2);
+        }
+    }
+    
+    public static class MyComponent2 {
+        Ensure m_ensure;
+        
+        public MyComponent2(Ensure e) {
+            m_ensure = e;
+        }
+
+        void added(Service1 s1) {
+            System.out.println("MyComponent2.bind(" + s1 + ")");
+            Assert.assertNotNull(s1);
+            m_ensure.step(3);
+        }
+        
+        void start() {
+            System.out.println("MyComponent2.start");
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.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/MultipleExtraDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,209 @@
+/*
+ * 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;
+
+/**
+ * Test which validates multi-dependencies combination.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes", "serial"})
+public class MultipleExtraDependencyTest extends TestBase {
+    public void testMultipleExtraDependencies()
+    {
+        DependencyManager m = getDM();
+        Ensure e = new Ensure();
+        
+        Component sp2 = component(m)
+              .impl(ServiceProvider2.class).provides(ServiceProvider2.class)
+              .withSrv(Runnable.class, srv->srv.filter("(foo=bar)").required(false).autoConfig("m_runnable"))
+              .withSrv(Sequencer.class, srv->srv.cb("bind"))
+              .composition("getComposition")
+              .build();
+
+        Component sp = component(m)
+              .impl(ServiceProvider.class)
+              .provides(ServiceInterface.class, foo -> "bar")
+              .start("start").stop("stop")
+              .withSrv(Sequencer.class, srv->srv.autoConfig("m_sequencer"))
+              .withSrv(ServiceProvider2.class, srv->srv.cb("bind", "unbind"))
+              .build();
+        
+        Component sc = component(m)
+              .impl(ServiceConsumer.class)
+              .start("start").stop("stop")
+              .withSrv(Sequencer.class, srv->srv.autoConfig("m_sequencer"))
+              .withSrv(ServiceInterface.class, srv->srv.filter("(foo=bar)").autoConfig("m_service"))
+              .build();
+        
+        Component sequencer = component(m)
+           .impl(new SequencerImpl(e))
+           .provides(Sequencer.class.getName())
+           .build();
+           
+        m.add(sp2);
+        m.add(sp);
+        m.add(sc);
+        m.add(sequencer);
+        
+        // Check if ServiceProvider component have been initialized orderly
+        e.waitForStep(7, 5000);
+        
+        // Stop the test.annotation bundle
+        m.remove(sequencer);
+        m.remove(sp);
+        m.remove(sp2);
+        m.remove(sc);
+        
+        // And check if ServiceProvider2 has been deactivated orderly
+        e.waitForStep(11, 5000);
+    }
+    
+    public interface Sequencer
+    {
+        void step();
+        void step(int step);
+        void waitForStep(int step, int timeout);
+    }
+    
+    public static class SequencerImpl implements Sequencer {
+        Ensure m_ensure;
+        
+        public SequencerImpl(Ensure e)
+        {
+            m_ensure = e;
+        }
+        
+        public void step()
+        {
+            m_ensure.step();
+        }
+
+        public void step(int step)
+        {
+            m_ensure.step(step);
+        }
+
+        public void waitForStep(int step, int timeout)
+        {
+            m_ensure.waitForStep(step, timeout);
+        }  
+    }
+    
+    public interface ServiceInterface
+    {
+        public void doService();
+    }
+    
+    public static class ServiceConsumer
+    {
+        volatile Sequencer m_sequencer;
+        volatile ServiceInterface m_service;
+
+        void start()
+        {
+            m_sequencer.step(6);
+            m_service.doService();
+        }
+
+        void stop()
+        {
+            m_sequencer.step(8);
+        }
+    }
+    
+    public static class ServiceProvider implements ServiceInterface
+    {
+        Sequencer m_sequencer;
+        ServiceProvider2 m_serviceProvider2;
+
+        void bind(ServiceProvider2 provider2)
+        {
+            m_serviceProvider2 = provider2;
+        }
+
+        void start()
+        {
+            m_serviceProvider2.step(4);
+            m_sequencer.step(5);
+        }
+
+        void stop()
+        {
+            m_sequencer.step(9);
+        }
+
+        void unbind(ServiceProvider2 provider2)
+        {
+            m_sequencer.step(10);
+        }
+
+        public void doService()
+        {
+            m_sequencer.step(7);
+        }
+    }
+
+    public static class ServiceProvider2
+    {
+        Composite m_composite = new Composite();
+        Sequencer m_sequencer;
+        Runnable m_runnable;
+
+        void bind(Sequencer seq)
+        {
+            m_sequencer = seq;
+            m_sequencer.step(1);
+        }
+
+        void start()
+        {
+            m_sequencer.step(3);
+            m_runnable.run(); // NullObject
+        }
+
+        public void step(int step) // called by ServiceProvider.start() method 
+        { 
+            m_sequencer.step(step);
+        }
+        
+        void stop()
+        {
+            m_sequencer.step(11);
+        }
+
+        Object[] getComposition()
+        {
+            return new Object[] { this, m_composite };
+        }
+    }
+    
+    public static class Composite
+    {
+        void bind(Sequencer seq)
+        {
+            seq.step(2);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.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/MultipleExtraDependencyTest2.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,235 @@
+/*
+ * 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.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ServiceDependency;
+
+/**
+ * Tests for extra dependencies which are declared from service's init method.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MultipleExtraDependencyTest2 extends TestBase {
+    public void testMultipleExtraDependencies() {
+        DependencyManager m = getDM();
+        Ensure e = new Ensure();
+        
+        Component sp2 = component(m)
+            .impl(ServiceProvider2.class)
+            .provides(ServiceProvider2.class)
+            .init("init").start("start").stop("stop")
+            .composition("getComposition").build();
+        
+        Component sp = component(m)
+            .impl(ServiceProvider.class)
+            .provides(ServiceInterface.class, "foo", "bar")                            
+            .init(ServiceProvider::init).start(ServiceProvider::start).stop(ServiceProvider::stop)
+            .build();
+        
+        Component sc = component(m)
+            .impl(ServiceConsumer.class)
+            .init("init").start("start").stop("stop")
+            .build();
+        
+        // Provide the Sequencer service to the MultipleAnnotationsTest class.
+        Component sequencer =  component(m)
+            .impl(new SequencerImpl(e))
+            .provides(Sequencer.class)
+            .build();
+        
+        m.add(sp2);
+        m.add(sp);
+        m.add(sc);
+        m.add(sequencer);
+
+        // Check if the test.annotation components have been initialized orderly
+        e.waitForStep(7, 10000);
+        
+        // Stop the test.annotation bundle
+        m.remove(sequencer);
+        m.remove(sp);
+        m.remove(sp2);
+        m.remove(sc);
+        
+//        m.remove(sp2);
+//        m.remove(sc);
+//        m.remove(sp);
+//        m.remove(sequencer);
+        
+
+        
+        // And check if the test.annotation bundle has been deactivated orderly
+        e.waitForStep(11, 10000);
+        m.clear();
+    }
+    
+    public interface Sequencer
+    {
+        void step();
+        void step(int step);
+        void waitForStep(int step, int timeout);
+    }
+    
+    public static class SequencerImpl implements Sequencer {
+        final Ensure m_ensure;
+        
+        public SequencerImpl(Ensure e)
+        {
+            m_ensure = e;
+        }
+        
+        public void step()
+        {
+            m_ensure.step();
+        }
+
+        public void step(int step)
+        {
+            m_ensure.step(step);
+        }
+
+        public void waitForStep(int step, int timeout)
+        {
+            m_ensure.waitForStep(step, timeout);
+        }  
+    }
+    
+    public interface ServiceInterface
+    {
+        public void doService();
+    }
+    
+    public static class ServiceConsumer {
+        volatile Sequencer m_sequencer;
+        volatile ServiceInterface m_service;
+        volatile Dependency m_d1, m_d2;
+
+        public void init(Component s) {
+            component(s, comp->comp
+                .withSrv(Sequencer.class, srv->srv.autoConfig("m_sequencer"))
+                .withSrv(ServiceInterface.class, srv->srv.filter("(foo=bar)").autoConfig("m_service")));
+        }
+        
+        void start() {
+            m_sequencer.step(6);
+            m_service.doService();
+        }
+
+        void stop() {
+            m_sequencer.step(8);
+        }
+    }
+    
+    public static class ServiceProvider implements ServiceInterface
+    {
+        volatile Sequencer m_sequencer;
+        volatile ServiceProvider2 m_serviceProvider2;
+        volatile ServiceDependency m_d1, m_d2;
+
+        public void init(Component c)
+        {
+            component(c, comp->comp
+                .withSrv(Sequencer.class, srv->srv.autoConfig("m_sequencer"))
+                .withSrv(ServiceProvider2.class, srv->srv.cb("bind", "unbind")));
+        }
+        
+        void bind(ServiceProvider2 provider2)
+        {
+            m_serviceProvider2 = provider2;
+        }
+
+        void start()
+        {
+            m_serviceProvider2.step(4);
+            m_sequencer.step(5);
+        }
+
+        void stop()
+        {
+            m_sequencer.step(9);
+        }
+
+        void unbind(ServiceProvider2 provider2)
+        {
+            m_sequencer.step(10);
+        }
+
+        public void doService()
+        {
+            m_sequencer.step(7);
+        }
+    }
+
+    public static class ServiceProvider2
+    {
+        final Composite m_composite = new Composite();
+        volatile Sequencer m_sequencer;
+        volatile Runnable m_runnable;
+        volatile ServiceDependency m_d1, m_d2;
+
+        public void init(Component c)
+        {
+            component(c, comp->comp
+		      .withSrv(Runnable.class, srv->srv.optional().filter("(foo=bar)"))
+		      .withSrv(Sequencer.class, srv->srv.cb("bind")));
+        }
+        
+        void bind(Sequencer seq)
+        {
+            System.out.println("ServiceProvider2.bind(" + seq + ")");
+            m_sequencer = seq;
+            m_sequencer.step(1);
+        }
+
+        void start()
+        {
+            System.out.println("ServiceProvider2.start: m_runnable=" + m_runnable + ", m_sequencer = " + m_sequencer);
+            m_sequencer.step(3);
+            m_runnable.run(); // NullObject
+        }
+
+        public void step(int step) // called by ServiceProvider.start() method 
+        { 
+            m_sequencer.step(step);
+        }
+        
+        void stop()
+        {
+            m_sequencer.step(11);
+        }
+
+        Object[] getComposition()
+        {
+            return new Object[] { this, m_composite };
+        }
+    }
+    
+    public static class Composite
+    {
+        void bind(Sequencer seq)
+        {
+            seq.step(2);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.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/MultipleServiceDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,144 @@
+/*
+ * 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.osgi.framework.Constants;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes", "serial"})
+public class MultipleServiceDependencyTest extends TestBase {
+   public void testMultipleServiceRegistrationAndConsumption() {
+       DependencyManager m = getDM();
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class.getName()).build();
+       Component providerWithHighRank = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface.class.getName(), Constants.SERVICE_RANKING, Integer.valueOf(5)).build();
+       Component consumer = component(m).impl(new ServiceConsumer(e)).withSrv(ServiceInterface.class).build();
+       m.add(provider);
+       m.add(providerWithHighRank);
+       m.add(consumer);
+       e.waitForStep(3, 5000);
+       m.remove(providerWithHighRank);
+       e.step(4);
+       e.waitForStep(5, 5000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 5000);
+   }
+
+   public void testReplacementAutoConfig() {
+       DependencyManager m = getDM();
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class.getName()).build();
+       Component provider2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface.class.getName()).build();
+       Component consumer = component(m).impl(new ServiceConsumer(e)).withSrv(ServiceInterface.class).build();
+       m.add(provider2);
+       m.add(consumer);
+       e.waitForStep(3, 5000);
+       m.add(provider);
+       m.remove(provider2);
+       e.step(4);
+       e.waitForStep(5, 5000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 5000);
+   }
+
+   public void testReplacementCallbacks() {
+       DependencyManager m = getDM();
+       // helper class that ensures certain steps get executed in sequence
+       Ensure e = new Ensure();
+       // create a service provider and consumer
+       Component provider = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class.getName()).build();
+       Component provider2 = component(m).impl(new ServiceProvider2(e)).provides(ServiceInterface.class.getName()).build();
+       Component consumer = component(m).impl(new ServiceConsumer(e)).withSrv(ServiceInterface.class, srv->srv.cb("add", "remove")).build();
+       m.add(provider2);
+       m.add(consumer);
+       e.waitForStep(3, 15000);
+       m.add(provider);
+       m.remove(provider2);
+       e.step(4);
+       e.waitForStep(5, 15000);
+       m.remove(provider);
+       m.remove(consumer);
+       e.waitForStep(6, 15000);
+   }
+
+   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(5);
+       }
+   }
+
+   static class ServiceProvider2 implements ServiceInterface {
+       private final Ensure m_ensure;
+       public ServiceProvider2(Ensure e) {
+           m_ensure = e;
+       }
+       public void invoke() {
+           m_ensure.step(2);
+       }
+   }
+
+   static class ServiceConsumer implements Runnable {
+       private volatile ServiceInterface m_service;
+       private final Ensure m_ensure;
+
+       @SuppressWarnings("unused")
+       private void add(ServiceInterface service) { m_service = service; }
+       
+       @SuppressWarnings("unused")
+       private void remove(ServiceInterface service) { if (m_service == service) { m_service = null; }}
+       public ServiceConsumer(Ensure e) { m_ensure = e; }
+
+       public void start() {
+           Thread t = new Thread(this);
+           t.start();
+       }
+
+       public void run() {
+           m_ensure.step(1);
+           m_service.invoke();
+           m_ensure.step(3);
+           m_ensure.waitForStep(4, 15000);
+           m_service.invoke();
+       }
+
+       public void stop() {
+           m_ensure.step(6);
+       }
+   }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.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/RemovedDependencyTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,173 @@
+/*
+ * 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 static org.apache.felix.dm.lambda.DependencyManagerActivator.serviceDependency;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * One consumer, Three providers. The Consumer has two required dependency on provider1, provider2, and one 
+ * instance-bound required dependency on provider3.
+ * When the three providers are there, the consumer is started.
+ * 
+ * This test asserts the following correct behaviors:
+ *   - when we remove the dependency on provider2, then the consumer is not stopped.
+ *   - when we remove the (instance-bound) dependency on provider3, then the consumer os not stopped.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes", "unused"})
+public class RemovedDependencyTest extends TestBase {
+    public void testRemoveDependencyAndConsumerMustRemainStarted() {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // Create two providers
+        Hashtable props = new Hashtable();
+        props.put("name", "provider1");
+        Component sp = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class, props).build();
+        props = new Properties();
+        props.put("name", "provider2");
+        Component sp2 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class.getName(), props).build();
+        props = new Properties();
+        props.put("name", "provider3");
+        Component sp3 = component(m).impl(new ServiceProvider(e)).provides(ServiceInterface.class.getName(), props).build();
+
+        // Create the consumer, and start it
+        Dependency d3 = m.createServiceDependency().setService(ServiceInterface.class, "(name=provider3)").setRequired(true).setCallbacks("add", "remove");
+
+        ServiceConsumer consumer = new ServiceConsumer(e, d3);
+        Component sc = component(m).impl(consumer).build();
+        
+        Dependency d1 = serviceDependency(sc, ServiceInterface.class).filter("(name=provider1)").cb("add", "remove").build();
+        Dependency d2 = serviceDependency(sc, ServiceInterface.class).filter("(name=provider2)").cb("add", "remove").build();
+        
+        sc.add(d1, d2);
+            
+        // Add the first two providers and the consumer
+        m.add(sp);
+        m.add(sp2);
+        m.add(sp3);
+        m.add(sc);
+        
+        // Check if consumer has been bound to the three providers
+        e.waitForStep(3,  5000);
+        Assert.assertEquals(3, consumer.getProvidersCount());
+        Assert.assertNotNull(consumer.getProvider("provider1"));
+        Assert.assertNotNull(consumer.getProvider("provider2"));
+        Assert.assertNotNull(consumer.getProvider("provider3"));
+        
+        // Now remove the provider2, and check if the consumer is still alive
+        sc.remove(d2);
+        Assert.assertFalse(consumer.isStopped());
+        Assert.assertEquals(2, consumer.getProvidersCount());
+        Assert.assertNotNull(consumer.getProvider("provider1"));
+        Assert.assertNull(consumer.getProvider("provider2"));
+        Assert.assertNotNull(consumer.getProvider("provider3"));
+
+        // Now remove the provider3 (the consumer has an instance bound dependency on it), and check if the consumer is still alive
+        sc.remove(d3);
+        Assert.assertFalse(consumer.isStopped());
+        Assert.assertEquals(1, consumer.getProvidersCount());
+        Assert.assertNotNull(consumer.getProvider("provider1"));
+        Assert.assertNull(consumer.getProvider("provider2"));
+        Assert.assertNull(consumer.getProvider("provider3"));
+        
+        m.clear();
+    }
+    
+    static interface ServiceInterface {
+        public void invoke();
+    }
+
+    class ServiceProvider implements ServiceInterface {
+        final Ensure m_ensure;
+        
+        public ServiceProvider(Ensure e) {
+            m_ensure = e;
+        }
+        public void invoke() {
+            m_ensure.step();
+        }
+    }
+    
+    class ServiceConsumer {
+        private final Ensure m_ensure;
+        private final List<ServiceReference> m_providers = new ArrayList<>();
+        private BundleContext m_bc;
+        private boolean m_stopped;
+        private final Dependency m_dependency3;
+
+        public ServiceConsumer(Ensure e, Dependency dependency3) {
+            m_ensure = e;
+            m_dependency3 = dependency3;
+        }
+                
+        public void add(ServiceReference ref) {
+            debug("ServiceConsumer.add(%s)", ref);
+            m_providers.add(ref);
+            ServiceInterface s = (ServiceInterface) m_bc.getService(ref);
+            s.invoke();
+        }
+        
+        public void remove(ServiceReference ref) {
+            debug("ServiceConsumer.remove(%s)", ref);
+            m_providers.remove(ref);
+            debug("ServiceConsumer: current providers list=%s", m_providers);
+        }
+        
+        public void init(Component c) {
+            c.add(m_dependency3);
+        }
+        
+        public int getProvidersCount() {
+            return m_providers.size();
+        }
+        
+        public ServiceInterface getProvider(String name) {
+            for (ServiceReference ref : m_providers) {
+                Object n = ref.getProperty("name");
+                if (n.equals(name)) {
+                    return (ServiceInterface) m_bc.getService(ref);
+                }
+            }
+            return null;
+        }
+        
+        public void stop() {
+            m_stopped = true;
+        }
+        
+        public boolean isStopped() {
+            return m_stopped;
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.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/ResourceProvider.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,122 @@
+/*
+ * 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.net.URL;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.dm.ResourceHandler;
+import org.apache.felix.dm.ResourceUtil;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+class ResourceProvider {
+	final URL[] m_resources;
+    final BundleContext m_context;
+    final Map<ResourceHandler, Filter> m_handlers = new HashMap<>();
+
+	ResourceProvider(BundleContext ctx, URL ... resources) {
+		m_context = ctx;
+		m_resources = resources;
+	}
+	
+    public void change() {
+        for (int i = 0; i < m_resources.length; i++) {
+        	change(i);
+        }    	
+    }
+    
+    @SuppressWarnings({ "deprecation", "unchecked" })
+	public void change(int resourceIndex) {
+        Map<ResourceHandler, Filter> handlers = new HashMap<>();
+        synchronized (m_handlers) {
+            handlers.putAll(m_handlers);
+        }
+        for (Map.Entry<ResourceHandler, Filter> e : handlers.entrySet()) {
+        	ResourceHandler handler = e.getKey();
+        	Filter filter = e.getValue();
+        	if (filter == null || filter.match((Dictionary<String, ? >)ResourceUtil.createProperties(m_resources[resourceIndex]))) {
+        		handler.changed(m_resources[resourceIndex]);
+            }
+        }
+    }
+
+    @SuppressWarnings({ "deprecation", "unchecked" })
+	public void add(ServiceReference<ResourceHandler> ref, ResourceHandler handler) {
+        String filterString = (String) ref.getProperty("filter");
+        Filter filter = null;
+        if (filterString != null) {
+            try {
+                filter = m_context.createFilter(filterString);
+            }
+            catch (InvalidSyntaxException e) {
+                Assert.fail("Could not create filter for resource handler: " + e);
+                return;
+            }
+        }
+        for (int i = 0; i < m_resources.length; i++) {
+            if (filter == null || filter.match((Dictionary<String, ? >) ResourceUtil.createProperties(m_resources[i]))) {
+                synchronized (m_handlers) {
+                    m_handlers.put(handler, filter);
+                }
+                handler.added(m_resources[i]);
+            }
+        }
+    }
+
+    public void remove(ServiceReference<ResourceHandler> ref, ResourceHandler handler) {
+        Filter filter;
+        synchronized (m_handlers) {
+            filter = (Filter) m_handlers.remove(handler);
+        }
+        if (filter != null) {
+        	removeResources(handler, filter);
+        }
+    }
+
+    @SuppressWarnings({ "deprecation", "unchecked" })
+	private void removeResources(ResourceHandler handler, Filter filter) {
+            for (int i = 0; i < m_resources.length; i++) {
+                if (filter == null || filter.match((Dictionary<String, ? >)ResourceUtil.createProperties(m_resources[i]))) {
+                    handler.removed(m_resources[i]);
+                }
+            }
+        }
+
+    public void destroy() {
+        Map<ResourceHandler, Filter> handlers = new HashMap<>();
+        synchronized (m_handlers) {
+            handlers.putAll(m_handlers);
+        }
+
+        for (Map.Entry<ResourceHandler, Filter> e : handlers.entrySet()) {
+            ResourceHandler handler = e.getKey();
+            Filter filter = e.getValue();
+            removeResources(handler, filter);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.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/ServiceDependencyCallbackSignaturesTest.java?rev=1727487&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java Fri Jan 29 06:50:09 2016
@@ -0,0 +1,297 @@
+/*
+ * 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 java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@SuppressWarnings({"unchecked", "rawtypes"})
+public class ServiceDependencyCallbackSignaturesTest extends TestBase {
+    volatile Ensure m_ensure;
+    
+    /**
+     * Tests if all possible dependency callbacks signatures supported by ServiceDependency.
+     */
+    public void testDependencyCallbackSignatures() {
+        DependencyManager m = getDM();
+        m_ensure = new Ensure();    
+        Hashtable<String, String> props = new Hashtable<>();
+        props.put("foo", "bar");
+        Component provider = component(m)
+            .impl(new ProviderImpl()).provides(Provider.class.getName(), props).build();
+        
+        component(m, c->c.impl(new Consumer1()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer2()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer3()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer4()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer5()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer6()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer7()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer8()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+        component(m, c->c.impl(new Consumer9()).withSrv(Provider.class, srv->srv.cb("bind", "change", "remove")));
+
+        m.add(provider);
+        m_ensure.waitForStep(9, 5000);
+        
+        props = new Hashtable<>();
+        props.put("foo", "zoo");
+        provider.setServiceProperties(props);
+        m_ensure.waitForStep(18, 5000);
+        
+        m.remove(provider);
+        m_ensure.waitForStep(26, 5000);
+    }
+    
+    /**
+     * Tests if all possible dependency callbacks signatures supported by ServiceDependency.
+     */
+    public void testDependencyCallbackSignaturesRef() {
+        DependencyManager m = getDM();
+        m_ensure = new Ensure();    
+        Hashtable<String, String> props = new Hashtable<>();
+        props.put("foo", "bar");
+        Component provider = component(m)
+            .impl(new ProviderImpl()).provides(Provider.class.getName(), props).build();
+        
+        component(m, c->c.impl(new Consumer1()).withSrv(Provider.class, srv->srv.cb(Consumer1::bind, Consumer1::change, Consumer1::remove)));
+        component(m, c->c.impl(new Consumer2()).withSrv(Provider.class, srv->srv.cb(Consumer2::bind, Consumer2::change, Consumer2::remove)));
+        component(m, c->c.impl(new Consumer3()).withSrv(Provider.class, srv->srv.cb(Consumer3::bind, Consumer3::change, Consumer3::remove)));
+        component(m, c->c.impl(new Consumer4()).withSrv(Provider.class, srv->srv.cb(Consumer4::bind, Consumer4::change, Consumer4::remove)));
+        component(m, c->c.impl(new Consumer5()).withSrv(Provider.class, srv->srv.cb(Consumer5::bind, Consumer5::change, Consumer5::remove)));
+        component(m, c->c.impl(new Consumer6()).withSrv(Provider.class, srv->srv.cb(Consumer6::bind, Consumer6::change, Consumer6::remove)));
+        component(m, c->c.impl(new Consumer7()).withSrv(Provider.class, srv->srv.cb(Consumer7::bind, Consumer7::change, Consumer7::remove)));
+        component(m, c->c.impl(new Consumer8()).withSrv(Provider.class, srv->srv.cb(Consumer8::bind, Consumer8::change, Consumer8::remove)));
+        component(m, c->c.impl(new Consumer9()).withSrv(Provider.class, srv->srv.cb(Consumer9::bind, Consumer9::change, Consumer9::remove)));
+
+        m.add(provider);
+        m_ensure.waitForStep(9, 5000);
+        
+        props = new Hashtable<>();
+        props.put("foo", "zoo");
+        provider.setServiceProperties(props);
+        m_ensure.waitForStep(18, 5000);
+        
+        m.remove(provider);
+        m_ensure.waitForStep(26, 5000);
+    }
+    
+    private void declareConsumer(DependencyManager m, Object consumerImpl) {
+        Component consumer = component(m)
+            .impl(consumerImpl)
+            .withSrv(Provider.class, srv->srv.cb("bind", "change", "change"))
+            .build();
+        m.add(consumer);
+    }
+
+    public static interface Provider {        
+    }
+    
+    public static class ProviderImpl implements Provider {        
+    }
+    
+    class Consumer1 {        
+        void bind(Provider provider) {
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+        void change(Provider provider) {
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+        
+        void remove(Provider provider) {
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+    }
+    
+    class Consumer2 {        
+        void bind(Provider provider, Map<String, Object> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("bar", props.get("foo"));
+            m_ensure.step();
+        }
+        void change(Provider provider, Map<String, Object> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", props.get("foo"));
+            m_ensure.step();
+        }
+        void remove(Provider provider, Map<String, Object> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", props.get("foo"));
+            m_ensure.step();
+        }
+    }
+    
+    class Consumer3 {        
+        void bind(Provider provider, Dictionary<?, ?> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("bar", props.get("foo"));
+            m_ensure.step();
+        }
+        void change(Provider provider, Dictionary<?, ?> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", props.get("foo"));
+            m_ensure.step();
+        }
+        void remove(Provider provider, Dictionary<?, ?> props) {
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", props.get("foo"));
+            m_ensure.step();
+        }
+    }
+
+    class Consumer4 {        
+        void bind(ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("bar", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+        void change(ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+        void remove(ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+    }
+        
+    class Consumer5 {        
+        void bind(ServiceReference ref) {
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("bar", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+        void change(ServiceReference ref) {
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+        void remove(ServiceReference ref) {
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            m_ensure.step();
+        }
+    }
+
+    class Consumer6 {        
+        void bind(Component c) {
+            Assert.assertNotNull(c);
+            m_ensure.step();
+        }
+        void change(Component c) {
+            Assert.assertNotNull(c);
+            m_ensure.step();
+        }
+        void remove(Component c) {
+            Assert.assertNotNull(c);
+            m_ensure.step();
+        }
+    }
+        
+    class Consumer7 {
+        void bind(Component c, ServiceReference ref) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("bar", ref.getProperty("foo"));
+            Assert.assertNotNull(context.getService(ref));
+            Assert.assertEquals(context.getService(ref).getClass(), ProviderImpl.class);
+            m_ensure.step();
+        }
+        void change(Component c, ServiceReference ref) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            Assert.assertNotNull(context.getService(ref));
+            Assert.assertEquals(context.getService(ref).getClass(), ProviderImpl.class);
+            m_ensure.step();
+        }
+        void remove(Component c, ServiceReference ref) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            Assert.assertNotNull(context.getService(ref));
+            Assert.assertEquals(context.getService(ref).getClass(), ProviderImpl.class);
+            m_ensure.step();
+        }
+    }
+        
+    class Consumer8 {
+        void bind(Component c, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+        void change(Component c, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+        void remove(Component c, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(provider);
+            m_ensure.step();
+        }
+    }
+    
+    class Consumer9 {
+        void bind(Component c, ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("bar", ref.getProperty("foo"));
+            Assert.assertEquals(context.getService(ref), provider);
+            m_ensure.step();
+        }
+        void change(Component c, ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            Assert.assertEquals(context.getService(ref), provider);
+            m_ensure.step();
+        }
+        void remove(Component c, ServiceReference ref, Provider provider) {
+            Assert.assertNotNull(c);
+            Assert.assertNotNull(ref);
+            Assert.assertNotNull(provider);
+            Assert.assertEquals("zoo", ref.getProperty("foo"));
+            Assert.assertEquals(context.getService(ref), provider);
+            m_ensure.step();
+        }
+    }
+        
+}



Mime
View raw message