FELIX-3651 TargetedPID tests

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1515661 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
index 0c0a240..598db65 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
@@ -71,8 +71,10 @@
      * @param props the property dictionary from the configuration.
      * @param changeCount change count of the configuration, or R4 imitation.
      * @param targetedPid TODO
+     * @return true if a new component is created for a factory PID, false if an existing factory pid configuration is updated or 
+     * we have no factory pid
      */
-    void configurationUpdated( String pid, Dictionary<String, Object> props, long changeCount, TargetedPID targetedPid );
+    boolean configurationUpdated( String pid, Dictionary<String, Object> props, long changeCount, TargetedPID targetedPid );
     
     /**
      * Change count (or fake R4 imitation)
@@ -82,9 +84,10 @@
     
     /**
      * Returns the targeted PID used to configure this component
+     * @param pid TODO
      * @return
      */
-    TargetedPID getConfigurationTargetedPID();
+    TargetedPID getConfigurationTargetedPID(TargetedPID pid);
 
     /**
      * Returns all <code>Component</code> instances held by this holder.
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
index a6af683..93725c7 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
@@ -102,7 +102,7 @@
 
     // ---------- BaseConfigurationSupport overwrites
 
-    public void configureComponentHolder(final ComponentHolder holder)
+    public boolean configureComponentHolder(final ComponentHolder holder)
     {
 
         // 112.7 configure unless configuration not required
@@ -111,11 +111,11 @@
             final BundleContext bundleContext = holder.getActivator().getBundleContext();
             if ( bundleContext == null )
             {
-                return;// bundle was stopped concurrently with configuration deletion
+                return false;// bundle was stopped concurrently with configuration deletion
             }
             final String confPid = holder.getComponentMetadata().getConfigurationPid();
 
-            final ServiceReference caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+            final ServiceReference<?> caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
             if (caRef != null)
             {
                 final Object cao = bundleContext.getService(caRef);
@@ -129,15 +129,17 @@
                             final Collection<Configuration> factory = findFactoryConfigurations(ca, confPid, bundleContext.getBundle());
                             if (!factory.isEmpty())
                             {
+                                boolean created = false;
                                 for (Configuration config: factory)
                                 {
                                     config = getConfiguration( ca, config.getPid() );
                                     if ( checkBundleLocation( config, bundleContext.getBundle() ))
                                     {
                                         long changeCount = changeCounter.getChangeCount( config, false, -1 );
-                                        holder.configurationUpdated(config.getPid(), config.getProperties(), changeCount, new TargetedPID(config.getFactoryPid()));
+                                        created |= holder.configurationUpdated(config.getPid(), config.getProperties(), changeCount, new TargetedPID(config.getFactoryPid()));
                                     }
                                 }
+                                return created;
                             }
                             else
                             {
@@ -148,8 +150,9 @@
                                     singleton = getConfiguration( ca, singleton.getPid() );
                                     if ( singleton != null && checkBundleLocation( singleton, bundleContext.getBundle() ))
                                     {
-                                    long changeCount = changeCounter.getChangeCount( singleton, false, -1 );
-                                    holder.configurationUpdated(confPid, singleton.getProperties(), changeCount, new TargetedPID(singleton.getPid()));
+                                        long changeCount = changeCounter.getChangeCount( singleton, false, -1 );
+                                        holder.configurationUpdated(confPid, singleton.getProperties(), changeCount, new TargetedPID(singleton.getPid()));
+                                        return true;
                                     }
                                 }
                             }
@@ -162,6 +165,7 @@
                                 "Component Bundle's Configuration Admin is not compatible with "
                                     + "ours. This happens if multiple Configuration Admin API versions "
                                     + "are deployed and different bundles wire to different versions", null );
+                            return false;
 
                         }
                     }
@@ -179,6 +183,7 @@
                 }
             }
         }
+        return false;
     }
 
     // ---------- ServiceListener
@@ -246,9 +251,10 @@
             {
                 switch (event.getType()) {
                 case ConfigurationEvent.CM_DELETED:
-                    componentHolder.configurationDeleted(pid.getServicePid());
-                    //fall back to less-strong pid match
-                    configureComponentHolder( componentHolder );
+                    if ( !configureComponentHolder( componentHolder ) )
+                    {
+                        componentHolder.configurationDeleted( pid.getServicePid() );
+                    }
                     break;
 
                 case ConfigurationEvent.CM_UPDATED:
@@ -266,7 +272,7 @@
                     }
 
                     TargetedPID targetedPid = factoryPid == null? pid: factoryPid;
-                    TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID();
+                    TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID(pid);
                     if ( targetedPid.equals(oldTargetedPID) || targetedPid.bindsStronger( oldTargetedPID ))
                     {
                         final ConfigurationInfo configInfo = getConfiguration( pid, componentHolder, bundleContext );
@@ -316,7 +322,7 @@
                     }
 
                     TargetedPID targetedPid = factoryPid == null? pid: factoryPid;
-                    TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID();
+                    TargetedPID oldTargetedPID = componentHolder.getConfigurationTargetedPID(pid);
                     if ( targetedPid.equals(oldTargetedPID))
                     {
                         //this sets the location to this component's bundle if not already set.  OK here
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
index 3d2edc0..89dc367 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
@@ -106,10 +106,7 @@
      * enabled. Otherwise they are not enabled immediately.
      */
     private volatile boolean m_enabled;
-    private final ComponentMethods m_componentMethods;
-    
-    private TargetedPID m_targetedPID;
-    
+    private final ComponentMethods m_componentMethods;    
 
     public ImmediateComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
     {
@@ -192,7 +189,6 @@
         log( LogService.LOG_DEBUG, "ImmediateComponentHolder configuration deleted for pid {0}",
                 new Object[] {pid}, null);
 
-        m_targetedPID = null;
         // component to deconfigure or dispose of
         final ImmediateComponentManager icm;
         boolean deconfigure = false;
@@ -251,7 +247,7 @@
         // is not the "last" and has to be disposed off
         if ( deconfigure )
         {
-	        icm.reconfigure( null, -1 );
+	        icm.reconfigure( null, -1, null );
         }
         else
         {
@@ -273,30 +269,24 @@
      * this case a new component is created, configured and stored in the map</li>
      * </ul>
      */
-    public void configurationUpdated( final String pid, final Dictionary<String, Object> props, long changeCount, TargetedPID targetedPid )
+    public boolean configurationUpdated( final String pid, final Dictionary<String, Object> props, long changeCount, TargetedPID targetedPid )
     {
         log( LogService.LOG_DEBUG, "ImmediateComponentHolder configuration updated for pid {0} with properties {1}",
                 new Object[] {pid, props}, null);
 
-        if ( m_targetedPID != null && !m_targetedPID.equals( targetedPid ))
-        {
-            log( LogService.LOG_ERROR, "ImmediateComponentHolder unexpected change in targetedPID from {0} to {1}",
-                    new Object[] {m_targetedPID, targetedPid}, null);
-            throw new IllegalStateException("Unexpected targetedPID change");
-        }
-        m_targetedPID = targetedPid;
         // component to update or create
         final ImmediateComponentManager icm;
         final String message;
         final boolean enable;
         Object[] notEnabledArguments = null;
+        boolean created = false;
 
         synchronized ( m_components )
         {
             // FELIX-2231: nothing to do any more, all components have been disposed off
             if (m_singleComponent == null) 
             {
-                return;
+                return false;
             }
 
             if ( pid.equals( getComponentMetadata().getConfigurationPid() ) )
@@ -319,6 +309,7 @@
                 else
                 {
                     // factory configuration created
+                    created = true;
                     if ( !m_singleComponent.hasConfiguration() )
                     {
                         // configure the single instance if this is not configured
@@ -351,7 +342,7 @@
         log( LogService.LOG_DEBUG, message, new Object[] {pid}, null);
 
         // configure the component
-        icm.reconfigure( props, changeCount );
+        icm.reconfigure( props, changeCount, targetedPid );
         log( LogService.LOG_DEBUG, "ImmediateComponentHolder Finished configuring the dependency managers for component for pid {0} ",
                 new Object[] {pid}, null );
 
@@ -366,6 +357,7 @@
             log( LogService.LOG_DEBUG, "ImmediateComponentHolder Will not enable component for pid {0}: holder enabled state: {1}, metadata enabled: {2} ",
                     notEnabledArguments, null );
         }
+        return created;
     }
 
     public synchronized long getChangeCount( String pid)
@@ -566,9 +558,25 @@
         }
     }
 
-    public TargetedPID getConfigurationTargetedPID()
+    public TargetedPID getConfigurationTargetedPID(TargetedPID pid)
     {
-        return m_targetedPID;
+        ImmediateComponentManager icm = null;
+        synchronized (m_components)
+        {
+            if ( pid.getServicePid().equals( m_componentMetadata.getConfigurationPid() )) {
+                //singleton
+                icm = m_singleComponent;
+            }
+            else 
+            {
+                icm = m_components.get( pid.getServicePid() );
+            }
+        }
+        if ( icm != null) 
+        {
+            return icm.getConfigurationTargetedPID();
+        }
+        return null;
     }
 
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
index 0996aa3..75e27b9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
@@ -91,7 +91,7 @@
      */
     protected volatile long m_changeCount = -1;
     
-    private TargetedPID m_targetedPID;
+    protected TargetedPID m_targetedPID;
 
     public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
     {
@@ -119,7 +119,7 @@
         ComponentInstance instance;
         cm.setFactoryProperties( ( Dictionary<String, Object> ) dictionary );
         //configure the properties
-        cm.reconfigure( m_configuration, m_changeCount );
+        cm.reconfigure( m_configuration, m_changeCount, m_targetedPID );
         // enable
         cm.enableInternal();
         //activate immediately
@@ -330,7 +330,7 @@
     }
 
 
-    public void configurationUpdated( String pid, Dictionary<String, Object> configuration, long changeCount, TargetedPID targetedPid )
+    public boolean configurationUpdated( String pid, Dictionary<String, Object> configuration, long changeCount, TargetedPID targetedPid )
     {
         if ( m_targetedPID != null && !m_targetedPID.equals( targetedPid ))
         {
@@ -346,7 +346,7 @@
                 log( LogService.LOG_DEBUG,
                         "ImmediateComponentHolder out of order configuration updated for pid {0} with existing count {1}, new count {2}",
                         new Object[] { getConfigurationPid(), m_changeCount, changeCount }, null );
-                return;
+                return false;
             }
             m_changeCount = changeCount;
         }
@@ -361,7 +361,7 @@
             // Ignore the configuration is our policy is 'ignore'
             if ( getComponentMetadata().isConfigurationIgnored() )
             {
-                return;
+                return false;
             }
 
             // Store the config admin configuration
@@ -388,7 +388,7 @@
                     log( LogService.LOG_DEBUG,
                             "Component Factory target filters not satisfied anymore: deactivating", null );
                     deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, getTrackingCount().get() );
-                    return;
+                    return false;
                 }
             }
 
@@ -406,6 +406,7 @@
             // 112.7 Factory Configuration not allowed for factory component
             log( LogService.LOG_ERROR, "Component Factory cannot be configured by factory configuration", null );
         }
+        return false;
     }
 
 
@@ -520,7 +521,7 @@
 
     }
 
-    public TargetedPID getConfigurationTargetedPID()
+    public TargetedPID getConfigurationTargetedPID(TargetedPID pid)
     {
         return m_targetedPID;
     }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
index 28dc231..54f05b2 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
@@ -130,11 +130,11 @@
     }
 
 
-    public void configurationUpdated( String pid, Dictionary<String, Object> configuration, long changeCount, TargetedPID targetedPid )
+    public boolean configurationUpdated( String pid, Dictionary<String, Object> configuration, long changeCount, TargetedPID targetedPid )
     {
         if ( pid.equals( getComponentMetadata().getConfigurationPid() ) )
         {
-            super.configurationUpdated( pid, configuration, changeCount, targetedPid );
+            return super.configurationUpdated( pid, configuration, changeCount, targetedPid );
         }
         else   //non-spec backwards compatible
         {
@@ -151,7 +151,7 @@
 
                 // this should not call component reactivation because it is
                 // not active yet
-                cm.reconfigure( configuration, changeCount );
+                cm.reconfigure( configuration, changeCount, m_targetedPID );
 
                 // enable asynchronously if components are already enabled
                 if ( getState() == STATE_FACTORY )
@@ -164,12 +164,14 @@
                     // keep a reference for future updates
                     m_configuredServices.put( pid, cm );
                 }
+                return true;
 
             }
             else
             {
                 // update the configuration as if called as ManagedService
-                cm.reconfigure( configuration, changeCount );
+                cm.reconfigure( configuration, changeCount, m_targetedPID );
+                return false;
             }
         }
     }
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 ff31830..0eea200 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
@@ -24,6 +24,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.TargetedPID;
 import org.apache.felix.scr.impl.config.ComponentHolder;
 import org.apache.felix.scr.impl.helper.ActivateMethod.ActivatorParameter;
 import org.apache.felix.scr.impl.helper.ComponentMethods;
@@ -71,6 +72,8 @@
     private Dictionary<String, Object> m_configurationProperties;
     
     private volatile long m_changeCount = -1;
+    private TargetedPID m_targetedPID;
+
 
     private final ThreadLocal<Boolean> m_circularReferences = new ThreadLocal<Boolean>();
     
@@ -521,9 +524,15 @@
      *                      the Configuration Admin Service or <code>null</code> if there is
      *                      no configuration or if the configuration has just been deleted.
      * @param changeCount TODO
+     * @param targetedPID TODO
      */
-    public void reconfigure( Dictionary<String, Object> configuration, long changeCount )
+    public void reconfigure( Dictionary<String, Object> configuration, long changeCount, TargetedPID targetedPID )
     {
+        if ( targetedPID == null || !targetedPID.equals( m_targetedPID ) )
+        {
+            m_targetedPID = targetedPID;
+            m_changeCount = -1;
+        }
         if ( configuration != null )
         {
             if ( changeCount <= m_changeCount )
@@ -874,4 +883,9 @@
     {
         return m_changeCount;
     }
+
+    public TargetedPID getConfigurationTargetedPID()
+    {
+        return m_targetedPID;
+    }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
index 8992782..5d3cc72 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
@@ -251,7 +251,7 @@
         }
 
 
-        public void reconfigure( Dictionary configuration, long changeCount )
+        public void reconfigure( Dictionary configuration, long changeCount, TargetedPID targetedPID )
         {
             this.m_configuration = configuration;
         }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index abbc7c5..8e86855 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -19,6 +19,7 @@
 package org.apache.felix.scr.integration;
 
 
+import static org.ops4j.pax.exam.CoreOptions.frameworkProperty;
 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.options;
@@ -109,6 +110,8 @@
 
     protected static String DS_LOGLEVEL = "debug";
 
+    protected static String bsnVersionUniqueness = "single";
+
     // the descriptor file to use for the installed test bundle
     protected static String descriptorFile = "/integration_test_simple_components.xml";
     protected static String COMPONENT_PACKAGE = "org.apache.felix.scr.integration.components";
@@ -160,6 +163,7 @@
                 mavenBundle( "org.apache.felix", "org.apache.felix.configadmin", felixCaVersion )
              ),
              junitBundles(),
+             frameworkProperty( "org.osgi.framework.bsnversion" ).value( bsnVersionUniqueness ),
              systemProperty( "ds.factory.enabled" ).value( Boolean.toString( NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR ) ),
              systemProperty( "ds.loglevel" ).value( DS_LOGLEVEL )
 
@@ -414,10 +418,10 @@
 
     protected Bundle installBundle( final String descriptorFile, String componentPackage ) throws BundleException
     {
-        return installBundle(descriptorFile, componentPackage, "simplecomponent", "0.0.11");
+        return installBundle(descriptorFile, componentPackage, "simplecomponent", "0.0.11", null);
     }
     
-    protected Bundle installBundle( final String descriptorFile, String componentPackage, String symbolicName, String version ) throws BundleException
+    protected Bundle installBundle( final String descriptorFile, String componentPackage, String symbolicName, String version, String location ) throws BundleException
     {
         final InputStream bundleStream = bundle()
                 .add("OSGI-INF/components.xml", getClass().getResource(descriptorFile))
@@ -430,7 +434,10 @@
 
         try
         {
-            final String location = "test:SimpleComponent/" + System.currentTimeMillis();
+            if ( location == null )
+            {
+                location = "test:SimpleComponent/" + System.currentTimeMillis();
+            }
             return bundleContext.installBundle( location, bundleStream );
         }
         finally
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java b/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java
index 63e24f1..4e10d1e 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/LocationTest.java
@@ -77,7 +77,7 @@
         TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
         
         
-        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11", null );
         b2.start();
         Component[] components = findComponentsByName( pid );
         TestCase.assertEquals( 2, components.length );
@@ -146,7 +146,7 @@
         TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
         
         
-        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11", null );
         b2.start();
         Component[] components = findComponentsByName( pid );
         TestCase.assertEquals( 2, components.length );
@@ -224,7 +224,7 @@
         TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
         
         
-        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11" );
+        Bundle b2 = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11", null );
         b2.start();
         Component[] components = findComponentsByName( pid );
         TestCase.assertEquals( 2, components.length );
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/TargetedPIDTest.java b/scr/src/test/java/org/apache/felix/scr/integration/TargetedPIDTest.java
new file mode 100644
index 0000000..25589fb
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/TargetedPIDTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.integration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.cm.ConfigurationPermission;
+
+@RunWith(JUnit4TestRunner.class)
+public class TargetedPIDTest extends ComponentTestBase
+{
+    
+    private static final String TARGETED_PID = "targetedPID";
+    private static final String COMPONENT_NAME = "SimpleComponent.configuration.require";
+    private static final String REGION = "?foo";
+    private boolean eventReceived;
+
+    static
+    {
+        bsnVersionUniqueness = "multiple";
+        descriptorFile = "/integration_test_simple_components_location.xml";
+        // uncomment to enable debugging of this test class
+//         paxRunnerVmOption = DEBUG_VM_OPTION;
+    }
+
+
+    @Test
+    public void testTargetedPID() throws Exception
+    {
+        try
+        {
+            new ConfigurationPermission(REGION, ConfigurationPermission.TARGET);
+        }
+        catch (IllegalArgumentException e)
+        {
+            return;//not an R5 CA
+        }
+        String pid = COMPONENT_NAME;
+        theConfig.put(TARGETED_PID, pid);
+        Configuration config = configure( pid );
+        config.setBundleLocation( REGION );
+        
+        String pidSN = pid + "|simplecomponent2";
+        theConfig.put(TARGETED_PID, pidSN);
+        Configuration configSN = configure( pidSN );
+        configSN.setBundleLocation( REGION );
+        
+        String pidSNV = pidSN + "|0.0.12";
+        theConfig.put(TARGETED_PID, pidSNV);
+        Configuration configSNV = configure( pidSNV );
+        configSNV.setBundleLocation( REGION );
+        
+        String pidSNVL = pidSNV + "|bundleLocation";
+        theConfig.put(TARGETED_PID, pidSNVL);
+        Configuration configSNVL = configure( pidSNVL );
+        configSNVL.setBundleLocation( REGION );
+        
+        //Add more and more specific components to check that they pick up the appropriate configuration
+        Set<Component> known = new HashSet<Component>();
+        
+        final Component component = findComponentByName( COMPONENT_NAME );
+        known.add( component );
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        TestCase.assertNotNull( SimpleComponent.INSTANCE );
+        SimpleComponent sc = SimpleComponent.INSTANCE;
+        TestCase.assertEquals( pid, sc.getProperty( TARGETED_PID ) );
+        
+        
+        Bundle bSN = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.11", null );
+        bSN.start();
+        Component[] components = findComponentsByName( pid );
+        TestCase.assertEquals( 2, components.length );
+        Component cSN = getNewComponent( known, components ); 
+
+        
+        cSN.enable();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSN.getState() );
+        SimpleComponent scSN = SimpleComponent.INSTANCE;
+        TestCase.assertEquals( pidSN, scSN.getProperty( TARGETED_PID ) );
+        
+        Bundle bSNV = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.12", null );
+        bSNV.start();
+        components = findComponentsByName( pid );
+        TestCase.assertEquals( 3, components.length );
+        Component cSNV = getNewComponent( known, components ); 
+        
+        cSNV.enable();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNV.getState() );
+        SimpleComponent scSNV = SimpleComponent.INSTANCE;
+        TestCase.assertEquals( pidSNV, scSNV.getProperty( TARGETED_PID ) );
+        
+        Bundle bSNVL = installBundle( descriptorFile, COMPONENT_PACKAGE, "simplecomponent2", "0.0.12", "bundleLocation" );
+        bSNVL.start();
+        components = findComponentsByName( pid );
+        TestCase.assertEquals( 4, components.length );
+        Component cSNVL = getNewComponent( known, components ); 
+        
+        cSNVL.enable();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNVL.getState() );
+        SimpleComponent scSNVL = SimpleComponent.INSTANCE;
+        TestCase.assertEquals( pidSNVL, scSNVL.getProperty( TARGETED_PID ) );
+        
+        //remove configurations to check that the components now use the less specific configurations.
+        
+        configSNVL.delete();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNVL.getState() );
+        TestCase.assertEquals( pidSNV, scSNVL.getProperty( TARGETED_PID ) );
+        
+        configSNV.delete();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNVL.getState() );
+        TestCase.assertEquals( pidSN, scSNVL.getProperty( TARGETED_PID ) );
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNV.getState() );
+        TestCase.assertEquals( pidSN, scSNV.getProperty( TARGETED_PID ) );
+        
+        configSN.delete();
+        delay();
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNVL.getState() );
+        TestCase.assertEquals( pid, scSNVL.getProperty( TARGETED_PID ) );
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSNV.getState() );
+        TestCase.assertEquals( pid, scSNV.getProperty( TARGETED_PID ) );
+        TestCase.assertEquals( Component.STATE_ACTIVE, cSN.getState() );
+        TestCase.assertEquals( pid, scSN.getProperty( TARGETED_PID ) );
+        
+        
+    }
+
+
+    private Component getNewComponent(Set<Component> known, Component[] components)
+    {
+        List<Component> cs = new ArrayList(Arrays.asList( components )); 
+        cs.removeAll( known );
+        Component c = cs.get( 0 );
+        known.add(c);
+        return c;
+    }
+
+
+}
diff --git a/scr/src/test/resources/integration_test_simple_components_location.xml b/scr/src/test/resources/integration_test_simple_components_location.xml
index 746497d..072c8a6 100644
--- a/scr/src/test/resources/integration_test_simple_components_location.xml
+++ b/scr/src/test/resources/integration_test_simple_components_location.xml
@@ -22,7 +22,8 @@
     <!-- component requires configuration -->
     <scr:component name="SimpleComponent.configuration.require"
         enabled="false"
-        configuration-policy="require" >
+        configuration-policy="require"
+        modified="modified" >
         <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
         <property name="service.pid" value="SimpleComponent.configuration.require" />
     </scr:component>