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>