FELIX-3410 Apply patch by David Jencks (thanks) and add
   integration test proving functionality

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1344812 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 29d2945..2bc619f 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
@@ -448,8 +448,10 @@
         // clear the current properties to force using the configuration data
         m_properties = null;
 
+        // unsatisfied component and non-ignored configuration may change targets
+        // to satisfy references
         if ( getState() == STATE_UNSATISFIED && configuration != null
-            && getComponentMetadata().isConfigurationRequired() )
+            && !getComponentMetadata().isConfigurationIgnored() )
         {
             activateInternal();
             return;
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
index b589301..309e25c 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConfigurationTest.java
@@ -23,6 +23,7 @@
 
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.apache.felix.scr.integration.components.SimpleServiceImpl;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
@@ -228,6 +229,91 @@
 
 
     @Test
+    public void test_SimpleComponent_dynamic_configuration_with_required_service()
+    {
+        final String targetProp = "ref.target";
+        final String filterProp = "required";
+        final SimpleServiceImpl service = SimpleServiceImpl.create( bundleContext, "sample" ).setFilterProperty( filterProp );
+        try
+        {
+            final String pid = "DynamicConfigurationComponentWithRequiredReference";
+            final Component component = findComponentByName( pid );
+
+            deleteConfig( pid );
+            delay();
+
+            TestCase.assertNotNull( component );
+            TestCase.assertFalse( component.isDefaultEnabled() );
+
+            TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+            TestCase.assertNull( SimpleComponent.INSTANCE );
+
+            component.enable();
+            delay();
+
+            // mandatory ref missing --> component unsatisfied
+            TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+            // dynamically configure without the correct target
+            configure( pid );
+            delay();
+
+            // mandatory ref missing --> component unsatisfied
+            TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+            // dynamically configure with correct target
+            theConfig.put( targetProp, "(filterprop=" + filterProp + ")" );
+            configure( pid );
+            delay();
+
+            TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+            TestCase.assertNotNull( SimpleComponent.INSTANCE );
+            TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+            TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) );
+
+            final SimpleComponent instance = SimpleComponent.INSTANCE;
+
+            configure( pid );
+            delay();
+
+            // same instance after reconfiguration
+            TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+            TestCase.assertEquals( instance, SimpleComponent.INSTANCE );
+            TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+            TestCase.assertEquals( pid, SimpleComponent.INSTANCE.getProperty( Constants.SERVICE_PID ) );
+
+            // reconfigure without target --> unsatisifed
+            theConfig.remove( targetProp );
+            configure( pid );
+            delay();
+
+            // mandatory ref missing --> component unsatisfied
+            TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+            deleteConfig( pid );
+            delay();
+
+            // mandatory ref missing --> component unsatisfied
+            TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+            component.disable();
+            delay();
+
+            TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+            TestCase.assertNull( SimpleComponent.INSTANCE );
+        }
+        finally
+        {
+            theConfig.remove( targetProp );
+            if ( service != null )
+            {
+                service.drop();
+            }
+        }
+    }
+
+
+    @Test
     public void test_SimpleComponent_factory_configuration()
     {
         final String factoryPid = "FactoryConfigurationComponent";
@@ -392,10 +478,10 @@
         final Component[] threeConfigs21 = findComponentsByName( factoryPid );
         TestCase.assertNotNull( threeConfigs21 );
         TestCase.assertEquals( 3, threeConfigs21.length );
+        TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
         TestCase.assertEquals( Component.STATE_ACTIVE, threeConfigs21[0].getState() );
         TestCase.assertEquals( Component.STATE_DISABLED, threeConfigs21[1].getState() );
         TestCase.assertEquals( Component.STATE_DISABLED, threeConfigs21[2].getState() );
-        TestCase.assertEquals( 1, SimpleComponent.INSTANCES.size() );
         TestCase.assertTrue( SimpleComponent.INSTANCES.containsKey( threeConfigs21[0].getId() ) );
         TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( threeConfigs21[1].getId() ) );
         TestCase.assertFalse( SimpleComponent.INSTANCES.containsKey( threeConfigs21[2].getId() ) );
diff --git a/scr/src/test/resources/integration_test_simple_components.xml b/scr/src/test/resources/integration_test_simple_components.xml
index d1410cb..e1b710d 100644
--- a/scr/src/test/resources/integration_test_simple_components.xml
+++ b/scr/src/test/resources/integration_test_simple_components.xml
@@ -50,6 +50,22 @@
         <property name="service.pid" value="DynamicConfigurationComponent" />
     </scr:component>
 
+    <!-- component dynamically updates configuration with a required reference plus target-->
+    <scr:component name="DynamicConfigurationComponentWithRequiredReference"
+        enabled="false" modified="configure">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <property name="service.pid" value="DynamicConfigurationComponentWithRequiredReference" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..1"
+            policy="dynamic"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            target="(filterprop=__nothing__)"
+        />
+    </scr:component>
+
     <!-- component instances created by factory configuration -->
     <scr:component name="FactoryConfigurationComponent"
         enabled="false"