FELIX-3559 Fix factory components whose newInstances are services referred to by other components
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1371859 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 732ba01..9445777 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -1536,7 +1536,7 @@
* deactivated due to not being satisified any longer. See section 112.5.5,
* Factory Component, for full details.
*/
- protected static final class FactoryInstance extends Satisfied
+ protected static final class FactoryInstance extends Satisfied//Registered
{
private static final FactoryInstance m_inst = new FactoryInstance();
@@ -1552,6 +1552,33 @@
return m_inst;
}
+ Object getService( ImmediateComponentManager dcm )
+ {
+ if ( dcm.createComponent() )
+ {
+ dcm.changeState( Active.getInstance() );
+ return dcm.getInstance();
+ }
+
+ // log that the delayed component cannot be created (we don't
+ // know why at this moment; this should already have been logged)
+ dcm.log( LogService.LOG_ERROR, "Failed creating the component instance; see log for reason", null );
+
+ // component could not really be created. This may be temporary
+ // so we stay in the registered state but ensure the component
+ // instance is deleted
+ try
+ {
+ dcm.deleteComponent( ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED );
+ }
+ catch ( Throwable t )
+ {
+ dcm.log( LogService.LOG_DEBUG, "Cannot delete incomplete component instance. Ignoring.", t );
+ }
+
+ // no service can be returned (be prepared for more logging !!)
+ return null;
+ }
void deactivate( AbstractComponentManager acm, int reason )
{
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
index 8ad0b8e..e6b1db3 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
@@ -50,7 +50,7 @@
static
{
// uncomment to enable debugging of this test class
- // paxRunnerVmOption = DEBUG_VM_OPTION;
+// paxRunnerVmOption = DEBUG_VM_OPTION;
}
@@ -517,4 +517,61 @@
// TestCase.assertNull( SimpleComponent.INSTANCE );
// TestCase.assertNull( instanceNonMatch.getInstance() ); // SCR 112.12.6.2
}
+
+ @Test
+ public void test_component_factory_referredTo() throws InvalidSyntaxException
+ {
+ //set up the component that refers to the service the factory will create.
+ final String referringComponentName = "ComponentReferringToFactoryObject";
+ final Component referringComponent = findComponentByName( referringComponentName );
+ TestCase.assertNotNull( referringComponent );
+ referringComponent.enable();
+ delay();
+
+ //make sure it's unsatisfied (service is not yet available
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, referringComponent.getState() );
+
+
+ final String componentname = "factory.component.referred";
+ final String componentfactory = "factory.component.factory.referred";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ 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 );
+
+ // create the factory instance
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put( "service.pid", "myFactoryInstance" );
+ final ComponentInstance instance = factory.newInstance( props );
+ TestCase.assertNotNull( instance );
+
+ TestCase.assertNotNull( instance.getInstance() );
+
+ //The referring service should now be active
+ TestCase.assertEquals( Component.STATE_ACTIVE, referringComponent.getState() );
+
+ instance.dispose();
+ TestCase.assertNull( instance.getInstance() ); // SCR 112.12.6.2
+
+ //make sure it's unsatisfied (service is no longer available)
+ TestCase.assertEquals( Component.STATE_UNSATISFIED, referringComponent.getState() );
+ }
+
}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/SimpleServiceImpl.java b/scr/src/test/java/org/apache/felix/scr/integration/components/SimpleServiceImpl.java
index f90d44a..49ac37d 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/components/SimpleServiceImpl.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/SimpleServiceImpl.java
@@ -52,6 +52,10 @@
return instance;
}
+ public SimpleServiceImpl()
+ {
+ this("", 0);
+ }
SimpleServiceImpl( final String value, final int ranking )
{
diff --git a/scr/src/test/resources/integration_test_simple_components.xml b/scr/src/test/resources/integration_test_simple_components.xml
index e1b710d..04f0f9d 100644
--- a/scr/src/test/resources/integration_test_simple_components.xml
+++ b/scr/src/test/resources/integration_test_simple_components.xml
@@ -138,4 +138,31 @@
/>
</scr:component>
+ <!-- Component Factory Instances, instance is referred to by another component -->
+ <scr:component name="factory.component.referred"
+ enabled="false"
+ factory="factory.component.factory.referred" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleServiceImpl" />
+ <service>
+ <provide interface="org.apache.felix.scr.integration.components.SimpleService" />
+ </service>
+ </scr:component>
+
+ <!-- component has a reference to service created by the factory.component.referred factory component-->
+ <scr:component name="ComponentReferringToFactoryObject"
+ enabled="false"
+ immediate="true">
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <property name="service.pid" value="ComponentReferringToFactoryObject" />
+ <reference
+ name="ref"
+ interface="org.apache.felix.scr.integration.components.SimpleService"
+ cardinality="1..1"
+ policy="dynamic"
+ bind="bindSimpleService"
+ unbind="unbindSimpleService"
+ target="(service.pid=myFactoryInstance)"
+ />
+ </scr:component>
+
</components>