/* * 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.scr.integration; import java.util.Arrays; import org.apache.felix.scr.integration.components.SimpleComponent; import org.apache.felix.scr.integration.components.SimpleServiceImpl; import org.junit.Test; import org.junit.runner.RunWith; import org.ops4j.pax.exam.junit.PaxExam; import org.osgi.framework.Constants; import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; import junit.framework.TestCase; @RunWith(PaxExam.class) public class ComponentConfigurationTest extends ComponentTestBase { static { // uncomment to enable debugging of this test class // paxRunnerVmOption = DEBUG_VM_OPTION; } @Test public void test_SimpleComponent_configuration_ignore() throws Exception { final String pid = "SimpleComponent.configuration.ignore"; TestCase.assertNull( SimpleComponent.INSTANCE ); deleteConfig( pid ); delay(); ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); configure( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); deleteConfig( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); disableAndCheck( cc ); TestCase.assertNull( SimpleComponent.INSTANCE ); } @Test public void test_SimpleComponent_configuration_optional() throws Exception { final String pid = "SimpleComponent.configuration.optional"; ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.ACTIVE); final SimpleComponent firstInstance = SimpleComponent.INSTANCE; TestCase.assertNotNull( firstInstance ); TestCase.assertNull( firstInstance.getProperty( PROP_NAME ) ); configure( pid ); delay(); final SimpleComponent secondInstance = SimpleComponent.INSTANCE; findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( secondInstance ); TestCase.assertEquals( PROP_NAME, secondInstance.getProperty( PROP_NAME ) ); deleteConfig( pid ); delay(); final SimpleComponent thirdInstance = SimpleComponent.INSTANCE; findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( thirdInstance ); TestCase.assertNull( thirdInstance.getProperty( PROP_NAME ) ); TestCase.assertNotSame( "Expect new instance object after reconfiguration", firstInstance, secondInstance ); TestCase.assertNotSame( "Expect new instance object after configuration deletion (1)", firstInstance, thirdInstance ); TestCase.assertNotSame( "Expect new instance object after configuration deletion (2)", secondInstance, thirdInstance ); disableAndCheck( cc ); TestCase.assertNull( SimpleComponent.INSTANCE ); } @Test public void test_SimpleComponent_configuration_require() throws Exception { final String pid = "SimpleComponent.configuration.require"; deleteConfig( pid ); delay(); TestCase.assertNull( SimpleComponent.INSTANCE ); getConfigurationsDisabledThenEnable(pid, 0, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); TestCase.assertNull( SimpleComponent.INSTANCE ); configure( pid ); delay(); ComponentConfigurationDTO cc = findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); deleteConfig( pid ); delay(); checkConfigurationCount(pid, 0, -1); TestCase.assertNull( SimpleComponent.INSTANCE ); disableAndCheck( cc ); TestCase.assertNull( SimpleComponent.INSTANCE ); } /** * same as test_SimpleComponent_configuration_require except configuration is present when component is enabled. */ @Test public void test_SimpleComponent_configuration_require_initialize() throws Exception { final String pid = "SimpleComponent.configuration.require"; deleteConfig( pid ); configure( pid ); delay(); TestCase.assertNull( SimpleComponent.INSTANCE ); ComponentConfigurationDTO cc = getConfigurationsDisabledThenEnable(pid, 1, ComponentConfigurationDTO.ACTIVE).iterator().next(); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); deleteConfig( pid ); delay(); checkConfigurationCount(pid, 0, -1); TestCase.assertNull( SimpleComponent.INSTANCE ); disableAndCheck( cc ); TestCase.assertNull( SimpleComponent.INSTANCE ); } @Test public void test_SimpleComponent_dynamic_configuration() throws Exception { final String pid = "DynamicConfigurationComponent"; boolean pre13 = true; boolean recreateOnDelete = true; dynamicConfigTest(pid, pre13, recreateOnDelete); } @Test public void test_SimpleComponent_dynamic_configuration_13() throws Exception { final String pid = "DynamicConfigurationComponent13"; boolean pre13 = false; boolean recreateOnDelete = false; dynamicConfigTest(pid, pre13, recreateOnDelete); } @Test public void test_SimpleComponent_dynamic_configuration_flag() throws Exception { final String pid = "DynamicConfigurationComponentFlag"; boolean pre13 = true; boolean recreateOnDelete = false; dynamicConfigTest(pid, pre13, recreateOnDelete); } private void dynamicConfigTest(final String pid, boolean pre13, boolean recreateOnDelete) throws Exception { Object pidWithout; Object pidWith; if (pre13) { pidWithout = pid + ".description"; pidWith = pid; } else { pidWithout = pid + ".description"; pidWith = Arrays.asList(new String[] {pid + ".description", pid}); } deleteConfig( pid ); delay(); ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals(pidWithout, SimpleComponent.INSTANCE.getProperty(Constants.SERVICE_PID)); final SimpleComponent instance = SimpleComponent.INSTANCE; configure( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals(pidWith, SimpleComponent.INSTANCE.getProperty(Constants.SERVICE_PID)); deleteConfig( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); if (recreateOnDelete) { TestCase.assertNotSame( instance, SimpleComponent.INSTANCE ); } else { TestCase.assertSame( instance, SimpleComponent.INSTANCE ); } TestCase.assertNull( SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals(pidWithout, SimpleComponent.INSTANCE.getProperty(Constants.SERVICE_PID)); disableAndCheck( cc ); TestCase.assertNull( SimpleComponent.INSTANCE ); } @Test public void test_SimpleComponent_dynamic_optional_configuration_with_required_service() throws Exception { final String targetProp = "ref.target"; final String filterProp = "required"; final SimpleServiceImpl service = SimpleServiceImpl.create( bundleContext, "sample" ).setFilterProperty( filterProp ); try { final String pid = "DynamicConfigurationComponentWithRequiredReference"; deleteConfig( pid ); delay(); // mandatory ref missing --> component unsatisfied ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); // dynamically configure without the correct target configure( pid ); delay(); // mandatory ref missing --> component unsatisfied findComponentConfigurationByName(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); // dynamically configure with correct target theConfig.put( targetProp, "(filterprop=" + filterProp + ")" ); configure( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); final SimpleComponent instance = SimpleComponent.INSTANCE; configure( pid ); delay(); // same instance after reconfiguration findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); TestCase.assertNotNull( SimpleComponent.INSTANCE.m_singleRef ); // reconfigure without target --> unsatisifed theConfig.remove( targetProp ); configure( pid ); delay(); // mandatory ref missing --> component unsatisfied findComponentConfigurationByName(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); deleteConfig( pid ); delay(); // mandatory ref missing --> component unsatisfied findComponentConfigurationByName(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); disableAndCheck(cc); TestCase.assertNull( SimpleComponent.INSTANCE ); } finally { theConfig.remove( targetProp ); if ( service != null ) { service.drop(); } } } /** * FELIX-3902. Start with filter matching two services, remove one, then change the filter * to (still) match the other one. 2nd service should remain bound. */ @Test public void test_SimpleComponent_dynamic_optional_configuration_with_required_service2() throws Exception { final String targetProp = "ref.target"; final String filterProp1 = "one"; final String filterProp2 = "two"; final SimpleServiceImpl service1 = SimpleServiceImpl.create( bundleContext, "one", 1 ).setFilterProperty( filterProp1 ); final SimpleServiceImpl service2 = SimpleServiceImpl.create( bundleContext, "two", 2 ).setFilterProperty( filterProp2 ); try { final String pid = "DynamicConfigurationComponentWithRequiredReference"; deleteConfig( pid ); delay(); // mandatory ref missing --> component unsatisfied ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); // dynamically configure without the correct target configure( pid ); delay(); // mandatory ref missing --> component unsatisfied findComponentConfigurationByName(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); // dynamically configure with correct target theConfig.put( targetProp, "(|(filterprop=" + filterProp1 + ")(filterprop=" + filterProp2 + "))" ); configure( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); final SimpleComponent instance = SimpleComponent.INSTANCE; configure( pid ); delay(); //remove higher ranked service if (service2 != null) { service2.drop(); } // same instance after reconfiguration findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); TestCase.assertNotNull( SimpleComponent.INSTANCE.m_singleRef ); // reconfigure with new filter --> active theConfig.put( targetProp, "(filterprop=" + filterProp1 + ")" ); configure( pid ); delay(); // same instance after reconfiguration findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); TestCase.assertNotNull( SimpleComponent.INSTANCE.m_singleRef ); deleteConfig( pid ); delay(); // mandatory ref missing --> component unsatisfied findComponentConfigurationByName(pid, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); disableAndCheck(cc); TestCase.assertNull( SimpleComponent.INSTANCE ); } finally { theConfig.remove( targetProp ); if ( service1 != null ) { service1.drop(); } } } @Test public void test_SimpleComponent_dynamic_optional_configuration_with_optional_service() throws Exception { final String targetProp = "ref.target"; final String filterProp = "required"; final SimpleServiceImpl service = SimpleServiceImpl.create( bundleContext, "sample" ).setFilterProperty( filterProp ); try { final String pid = "DynamicConfigurationComponentWithOptionalReference"; deleteConfig( pid ); delay(); // optional ref missing --> component active ComponentConfigurationDTO cc = getDisabledConfigurationAndEnable(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotNull( SimpleComponent.INSTANCE ); final SimpleComponent instance = SimpleComponent.INSTANCE; // dynamically configure without the correct target configure( pid ); delay(); // optional ref missing --> component active findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.m_singleRef ); // dynamically configure with correct target theConfig.put( targetProp, "(filterprop=" + filterProp + ")" ); configure( pid ); delay(); findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); TestCase.assertNotNull( SimpleComponent.INSTANCE.m_singleRef ); configure( pid ); delay(); // same instance after reconfiguration findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) ); TestCase.assertNotNull( SimpleComponent.INSTANCE.m_singleRef ); // reconfigure without target --> active theConfig.remove( targetProp ); configure( pid ); delay(); // optional ref missing --> component active findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertEquals( instance, SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.m_singleRef ); deleteConfig( pid ); delay(); // optional ref missing --> component active findComponentConfigurationByName(pid, ComponentConfigurationDTO.ACTIVE); TestCase.assertNotSame( instance, SimpleComponent.INSTANCE ); TestCase.assertNull( SimpleComponent.INSTANCE.m_singleRef ); disableAndCheck(cc); TestCase.assertNull( SimpleComponent.INSTANCE ); } finally { // Thread.sleep( 60000 ); theConfig.remove( targetProp ); if ( service != null ) { service.drop(); } } } @Test public void test_SimpleComponent_factory_configuration() throws Exception { final String factoryPid = "FactoryConfigurationComponent"; deleteFactoryConfigurations( factoryPid ); delay(); getConfigurationsDisabledThenEnable(factoryPid, 0, -1); TestCase.assertTrue( SimpleComponent.INSTANCES.isEmpty() ); // create two factory configurations expecting two components final String pid0 = createFactoryConfiguration( factoryPid, "?" ); final String pid1 = createFactoryConfiguration( factoryPid, "?" ); delay(); // expect two active components, //TODO WTF?? only first is active, second is disabled checkConfigurationCount(factoryPid, 2, ComponentConfigurationDTO.ACTIVE); // delete a configuration deleteConfig( pid0 ); delay(); // expect one component checkConfigurationCount(factoryPid, 1, ComponentConfigurationDTO.ACTIVE); // delete second configuration deleteConfig( pid1 ); delay(); checkConfigurationCount(factoryPid, 0, ComponentConfigurationDTO.ACTIVE); } /** * same as test_SimpleComponent_factory_configuration except configurations are present before * component is enabled to test initialization. */ @Test public void test_SimpleComponent_factory_configuration_initialize() throws Exception { final String factoryPid = "FactoryConfigurationComponent"; deleteFactoryConfigurations( factoryPid ); // create two factory configurations expecting two components final String pid0 = createFactoryConfiguration( factoryPid, "?" ); final String pid1 = createFactoryConfiguration( factoryPid, "?" ); delay(); getConfigurationsDisabledThenEnable(factoryPid, 2, ComponentConfigurationDTO.ACTIVE); // delete a configuration deleteConfig( pid0 ); delay(); // expect one component checkConfigurationCount(factoryPid, 1, ComponentConfigurationDTO.ACTIVE); // delete second configuration deleteConfig( pid1 ); delay(); checkConfigurationCount(factoryPid, 0, ComponentConfigurationDTO.ACTIVE); } @Test public void test_SimpleComponent_factory_configuration_enabled() throws Exception { final String factoryPid = "FactoryConfigurationComponent_enabled"; deleteFactoryConfigurations( factoryPid ); delay(); checkConfigurationCount(factoryPid, 0, ComponentConfigurationDTO.ACTIVE); // no component config exists without configuration // create two factory configurations expecting two components createFactoryConfiguration( factoryPid, "?" ); createFactoryConfiguration( factoryPid, "?" ); delay(); // expect two components, all active checkConfigurationCount(factoryPid, 2, ComponentConfigurationDTO.ACTIVE); // disable the name component disableAndCheck( factoryPid ); delay(); // create a configuration createFactoryConfiguration( factoryPid, "?" ); delay(); getConfigurationsDisabledThenEnable(factoryPid, 3, ComponentConfigurationDTO.ACTIVE); } }