This is an automated email from the ASF dual-hosted git repository.

tjwatson pushed a commit to branch scrR8
in repository https://gitbox.apache.org/repos/asf/felix-dev.git

commit 5d167e215e240ae5a779023c0f7e6b24f9c6b425
Author: Thomas Watson <[email protected]>
AuthorDate: Tue Jan 12 12:24:45 2021 -0600

    Add support for Optional<ServiceType> to be injected
    
    This is only supported for unary (0..1, 1..1) cardinality injection to
    fields and constructor.  Method injection is not supported for Optional
    type injection.
---
 .../apache/felix/scr/impl/inject/ValueUtils.java   |  14 +-
 .../felix/scr/impl/inject/field/FieldHandler.java  |  45 ++++--
 .../felix/scr/impl/inject/internal/ClassUtils.java |   3 +
 .../inject/internal/ComponentConstructorImpl.java  |  10 +-
 .../scr/integration/ComponentOptionalTest.java     | 170 +++++++++++++++++++++
 .../components/ConstructorSingleReference.java     |  12 ++
 .../components/InjectOptionalComponent.java        | 162 ++++++++++++++++++++
 .../resources/integration_test_inject_optional.xml | 121 +++++++++++++++
 8 files changed, 523 insertions(+), 14 deletions(-)

diff --git a/scr/src/main/java/org/apache/felix/scr/impl/inject/ValueUtils.java 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/ValueUtils.java
index 2e29a3c..4f2af5c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/inject/ValueUtils.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/inject/ValueUtils.java
@@ -23,6 +23,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.felix.scr.impl.helper.ReadOnlyDictionary;
 import org.apache.felix.scr.impl.inject.internal.Annotations;
@@ -54,7 +55,8 @@ public class ValueUtils {
         ref_serviceObjects,     // reference (field, constructor, method)
         ref_serviceType,        // reference (field, constructor, method)
         ref_map,                // reference (field, constructor, method)
-        ref_tuple               // reference (field, constructor ??) // TDODO
+        ref_tuple, // reference (field, constructor ??) // TDODO
+        ref_optional // reference (field, constructor, XX)
     }
 
     /** Empty array. */
@@ -148,6 +150,14 @@ public class ValueUtils {
             {
                 return ValueType.ref_formatterLogger;
             }
+            // 1.5 Optional
+            else if (typeClass == ClassUtils.OPTIONAL_CLASS)
+            {
+                // Note that the first check for 
"typeClass.isAssignableFrom(referenceType)"
+                // will handle case where they want an actual Optional service 
type.
+
+                valueType = ValueType.ref_optional;
+            }
             else
             {
                 if ( field != null )
@@ -320,6 +330,8 @@ public class ValueUtils {
             case ref_logger             :
             case ref_formatterLogger    : value = getLogger(componentType, 
targetType, componentContext, refPair);
                                           break;
+            case ref_optional           : value = 
Optional.ofNullable(refPair.getServiceObject(componentContext));
+                                          break;
             default: value = null;
         }
         return value;
diff --git 
a/scr/src/main/java/org/apache/felix/scr/impl/inject/field/FieldHandler.java 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/field/FieldHandler.java
index ce6f926..a5d25bd 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/inject/field/FieldHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/inject/field/FieldHandler.java
@@ -25,6 +25,7 @@ import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
@@ -129,23 +130,32 @@ public class FieldHandler
                         }
                         if ( fieldType == ClassUtils.LIST_CLASS )
                         {
-                                   this.setFieldValue(componentInstance, new 
CopyOnWriteArrayList<>());
+                            this.setFieldValue(componentInstance,
+                                new CopyOnWriteArrayList<>());
                         }
                         else
                         {
-                                   this.setFieldValue(componentInstance, new 
CopyOnWriteArraySet<>());
+                            this.setFieldValue(componentInstance,
+                                new CopyOnWriteArraySet<>());
                         }
                     }
                 }
             }
             else
             {
-               // only optional field need initialization
-               if ( metadata.isOptional() )
-               {
-                       // null the field if optional and unary
-                       this.setFieldValue(componentInstance, null);
-                   }
+                // only optional field need initialization
+                if (metadata.isOptional())
+                {
+                    if (valueType == ValueType.ref_optional)
+                    {
+                        this.setFieldValue(componentInstance, 
Optional.empty());
+                    }
+                    else
+                    {
+                        // null the field if optional and unary
+                        this.setFieldValue(componentInstance, null);
+                    }
+                }
             }
         }
         catch ( final InvocationTargetException ite)
@@ -182,7 +192,7 @@ public class FieldHandler
         {
             // unary references
 
-               // unbind needs only be done, if reference is dynamic and 
optional
+            // unbind needs only be done, if reference is dynamic and optional
             if ( mType == METHOD_TYPE.UNBIND )
             {
                 if ( this.metadata.isOptional() && !this.metadata.isStatic() )
@@ -190,7 +200,15 @@ public class FieldHandler
                     // we only reset if it was previously set with this value
                     if ( 
bp.getComponentContext().getBoundValues(metadata.getName()).size() == 1 )
                     {
-                        this.setFieldValue(componentInstance, null);
+                        if (valueType == ValueType.ref_optional)
+                        {
+                            this.setFieldValue(componentInstance, 
Optional.empty());
+                        }
+                        else
+                        {
+                            // null the field if optional and unary
+                            this.setFieldValue(componentInstance, null);
+                        }
                     }
                 }
                 
bp.getComponentContext().getBoundValues(metadata.getName()).remove(refPair);
@@ -518,8 +536,11 @@ public class FieldHandler
                 //??? this resolves which we need.... better way?
                 if 
(rawParameter.getRefPair().getServiceObject(rawParameter.getComponentContext()) 
== null
                   && handler.fieldExists( 
rawParameter.getComponentContext().getLogger() )
-                  && (handler.valueType == ValueType.ref_serviceType || 
handler.valueType == ValueType.ref_tuple
-                      || handler.valueType == ValueType.ref_logger || 
handler.valueType == ValueType.ref_formatterLogger) )
+                    && (handler.valueType == ValueType.ref_serviceType //
+                        || handler.valueType == ValueType.ref_tuple
+                        || handler.valueType == ValueType.ref_logger
+                        || handler.valueType == ValueType.ref_formatterLogger
+                        || handler.valueType == ValueType.ref_optional))
                 {
                     return 
rawParameter.getRefPair().getServiceObject(rawParameter.getComponentContext(), 
context);
                 }
diff --git 
a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ClassUtils.java 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ClassUtils.java
index dcdd6b7..04b7a36 100755
--- 
a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ClassUtils.java
+++ 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ClassUtils.java
@@ -21,6 +21,7 @@ package org.apache.felix.scr.impl.inject.internal;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.felix.scr.impl.logger.ComponentLogger;
 import org.apache.felix.scr.impl.logger.InternalLogger.Level;
@@ -55,6 +56,8 @@ public class ClassUtils
     public static final Class<?> COLLECTION_CLASS = Collection.class;
     public static final Class<?> LIST_CLASS = List.class;
 
+    public static final Class<?> OPTIONAL_CLASS = Optional.class;
+
     public static final Class<?> COMPONENT_CONTEXT_CLASS = 
ComponentContext.class;
     public static final Class<?> BUNDLE_CONTEXT_CLASS = BundleContext.class;
     public static final Class<?> INTEGER_CLASS = Integer.class;
diff --git 
a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
index 0e44eb0..5d9fc5a 100755
--- 
a/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
+++ 
b/scr/src/main/java/org/apache/felix/scr/impl/inject/internal/ComponentConstructorImpl.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.felix.scr.impl.inject.ComponentConstructor;
@@ -279,7 +280,8 @@ public class ComponentConstructorImpl<S> implements 
ComponentConstructor<S>
                                     && (constructorArgTypes[i] == 
ValueType.ref_serviceType
                                     || constructorArgTypes[i] == 
ValueType.ref_tuple
                                     || constructorArgTypes[i] == 
ValueType.ref_logger
-                                    || constructorArgTypes[i] == 
ValueType.ref_formatterLogger) )
+                                    || constructorArgTypes[i] == 
ValueType.ref_formatterLogger
+                                    || constructorArgTypes[i] == 
ValueType.ref_optional))
                             {
                                 refPair.getServiceObject(componentContext, 
componentContext.getBundleContext());
                             }
@@ -294,6 +296,12 @@ public class ComponentConstructorImpl<S> implements 
ComponentConstructor<S>
                             }
                         }
                     }
+                    // check for optional ref type; if null then use empty 
Optional
+                    if (ref == null && constructorArgTypes[i] == 
ValueType.ref_optional)
+                    {
+                        ref = Optional.empty();
+                    }
+
                     if ( !refMetadata.isMultiple())
                     {
                         if (ref == null && !refMetadata.isOptional())
diff --git 
a/scr/src/test/java/org/apache/felix/scr/integration/ComponentOptionalTest.java 
b/scr/src/test/java/org/apache/felix/scr/integration/ComponentOptionalTest.java
new file mode 100644
index 0000000..efd13e7
--- /dev/null
+++ 
b/scr/src/test/java/org/apache/felix/scr/integration/ComponentOptionalTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.apache.felix.scr.integration.components.ConstructorSingleReference;
+import org.apache.felix.scr.integration.components.InjectOptionalComponent;
+import 
org.apache.felix.scr.integration.components.InjectOptionalComponent.Mode;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+
+
+@RunWith(PaxExam.class)
+public class ComponentOptionalTest extends ComponentTestBase
+{
+
+    static
+    {
+        // use different components
+        descriptorFile = "/integration_test_inject_optional.xml";
+
+        // uncomment to enable debugging of this test class
+        // paxRunnerVmOption = DEBUG_VM_OPTION;
+    }
+
+    static final String SINGLE_REFERENCE1 = "SingleReference1";
+    static final String SINGLE_REFERENCE2 = "SingleReference2";
+
+    private void doTest(Mode mode) throws Exception
+    {
+        final String componentname = mode.name();
+        ComponentConfigurationDTO cc = 
getDisabledConfigurationAndEnable(componentname,
+            mode.getInitialState());
+        assertEquals(mode.getInitCount(), cc.description.init);
+
+        InjectOptionalComponent cmp1 = null;
+        if (!mode.isMandatory())
+        {
+            cmp1 = this.getServiceFromConfiguration(cc, 
InjectOptionalComponent.class);
+            cmp1.checkMode(mode, null);
+        }
+
+        ComponentConfigurationDTO ref1DTO = getDisabledConfigurationAndEnable(
+            SINGLE_REFERENCE1,
+            mode.isDynamic() && !mode.isMandatory()//
+                ? ComponentConfigurationDTO.ACTIVE
+                : ComponentConfigurationDTO.SATISFIED);
+        ConstructorSingleReference ref1Service = 
getServiceFromConfiguration(ref1DTO,
+            ConstructorSingleReference.class);
+
+        cc = findComponentConfigurationByName(componentname, 
mode.getSecondState());
+        InjectOptionalComponent cmp2 = this.getServiceFromConfiguration(cc,
+            InjectOptionalComponent.class);
+
+        if (!mode.isMandatory())
+        {
+            assertEquals(cmp1, cmp2);
+        }
+
+        if (mode.isMandatory() || mode.isDynamic())
+        {
+            cmp2.checkMode(mode, ref1Service);
+        }
+        else
+        {
+            cmp2.checkMode(mode, null);
+        }
+
+        ComponentConfigurationDTO ref2DTO = getDisabledConfigurationAndEnable(
+            SINGLE_REFERENCE2, ComponentConfigurationDTO.SATISFIED);
+
+        ConstructorSingleReference ref2Service = 
getServiceFromConfiguration(ref2DTO,
+            ConstructorSingleReference.class);
+
+        if (mode.isMandatory() || mode.isDynamic())
+        {
+            cmp2.checkMode(mode, ref1Service);
+        }
+        else
+        {
+            cmp2.checkMode(mode, null);
+        }
+
+        disableAndCheck(ref1DTO);
+
+        if (mode.isDynamic())
+        {
+            cmp2.checkMode(mode, ref2Service);
+        }
+        else if (mode.isMandatory())
+        {
+            cc = findComponentConfigurationByName(componentname,
+                ComponentConfigurationDTO.SATISFIED);
+            InjectOptionalComponent cmp3 = this.getServiceFromConfiguration(cc,
+                InjectOptionalComponent.class);
+            cmp3.checkMode(mode, ref2Service);
+        }
+        else // is optional
+        {
+            cmp2.checkMode(mode, null);
+        }
+
+        disableAndCheck(cc);
+
+        cc = getDisabledConfigurationAndEnable(componentname,
+            ComponentConfigurationDTO.SATISFIED);
+        assertEquals(mode.getInitCount(), cc.description.init);
+        cmp1 = this.getServiceFromConfiguration(cc, 
InjectOptionalComponent.class);
+
+        cmp1.checkMode(mode, ref2Service);
+
+        disableAndCheck(cc);
+    }
+
+    @Test
+    public void test_field_static_optional() throws Exception
+    {
+        doTest(Mode.FIELD_STATIC_OPTIONAL);
+    }
+
+    @Test
+    public void test_field_dynamic_optional() throws Exception
+    {
+        doTest(Mode.FIELD_DYNAMIC_OPTIONAL);
+    }
+
+    @Test
+    public void test_field_static_mandatory() throws Exception
+    {
+        doTest(Mode.FIELD_STATIC_MANDATORY);
+    }
+
+    @Test
+    public void test_field_dynamic_mandatory() throws Exception
+    {
+        doTest(Mode.FIELD_DYNAMIC_MANDATORY);
+    }
+
+    @Test
+    public void test_constructor_mandatory() throws Exception
+    {
+        doTest(Mode.CONSTRUCTOR_MANDATORY);
+    }
+
+    @Test
+    public void test_constructor_optional() throws Exception
+    {
+        doTest(Mode.CONSTRUCTOR_OPTIONAL);
+    }
+}
diff --git 
a/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorSingleReference.java
 
b/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorSingleReference.java
index 0905f8e..96e0e37 100644
--- 
a/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorSingleReference.java
+++ 
b/scr/src/test/java/org/apache/felix/scr/integration/components/ConstructorSingleReference.java
@@ -18,8 +18,14 @@
  */
 package org.apache.felix.scr.integration.components;
 
+import java.util.concurrent.atomic.AtomicLong;
+
 public class ConstructorSingleReference
 {
+    private static final AtomicLong instances = new AtomicLong();
+
+    private final long instanceID = instances.incrementAndGet();
+
     public @interface Config
     {
         String name();
@@ -37,4 +43,10 @@ public class ConstructorSingleReference
     {
         return this.name;
     }
+
+    @Override
+    public String toString()
+    {
+        return getClass().getSimpleName() + '-' + instanceID;
+    }
 }
diff --git 
a/scr/src/test/java/org/apache/felix/scr/integration/components/InjectOptionalComponent.java
 
b/scr/src/test/java/org/apache/felix/scr/integration/components/InjectOptionalComponent.java
new file mode 100644
index 0000000..90cbd1d
--- /dev/null
+++ 
b/scr/src/test/java/org/apache/felix/scr/integration/components/InjectOptionalComponent.java
@@ -0,0 +1,162 @@
+/*
+ * 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.components;
+
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+
+public class InjectOptionalComponent
+{
+    public enum Mode
+    {
+        FIELD_STATIC_MANDATORY(1, false, true), //
+        FIELD_DYNAMIC_MANDATORY(1, true, true), //
+        FIELD_STATIC_OPTIONAL(1, false, false), //
+        FIELD_DYNAMIC_OPTIONAL(1, true, false), //
+        CONSTRUCTOR_MANDATORY(2, false, true), //
+        CONSTRUCTOR_OPTIONAL(2, false, false);
+
+        final int initCount;
+        final int initialState;
+        final int secondState;
+        final boolean isMandatory;
+        final boolean isDynamic;
+
+        Mode(int initCount, boolean isDynamic, boolean isMandatory)
+        {
+            this.initCount = initCount;
+            this.initialState = isMandatory
+                ? ComponentConfigurationDTO.UNSATISFIED_REFERENCE
+                : ComponentConfigurationDTO.SATISFIED;
+            this.secondState = isMandatory ? 
ComponentConfigurationDTO.SATISFIED
+                : ComponentConfigurationDTO.ACTIVE;
+            this.isMandatory = isMandatory;
+            this.isDynamic = isDynamic;
+        }
+
+        public int getInitCount()
+        {
+            return initCount;
+        }
+
+        public int getInitialState()
+        {
+            return initialState;
+        }
+
+        public int getSecondState()
+        {
+            return secondState;
+        }
+
+        public final boolean isMandatory()
+        {
+            return isMandatory;
+        }
+
+        public final boolean isDynamic()
+        {
+            return isDynamic;
+        }
+
+    }
+
+    private final Mode mode;
+
+    private final Optional<ConstructorSingleReference> refConstructor;
+    private Optional<ConstructorSingleReference> refFieldStatic = null;
+    private volatile Optional<ConstructorSingleReference> refFieldDynamic = 
null;
+
+    public InjectOptionalComponent(Map<String, Object> props, 
Optional<ConstructorSingleReference> single)
+    {
+        this.mode = getMode(props);
+        this.refConstructor = single;
+    }
+
+    public InjectOptionalComponent(Map<String, Object> props)
+    {
+        this(props, null);
+    }
+
+    private Mode getMode(Map<String, Object> props)
+    {
+        return Mode.valueOf((String) 
props.get(ComponentConstants.COMPONENT_NAME));
+    }
+
+    public boolean checkMode(Mode mode, ConstructorSingleReference expected)
+    {
+        if (this.mode != mode)
+        {
+            throw new AssertionError(
+                "Wrong mode, expected \"" + mode + "\" but was\"" + this.mode);
+        }
+        Optional<ConstructorSingleReference> optional = getOptional();
+        if (expected != null)
+        {
+            return optional.map((c) -> checkExpected(expected, c)).orElseGet(
+                () -> throwAssertionError(
+                    "FAILED - expected: " + expected + " but got empty 
optional."));
+        }
+        else
+        {
+            return optional.map(
+                (c) -> throwAssertionError(
+                    "FAILED - expected empty optional but got: " + 
c)).orElse(true);
+        }
+    }
+
+    private boolean throwAssertionError(String message)
+    {
+        throw new AssertionError(message);
+    }
+
+    private boolean checkExpected(ConstructorSingleReference expected,
+        ConstructorSingleReference actual)
+    {
+        if (expected == actual)
+        {
+            return true;
+        }
+        throw new AssertionError(
+            "FAILED - expected: " + expected + " bug got: " + actual);
+    }
+
+    private Optional<ConstructorSingleReference> getOptional()
+    {
+        switch (mode)
+        {
+            case CONSTRUCTOR_MANDATORY:
+            case CONSTRUCTOR_OPTIONAL:
+                return refConstructor;
+            case FIELD_DYNAMIC_MANDATORY:
+            case FIELD_DYNAMIC_OPTIONAL:
+                return refFieldDynamic;
+            case FIELD_STATIC_MANDATORY:
+            case FIELD_STATIC_OPTIONAL:
+                return refFieldStatic;
+            default:
+                throw new UnsupportedOperationException(String.valueOf(mode));
+        }
+    }
+
+}
diff --git a/scr/src/test/resources/integration_test_inject_optional.xml 
b/scr/src/test/resources/integration_test_inject_optional.xml
new file mode 100644
index 0000000..a40be9d
--- /dev/null
+++ b/scr/src/test/resources/integration_test_inject_optional.xml
@@ -0,0 +1,121 @@
+<?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.4.0";>
+
+    <!-- Static Field -->
+    <scr:component name="FIELD_STATIC_MANDATORY" enabled="false"
+                   init="1">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference
+            name="refFieldStatic"
+            
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+            field="refFieldStatic"
+            cardinality="1..1"
+        />
+    </scr:component>
+
+    <scr:component name="FIELD_STATIC_OPTIONAL" enabled="false"
+                   init="1">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference
+            name="refFieldStatic"
+            
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+            field="refFieldStatic"
+            cardinality="0..1"
+        />
+    </scr:component>
+
+    <!-- Dynamic Field -->
+    <scr:component name="FIELD_DYNAMIC_MANDATORY" enabled="false"
+                   init="1">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference
+            name="refFieldDynamic"
+            
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+            field="refFieldDynamic"
+            cardinality="1..1"
+            policy="dynamic"
+        />
+    </scr:component>
+
+    <scr:component name="FIELD_DYNAMIC_OPTIONAL" enabled="false"
+                   init="1">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference
+            name="refFieldDynamic"
+            
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+            field="refFieldDynamic"
+            cardinality="0..1"
+            policy="dynamic"
+        />
+    </scr:component>
+
+    <!-- mandatory constructor -->
+    <scr:component name="CONSTRUCTOR_MANDATORY" enabled="false"
+                   init="2">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference 
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+                   cardinality="1..1"
+                   parameter="1"/>
+    </scr:component>
+
+    <!-- optional constructor -->
+    <scr:component name="CONSTRUCTOR_OPTIONAL" enabled="false"
+                   init="2">
+        <implementation 
class="org.apache.felix.scr.integration.components.InjectOptionalComponent" />
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.InjectOptionalComponent"/>
+        </service>
+        <reference 
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"
+                   cardinality="0..1"
+                   parameter="1"/>
+    </scr:component>
+
+    <scr:component name="SingleReference1" enabled="false" 
activate="activator">
+        <implementation 
class="org.apache.felix.scr.integration.components.ConstructorSingleReference" 
/>
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"/>
+        </service>
+        <property name="name" value="single"/>
+    </scr:component>
+
+    <scr:component name="SingleReference2" enabled="false" 
activate="activator">
+        <implementation 
class="org.apache.felix.scr.integration.components.ConstructorSingleReference" 
/>
+        <service factory="false">
+            <provide 
interface="org.apache.felix.scr.integration.components.ConstructorSingleReference"/>
+        </service>
+        <property name="name" value="single"/>
+    </scr:component>
+</components>

Reply via email to