FELIX-3754 Internally register the component instance before calling the activate method to make sure (dynamic) services can be bound during activation. In case of activation failure, the instance has to be unregistered again. Plus test case.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1409028 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
index ceed436..e4647da 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
@@ -123,6 +123,14 @@
                     m_componentContext = tmpContext;
                     m_implementationObject = implementationObject;
                 }
+
+
+                public void unsetImplementationObject( Object implementationObject )
+                {
+                    m_componentContext = null;
+                    m_implementationObject = null;
+                }
+
             } );
 
             // if something failed creating the component instance, return false
@@ -180,6 +188,7 @@
 
     protected interface SetImplementationObject {
         void setImplementationObject(Object implementationObject);
+        void unsetImplementationObject(Object implementationObject);
     }
 
     protected Object createImplementationObject( ComponentContext componentContext, SetImplementationObject setter )
@@ -235,11 +244,17 @@
             }
         }
 
-        // 4. Call the activate method, if present
+        // 4. set the implementation object prematurely
+        setter.setImplementationObject( implementationObject );
+
+        // 5. Call the activate method, if present
         final MethodResult result = getComponentMethods().getActivateMethod().invoke( implementationObject, new ActivatorParameter(
                 componentContext, 1 ), null );
         if ( result == null )
         {
+            // make sure the implementation object is not available
+            setter.unsetImplementationObject( implementationObject );
+
             // 112.5.8 If the activate method throws an exception, SCR must log an error message
             // containing the exception with the Log Service and activation fails
             it = getDependencyManagers();
@@ -253,7 +268,6 @@
         }
         else
         {
-            setter.setImplementationObject( implementationObject );
             setServiceProperties( result );
         }
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
index 1798f22..d6a5826 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
@@ -152,6 +152,13 @@
                     changeState( Active.getInstance() );
                 }
             }
+
+
+            public void unsetImplementationObject( Object implementationObject )
+            {
+                serviceContexts.remove( implementationObject );
+                serviceContext.setImplementationObject( null );
+            }
         } );
 
         // register the components component context if successfull
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
index 510764c..a6d7d53 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentActivationTest.java
@@ -22,6 +22,7 @@
 import junit.framework.TestCase;
 
 import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.ActivatorComponent;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
@@ -185,4 +186,31 @@
         delay();
         TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
     }
+
+
+    @Test
+    public void test_activate_register_service()
+    {
+        final String componentname = "ActivatorComponent.activate.with.bind";
+
+        final Component component = findComponentByName( componentname );
+
+        TestCase.assertNotNull( component );
+        TestCase.assertFalse( component.isDefaultEnabled() );
+
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+
+        ActivatorComponent ac = (ActivatorComponent) component.getComponentInstance().getInstance();
+        TestCase.assertNotNull( ac.getSimpleService() );
+
+        component.disable();
+
+        delay();
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+    }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/ActivatorComponent.java b/scr/src/test/java/org/apache/felix/scr/integration/components/ActivatorComponent.java
index 0aa747f..cc68d99 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/components/ActivatorComponent.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/ActivatorComponent.java
@@ -21,6 +21,9 @@
 
 import java.util.Map;
 
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
 
 public class ActivatorComponent
 {
@@ -29,14 +32,23 @@
 
     public static final String FLAG_FAIL_DEACTIVATE = "failDeactivate";
 
+    public static final String FLAG_REGISTER_SERVICE = "registerService";
+
+    private ServiceRegistration registration;
+
+    private SimpleService simpleService;
 
     @SuppressWarnings("unused")
-    private void myActivate( Map<?, ?> configuration )
+    private void myActivate( BundleContext context, Map<?, ?> configuration )
     {
         if ( configuration.containsKey( FLAG_FAIL_ACTIVATE ) )
         {
             throw new IllegalStateException( "myActivate fails" );
         }
+        if ( configuration.containsKey( FLAG_REGISTER_SERVICE ) )
+        {
+            registration = context.registerService( SimpleService.class.getName(), new SimpleServiceImpl(), null );
+        }
     }
 
 
@@ -47,5 +59,33 @@
         {
             throw new IllegalStateException( "myDeactivate fails" );
         }
+        if ( registration != null )
+        {
+            registration.unregister();
+            registration = null;
+        }
+    }
+
+
+    public SimpleService getSimpleService()
+    {
+        return simpleService;
+    }
+
+
+    @SuppressWarnings("unused")
+    private void bindSimpleService( SimpleService simpleService )
+    {
+        this.simpleService = simpleService;
+    }
+
+
+    @SuppressWarnings("unused")
+    private void unbindSimpleService( SimpleService simpleService )
+    {
+        if ( this.simpleService == simpleService )
+        {
+            this.simpleService = null;
+        }
     }
 }
diff --git a/scr/src/test/resources/integration_test_activation_components.xml b/scr/src/test/resources/integration_test_activation_components.xml
index 00ccba9..a3026e8 100644
--- a/scr/src/test/resources/integration_test_activation_components.xml
+++ b/scr/src/test/resources/integration_test_activation_components.xml
@@ -70,4 +70,21 @@
         <implementation class="org.apache.felix.scr.integration.components.ActivatorComponent" />
         <property name="failDeactivate" value="true" />
     </scr:component>
+
+    <!-- bind service during activate -->
+    <scr:component name="ActivatorComponent.activate.with.bind"
+        enabled="false"
+        activate="myActivate"
+        deactivate="myDeactivate">
+        <implementation class="org.apache.felix.scr.integration.components.ActivatorComponent" />
+        <property name="registerService" value="true" />
+        <reference
+            name="service"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            policy="dynamic"
+            cardinality="0..n"
+        />
+    </scr:component>
 </components>