Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryConfigurationAdapterTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/FactoryInjectedWithConfigurationBeforeTheCreateMethod.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/InstanceBoundDependencyTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ModifiedBundleDependencyTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependenciesTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleExtraDependencyTest2.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/MultipleServiceDependencyTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/RemovedDependencyTest.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ResourceProvider.java Sun Jan 31 23:27:05 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:[email protected]">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/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java?rev=1727869&view=auto ============================================================================== --- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java (added) +++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/lambda/itest/ServiceDependencyCallbackSignaturesTest.java Sun Jan 31 23:27:05 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:[email protected]">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(); + } + } + +}
