[DS][RFC-212] Various issues with field references

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1690370 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
index b2ba734..12031ce 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
@@ -91,7 +91,7 @@
      * the index in metadata.getConfigurationPid() of the base factory pid, if any.  Each component created from a factory configuration
      * might have a different targeted pid.
      */
-    private Integer m_factoryPidIndex;
+    private volatile Integer m_factoryPidIndex;
 
     /**
      * the non-factory configurations shared between all instances.
@@ -132,7 +132,7 @@
      * by this field is also contained in the map</li>
      * <ul>
      */
-    private AbstractComponentManager<S> m_singleComponent;
+    private volatile AbstractComponentManager<S> m_singleComponent;
 
     /**
      * Whether components have already been enabled by calling the
@@ -143,8 +143,8 @@
      */
     private volatile boolean m_enabled;
     private final Object enableLock = new Object();
-    private Promise<Void> m_enablePromise;
-    private Promise<Void> m_disablePromise = Promises.resolved(null);
+    private volatile Promise<Void> m_enablePromise;
+    private volatile Promise<Void> m_disablePromise = Promises.resolved(null);
 
     private final ComponentMethods m_componentMethods;
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java
index 8a6cb75..0dcc431 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/FieldHandler.java
@@ -50,7 +50,8 @@
         serviceObjects,
         serviceType,
         map,
-        tuple
+        tuple,
+        ignore
     }
 
     /** The reference metadata. */
@@ -304,66 +305,23 @@
                 return null;
             }
 
-            // if the field is dynamic and optional it has to be volatile
-            if ( !metadata.isStatic() && metadata.isOptional() )
-            {
-                if ( !Modifier.isVolatile(f.getModifiers()) )
-                {
-                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must be declared volatile to handle a dynamic reference", new Object[]
-                            {metadata.getField(), this.componentClass}, null );
-                    return null;
-                }
+            // if the field is dynamic, it has to be volatile (field is ignored, case logged) (112.3.8.1)
+            if ( !metadata.isStatic() && !Modifier.isVolatile(f.getModifiers()) ) {
+                logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must be declared volatile to handle a dynamic reference", new Object[]
+                        {metadata.getField(), this.componentClass}, null );
+                valueType = ParamType.ignore;
             }
 
-            // the field must not be final
+            // the field must not be final (field is ignored, case logged) (112.3.8.1)
             if ( Modifier.isFinal(f.getModifiers()) )
             {
                 logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must not be declared as final", new Object[]
                         {metadata.getField(), this.componentClass}, null );
-                return null;
+                valueType = ParamType.ignore;
             }
         }
         else
         {
-            // multiple cardinality, field type must be collection or subtype
-            if ( !ClassUtils.COLLECTION_CLASS.isAssignableFrom(fieldType) )
-            {
-                logger.log( LogService.LOG_ERROR, "Field {0} in component {1} has unsupported type {2}", new Object[]
-                        {metadata.getField(), this.componentClass, fieldType.getName()}, null );
-                return null;
-            }
-
-            // if the field is dynamic with the replace strategy it has to be volatile
-            if ( !metadata.isStatic() && metadata.isReplace() )
-            {
-                if ( !Modifier.isVolatile(f.getModifiers()) )
-                {
-                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must be declared volatile to handle a dynamic reference", new Object[]
-                            {metadata.getField(), this.componentClass}, null );
-                    return null;
-                }
-            }
-
-            // replace strategy: field must not be final
-            //                   only collection and list allowed
-            if ( metadata.isReplace()  )
-            {
-                if ( Modifier.isFinal(f.getModifiers()) )
-                {
-                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must not be declared as final", new Object[]
-                            {metadata.getField(), this.componentClass}, null );
-                    return null;
-                }
-                if ( fieldType != ClassUtils.LIST_CLASS && fieldType != ClassUtils.COLLECTION_CLASS )
-                {
-                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} has unsupported type {2}."+
-                    " It must be one of java.util.Collection or java.util.List.",
-                    new Object[] {metadata.getField(), this.componentClass, fieldType.getName()}, null );
-                    return null;
-
-                }
-            }
-
             if ( ReferenceMetadata.FIELD_VALUE_TYPE_SERVICE.equals(metadata.getFieldCollectionType()) )
             {
                 valueType = ParamType.serviceType;
@@ -384,6 +342,45 @@
             {
                 valueType = ParamType.tuple;
             }
+
+            // multiple cardinality, field type must be collection or subtype
+            if ( !ClassUtils.COLLECTION_CLASS.isAssignableFrom(fieldType) )
+            {
+                logger.log( LogService.LOG_ERROR, "Field {0} in component {1} has unsupported type {2}", new Object[]
+                        {metadata.getField(), this.componentClass, fieldType.getName()}, null );
+                return null;
+            }
+
+            // if the field is dynamic with the replace strategy it has to be volatile (field is ignored, case logged) (112.3.8.1)
+            if ( !metadata.isStatic() && metadata.isReplace() )
+            {
+                if ( !Modifier.isVolatile(f.getModifiers()) )
+                {
+                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must be declared volatile to handle a dynamic reference", new Object[]
+                            {metadata.getField(), this.componentClass}, null );
+                    valueType = ParamType.ignore;
+                }
+            }
+
+            // replace strategy: field must not be final (field is ignored, case logged) (112.3.8.1)
+            //                   only collection and list allowed
+            if ( metadata.isReplace()  )
+            {
+                if ( fieldType != ClassUtils.LIST_CLASS && fieldType != ClassUtils.COLLECTION_CLASS )
+                {
+                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} has unsupported type {2}."+
+                    " It must be one of java.util.Collection or java.util.List.",
+                    new Object[] {metadata.getField(), this.componentClass, fieldType.getName()}, null );
+                    return null;
+
+                }
+                if ( Modifier.isFinal(f.getModifiers()) )
+                {
+                    logger.log( LogService.LOG_ERROR, "Field {0} in component {1} must not be declared as final", new Object[]
+                            {metadata.getField(), this.componentClass}, null );
+                    valueType = ParamType.ignore;
+                }
+            }
         }
         return f;
     }
@@ -452,7 +449,7 @@
         {
             case serviceType : obj = refPair.getServiceObject(key); break;
             case serviceReference : obj = refPair.getRef(); break;
-            case serviceObjects : obj = ((ComponentServiceObjectsHelper)key.getComponentServiceObjectsHelper()).getServiceObjects(refPair.getRef()); break;
+            case serviceObjects : obj = key.getComponentServiceObjectsHelper().getServiceObjects(refPair.getRef()); break;
             case map : obj = new ReadOnlyDictionary<String, Object>( refPair.getRef() ); break;
             case tuple : final Object tupleKey = new ReadOnlyDictionary<String, Object>( refPair.getRef() );
                          final Object tupleValue = refPair.getServiceObject(key);
@@ -889,6 +886,11 @@
                 final MethodResult methodCallFailureResult,
                 final SimpleLogger logger)
         {
+            if ( handler.valueType == ParamType.ignore )
+            {
+                return MethodResult.VOID;
+            }
+
             try
             {
                 return handler.state.invoke( handler,
@@ -923,8 +925,8 @@
             }
             return true;
         }
-
     }
+
     public ReferenceMethod getBind()
     {
         return new ReferenceMethodImpl(METHOD_TYPE.BIND, this);
@@ -942,6 +944,10 @@
 
     public InitReferenceMethod getInit()
     {
+        if ( valueType == ParamType.ignore )
+        {
+            return null;
+        }
         return new InitReferenceMethod()
         {