Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentConfigurationTest.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentConfigurationTest.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentConfigurationTest.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentConfigurationTest.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,588 @@ +/* + * 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 java.util.Collection; +import java.util.Collections; + +import org.apache.felix.scr.integration.components.SimpleComponent; +import org.apache.felix.scr.integration.components.SimpleServiceImpl; +import org.junit.Test; +import org.osgi.framework.Constants; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; + +import junit.framework.TestCase; + + +public class ComponentConfigurationTest extends ComponentTestBase +{ + @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(); + + Collection<ComponentConfigurationDTO> confs = 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); + disableAndCheck(confs); + } + + /** + * 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(); + + Collection<ComponentConfigurationDTO> confs = 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); + disableAndCheck(confs); + } + + @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 + final String pid0 = createFactoryConfiguration( factoryPid ); + final String pid1 = createFactoryConfiguration( factoryPid ); + delay(); + + // expect two components, all active + checkConfigurationCount(factoryPid, 2, ComponentConfigurationDTO.ACTIVE); + + // disable the name component + disableAndCheck( factoryPid ); + delay(); + + + // create a configuration + final String pid3 = createFactoryConfiguration( factoryPid ); + delay(); + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(factoryPid, 3, ComponentConfigurationDTO.ACTIVE); + deleteFactoryConfigurations( factoryPid ); + for (ComponentConfigurationDTO conf : confs) { + disableAndCheck(conf); + } + } + + +}
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentDisposeTest.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentDisposeTest.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentDisposeTest.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentDisposeTest.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,77 @@ +/* + * 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.Collection; + +import org.apache.felix.scr.integration.components.SimpleComponent; +import org.junit.Test; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; + +import junit.framework.Assert; +import junit.framework.TestCase; + + +public class ComponentDisposeTest extends ComponentTestBase +{ + @Test + public void test_SimpleComponent_factory_configuration() throws Exception + { + final String factoryPid = "FactoryConfigurationComponent"; + + deleteFactoryConfigurations( factoryPid ); + delay(); + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(factoryPid, 0, ComponentConfigurationDTO.ACTIVE);//there should be none + + // create two factory configurations expecting two components + final String pid0 = createFactoryConfiguration( factoryPid ); + final String pid1 = createFactoryConfiguration( factoryPid ); + delay(); + + Collection<ComponentConfigurationDTO> ccs = findComponentConfigurationsByName(factoryPid, ComponentConfigurationDTO.ACTIVE); + Assert.assertEquals(2, ccs.size()); + // expect two components, only first is active, second is disabled + TestCase.assertEquals( 2, SimpleComponent.INSTANCES.size() ); + for (ComponentConfigurationDTO cc: ccs) + { + TestCase.assertTrue(SimpleComponent.INSTANCES.containsKey(cc.id)); + } + + // dispose an instance + final SimpleComponent anInstance = SimpleComponent.INSTANCE; + TestCase.assertNotNull( anInstance ); + TestCase.assertNotNull( anInstance.m_activateContext ); + anInstance.m_activateContext.getComponentInstance().dispose(); + delay(); + + // expect one component + ComponentConfigurationDTO cc = findComponentConfigurationByName(factoryPid, ComponentConfigurationDTO.ACTIVE); + + TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() ); + TestCase.assertTrue(SimpleComponent.INSTANCES.containsKey(cc.id)); + + final SimpleComponent instance = SimpleComponent.INSTANCES.values().iterator().next(); + disableAndCheck(confs); + deleteFactoryConfigurations(factoryPid); + } + + +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentEnableTest.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentEnableTest.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentEnableTest.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentEnableTest.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,59 @@ +/* + * 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 org.apache.felix.scr.integration.components.EnableComponent; +import org.apache.felix.scr.integration.components.SimpleComponent; +import org.junit.Test; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; + +import junit.framework.TestCase; + + +public class ComponentEnableTest extends ComponentTestBase +{ + public ComponentEnableTest() + { + super("/resource/integration_test_enable.xml"); + } + + @Test + public void test_Component_Enable() throws Exception + { + final String enable = "org.apache.felix.scr.integration.components.enable"; + final String name = "org.apache.felix.scr.integration.components.SimpleComponent"; + + ComponentConfigurationDTO dto = findComponentConfigurationByName(enable, ComponentConfigurationDTO.SATISFIED); + + EnableComponent ec = getServiceFromConfiguration(dto, EnableComponent.class); + + TestCase.assertEquals(0, SimpleComponent.INSTANCES.size()); + + ec.enable(name); + delay(); + TestCase.assertEquals(1, SimpleComponent.INSTANCES.size()); + ec.enable(name); + delay(); + TestCase.assertEquals(1, SimpleComponent.INSTANCES.size()); + + } + + +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentFactoryTest.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentFactoryTest.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentFactoryTest.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentFactoryTest.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,434 @@ +/* + * 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.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Hashtable; + +import org.apache.felix.scr.integration.components.SimpleComponent; +import org.apache.felix.scr.integration.components.SimpleService; +import org.apache.felix.scr.integration.components.SimpleServiceImpl; +import org.junit.Test; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentException; +import org.osgi.service.component.ComponentFactory; +import org.osgi.service.component.ComponentInstance; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; +import org.osgi.service.log.LogService; + +import junit.framework.TestCase; + + +public class ComponentFactoryTest extends ComponentTestBase +{ + public ComponentFactoryTest() + { + super("/resource/integration_test_simple_factory_components.xml"); + ignoredWarnings = new String[] { + "ComponentFactoryTest: Bound Services=\\[SimpleServiceImpl: value=service2, filterprop=match\\]", + "\\[factory.component.*\\] The activate method has thrown an exception\\njava.lang.RuntimeException: Requested Failure", + "\\[factory.component.*\\] Failed creating the component instance; see log for reason" + }; + } + + @Test + public void test_component_factory() throws Exception + { + final String componentname = "factory.component"; + final String componentfactory = "factory.component.factory"; + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 0, -1); + + TestCase.assertNull( SimpleComponent.INSTANCE ); + + final ComponentInstance instance = createFactoryComponentInstance(componentfactory); + + // check registered components + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + instance.dispose(); + TestCase.assertNull( SimpleComponent.INSTANCE ); + TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2 + + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + disableAndCheck(confs); + } + + + @Test + public void test_component_factory_disable_factory() throws Exception + { + // tests components remain alive after factory has been disabled + + final String componentname = "factory.component"; + final String componentfactory = "factory.component.factory"; + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 0, -1); + + TestCase.assertNull( SimpleComponent.INSTANCE ); + + final ComponentInstance instance = createFactoryComponentInstance(componentfactory); + + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + // disable the factory + disableAndCheck(componentname); + delay(); + + // factory is disabled but the instance is still alive + TestCase.assertNotNull( SimpleComponent.INSTANCE ); + + instance.dispose(); + TestCase.assertNull( SimpleComponent.INSTANCE ); + TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2 + disableAndCheck(confs); + } + + + @Test + public void test_component_factory_newInstance_failure() throws Exception + { + final String componentname = "factory.component"; + final String componentfactory = "factory.component.factory"; + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 0, -1); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + try + { + Hashtable<String, String> props = new Hashtable<String, String>(); + props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY ); + props.put( SimpleComponent.PROP_ACTIVATE_FAILURE, "Requested Failure" ); + createFactoryComponentInstance(componentfactory, props); + TestCase.fail( "Expected newInstance method to fail with ComponentException" ); + } + catch ( ComponentException ce ) + { + // this is expected ! + } + + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + disableAndCheck(confs); + } + + + @Test + public void test_component_factory_require_configuration() throws Exception + { + final String componentname = "factory.component.configuration"; + final String componentfactory = "factory.component.factory.configuration"; + + testConfiguredFactory(componentname, componentfactory, false, false); + } + + @Test + public void test_component_factory_require_configuration_obsolete() throws Exception + { + final String componentname = "factory.component.configuration.obsolete"; + + TestCase.assertNull(SimpleComponent.INSTANCE); + + createFactoryConfiguration(componentname); + delay(); + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 1, ComponentConfigurationDTO.ACTIVE); + TestCase.assertEquals(PROP_NAME, SimpleComponent.INSTANCE.getProperty(PROP_NAME)); + disableAndCheck(confs); + deleteFactoryConfigurations(componentname); + } + + @Test + public void test_component_factory_optional_configuration() throws Exception + { + final String componentname = "factory.component.configuration.optional"; + final String componentfactory = "factory.component.factory.configuration.optional"; + + testConfiguredFactory(componentname, componentfactory, true, false); + } + + @Test + public void test_component_factory_optional_configuration_13() throws Exception + { + final String componentname = "factory.component.configuration.optional.13"; + final String componentfactory = "factory.component.factory.configuration.optional.13"; + + testConfiguredFactory(componentname, componentfactory, true, true); + } + + @Test + public void test_component_factory_optional_configuration_nomodify() throws Exception + { + final String componentname = "factory.component.configuration.optional.nomodify"; + final String componentfactory = "factory.component.factory.configuration.optional.nomodify"; + + testConfiguredFactory(componentname, componentfactory, true, false); + } + + + private void testConfiguredFactory(final String componentname, + final String componentfactory, boolean optional, boolean expectComponent) throws InvocationTargetException, + InterruptedException, InvalidSyntaxException + { + // ensure there is no configuration for the component + deleteConfig( componentname ); + delay(); + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 0, -1); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + // At this point, since we don't have created the configuration, then the ComponentFactory + // should not be available. + + checkFactory(componentfactory, optional); + + // supply configuration now and ensure active + configure( componentname ); + delay(); + + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + // get the component factory service + final ComponentInstance instance = createFactoryComponentInstance(componentfactory); + + final Object instanceObject = instance.getInstance(); + TestCase.assertNotNull( instanceObject ); + TestCase.assertEquals( SimpleComponent.INSTANCE, instanceObject ); + TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) ); + TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) ); + + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + // delete config, ensure factory is not active anymore and component instance gone + //(configuration required >> dispose of instance. Also for pre-1.3 components, removing config unconditionally + //deactivates component. + deleteConfig( componentname ); + delay(); + + checkFactory(componentfactory, optional); + + if (expectComponent) + { + TestCase.assertNotNull( instance.getInstance() ); + TestCase.assertNotNull( SimpleComponent.INSTANCE ); + + // with removal of the factory, the created instance should also be removed + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + } + else + { + TestCase.assertNull( instance.getInstance() ); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + // with removal of the factory, the created instance should also be removed + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + } + disableAndCheck(confs); + instance.dispose(); + } + + + @Test + public void test_component_factory_reference() throws Exception + { + final String componentname = "factory.component.reference"; + final String componentfactory = "factory.component.factory.reference"; + + SimpleServiceImpl simpleService = SimpleServiceImpl.create( bundleContext, "ignored" ).setFilterProperty( "ignored" ); + + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentname, 0, -1); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + // register a service : filterprop=match + SimpleServiceImpl match = SimpleServiceImpl.create( bundleContext, "required" ).setFilterProperty( "required" ); + delay(); + + TestCase.assertNull( SimpleComponent.INSTANCE ); + + final ComponentInstance instance = createFactoryComponentInstance(componentfactory); + TestCase.assertEquals( 1, SimpleComponent.INSTANCE.m_multiRef.size() ); + TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( match ) ); + + // check registered components + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + instance.dispose(); + TestCase.assertNull( SimpleComponent.INSTANCE ); + TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2 + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + + + // overwritten filterprop + Hashtable<String, String> propsNonMatch = new Hashtable<String, String>(); + propsNonMatch.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY ); + propsNonMatch.put( "ref.target", "(filterprop=nomatch)" ); + ComponentFactory factory = getComponentFactory(componentfactory); + try + { + factory.newInstance( propsNonMatch ); + TestCase.fail( "Missing reference must fail instance creation" ); + } + catch ( ComponentException ce ) + { + // expected + } + + final SimpleServiceImpl noMatch = SimpleServiceImpl.create( bundleContext, "nomatch" ).setFilterProperty( + "nomatch" ); + delay(); + + final ComponentInstance instanceNonMatch = factory.newInstance( propsNonMatch ); + + TestCase.assertNotNull( instanceNonMatch ); + + TestCase.assertNotNull( instanceNonMatch.getInstance() ); + TestCase.assertEquals( SimpleComponent.INSTANCE, instanceNonMatch.getInstance() ); + TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) ); + + TestCase.assertEquals( 1, SimpleComponent.INSTANCE.m_multiRef.size() ); + TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( noMatch ) ); + + // check registered components + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + match.getRegistration().unregister(); + delay(); + + // check registered components (ComponentFactory aint no longer) + checkConfigurationCount(componentname, 1, ComponentConfigurationDTO.ACTIVE); + + //it has already been deactivated.... this should cause an exception? + noMatch.getRegistration().unregister(); + delay(); + + // check registered components (ComponentFactory aint no longer) + checkConfigurationCount(componentname, 0, ComponentConfigurationDTO.ACTIVE); + + // deactivated due to unsatisfied reference + TestCase.assertNull( instanceNonMatch.getInstance() ); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + //Check that calling dispose on a deactivated instance has no effect + instanceNonMatch.dispose(); + TestCase.assertNull( SimpleComponent.INSTANCE ); + TestCase.assertNull( instanceNonMatch.getInstance() ); // SCR 112.12.6.2 + disableAndCheck(confs); + simpleService.drop(); + } + + @Test + public void test_component_factory_referredTo() throws Exception + { + //set up the component that refers to the service the factory will create. + final String referringComponentName = "ComponentReferringToFactoryObject"; + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(referringComponentName, 1, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); + + final String componentname = "factory.component.referred"; + final String componentfactory = "factory.component.factory.referred"; + + getConfigurationsDisabledThenEnable(componentname, 0, -1); + TestCase.assertNull( SimpleComponent.INSTANCE ); + + Hashtable<String, String> props = new Hashtable<String, String>(); + props.put( "service.pid", "myFactoryInstance" ); + final ComponentFactory factory = getComponentFactory(componentfactory); + + final ComponentInstance instance = factory.newInstance( props ); + TestCase.assertNotNull( instance ); + + TestCase.assertNotNull( instance.getInstance() ); + TestCase.assertTrue( instance.getInstance() instanceof SimpleService ); + //The referring service should now be active + checkConfigurationCount(referringComponentName, 1, ComponentConfigurationDTO.ACTIVE); + + instance.dispose(); + TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2 + + //make sure it's unsatisfied (service is no longer available) + checkConfigurationCount(referringComponentName, 1, ComponentConfigurationDTO.UNSATISFIED_REFERENCE); + disableAndCheck(confs); + } + + @Test + public void test_component_factory_with_target_filters() throws Exception + { + final String componentfactory = "factory.component.reference.targetfilter"; + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentfactory, 0, -1); + + SimpleServiceImpl s1 = SimpleServiceImpl.create(bundleContext, "service1"); + SimpleServiceImpl s2 = SimpleServiceImpl.create(bundleContext, "service2"); + + // supply configuration now and ensure active + Configuration conf = configure( componentfactory ); + delay(); + + TestCase.assertNull( SimpleComponent.INSTANCE ); + + Hashtable<String, String> props = new Hashtable<String, String>(); + props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY ); + props.put("ref.target", "(value=service2)"); + final ComponentInstance instance = createFactoryComponentInstance(componentfactory, props); + + log.log(LogService.LOG_WARNING, "ComponentFactoryTest: Bound Services=" + SimpleComponent.INSTANCE.m_multiRef); + TestCase.assertFalse( SimpleComponent.INSTANCE.m_multiRef.contains( s1 ) ); + TestCase.assertTrue( SimpleComponent.INSTANCE.m_multiRef.contains( s2 ) ); + + instance.dispose(); + TestCase.assertNull( SimpleComponent.INSTANCE ); + TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2 + + s2.drop(); + s1.drop(); + conf.delete(); + disableAndCheck(confs); + } + + @Test + public void test_component_factory_set_bundle_location_null() throws Exception + { + final String componentfactory = "factory.component.reference.targetfilter"; + Collection<ComponentConfigurationDTO> confs = getConfigurationsDisabledThenEnable(componentfactory, 0, -1); + SimpleServiceImpl s1 = SimpleServiceImpl.create(bundleContext, "service1"); + + ConfigurationAdmin ca = getConfigurationAdmin(); + org.osgi.service.cm.Configuration config = ca.getConfiguration( componentfactory, null ); + config.setBundleLocation( null ); + delay(); + if ( isAtLeastR5() ) + { + //check that ConfigurationSupport got a Location changed event and set the bundle location + TestCase.assertNotNull( config.getBundleLocation() ); + } + // supply configuration now and ensure active + configure( componentfactory ); + delay(); + + TestCase.assertNull( SimpleComponent.INSTANCE ); + + final ComponentFactory factory = getComponentFactory(componentfactory); + + disableAndCheck(confs); + s1.drop(); + config.delete(); + } + +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentTestBase.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentTestBase.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentTestBase.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds.itest/src/org/apache/felix/scr/integration/ComponentTestBase.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,1098 @@ +/* + * 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 static java.lang.System.err; +import static java.lang.System.out; + +import java.io.BufferedOutputStream; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.LinkedBlockingQueue; + +import org.apache.felix.scr.integration.components.Felix4350Component; +import org.apache.felix.scr.integration.components.SimpleComponent; +import org.junit.After; +import org.junit.Before; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.namespace.extender.ExtenderNamespace; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentConstants; +import org.osgi.service.component.ComponentFactory; +import org.osgi.service.component.ComponentInstance; +import org.osgi.service.component.runtime.ServiceComponentRuntime; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; +import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public abstract class ComponentTestBase extends TestCase +{ + // Injected + protected BundleContext bundleContext; + + // Our integration test bundle + protected Bundle bundle; + + protected ServiceTracker<ServiceComponentRuntime, ServiceComponentRuntime> scrTracker; + + protected ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> configAdminTracker; + + // the name of the system property providing the bundle file to be installed and tested + protected static final String BUNDLE_JAR_SYS_PROP = "project.bundle.file"; + + // the default bundle jar file name + protected static final String BUNDLE_JAR_DEFAULT = "target/scr.jar"; + + protected static final String PROP_NAME = "theValue"; + protected static final Hashtable<String, Object> theConfig = new Hashtable<>(); + + // the JVM option to set to enable remote debugging + protected static final String DEBUG_VM_OPTION = "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=30303"; + + // the actual JVM option set, extensions may implement a static + // initializer overwriting this value to have the configuration() + // method include it when starting the OSGi framework JVM + protected static String paxRunnerVmOption = null; + + protected String DS_LOGLEVEL = "warn"; + + protected static String bsnVersionUniqueness = "single"; + + // the descriptor file to use for the installed test bundle + protected String descriptorFile = "/resource/integration_test_simple_components.xml"; + protected String COMPONENT_PACKAGE = "org.apache.felix.scr.integration.components"; + + + protected static boolean NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR = false; + protected volatile Log log; + + private ServiceRegistration<?> logService; + + private final Set<ServiceReference> existingServices = new HashSet<>(); + private final Set<Configuration> existingConfigurations = new HashSet<>(); + + protected String[] ignoredWarnings; //null unless you need it. + + //set to true to only get last 1000 lines of log. + protected boolean restrictedLogging; + + protected static String felixCaVersion = System.getProperty( "felix.ca.version" ); + + protected static final String PROP_NAME_FACTORY = ComponentTestBase.PROP_NAME + ".factory"; + + + public ComponentTestBase() + { + // Will use by default this.descriptorFile and this.COMPONENT_PACKAGE + } + + public ComponentTestBase(String descriptorFile) + { + this.descriptorFile = descriptorFile; + // Will use by default this.COMPONENT_PACKAGE + } + + public ComponentTestBase(String descriptorFile, String componentPackage) + { + this.descriptorFile = descriptorFile; + this.COMPONENT_PACKAGE = COMPONENT_PACKAGE + "." + componentPackage; + } + + @Before + public void setUp() throws BundleException, IOException + { + bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + init(); + + log = new Log(restrictedLogging, ignoredWarnings); + log.start(); + bundleContext.addFrameworkListener( log ); + logService = bundleContext.registerService( LogService.class.getName(), log, null ); + + scrTracker = new ServiceTracker<ServiceComponentRuntime, ServiceComponentRuntime>( bundleContext, ServiceComponentRuntime.class, null ); + scrTracker.open(); + configAdminTracker = new ServiceTracker<ConfigurationAdmin, ConfigurationAdmin>( bundleContext, ConfigurationAdmin.class, null ); + configAdminTracker.open(); + + out.println("Running " + getClass().getName() + "." + super.getName()); + bundle = installBundle( descriptorFile, COMPONENT_PACKAGE ); + bundle.start(); + + recordExistingConfigurations(); + } + + + @After + public void tearDown() throws BundleException, InterruptedException + { + boolean foundWarnings = false; + try + { + // Check if the bundle has cleaned of configuration it may have created. + checkConfigurationCleaned(); + + if ( bundle != null && bundle.getState() != Bundle.UNINSTALLED ) + { + bundle.stop(); + bundle.uninstall(); + bundle = null; + } + + Bundle scrBundle = scrTracker.getServiceReference().getBundle(); + scrBundle.stop(); + scrBundle.start(); + + configAdminTracker.close(); + configAdminTracker = null; + scrTracker.close(); + scrTracker = null; + logService.unregister(); + bundleContext.removeFrameworkListener( log ); + } + finally + { + foundWarnings = log.stop(); + } + + if (foundWarnings) + { + TestCase.fail("Test failed (see previous warnings)."); + } + + } + + protected Collection<ComponentDescriptionDTO> getComponentDescriptions() + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr == null ) + { + TestCase.fail("no ServiceComponentRuntime"); + } + return scr.getComponentDescriptionDTOs(); + } + + + protected ComponentDescriptionDTO findComponentDescriptorByName( String name ) + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr == null ) + { + TestCase.fail("no ServiceComponentRuntime"); + } + return scr.getComponentDescriptionDTO(bundle, name); + } + + + protected Collection<ComponentConfigurationDTO> findComponentConfigurationsByName( Bundle b, String name, int expected ) + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr == null ) + { + TestCase.fail("no ServiceComponentRuntime"); + } + ComponentDescriptionDTO cd = scr.getComponentDescriptionDTO(b, name); + Collection<ComponentConfigurationDTO> ccs = scr.getComponentConfigurationDTOs(cd); + if (expected != -1) + { + for (ComponentConfigurationDTO cc: ccs) + { + Assert.assertEquals( "for ComponentConfiguration name: " + cc.description.name + " properties" + cc.properties + "Expected state " + STATES.get(expected) + " but was " + STATES.get(cc.state), expected, cc.state); + } + } + return ccs; + } + + protected Collection<ComponentConfigurationDTO> findComponentConfigurationsByName( String name, int expected ) + { + return findComponentConfigurationsByName(bundle, name, expected); + } + + protected ComponentConfigurationDTO findComponentConfigurationByName( Bundle b, String name, int expected ) + { + Collection<ComponentConfigurationDTO> ccs = findComponentConfigurationsByName( b, name, expected); + Assert.assertEquals(1, ccs.size()); + return ccs.iterator().next(); + } + + protected ComponentConfigurationDTO findComponentConfigurationByName( String name, int expected ) + { + return findComponentConfigurationByName( bundle, name, expected ); + } + + static final Map<Integer, String> STATES = new HashMap<Integer, String>(); + + static { + STATES.put(ComponentConfigurationDTO.UNSATISFIED_REFERENCE, "Unsatisfied (" + ComponentConfigurationDTO.UNSATISFIED_REFERENCE + ")" ); + STATES.put(ComponentConfigurationDTO.SATISFIED, "Satisified (" + ComponentConfigurationDTO.SATISFIED + ")" ); + STATES.put(ComponentConfigurationDTO.ACTIVE, "Active (" + ComponentConfigurationDTO.ACTIVE + ")" ); + } + + protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( Bundle b, String name, int initialState ) throws InvocationTargetException, InterruptedException + { + int count = 1; + Collection<ComponentConfigurationDTO> ccs = getConfigurationsDisabledThenEnable( + b, name, count, initialState); + ComponentConfigurationDTO cc = ccs.iterator().next(); + return cc; + } + + protected ComponentConfigurationDTO getDisabledConfigurationAndEnable( String name, int initialState ) throws InvocationTargetException, InterruptedException + { + return getDisabledConfigurationAndEnable( bundle, name, initialState ); + } + + protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( Bundle b, String name, int count, int initialState) throws InvocationTargetException, InterruptedException + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr == null ) + { + TestCase.fail("no ServiceComponentRuntime"); + } + ComponentDescriptionDTO cd = scr.getComponentDescriptionDTO(b, name); + Assert.assertFalse("Expected component disabled", scr.isComponentEnabled(cd)); + scr.enableComponent(cd).getValue(); + Assert.assertTrue("Expected component enabled", scr.isComponentEnabled(cd)); + + Collection<ComponentConfigurationDTO> ccs = scr.getComponentConfigurationDTOs(cd); + Assert.assertEquals(count, ccs.size()); + for (ComponentConfigurationDTO cc: ccs) { + Assert.assertEquals("Expected state " + STATES.get(initialState) + + " but was " + STATES.get(cc.state), initialState, + cc.state); + } + return ccs; + } + + protected Collection<ComponentConfigurationDTO> getConfigurationsDisabledThenEnable( String name, int count, int initialState) throws InvocationTargetException, InterruptedException + { + return getConfigurationsDisabledThenEnable(bundle, name, count, initialState); + } + + protected ComponentDescriptionDTO checkConfigurationCount( Bundle b, String name, int count, int expectedState ) + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr == null ) + { + TestCase.fail("no ServiceComponentRuntime"); + } + ComponentDescriptionDTO cd = scr.getComponentDescriptionDTO(b, name); + Assert.assertTrue("Expected component enabled", scr.isComponentEnabled(cd)); + + Collection<ComponentConfigurationDTO> ccs = scr.getComponentConfigurationDTOs(cd); + Assert.assertEquals(count, ccs.size()); + if (expectedState != -1) + { + for (ComponentConfigurationDTO cc: ccs) + { + Assert.assertEquals("Expected state " + STATES.get(expectedState) + + " but was " + STATES.get(cc.state), expectedState, + cc.state); + } + } + return cd; + } + + protected ComponentDescriptionDTO checkConfigurationCount( String name, int count, int expectedState ) + { + return checkConfigurationCount(bundle, name, count, expectedState); + } + + protected <S> S getServiceFromConfiguration( ComponentConfigurationDTO dto, Class<S> clazz ) + { + long id = dto.id; + String filter = "(component.id=" + id + ")"; + Collection<ServiceReference<S>> srs; + try { + srs = bundleContext.getServiceReferences(clazz, filter); + Assert.assertEquals(1, srs.size()); + ServiceReference<S> sr = srs.iterator().next(); + S s = bundleContext.getService(sr); + Assert.assertNotNull(s); + return s; + } catch (InvalidSyntaxException e) { + TestCase.fail(e.getMessage()); + return null;//unreachable in fact + } + } + + protected <S> void ungetServiceFromConfiguration( ComponentConfigurationDTO dto, Class<S> clazz ) + { + long id = dto.id; + String filter = "(component.id=" + id + ")"; + Collection<ServiceReference<S>> srs; + try { + srs = bundleContext.getServiceReferences(clazz, filter); + Assert.assertEquals(1, srs.size()); + ServiceReference<S> sr = srs.iterator().next(); + bundleContext.ungetService(sr); + } catch (InvalidSyntaxException e) { + TestCase.fail(e.getMessage()); + } + } + + + @SuppressWarnings({ "unchecked" }) + protected <S> ServiceReference<S> findServiceByPid(BundleContext ctx, String type, String filter) + { + try + { + ServiceReference<S>[] refs = (ServiceReference<S>[]) ctx.getServiceReferences(type, filter); + return refs != null ? refs[0] : null; + } + catch (InvalidSyntaxException e) + { + throw new IllegalStateException("Could not get service using filter " + filter); + } + } + + protected void enableAndCheck( ComponentDescriptionDTO cd ) throws InvocationTargetException, InterruptedException + { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr != null ) + { + scr.enableComponent(cd).getValue(); + Assert.assertTrue("Expected component enabled", scr.isComponentEnabled(cd)); + } + else + { + throw new NullPointerException("no ServiceComponentRuntime"); + } + + } + + protected void disableAndCheck(ComponentDescriptionDTO cd) throws InvocationTargetException, InterruptedException { + ServiceComponentRuntime scr = scrTracker.getService(); + if ( scr != null ) + { + scr.disableComponent(cd).getValue(); + Assert.assertFalse("Expected component disabled", scr.isComponentEnabled(cd)); + } + else + { + throw new NullPointerException("no ServiceComponentRuntime"); + } + } + + protected void disableAndCheck(Collection<ComponentConfigurationDTO> confs) throws InvocationTargetException, InterruptedException { + if (confs != null) { + for (ComponentConfigurationDTO conf : confs) { + disableAndCheck(conf); + } + } + } + + protected void disableAndCheck( ComponentConfigurationDTO cc ) throws InvocationTargetException, InterruptedException + { + ComponentDescriptionDTO cd = cc.description; + disableAndCheck(cd); + } + + protected void disableAndCheck(String name) throws InvocationTargetException, InterruptedException { + ComponentDescriptionDTO cd = findComponentDescriptorByName(name); + disableAndCheck(cd); + } + + protected static void delay() + { + delay(300); + } + + protected static void delay(int millis) + { + try + { + Thread.sleep(millis); + } + catch (InterruptedException ie) + { + } + } + + + protected ConfigurationAdmin getConfigurationAdmin() + { + ConfigurationAdmin ca = configAdminTracker.getService(); + if ( ca == null ) + { + TestCase.fail( "Missing ConfigurationAdmin service" ); + } + return ca; + } + + protected org.osgi.service.cm.Configuration configure( String pid ) + { + return configure( pid, null ); + + } + + protected org.osgi.service.cm.Configuration configure( String pid, String bundleLocation ) + { + return configure(pid, bundleLocation, theConfig); + } + + protected org.osgi.service.cm.Configuration configure(String pid, + String bundleLocation, Dictionary<String, Object> props) + { + ConfigurationAdmin ca = getConfigurationAdmin(); + try + { + org.osgi.service.cm.Configuration config = ca.getConfiguration( pid, null ); + if (bundleLocation != null) + { + config.setBundleLocation( bundleLocation ); + } + config.update( props ); + return config; + } + catch ( IOException ioe ) + { + TestCase.fail( "Failed updating configuration " + pid + ": " + ioe.toString() ); + } + return null; + } + + + protected void deleteConfig( String pid ) + { + ConfigurationAdmin ca = getConfigurationAdmin(); + try + { + org.osgi.service.cm.Configuration config = ca.getConfiguration( pid ); + config.delete(); + } + catch ( IOException ioe ) + { + TestCase.fail( "Failed deleting configuration " + pid + ": " + ioe.toString() ); + } + } + + + protected String createFactoryConfiguration( String factoryPid ) + { + ConfigurationAdmin ca = getConfigurationAdmin(); + try + { + org.osgi.service.cm.Configuration config = ca.createFactoryConfiguration( factoryPid, null ); + config.update( theConfig ); + return config.getPid(); + } + catch ( IOException ioe ) + { + TestCase.fail( "Failed updating factory configuration " + factoryPid + ": " + ioe.toString() ); + return null; + } + } + + + protected void deleteFactoryConfigurations( String factoryPid ) + { + ConfigurationAdmin ca = getConfigurationAdmin(); + try + { + final String filter = "(service.factoryPid=" + factoryPid + ")"; + org.osgi.service.cm.Configuration[] configs = ca.listConfigurations( filter ); + if ( configs != null ) + { + for ( org.osgi.service.cm.Configuration configuration : configs ) + { + configuration.delete(); + } + } + } + catch ( InvalidSyntaxException ise ) + { + // unexpected + } + catch ( IOException ioe ) + { + TestCase.fail( "Failed deleting configurations " + factoryPid + ": " + ioe.toString() ); + } + } + + //component factory test helper methods + protected ComponentFactory getComponentFactory(final String componentfactory) + throws InvalidSyntaxException + { + final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "(" + + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" ); + TestCase.assertNotNull( refs ); + TestCase.assertEquals( 1, refs.length ); + final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] ); + TestCase.assertNotNull( factory ); + return factory; + } + + + protected void checkFactory(final String componentfactory, boolean expectFactoryPresent) + throws InvalidSyntaxException + { + ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "(" + + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" ); + if ( expectFactoryPresent ) + { + TestCase.assertNotNull( refs ); + TestCase.assertEquals(1, refs.length); + + } + else + { + TestCase.assertNull( refs ); + } + } + + protected ComponentInstance createFactoryComponentInstance(final String componentfactory) + throws InvalidSyntaxException + { + Hashtable<String, String> props = new Hashtable<String, String>(); + props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY ); + + return createFactoryComponentInstance(componentfactory, props); + } + + + protected ComponentInstance createFactoryComponentInstance( + final String componentfactory, Hashtable<String, String> props) + throws InvalidSyntaxException + { + final ComponentFactory factory = getComponentFactory(componentfactory); + + final ComponentInstance instance = factory.newInstance( props ); + TestCase.assertNotNull( instance ); + + TestCase.assertNotNull( instance.getInstance() ); + TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() ); + TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME_FACTORY ) ); + return instance; + } + + + + + protected static Class<?> getType( Object object, String desiredName ) + { + Class<?> ccImpl = object.getClass(); + while ( ccImpl != null && !desiredName.equals( ccImpl.getSimpleName() ) ) + { + ccImpl = ccImpl.getSuperclass(); + } + if ( ccImpl == null ) + { + TestCase.fail( "ComponentContext " + object + " is not a " + desiredName ); + } + + return ccImpl; + } + + + protected static Object getFieldValue( Object object, String fieldName ) + { + try + { + final Field m_componentsField = getField( object.getClass(), fieldName ); + return m_componentsField.get( object ); + } + catch ( Throwable t ) + { + TestCase.fail( "Cannot get " + fieldName + " from " + object + ": " + t ); + return null; // keep the compiler happy + } + } + + protected Object getComponentManagerFromComponentInstance( Object instance ) + { + Object cc = getFieldValue( instance, "m_componentContext"); + return getFieldValue( cc, "m_componentManager" ); + } + + + protected static Field getField( Class<?> type, String fieldName ) throws NoSuchFieldException + { + Class<?> clazz = type; + while (clazz != null) + { + Field[] fields = clazz.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if (field.getName().equals(fieldName)) + { + field.setAccessible( true ); + return field; + } + } + clazz = clazz.getSuperclass(); + } + throw new NoSuchFieldException(fieldName); + } + + protected Bundle installBundle( final String descriptorFile, String componentPackage ) throws BundleException, IOException + { + return installBundle(descriptorFile, componentPackage, "simplecomponent", "0.0.11", null); + } + + protected Bundle installBundle( final String descriptorFile, String componentPackage, String symbolicName, String version, String location ) throws BundleException, IOException + { + BundleGenerator generator = new BundleGenerator(); + + try(InputStream bundleStream = + generator + .add("OSGI-INF/components.xml", bundleContext.getBundle().getEntry(descriptorFile)) + .set(Constants.BUNDLE_SYMBOLICNAME, symbolicName) + .set(Constants.BUNDLE_VERSION, version) + .set(Constants.IMPORT_PACKAGE, componentPackage) + .set("Service-Component", "OSGI-INF/components.xml") + .set(Constants.REQUIRE_CAPABILITY, ExtenderNamespace.EXTENDER_NAMESPACE + ";filter:=\"(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))\"") + .buildWithBnd()) { + + if ( location == null ) + { + location = "test:SimpleComponent/" + System.currentTimeMillis(); + } + return bundleContext.installBundle( location, bundleStream ); + } + } + + protected boolean isAtLeastR5() + { + try + { + Method m = org.osgi.service.cm.Configuration.class.getDeclaredMethod( "getChangeCount"); + return true; + } + catch ( SecurityException e ) + { + throw new RuntimeException(e); + } + catch ( NoSuchMethodException e ) + { + return false; + } + } + + /** + * Reset some integration test components and some configurations before running a test. + */ + private void init() { + theConfig.clear(); + theConfig.put( PROP_NAME, PROP_NAME ); + SimpleComponent.INSTANCES.clear(); + SimpleComponent.PREVIOUS_INSTANCES.clear(); + Felix4350Component.init(); + } + + /** + * Record all existing services and configuration. + */ + protected void recordExistingConfigurations() { + Configuration[] confs = getAllConfigurations(); + existingConfigurations.addAll(Arrays.asList(confs)); + } + + private Configuration[] getAllConfigurations() { + ConfigurationAdmin ca = getConfigurationAdmin(); + try + { + Configuration[] confs = ca.listConfigurations( null ); + return confs == null ? new Configuration[0] : confs; + } + catch ( Throwable ignored ) + { + return null; + } + } + + /** + * Check if the test has removed all its resources (services, configurations). + */ + private void checkConfigurationCleaned() { + Configuration[] confs = getAllConfigurations(); + for (Configuration conf : confs) { + if (! existingConfigurations.contains(conf)) { + log.log(LogService.LOG_ERROR, "Tested ended but did not unregister " + conf); + Assert.fail("Tested ended but did not unregister configuration " + conf); + } + } + + existingServices.clear(); + existingConfigurations.clear(); + } + + public static class LogEntry + { + private final String m_msg; + private final int m_level; + private final Throwable m_err; + private final long m_time; + private final Thread m_thread; + + + LogEntry( int level, String msg, Throwable t ) + { + m_level = level; + m_msg = msg; + m_err = t; + m_time = System.currentTimeMillis(); + m_thread = Thread.currentThread(); + } + + + @Override + public String toString() + { + return m_msg; + } + + + public int getLevel() + { + return m_level; + } + + + public String getMessage() + { + return m_msg; + } + + + public Throwable getError() + { + return m_err; + } + + + public long getTime() + { + return m_time; + } + + + public Thread getThread() + { + return m_thread; + } + } + + public class Log implements LogService, FrameworkListener, Runnable + { + private static final int RESTRICTED_LOG_SIZE = 1000; + private final SimpleDateFormat m_sdf = new SimpleDateFormat( "HH:mm:ss,S" ); + private final PrintStream m_out = new PrintStream( new BufferedOutputStream( new FileOutputStream( + FileDescriptor.err ), 128 ) ); + private final List<String> m_warnings = Collections.synchronizedList( new ArrayList<String>() ); + private LinkedBlockingQueue<LogEntry> m_logQueue = new LinkedBlockingQueue<LogEntry>(); + private volatile Thread m_logThread; + private String[] ignoredWarnings; // Format is : log message [:exception message] + + protected Throwable firstFrameworkThrowable; + + private final boolean restrictedLogging; + private final String[] log = new String[1000]; + private int i = 0; + + public Log( boolean restrictedLogging, String[] ignoredWarnings ) + { + this.restrictedLogging = restrictedLogging; + this.ignoredWarnings = ignoredWarnings; + } + + public void start() + { + m_logThread = new Thread( this ); + m_logThread.start(); + } + + + public boolean stop() + { + // Make sure logging threads is done. + m_logThread.interrupt(); + try + { + m_logThread.join(); + } + catch ( InterruptedException e ) + { + } + + if ( restrictedLogging ) + { + for (int j = 0; j < RESTRICTED_LOG_SIZE; j++) + { + if ( log[i] != null ) + { + err.println(log[i]); + } + i ++; + if (i == RESTRICTED_LOG_SIZE) + { + i = 0; + } + } + } + else + { + m_out.flush(); + } + boolean foundWarning = m_warnings.size() > 0; + m_warnings.clear(); + m_logThread.interrupt(); + return foundWarning; + } + + + List<String> foundWarnings() + { + return m_warnings; + } + + Throwable getFirstFrameworkThrowable() + { + return firstFrameworkThrowable; + } + + + + public void run() + { + try + { + LogEntry entry = null; + while ( true ) + { + entry = m_logQueue.take(); + boolean acceptedWarning = false; + if ( entry.getLevel() <= 2 ) + { + if (acceptWarning( entry)) + { + acceptedWarning = true; + if ( m_warnings.size() < 1024 ) + { + m_warnings.add( entry.getMessage() ); + } + else + { + // Avoid out of memory ... + m_warnings.set( 1023, "Unexpected errors logged. Please look at previous logs" ); + } + } + } + + StringWriter sw = new StringWriter(); + sw.append( "L=" + entry.getLevel() ); + sw.append( " D=" ); + sw.append( m_sdf.format( new Date( entry.getTime() ) ) ); + sw.append( " T=\"" + entry.getThread().getName() + "\""); + sw.append((entry.getLevel() <= 2 && ! acceptedWarning) ? " (log expected)" : " (log Unexpected)"); + sw.append( ": " ); + sw.append( entry.getMessage() ); + if ( entry.getLevel() <= 2 && entry.getError() != null) + { + PrintWriter pw = new PrintWriter( sw ); + sw.append( System.getProperty( "line.separator" ) ); + if (acceptWarning(entry)) + { + entry.getError().printStackTrace( pw ); + } + else + { + pw.print(entry.getError().toString()); + } + pw.flush(); + } + // We really want to log to stdout warnings that are ignored by the test. + if ( restrictedLogging && (entry.getLevel() <= 2 && acceptedWarning)) + { + log[i++] = sw.toString(); + if ( i == RESTRICTED_LOG_SIZE ) i = 0; + } + else + { + m_out.println( sw.toString() ); + m_out.flush(); + } + } + } + catch ( InterruptedException e ) + { + return; + } + } + + + // ------------- FrameworkListener ----------------------------------------------------------- + + private boolean acceptWarning(LogEntry entry) { + if ( ignoredWarnings != null ) + { + for (String ignore : ignoredWarnings) { + if (entry.getError() == null) { + if (entry.getMessage().matches(ignore)) { + return false; + } + } else { + String msg = entry.getMessage() + System.getProperty( "line.separator" ) + entry.getError().toString(); + if (msg.matches(ignore)) { + return false; + } + } + } + } + return true; + } + + public void frameworkEvent( final FrameworkEvent event ) + { + int eventType = event.getType(); + String msg = getFrameworkEventMessage( eventType ); + int level = ( eventType == FrameworkEvent.ERROR ) ? LogService.LOG_ERROR : LogService.LOG_INFO; + log( level, msg, event.getThrowable() ); + if (event.getThrowable() != null && firstFrameworkThrowable == null) + { + firstFrameworkThrowable = event.getThrowable(); + } + } + + + // ------------ LogService ---------------------------------------------------------------- + + public void log( int level, String message ) + { + log( level, message, null ); + } + + + public void log( int level, String message, Throwable exception ) + { + if ( level > getEnabledLogLevel() ) + { + return; + } + m_logQueue.offer( new LogEntry( level, message, exception ) ); + } + + + public void log( ServiceReference sr, int osgiLevel, String message ) + { + log( sr, osgiLevel, message, null ); + } + + + public void log( ServiceReference sr, int level, String msg, Throwable exception ) + { + if ( sr != null ) + { + StringBuilder sb = new StringBuilder(); + Object serviceId = sr.getProperty( Constants.SERVICE_ID ); + if ( serviceId != null ) + { + sb.append( "[" + serviceId.toString() + "] " ); + } + sb.append( msg ); + log( level, sb.toString(), exception ); + } + else + { + log( level, msg, exception ); + } + } + + + private int getEnabledLogLevel() + { + if ( DS_LOGLEVEL.regionMatches( true, 0, "err", 0, "err".length() ) ) + { + return LogService.LOG_ERROR; + } + else if ( DS_LOGLEVEL.regionMatches( true, 0, "warn", 0, "warn".length() ) ) + { + return LogService.LOG_WARNING; + } + else if ( DS_LOGLEVEL.regionMatches( true, 0, "info", 0, "info".length() ) ) + { + return LogService.LOG_INFO; + } + else + { + return LogService.LOG_DEBUG; + } + } + + + private String getFrameworkEventMessage( int event ) + { + switch ( event ) + { + case FrameworkEvent.ERROR: + return "FrameworkEvent: ERROR"; + case FrameworkEvent.INFO: + return "FrameworkEvent INFO"; + case FrameworkEvent.PACKAGES_REFRESHED: + return "FrameworkEvent: PACKAGE REFRESHED"; + case FrameworkEvent.STARTED: + return "FrameworkEvent: STARTED"; + case FrameworkEvent.STARTLEVEL_CHANGED: + return "FrameworkEvent: STARTLEVEL CHANGED"; + case FrameworkEvent.WARNING: + return "FrameworkEvent: WARNING"; + default: + return null; + } + } + } +}
