FELIX-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
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1339600 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/pom.xml b/scr/pom.xml
index 90faaeb..83f5058 100644
--- a/scr/pom.xml
+++ b/scr/pom.xml
@@ -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
diff --git a/scr/src/main/java/org/apache/felix/scr/Reference.java b/scr/src/main/java/org/apache/felix/scr/Reference.java
index 7811ce0..e5518bf 100644
--- a/scr/src/main/java/org/apache/felix/scr/Reference.java
+++ b/scr/src/main/java/org/apache/felix/scr/Reference.java
@@ -85,6 +85,15 @@
*/
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
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java b/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
index 48bc3c4..498915b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ScrCommand.java
@@ -272,6 +272,8 @@
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");
}
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
index 27373ac..dffcff3 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
@@ -266,6 +266,8 @@
* 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 @@
// 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 @@
// 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 @@
return m_dependencyMetadata.isStatic();
}
+ public boolean isReluctant()
+ {
+ return m_dependencyMetadata.isReluctant();
+ }
public String getBindMethodName()
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
index 7b0a5c7..c683f3a 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java
@@ -54,6 +54,15 @@
// 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 @@
// 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 @@
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 @@
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 @@
/**
+ * 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 @@
/**
+ * 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 @@
/**
+ * 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 @@
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() )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
index 1e18a91..f743610 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/XmlHandler.java
@@ -75,7 +75,7 @@
// 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 @@
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" ) );
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
new file mode 100644
index 0000000..3d841f7
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceBindGreedyTest.java
@@ -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
diff --git a/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml b/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml
new file mode 100644
index 0000000..7b35e5f
--- /dev/null
+++ b/scr/src/test/resources/integration_test_simple_components_service_binding_greedy.xml
@@ -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>