FELIX-4957 : [DS][RFC-212] Various issues with field references

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1690440 13f79535-47bb-0310-9956-ffa450edef68
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 eac2f18..1447a79 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
@@ -551,17 +551,21 @@
                 }
                 this.boundValues.remove(refPair);
             }
-            // updated needs only be done, if reference is dynamic
-            // and the value type is map or tuple
+            // updated needs only be done, if the value type is map or tuple
+            // If it's a dynamic reference, the value can be updated
+            // for a static reference we need a reactivation
             else if ( mType == METHOD_TYPE.UPDATED )
             {
-                if ( !this.metadata.isStatic() 
-                	 && ( this.valueType == ParamType.map || this.valueType == ParamType.tuple ) )
-                {
+            	if ( this.valueType == ParamType.map || this.valueType == ParamType.tuple )
+            	{
+            		if ( this.metadata.isStatic() )
+            		{
+            			return MethodResult.REACTIVATE;
+            		}
                     final Object obj = getValue(key, refPair);
                     this.setFieldValue(componentInstance, obj);
                     this.boundValues.put(refPair, obj);
-                }
+            	}
             }
             // bind needs always be done
             else
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/MethodResult.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/MethodResult.java
index 87d1c72..d1526d6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/MethodResult.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/MethodResult.java
@@ -34,11 +34,16 @@
 {
 
     /**
-     * Predefined instance indicating a successfull call to a void method.
+     * Predefined instance indicating a successful call to a void method.
      */
     public static final MethodResult VOID = new MethodResult(false, null);
 
     /**
+     * Predefined instance indicating to reactivate the component.
+     */
+    public static final MethodResult REACTIVATE = new MethodResult(false, null);
+
+    /**
      * The actual result from the method, which may be <code>null</code>.
      */
     private final Map<String, Object> result;
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 902efdb..65364f8 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -993,7 +993,11 @@
         return true;
     }
 
-    abstract <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount );
+    /**
+     * Invoke updated method
+     * @return {@code true} if the component needs reactivation, {@code false} otherwise.
+     */
+    abstract <T> boolean invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount );
 
     abstract <T> void invokeBindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount );
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
index 3ba0c57..d11139d 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
@@ -300,8 +300,9 @@
         return true;
     }
 
-    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> ref, int trackingCount )
+    <T> boolean invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> ref, int trackingCount )
     {
+    	return false;
     }
 
     <T> void invokeBindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> reference, int trackingCount )
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 724a122..45d6c03 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
@@ -932,17 +932,31 @@
         {
             m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic modified {2} (enter)", new Object[] {getName(), trackingCount, serviceReference}, null );
             boolean invokeUpdated;
-            synchronized (getTracker().tracked())
+            final Object sync = getTracker().tracked();
+            synchronized (sync)
             {
                 invokeUpdated = isActive() && refPair == this.refPair;
             }
+            boolean reactivate = false;
             if ( invokeUpdated )
             {
-                m_componentManager.invokeUpdatedMethod( DependencyManager.this, refPair, trackingCount );
+                reactivate = m_componentManager.invokeUpdatedMethod( DependencyManager.this, refPair, trackingCount );
             }
             this.trackingCount = trackingCount;
-            m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic modified {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );
             tracked( trackingCount );
+            if ( reactivate )
+            {
+                m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false, false );
+                synchronized ( sync )
+                {
+                    if (refPair == this.refPair)
+                    {
+                        this.refPair = null;
+                    }
+                }
+                m_componentManager.activateInternal( trackingCount );            	
+            }
+            m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} SingleStatic modified {2} (exit)", new Object[] {getName(), trackingCount, serviceReference}, null );            
         }
 
         public void removedService( ServiceReference<T> serviceReference, RefPair<S, T> refPair, int trackingCount )
@@ -1617,13 +1631,14 @@
      *
      * @param componentContext instance we are calling updated on.
      * @param refPair A service reference corresponding to the service whose service
-     * @param edgeInfo EdgeInfo for the comibination of this instance and this dependency manager.
+     * @param edgeInfo EdgeInfo for the combination of this instance and this dependency manager.
+     * @return {@code true} if reactivation is required.
      */
-    void invokeUpdatedMethod( ComponentContextImpl<S> componentContext, final RefPair<S, T> refPair, int trackingCount, EdgeInfo info )
+    boolean invokeUpdatedMethod( ComponentContextImpl<S> componentContext, final RefPair<S, T> refPair, int trackingCount, EdgeInfo info )
     {
         if ( m_dependencyMetadata.getUpdated() == null && m_dependencyMetadata.getField() == null )
         {
-            return;
+            return false;
         }
         // The updated method is only invoked if the implementation object is not
         // null. This is valid for both immediate and delayed components
@@ -1634,7 +1649,7 @@
                 if (info.outOfRange( trackingCount ) )
                 {
                     //ignore events after close started or we will have duplicate unbinds.
-                    return;
+                    return false;
                 }
             }
             info.waitForOpen( m_componentManager, getName(), "invokeUpdatedMethod" );
@@ -1643,15 +1658,16 @@
                 m_componentManager.log( LogService.LOG_WARNING,
                         "DependencyManager : invokeUpdatedMethod : Service not available from service registry for ServiceReference {0} for reference {1}",
                         new Object[] {refPair.getRef(), getName()}, null );
-                return;
+                return false;
 
             }
-            BindParameters bp = new BindParameters(componentContext, refPair);
-            MethodResult methodResult = m_bindMethods.getUpdated().invoke( componentContext.getImplementationObject( false ), bp, MethodResult.VOID, m_componentManager );
+            final BindParameters bp = new BindParameters(componentContext, refPair);
+            final MethodResult methodResult = m_bindMethods.getUpdated().invoke( componentContext.getImplementationObject( false ), bp, MethodResult.VOID, m_componentManager );
             if ( methodResult != null)
             {
                 m_componentManager.setServiceProperties( methodResult );
             }
+            return methodResult == MethodResult.REACTIVATE;
         }
         else
         {
@@ -1661,6 +1677,7 @@
             m_componentManager.log( LogService.LOG_DEBUG,
                     "DependencyManager : Component not set, no need to call updated method", null );
         }
+        return false;
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
index f2d7d04..a3ec9eb 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
@@ -176,12 +176,19 @@
         }
     }
 
-    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    <T> boolean invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
     {
+    	// as all instances are treated the same == have the same updated signatures for methods/fields
+    	// we just need one result
+    	boolean reactivate = false;
         for ( ComponentContextImpl<S> cc : getComponentContexts() )
         {
-            dependencyManager.invokeUpdatedMethod( cc, refPair, trackingCount, cc.getEdgeInfo( dependencyManager ) );
+            if ( dependencyManager.invokeUpdatedMethod( cc, refPair, trackingCount, cc.getEdgeInfo( dependencyManager ) ) ) 
+            {
+            	reactivate = true;
+            }
         }
+        return reactivate;
     }
 
     <T> void invokeUnbindMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> oldRefPair, int trackingCount )
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
index 14858e6..1feae11 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
@@ -372,14 +372,15 @@
     }
 
     @Override
-    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
+    <T> boolean invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, RefPair<S, T> refPair, int trackingCount )
     {
-        ComponentContextImpl<S> componentContext = m_componentContext;
+        final ComponentContextImpl<S> componentContext = m_componentContext;
         if ( componentContext != null )
         {
-            EdgeInfo info = componentContext.getEdgeInfo( dependencyManager );
-            dependencyManager.invokeUpdatedMethod( componentContext, refPair, trackingCount, info );
+            final EdgeInfo info = componentContext.getEdgeInfo( dependencyManager );
+            return dependencyManager.invokeUpdatedMethod( componentContext, refPair, trackingCount, info );
         }
+        return false;
     }
 
     @Override