You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2012/05/17 15:39:35 UTC

svn commit: r1339600 - in /felix/trunk/scr: ./ src/main/java/org/apache/felix/scr/ src/main/java/org/apache/felix/scr/impl/ src/main/java/org/apache/felix/scr/impl/manager/ src/main/java/org/apache/felix/scr/impl/metadata/ src/test/java/org/apache/feli...

Author: fmeschbe
Date: Thu May 17 13:39:34 2012
New Revision: 1339600

URL: http://svn.apache.org/viewvc?rev=1339600&view=rev
Log:
SLING-3507 Apply patch by David Jencks (thank you very much) and update the API export to 1.7 due to the new Reference.isReluctant() method

Added:
    felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
    felix/trunk/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml
Modified:
    felix/trunk/scr/pom.xml
    felix/trunk/scr/src/main/java/org/apache/felix/scr/Reference.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java

Modified: felix/trunk/scr/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/scr/pom.xml?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/pom.xml (original)
+++ felix/trunk/scr/pom.xml Thu May 17 13:39:34 2012
@@ -224,7 +224,7 @@
                             org.apache.felix.scr.impl.Activator
                         </Bundle-Activator>
                         <Export-Package>
-                            org.apache.felix.scr;version=1.6,
+                            org.apache.felix.scr;version=1.7,
                             org.apache.felix.scr.component;version=1.0;
                                 mandatory:="status"; status="provisional",
                             org.osgi.service.component

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/Reference.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/Reference.java?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/Reference.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/Reference.java Thu May 17 13:39:34 2012
@@ -85,6 +85,15 @@ public interface Reference
      */
     boolean isStatic();
 
+    /**
+     * Returns <code>true</code> if the reference is defined with reluctant
+     * policy option.  This method provides access to the <code>policy-option</code>
+     * element of the <code>reference</code> element.  <code>true</code> is
+     * returned if the policy option is defined as <em>reluctant</em>
+     *
+     * @since 1.7
+     */
+    boolean isReluctant();
 
     /**
      * Returns the value of the target property of this reference. Initially

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java Thu May 17 13:39:34 2012
@@ -272,6 +272,8 @@ class ScrCommand
                     out.println(refs[i].isOptional() ? "optional" : "mandatory");
                     out.print("    Policy: ");
                     out.println(refs[i].isStatic() ? "static" : "dynamic");
+                    out.print("    Policy option: ");
+                    out.println(refs[i].isReluctant() ? "reluctant" : "greedy");
                 }
             }
 

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java Thu May 17 13:39:34 2012
@@ -266,6 +266,8 @@ public class DependencyManager implement
      * Depending on the component state and dependency configuration, the
      * component may be activated, re-activated or the service just be provided.
      *
+     * See Compendium 4.3 table 112.1
+     *
      * @param reference The reference to the service newly registered or
      *      modified.
      */
@@ -293,9 +295,19 @@ public class DependencyManager implement
             // the component is reactivated for other reasons.
             if ( m_dependencyMetadata.isStatic() )
             {
-                m_componentManager.log( LogService.LOG_DEBUG,
-                    "Dependency Manager: Added service {0} is ignored for static reference", new Object[]
-                        { m_dependencyMetadata.getName() }, null );
+                if ( m_dependencyMetadata.isReluctant() )
+                {
+                    m_componentManager.log( LogService.LOG_DEBUG,
+                            "Dependency Manager: Added service {0} is ignored for static reluctant reference", new Object[]
+                            {m_dependencyMetadata.getName()}, null );
+                }
+                else if ( m_dependencyMetadata.isMultiple() ||
+                        m_bound.isEmpty() ||
+                        reference.compareTo( m_bound.keySet().iterator().next() ) > 0 )
+                {
+                    m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
+                    m_componentManager.activateInternal();
+                }
             }
 
             // otherwise bind if we have a bind method and the service needs
@@ -308,6 +320,16 @@ public class DependencyManager implement
                     // bind the service, getting it if required
                     invokeBindMethod( reference );
                 }
+                else if ( !isReluctant() )
+                {
+                    //dynamic greedy single: bind then unbind
+                    ServiceReference oldRef = ( ServiceReference ) m_bound.keySet().iterator().next();
+                    if ( reference.compareTo( oldRef ) > 0 )
+                    {
+                        invokeBindMethod( reference );
+                        invokeUnbindMethod( oldRef );
+                    }
+                }
             }
         }
 
@@ -456,6 +478,10 @@ public class DependencyManager implement
         return m_dependencyMetadata.isStatic();
     }
 
+    public boolean isReluctant()
+    {
+        return m_dependencyMetadata.isReluctant();
+    }
 
     public String getBindMethodName()
     {

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java Thu May 17 13:39:34 2012
@@ -54,6 +54,15 @@ public class ReferenceMetadata
     // set of valid policy settings
     private static final Set POLICY_VALID;
 
+    // constant for reluctant policy option
+    public static final String POLICY_OPTION_RELUCTANT = "reluctant";
+
+    // constant for greedy policy option
+    public static final String POLICY_OPTION_GREEDY = "greedy";
+
+    // set of valid policy option settings
+    private static final Set POLICY_OPTION_VALID;
+
     // Name for the reference (required)
     private String m_name = null;
 
@@ -78,6 +87,9 @@ public class ReferenceMetadata
     // Policy attribute (optional, default = static)
     private String m_policy = null;
 
+    // Policy option attribute (optional, default = reluctant)
+    private String m_policy_option = null;
+
     // Flag that is set once the component is verified (its properties cannot be changed)
     private boolean m_validated = false;
 
@@ -85,6 +97,7 @@ public class ReferenceMetadata
     private boolean m_isStatic = true;
     private boolean m_isOptional = false;
     private boolean m_isMultiple = false;
+    private boolean m_isReluctant = true;
 
     static
     {
@@ -97,6 +110,10 @@ public class ReferenceMetadata
         POLICY_VALID = new TreeSet();
         POLICY_VALID.add( POLICY_DYNAMIC );
         POLICY_VALID.add( POLICY_STATIC );
+
+        POLICY_OPTION_VALID = new TreeSet();
+        POLICY_OPTION_VALID.add( POLICY_OPTION_RELUCTANT );
+        POLICY_OPTION_VALID.add( POLICY_OPTION_GREEDY );
     }
 
 
@@ -175,6 +192,25 @@ public class ReferenceMetadata
 
 
     /**
+     *	Setter for the policy option attribute
+     *
+     * @param policyOption
+     */
+    public void setPolicyOption( String policyOption )
+    {
+        if ( m_validated )
+        {
+            return;
+        }
+
+        m_policy_option = policyOption;
+
+        // secondary property
+        m_isReluctant = POLICY_OPTION_RELUCTANT.equals( policyOption );
+    }
+
+
+    /**
      * Setter for the target attribute (filter)
      *
      * @param target
@@ -285,6 +321,17 @@ public class ReferenceMetadata
 
 
     /**
+     * Get the policy option as a string
+     *
+     * @return A string with the policy option
+    **/
+    public String getPolicyOption()
+    {
+        return m_policy_option;
+    }
+
+
+    /**
      * Returns the filter expression that further constrains the set of target services
      *
      * @return A string with a filter
@@ -367,6 +414,17 @@ public class ReferenceMetadata
 
 
     /**
+     * Test if policy option is reluctant
+     *
+     * @return true if policy option is reluctant
+     */
+    public boolean isReluctant()
+    {
+        return m_isReluctant;
+    }
+
+
+    /**
      * Returns the name of the component property referring to the {@link #getTarget() target}
      * property of this reference.
      *
@@ -419,6 +477,20 @@ public class ReferenceMetadata
             throw componentMetadata.validationFailure( "Policy must be one of " + POLICY_VALID );
         }
 
+        if ( m_policy_option == null )
+        {
+            setPolicyOption( POLICY_OPTION_RELUCTANT );
+        }
+        else if ( !POLICY_OPTION_VALID.contains( m_policy_option ) )
+        {
+            throw componentMetadata.validationFailure( "Policy option must be one of " + POLICY_OPTION_VALID );
+        }
+        else if ( !componentMetadata.isDS12() && !POLICY_OPTION_RELUCTANT.equals( m_policy_option ) )
+        {
+            throw componentMetadata.validationFailure( "Policy option must be reluctant for DS < 1.2" );
+        }
+
+
         // updated method is only supported in namespace xxx and later
         if ( m_updated != null && !componentMetadata.isDS11Felix() )
         {

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java?rev=1339600&r1=1339599&r2=1339600&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java Thu May 17 13:39:34 2012
@@ -75,7 +75,7 @@ public class XmlHandler implements KXml2
     // namespace code for the DS 1.2 specification
     public static final int DS_VERSION_1_2 = 3;
 
-    // namespace code for the DS 1.1-felix specification
+    // namespace code for the DS 1.2-felix specification
     public static final int DS_VERSION_1_2_FELIX = 4;
 
     // mapping of namespace URI to namespace code
@@ -331,6 +331,11 @@ public class XmlHandler implements KXml2
                         ref.setPolicy( attrib.getProperty( "policy" ) );
                     }
 
+                    if ( attrib.getProperty( "policy-option" ) != null )
+                    {
+                        ref.setPolicyOption( attrib.getProperty( "policy-option" ) );
+                    }
+
                     //if
                     ref.setTarget( attrib.getProperty( "target" ) );
                     ref.setBind( attrib.getProperty( "bind" ) );

Added: felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java?rev=1339600&view=auto
==============================================================================
--- felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java (added)
+++ felix/trunk/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java Thu May 17 13:39:34 2012
@@ -0,0 +1,1265 @@
+/*
+ * 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.Hashtable;
+
+import junit.framework.TestCase;
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.apache.felix.scr.integration.components.SimpleComponent2;
+import org.apache.felix.scr.integration.components.SimpleService2Impl;
+import org.apache.felix.scr.integration.components.SimpleServiceImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+
+@RunWith(JUnit4TestRunner.class)
+public class ServiceBindGreedyTest extends ComponentTestBase
+{
+
+    private static final String PROP_NAME_FACTORY = ComponentTestBase.PROP_NAME + ".factory";
+
+    static
+    {
+        // uncomment to enable debugging of this test class
+        // paxRunnerVmOption = DEBUG_VM_OPTION;
+
+        descriptorFile = "/integration_test_simple_components_service_binding_greedy.xml";
+    }
+
+
+    @Test
+    public void test_optional_single_dynamic()
+    {
+        final Component component = findComponentByName( "test_optional_single_dynamic" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1", 1 );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertEquals( srv1, comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.isEmpty() );
+
+        srv1.drop();
+        // no delay, should be immediate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp10, comp11 );
+        TestCase.assertNull( comp11.m_singleRef );
+        TestCase.assertTrue( comp11.m_multiRef.isEmpty() );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2", 2 );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp10, comp12 );
+        TestCase.assertEquals( srv2, comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.isEmpty() );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3", 2 );
+
+        // enable component with two services available of same ranking, expect srv2 bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertEquals( srv2, comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.isEmpty() );
+
+        // drop srv2, expect rebind to srv3 (synchronously)
+        srv2.drop();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp21 );
+        TestCase.assertEquals( srv3, comp21.m_singleRef );
+        TestCase.assertTrue( comp21.m_multiRef.isEmpty() );
+
+        // create srv4, expect greedy rebind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4", 4 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp22 );
+        TestCase.assertEquals( srv4, comp22.m_singleRef );
+        TestCase.assertTrue( comp22.m_multiRef.isEmpty() );
+
+        // drop srv4 again, expect rebind to srv3
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp23 );
+        TestCase.assertEquals( srv3, comp23.m_singleRef );
+        TestCase.assertTrue( comp23.m_multiRef.isEmpty() );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp30 );
+        TestCase.assertEquals( srv6, comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.isEmpty() );
+
+        // another service with higher ranking -- greedy rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp31 );
+        TestCase.assertEquals( srv7, comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.isEmpty() );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp32 );
+        TestCase.assertEquals( srv7, comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.isEmpty() );
+    }
+
+
+    @Test
+    public void test_required_single_dynamic()
+    {
+        final Component component = findComponentByName( "test_required_single_dynamic" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1", 1 );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertEquals( srv1, comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.isEmpty() );
+
+        srv1.drop();
+        // no delay, should be immediate
+
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNull( comp11 );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2", 2 );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertEquals( srv2, comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.isEmpty() );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3", 2 );
+
+        // enable component with two services available of same ranking, expect srv2 bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertEquals( srv2, comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.isEmpty() );
+
+        // drop srv2, expect rebind to srv3 (synchronously)
+        srv2.drop();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp21 );
+        TestCase.assertEquals( srv3, comp21.m_singleRef );
+        TestCase.assertTrue( comp21.m_multiRef.isEmpty() );
+
+        // create srv4, expect no rebind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4", 2 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp22 );
+        TestCase.assertEquals( srv3, comp22.m_singleRef );
+        TestCase.assertTrue( comp22.m_multiRef.isEmpty() );
+
+        // drop srv4 again, expect no rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp23 );
+        TestCase.assertEquals( srv3, comp23.m_singleRef );
+        TestCase.assertTrue( comp23.m_multiRef.isEmpty() );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp30 );
+        TestCase.assertEquals( srv6, comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.isEmpty() );
+
+        // another service with higher ranking --  greedy rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp31 );
+        TestCase.assertEquals( srv7, comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.isEmpty() );
+
+        // srv6 goes, no rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp32 );
+        TestCase.assertEquals( srv7, comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.isEmpty() );
+    }
+
+
+    @Test
+    public void test_optional_multiple_dynamic()
+    {
+        final Component component = findComponentByName( "test_optional_multiple_dynamic" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertNull( comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.contains( srv1 ) );
+
+        srv1.drop();
+        // no delay, should be immediate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp10, comp11 );
+        TestCase.assertNull( comp11.m_singleRef );
+        TestCase.assertTrue( comp11.m_multiRef.isEmpty() );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp10, comp12 );
+        TestCase.assertNull( comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.contains( srv2 ) );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect both bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertNull( comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv3 ) );
+
+        srv2.drop();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp21 );
+        TestCase.assertNull( comp21.m_singleRef );
+        TestCase.assertFalse( comp21.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp21.m_multiRef.contains( srv3 ) );
+
+        // create srv4, expect bind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp22 );
+        TestCase.assertNull( comp22.m_singleRef );
+        TestCase.assertFalse( comp22.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv3 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv4 ) );
+
+        // drop srv4 again, expect no rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp23 );
+        TestCase.assertNull( comp23.m_singleRef );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp23.m_multiRef.contains( srv3 ) );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv4 ) );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp30 );
+        TestCase.assertNull( comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv6 ) );
+
+        // another service with higher ranking -- no rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp31 );
+        TestCase.assertNull( comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv7 ) );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp32 );
+        TestCase.assertNull( comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv5 ) );
+        TestCase.assertFalse( comp32.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv7 ) );
+    }
+
+
+    @Test
+    public void test_required_multiple_dynamic()
+    {
+        final Component component = findComponentByName( "test_required_multiple_dynamic" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertNull( comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.contains( srv1 ) );
+
+        srv1.drop();
+        // no delay, should be immediate
+
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNull( comp11 );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertNull( comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.contains( srv2 ) );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect both bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertNull( comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv3 ) );
+
+        srv2.drop();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp21 );
+        TestCase.assertNull( comp21.m_singleRef );
+        TestCase.assertFalse( comp21.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp21.m_multiRef.contains( srv3 ) );
+
+        // create srv4, expect bind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp22 );
+        TestCase.assertNull( comp22.m_singleRef );
+        TestCase.assertFalse( comp22.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv3 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv4 ) );
+
+        // drop srv4 again, expect no rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp20, comp23 );
+        TestCase.assertNull( comp23.m_singleRef );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp23.m_multiRef.contains( srv3 ) );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv4 ) );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp30 );
+        TestCase.assertNull( comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv6 ) );
+
+        // another service with higher ranking -- no rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp31 );
+        TestCase.assertNull( comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv7 ) );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertSame( comp30, comp32 );
+        TestCase.assertNull( comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv5 ) );
+        TestCase.assertFalse( comp32.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv7 ) );
+    }
+
+
+    @Test
+    public void test_required_multiple_dynamic_factory() throws InvalidSyntaxException
+    {
+        final String pid = "test_required_multiple_dynamic_factory";
+        final String factoryPid = "factory_" + pid;
+
+        final Component component = findComponentByName( pid );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        // async enabling (unsatisfied)
+        component.enable();
+        delay();
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+
+        // register service, satisfying
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+        delay();
+        TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+
+        // create a component instance
+        final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+            + ComponentConstants.COMPONENT_FACTORY + "=" + factoryPid + ")" );
+        TestCase.assertNotNull( refs );
+        TestCase.assertEquals( 1, refs.length );
+        final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+        TestCase.assertNotNull( factory );
+
+        Hashtable<String, String> props = new Hashtable<String, String>();
+        props.put( PROP_NAME_FACTORY, PROP_NAME_FACTORY );
+        final ComponentInstance instance = factory.newInstance( props );
+        TestCase.assertNotNull( instance );
+        TestCase.assertNotNull( instance.getInstance() );
+        TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+
+        // ensure instance is bound
+        final SimpleComponent sc = SimpleComponent.INSTANCE;
+        TestCase.assertEquals( 1, sc.m_multiRef.size() );
+        TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+
+        // ensure factory is not bound
+        TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+        // assert two components managed
+        final Component[] allFactoryComponents = findComponentsByName( pid );
+        TestCase.assertNotNull( allFactoryComponents );
+        TestCase.assertEquals( 2, allFactoryComponents.length );
+        for ( int i = 0; i < allFactoryComponents.length; i++ )
+        {
+            final Component c = allFactoryComponents[i];
+            if ( c.getId() == component.getId() )
+            {
+                TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+            }
+            else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+            {
+                TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+            }
+            else
+            {
+                TestCase.fail( "Unexpected Component " + c );
+            }
+        }
+
+        // register second service
+        final SimpleServiceImpl srv11 = SimpleServiceImpl.create( bundleContext, "srv11" );
+        delay();
+
+        // ensure instance is bound
+        TestCase.assertEquals( 2, sc.m_multiRef.size() );
+        TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+        TestCase.assertTrue( sc.m_multiRef.contains( srv11 ) );
+
+        // ensure factory is not bound
+        TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+        // drop second service and ensure unbound (and active)
+        srv11.drop();
+        delay();
+        TestCase.assertNotNull( instance.getInstance() );
+        TestCase.assertEquals( SimpleComponent.INSTANCE, instance.getInstance() );
+        TestCase.assertEquals( 1, sc.m_multiRef.size() );
+        TestCase.assertTrue( sc.m_multiRef.contains( srv1 ) );
+        TestCase.assertNull( component.getReferences()[0].getServiceReferences() );
+
+
+        // remove the service, expect factory to deactivate and instance to dispose
+        srv1.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+        TestCase.assertNull( instance.getInstance() );
+
+        // assert component factory only managed
+        final Component[] allFactoryComponents2 = findComponentsByName( pid );
+        TestCase.assertNotNull( allFactoryComponents2 );
+        TestCase.assertEquals( 1, allFactoryComponents2.length );
+        for ( int i = 0; i < allFactoryComponents2.length; i++ )
+        {
+            final Component c = allFactoryComponents2[i];
+            if ( c.getId() == component.getId() )
+            {
+                TestCase.assertEquals( Component.STATE_UNSATISFIED, c.getState() );
+            }
+            else
+            {
+                TestCase.fail( "Unexpected Component " + c );
+            }
+        }
+
+        // registeranother service, factory must come back, instance not
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+        TestCase.assertNull( instance.getInstance() );
+
+        // assert component factory only managed
+        final Component[] allFactoryComponents3 = findComponentsByName( pid );
+        TestCase.assertNotNull( allFactoryComponents3 );
+        TestCase.assertEquals( 1, allFactoryComponents3.length );
+        for ( int i = 0; i < allFactoryComponents3.length; i++ )
+        {
+            final Component c = allFactoryComponents3[i];
+            if ( c.getId() == component.getId() )
+            {
+                TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+            }
+            else
+            {
+                TestCase.fail( "Unexpected Component " + c );
+            }
+        }
+    }
+
+
+    @Test
+    public void test_optional_single_static()
+    {
+        final Component component = findComponentByName( "test_optional_single_static" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertEquals( srv1, comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.isEmpty() );
+
+        srv1.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp11 );
+        TestCase.assertNull( comp11.m_singleRef );
+        TestCase.assertTrue( comp11.m_multiRef.isEmpty() );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        // greedy static reference rebinds
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertNotSame( comp11, comp12 );
+        TestCase.assertEquals( srv2, comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.isEmpty() );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect srv2 bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertEquals( srv2, comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.isEmpty() );
+
+        // drop srv2, expect rebind to srv3 (synchronously)
+        srv2.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp21 );
+        TestCase.assertEquals( srv3, comp21.m_singleRef );
+        TestCase.assertTrue( comp21.m_multiRef.isEmpty() );
+
+        // create srv4 of lower rank, expect no rebind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4", -1 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp22 );
+        TestCase.assertSame( comp21, comp22 );
+        TestCase.assertEquals( srv3, comp22.m_singleRef );
+        TestCase.assertTrue( comp22.m_multiRef.isEmpty() );
+
+        // drop srv4 again, expect no rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp23 );
+        TestCase.assertSame( comp21, comp23 );
+        TestCase.assertSame( comp22, comp23 );
+        TestCase.assertEquals( srv3, comp23.m_singleRef );
+        TestCase.assertTrue( comp23.m_multiRef.isEmpty() );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp23, comp30 );
+        TestCase.assertEquals( srv6, comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.isEmpty() );
+
+        // another service with higher ranking rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp31 );
+        TestCase.assertEquals( srv7, comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.isEmpty() );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp32 );
+        TestCase.assertSame( comp31, comp32 );
+        TestCase.assertEquals( srv7, comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.isEmpty() );
+    }
+
+
+    @Test
+    public void test_required_single_static()
+    {
+        final Component component = findComponentByName( "test_required_single_static" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertEquals( srv1, comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.isEmpty() );
+
+        srv1.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNull( comp11 );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertEquals( srv2, comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.isEmpty() );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect srv2 bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertEquals( srv2, comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.isEmpty() );
+
+        // drop srv2, expect rebind to srv3
+        srv2.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp21 );
+        TestCase.assertEquals( srv3, comp21.m_singleRef );
+        TestCase.assertTrue( comp21.m_multiRef.isEmpty() );
+
+        // create srv4, expect no rebind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp22 );
+        TestCase.assertSame( comp21, comp22 );
+        TestCase.assertEquals( srv3, comp22.m_singleRef );
+        TestCase.assertTrue( comp22.m_multiRef.isEmpty() );
+
+        // drop srv4 again, expect no rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp23 );
+        TestCase.assertSame( comp21, comp23 );
+        TestCase.assertSame( comp22, comp23 );
+        TestCase.assertEquals( srv3, comp23.m_singleRef );
+        TestCase.assertTrue( comp23.m_multiRef.isEmpty() );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp23, comp30 );
+        TestCase.assertEquals( srv6, comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.isEmpty() );
+
+        // another service with higher ranking -- rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp31 );
+        TestCase.assertEquals( srv7, comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.isEmpty() );
+
+        // srv6 goes, no rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp32 );
+        TestCase.assertSame( comp31, comp32 );
+        TestCase.assertEquals( srv7, comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.isEmpty() );
+    }
+
+
+    @Test
+    public void test_optional_multiple_static()
+    {
+        final Component component = findComponentByName( "test_optional_multiple_static" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertNull( comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.contains( srv1 ) );
+
+        srv1.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp11 );
+        TestCase.assertNull( comp11.m_singleRef );
+        TestCase.assertTrue( comp11.m_multiRef.isEmpty() );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertNotSame( comp11, comp12 );
+        TestCase.assertNull( comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.contains( srv2 ) );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect both bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertNotSame( comp11, comp20 );
+        TestCase.assertNotSame( comp12, comp20 );
+        TestCase.assertNull( comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv3 ) );
+
+        srv2.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp21 );
+        TestCase.assertNull( comp21.m_singleRef );
+        TestCase.assertFalse( comp21.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp21.m_multiRef.contains( srv3 ) );
+
+        // create srv4, expect greedy bind (static case)
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp22 );
+        TestCase.assertNotSame( comp21, comp22 );
+        TestCase.assertNull( comp22.m_singleRef );
+        TestCase.assertFalse( comp22.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv3 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv4 ) );
+
+        // drop srv4 again, expect rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp23 );
+        TestCase.assertNotSame( comp21, comp23 );
+        TestCase.assertNotSame( comp22, comp23 );
+        TestCase.assertNull( comp23.m_singleRef );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp23.m_multiRef.contains( srv3 ) );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv4 ) );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp23, comp30 );
+        TestCase.assertNull( comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv6 ) );
+
+        // another service with higher ranking -- greedy rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp31 );
+        TestCase.assertNull( comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv7 ) );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp32 );
+        TestCase.assertNotSame( comp31, comp32 );
+        TestCase.assertNull( comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv5 ) );
+        TestCase.assertFalse( comp32.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv7 ) );
+    }
+
+
+    @Test
+    public void test_required_multiple_static()
+    {
+        final Component component = findComponentByName( "test_required_multiple_static" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp10 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertNull( comp10.m_singleRef );
+        TestCase.assertTrue( comp10.m_multiRef.contains( srv1 ) );
+
+        srv1.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_UNSATISFIED, component.getState() );
+        final SimpleComponent comp11 = SimpleComponent.INSTANCE;
+        TestCase.assertNull( comp11 );
+
+        final SimpleServiceImpl srv2 = SimpleServiceImpl.create( bundleContext, "srv2" );
+        delay(); // async binding
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp12 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp10, comp12 );
+        TestCase.assertNull( comp12.m_singleRef );
+        TestCase.assertTrue( comp12.m_multiRef.contains( srv2 ) );
+
+        component.disable();
+        delay(); // async disabling
+
+        final SimpleServiceImpl srv3 = SimpleServiceImpl.create( bundleContext, "srv3" );
+
+        // enable component with two services available, expect both bind
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp20 = SimpleComponent.INSTANCE;
+        TestCase.assertNotNull( comp20 );
+        TestCase.assertNotSame( comp10, comp20 );
+        TestCase.assertNotSame( comp12, comp20 );
+        TestCase.assertNull( comp20.m_singleRef );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp20.m_multiRef.contains( srv3 ) );
+
+        srv2.drop();
+        delay(); // async reactivate
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp21 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp21 );
+        TestCase.assertNull( comp21.m_singleRef );
+        TestCase.assertFalse( comp21.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp21.m_multiRef.contains( srv3 ) );
+
+        // create srv4, expect greedy bind
+        final SimpleServiceImpl srv4 = SimpleServiceImpl.create( bundleContext, "srv4" );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp22 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp22 );
+        TestCase.assertNotSame( comp21, comp22 );
+        TestCase.assertNull( comp22.m_singleRef );
+        TestCase.assertFalse( comp22.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv3 ) );
+        TestCase.assertTrue( comp22.m_multiRef.contains( srv4 ) );
+
+        // drop srv4 again, expect greedy rebind
+        srv4.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp23 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp20, comp23 );
+        TestCase.assertNotSame( comp21, comp23 );
+        TestCase.assertNotSame( comp22, comp23 );
+        TestCase.assertNull( comp23.m_singleRef );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv2 ) );
+        TestCase.assertTrue( comp23.m_multiRef.contains( srv3 ) );
+        TestCase.assertFalse( comp23.m_multiRef.contains( srv4 ) );
+
+        // "reset"
+        component.disable();
+        srv3.drop();
+        delay();
+
+        // two services with service ranking (srv6 > srv5)
+        final SimpleServiceImpl srv5 = SimpleServiceImpl.create( bundleContext, "srv5", 10 );
+        final SimpleServiceImpl srv6 = SimpleServiceImpl.create( bundleContext, "srv6", 20 );
+
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp30 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp23, comp30 );
+        TestCase.assertNull( comp30.m_singleRef );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp30.m_multiRef.contains( srv6 ) );
+
+        // another service with higher ranking -- greedy rebind !
+        final SimpleServiceImpl srv7 = SimpleServiceImpl.create( bundleContext, "srv7", 30 );
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp31 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp31 );
+        TestCase.assertNull( comp31.m_singleRef );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv5 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp31.m_multiRef.contains( srv7 ) );
+
+        // srv6 goes, rebind to srv7
+        srv6.drop();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent comp32 = SimpleComponent.INSTANCE;
+        TestCase.assertNotSame( comp30, comp32 );
+        TestCase.assertNotSame( comp31, comp32 );
+        TestCase.assertNull( comp32.m_singleRef );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv5 ) );
+        TestCase.assertFalse( comp32.m_multiRef.contains( srv6 ) );
+        TestCase.assertTrue( comp32.m_multiRef.contains( srv7 ) );
+    }
+
+    @Test
+    public void test_multi_service_bind_unbind_order()
+    {
+        final Component component = findComponentByName( "test_multi_service_bind_unbind_order" );
+        TestCase.assertNotNull( component );
+        TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+        final SimpleServiceImpl srv1 = SimpleServiceImpl.create( bundleContext, "srv1" );
+        final SimpleService2Impl srv2 = SimpleService2Impl.create( bundleContext, "srv2" );
+
+        // async enabling
+        component.enable();
+        delay();
+
+        TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+        final SimpleComponent2 comp10 = SimpleComponent2.INSTANCE;
+        TestCase.assertNotNull( comp10 );
+        TestCase.assertEquals( 2, comp10.getBindings().size() );
+        TestCase.assertEquals( "bindSimpleService", comp10.getBindings().get( 0 ) );
+        TestCase.assertEquals( "bindSimpleService2", comp10.getBindings().get( 1 ) );
+
+        component.disable();
+        delay();
+
+        TestCase.assertEquals( 4, comp10.getBindings().size() );
+        TestCase.assertEquals( "bindSimpleService", comp10.getBindings().get( 0 ) );
+        TestCase.assertEquals( "bindSimpleService2", comp10.getBindings().get( 1 ) );
+        TestCase.assertEquals( "unbindSimpleService2", comp10.getBindings().get( 2 ) );
+        TestCase.assertEquals( "unbindSimpleService", comp10.getBindings().get( 3 ) );
+
+        srv1.drop();
+        srv2.drop();
+    }
+}
\ No newline at end of file

Added: felix/trunk/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml?rev=1339600&view=auto
==============================================================================
--- felix/trunk/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml (added)
+++ felix/trunk/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml Thu May 17 13:39:34 2012
@@ -0,0 +1,313 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.2.0">
+
+    <scr:component name="test_optional_single_dynamic"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..1"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_single_dynamic"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..1"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_optional_multiple_dynamic"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..n"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_multiple_dynamic"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..n"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+    </scr:component>
+    
+    <scr:component name="test_optional_single_static"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..1"
+            policy="static"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_single_static"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..1"
+            policy="static"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_multiple_dynamic_factory"
+        enabled="false"
+        configuration-policy="ignore"
+        factory="factory_test_required_multiple_dynamic_factory">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..n"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_optional_multiple_static"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_multiple_static"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+    </scr:component>
+
+    
+    <!-- Same components as above but using a target spec -->
+
+    <scr:component name="test_optional_single_dynamic_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..1"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_single_dynamic_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..1"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_optional_multiple_dynamic_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..n"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_multiple_dynamic_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..n"
+            policy="dynamic"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+    
+    <scr:component name="test_optional_single_static_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..1"
+            policy="static"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_single_static_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..1"
+            policy="static"
+            policy-option="greedy"
+            bind="setSimpleService"
+            unbind="unsetSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_optional_multiple_static_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_required_multiple_static_target"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="1..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+            target="(filterprop=match)"
+        />
+    </scr:component>
+
+    <scr:component name="test_multi_service_bind_unbind_order"
+        enabled="false"
+        configuration-policy="ignore">
+        <implementation class="org.apache.felix.scr.integration.components.SimpleComponent2" />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService"
+            cardinality="0..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService"
+            unbind="unbindSimpleService"
+        />
+        <reference
+            name="ref"
+            interface="org.apache.felix.scr.integration.components.SimpleService2"
+            cardinality="0..n"
+            policy="static"
+            policy-option="greedy"
+            bind="bindSimpleService2"
+            unbind="unbindSimpleService2"
+        />
+    </scr:component>
+
+</components>