FELIX-1943 Ensure components which are not satisfied any longer if a service is unregistered are deactivated. Before this would only happen if the component had the service bound, which is not always the case (for example for ComponentFactory components).
FELIX-1944 Ensure Reference.getServiceReferences() returns null if no services are bound to the component (an empty array used to be returned).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@890260 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
index 1404012..5c8ae65 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindTest.java
@@ -19,6 +19,8 @@
package org.apache.felix.scr.integration;
+import java.util.Hashtable;
+
import junit.framework.TestCase;
import org.apache.felix.scr.Component;
@@ -27,11 +29,19 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
@RunWith(JUnit4TestRunner.class)
public class ServiceBindTest extends ComponentTestBase
{
+
+ private static final String PROP_NAME_FACTORY = ComponentTestBase.PROP_NAME + ".factory";
+
static
{
// uncomment to enable debugging of this test class
@@ -550,6 +560,142 @@
@Test
+ public void test_required_multiple_dynamic_factory() throws InvalidSyntaxException
+ {
+ final String pid = "test_required_multiple_dynamic_factory";
+ final String factoryPid = "factory_" + pid;
+
+ final Component component = findComponentByName( pid );
+ TestCase.assertNotNull( component );
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+ // async enabling (unsatisfied)
+ component.enable();
+ delay();
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+ // register service, satisfying
+ final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+ delay();
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+
+ // create a component instance
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + factoryPid + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+
+ // ensure instance is bound
+ final SimpleComponent sc = SimpleComponent.INSTANCE;
+ TestCase.assertEquals( 1, sc.m_multiRef.size() );
+ TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+
+ // ensure factory is not bound
+ TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+ // assert two components managed
+ final Component[] allFactoryComponents = findComponentsByName( pid );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // register second service
+ final SimpleServiceImpl srv11 = SimpleServiceImpl.create( bundleContext, "srv11" );
+ delay();
+
+ // ensure instance is bound
+ TestCase.assertEquals( 2, sc.m_multiRef.size() );
+ TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+ TestCase.assertTrue( sc.m_multiRef.contains( srv11 ) );
+
+ // ensure factory is not bound
+ TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+ // drop second service and ensure unbound (and active)
+ srv11.drop();
+ delay();
+ TestCase.assertNotNull( instance.getInstance() );
+ TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+ TestCase.assertEquals( 1, sc.m_multiRef.size() );
+ TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+ TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+
+ // remove the service, expect factory to deactivate and instance to dispose
+ srv1.drop();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+ TestCase.assertNull( instance.getInstance() );
+
+ // assert component factory only managed
+ final Component[] allFactoryComponents2 = findComponentsByName( pid );
+ TestCase.assertNotNull( allFactoryComponents2 );
+ TestCase.assertEquals( 1, allFactoryComponents2.length );
+ for ( int i = 0; i < allFactoryComponents2.length; i++ )
+ {
+ final Component c = allFactoryComponents2[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // registeranother service, factory must come back, instance not
+ final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( instance.getInstance() );
+
+ // assert component factory only managed
+ final Component[] allFactoryComponents3 = findComponentsByName( pid );
+ TestCase.assertNotNull( allFactoryComponents3 );
+ TestCase.assertEquals( 1, allFactoryComponents3.length );
+ for ( int i = 0; i < allFactoryComponents3.length; i++ )
+ {
+ final Component c = allFactoryComponents3[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+ }
+
+
+ @Test
public void test_optional_single_static()
{
final Component component = findComponentByName( "test_optional_single_static" );
diff --git a/scr/src/test/resources/integration_test_simple_components_service_binding.xml b/scr/src/test/resources/integration_test_simple_components_service_binding.xml
index 9c8c630..afba9e1 100644
--- a/scr/src/test/resources/integration_test_simple_components_service_binding.xml
+++ b/scr/src/test/resources/integration_test_simple_components_service_binding.xml
@@ -103,6 +103,21 @@
/>
</scr:component>
+ <scr:component name="test_required_multiple_dynamic_factory"
+ enabled="false"
+ configuration-policy="ignore"
+ factory="factory_test_required_multiple_dynamic_factory">
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <reference
+ name="ref"
+ interface="org.apache.felix.scr.integration.components.SimpleService"
+ cardinality="1..n"
+ policy="dynamic"
+ bind="bindSimpleService"
+ unbind="unbindSimpleService"
+ />
+ </scr:component>
+
<scr:component name="test_optional_multiple_static"
enabled="false"
configuration-policy="ignore">