blob: 7cca5ca2a0cab69086564d16d0cc7bd94d4a909d [file] [log] [blame]
/*
* 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 org.junit.Assert.assertNotNull;
import java.lang.reflect.InvocationTargetException;
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.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.PaxExam;
import org.osgi.framework.InvalidSyntaxException;
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;
@RunWith(PaxExam.class)
public class ComponentFactoryTest extends ComponentTestBase
{
static
{
descriptorFile = "/integration_test_simple_factory_components.xml";
// uncomment to enable debugging of this test class
// paxRunnerVmOption = DEBUG_VM_OPTION;
}
@Test
public void test_component_factory() throws Exception
{
final String componentname = "factory.component";
final String componentfactory = "factory.component.factory";
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 );
}
@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";
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
}
@Test
public void test_component_factory_newInstance_failure() throws Exception
{
final String componentname = "factory.component";
final String componentfactory = "factory.component.factory";
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 );
}
@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();
getConfigurationsDisabledThenEnable( componentname, 1, ComponentConfigurationDTO.ACTIVE );
TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
}
@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 ComponentInstance 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();
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 );
}
return instance;
}
@Test
public void test_component_factory_reference() throws Exception
{
final String componentname = "factory.component.reference";
final String componentfactory = "factory.component.factory.reference";
SimpleServiceImpl.create( bundleContext, "ignored" ).setFilterProperty( "ignored" );
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
}
@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";
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 );
}
@Test
public void test_component_factory_with_target_filters() throws Exception
{
final String componentfactory = "factory.component.reference.targetfilter";
getConfigurationsDisabledThenEnable( componentfactory, 0, -1 );
SimpleServiceImpl s1 = SimpleServiceImpl.create( bundleContext, "service1" );
SimpleServiceImpl s2 = SimpleServiceImpl.create( bundleContext, "service2" );
// supply configuration now and ensure active
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, "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();
}
@Test
public void test_component_factory_set_bundle_location() throws Exception
{
final String componentfactoryPid = "factory.component.configuration";
final String componentFactoryName = "factory.component.factory.configuration";
getConfigurationsDisabledThenEnable( componentfactoryPid, 0, -1 );
checkFactory( componentFactoryName, false );
org.osgi.service.cm.Configuration config = configure( componentfactoryPid );
delay();
assertNotNull( getComponentFactory( componentFactoryName ) );
config.setBundleLocation( "foo" );
delay();
checkFactory( componentFactoryName, false );
config.setBundleLocation( bundle.getLocation() );
delay();
assertNotNull( getComponentFactory( componentFactoryName ) );
config.setBundleLocation( "foo" );
delay();
checkFactory( componentFactoryName, false );
config.setBundleLocation( "?" );
delay();
assertNotNull( getComponentFactory( componentFactoryName ) );
}
}