FELIX-2521 Support separation between "no method to be called" and "method execution failure" situations to handle according specification:
  - activate method failure is logged and must cause activation failure
  - deactivate method failure is just logged
  - modified method failure is just logged
  - bind method failure is just logged
  - unbind method failure is just logged

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@982605 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
index b722013..515557a 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
@@ -24,10 +24,18 @@
 
 import org.apache.felix.scr.impl.manager.AbstractComponentManager;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
 
 
 public class ActivateMethod extends BaseMethod
 {
+
+    Class[] ACTIVATE_TYPES_DS11 =
+        { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS };
+    Class[] ACTIVATE_TYPES_DS10 =
+        { COMPONENT_CONTEXT_CLASS };
+
+
     public ActivateMethod( final AbstractComponentManager componentManager, final String methodName,
         final boolean methodRequired, final Class componentClass )
     {
@@ -133,9 +141,9 @@
     }
 
 
-    public boolean invoke( Object componentInstance, Object rawParameter )
+    public boolean invoke( Object componentInstance, Object rawParameter, final boolean methodCallFailureResult )
     {
-        return methodExists() && super.invoke( componentInstance, rawParameter );
+        return methodExists() && super.invoke( componentInstance, rawParameter, methodCallFailureResult );
     }
 
 
@@ -173,9 +181,9 @@
             }
             catch ( SuitableMethodNotAccessibleException thrown )
             {
+                getComponentManager().log( LogService.LOG_DEBUG, "SuitableMethodNotAccessible", thrown );
                 ex = thrown;
             }
-
         }
 
         // rethrow if we looked for all method signatures and only found
@@ -223,14 +231,7 @@
 
     protected Class[] getAcceptedParameterTypes()
     {
-        if ( isDS11() )
-        {
-            return new Class[]
-                { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS };
-        }
-
-        return new Class[]
-            { COMPONENT_CONTEXT_CLASS };
+        return isDS11() ? ACTIVATE_TYPES_DS11 : ACTIVATE_TYPES_DS10;
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index a1208ac..e2029be 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -22,6 +22,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.felix.scr.impl.manager.AbstractComponentManager;
@@ -49,7 +50,7 @@
     private final String m_methodName;
     private final Class m_componentClass;
 
-    private Method m_method = null;
+    private Method m_method;
 
     private final boolean m_methodRequired;
 
@@ -112,10 +113,15 @@
         if ( method != null )
         {
             m_state = Resolved.INSTANCE;
+            getComponentManager().log( LogService.LOG_DEBUG, "Found {0} method: {1}", new Object[]
+                { getMethodNamePrefix(), method }, null );
         }
         else if ( m_methodRequired )
         {
             m_state = NotFound.INSTANCE;
+            getComponentManager().log( LogService.LOG_DEBUG, "{0} method [{1}] not found, will not invoke",
+                new Object[]
+                    { getMethodNamePrefix(), getMethodName() }, null );
         }
         else
         {
@@ -161,6 +167,12 @@
         for ( Class theClass = targetClass; theClass != null; )
         {
 
+            if ( getComponentManager().isLogEnabled( LogService.LOG_DEBUG ) )
+            {
+                getComponentManager().log( LogService.LOG_DEBUG,
+                    "Locating method " + getMethodName() + " in class " + theClass.getName(), null );
+            }
+
             try
             {
                 Method method = doFindMethod( theClass, acceptPrivate, acceptPackage );
@@ -205,6 +217,7 @@
 
 
     private boolean invokeMethod( final Object componentInstance, final Object rawParameter )
+        throws InvocationTargetException
     {
         try
         {
@@ -235,20 +248,11 @@
         }
         catch ( InvocationTargetException ex )
         {
-            // 112.5.7 If a bind method throws an exception, SCR must log an
-            // error message containing the exception [...]
-            getComponentManager().log( LogService.LOG_ERROR, "The {0} method has thrown an exception", new Object[]
-                { getMethodName() }, ex.getCause() );
-            return false;
+            throw ex;
         }
         catch ( Throwable t )
         {
-            // anything else went wrong, log the message and fail the invocation
-            getComponentManager().log( LogService.LOG_ERROR, "The {0} method could not be called", new Object[]
-                { getMethodName() }, t );
-
-            // method invocation threw, so it was a failure
-            return false;
+            throw new InvocationTargetException( t );
         }
 
         // assume success (also if the mehotd is not available or accessible)
@@ -319,6 +323,12 @@
         {
             // thrown if no method is declared with the given name and
             // parameters
+            if ( getComponentManager().isLogEnabled( LogService.LOG_DEBUG ) )
+            {
+                String argList = ( parameterTypes != null ) ? Arrays.asList( parameterTypes ).toString() : "";
+                getComponentManager().log( LogService.LOG_DEBUG, "Declared Method {0}.{1}({2}) not found", new Object[]
+                    { clazz.getName(), name, argList }, null );
+            }
         }
         catch ( NoClassDefFoundError cdfe )
         {
@@ -437,9 +447,37 @@
 
     //---------- State management  ------------------------------------
 
-    public boolean invoke( final Object componentInstance, final Object rawParameter )
+    /**
+     * Calls the declared method on the given component with the provided
+     * method call arguments.
+     *
+     * @param componentInstance The component instance on which to call the
+     *      method
+     * @param rawParameter The parameter container providing the actual
+     *      parameters to provide to the called method
+     * @param methodCallFailureResult The result to return from this method if
+     *      calling the method resulted in an exception.
+     *
+     * @return <code>true</code> if the method was called successfully or the
+     *      method was not found and was not required. <code>false</code> if
+     *      the method was not found but required.
+     *      <code>methodCallFailureResult</code> is returned if the method was
+     *      found and called, but the method threw an exception.
+     */
+    public boolean invoke( final Object componentInstance, final Object rawParameter,
+        final boolean methodCallFailureResult )
     {
-        return m_state.invoke( this, componentInstance, rawParameter );
+        try
+        {
+            return m_state.invoke( this, componentInstance, rawParameter );
+        }
+        catch ( InvocationTargetException ite )
+        {
+            getComponentManager().log( LogService.LOG_ERROR, "The {0} method has thrown an exception", new Object[]
+                { getMethodName() }, ite.getCause() );
+        }
+
+        return methodCallFailureResult;
     }
 
 
@@ -451,7 +489,8 @@
     private static interface State
     {
 
-        boolean invoke( final BaseMethod baseMethod, final Object componentInstance, final Object rawParameter );
+        boolean invoke( final BaseMethod baseMethod, final Object componentInstance, final Object rawParameter )
+            throws InvocationTargetException;
 
 
         boolean methodExists( final BaseMethod baseMethod );
@@ -485,24 +524,25 @@
             baseMethod.getComponentManager().log( LogService.LOG_DEBUG, "getting {0}: {1}", new Object[]
                 { baseMethod.getMethodNamePrefix(), baseMethod.getMethodName() }, null );
 
-            // resolve the method
-            Method method;
-            try
-            {
-                method = baseMethod.findMethod();
-            }
-            catch ( InvocationTargetException ex )
-            {
-                method = null;
-                baseMethod.getComponentManager().log( LogService.LOG_WARNING, "{0} cannot be found", new Object[]
-                    { baseMethod.getMethodName() }, ex.getTargetException() );
-            }
+                // resolve the method
+                Method method;
+                try
+                {
+                    method = baseMethod.findMethod();
+                }
+                catch ( InvocationTargetException ex )
+                {
+                    method = null;
+                    baseMethod.getComponentManager().log( LogService.LOG_WARNING, "{0} cannot be found", new Object[]
+                        { baseMethod.getMethodName() }, ex.getTargetException() );
+                }
 
-            baseMethod.setMethod( method );
-        }
+                baseMethod.setMethod( method );
+            }
 
 
         public boolean invoke( final BaseMethod baseMethod, final Object componentInstance, final Object rawParameter )
+            throws InvocationTargetException
         {
             resolve( baseMethod );
             return baseMethod.getState().invoke( baseMethod, componentInstance, rawParameter );
@@ -544,6 +584,7 @@
 
 
         public boolean invoke( final BaseMethod baseMethod, final Object componentInstance, final Object rawParameter )
+            throws InvocationTargetException
         {
             baseMethod.getComponentManager().log( LogService.LOG_DEBUG, "invoking {0}: {1}", new Object[]
                 { baseMethod.getMethodNamePrefix(), baseMethod.getMethodName() }, null );
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 c5aa5e3..c98a516 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
@@ -1025,22 +1025,20 @@
         // null. This is valid for both immediate and delayed components
         if( m_componentInstance != null )
         {
-            return m_bind.invoke(
-                m_componentInstance,
-                new BindMethod.Service()
+            return m_bind.invoke( m_componentInstance, new BindMethod.Service()
+            {
+                public ServiceReference getReference()
                 {
-                    public ServiceReference getReference()
-                    {
-                        bindService( ref );
-                        return ref;
-                    }
-
-                    public Object getInstance()
-                    {
-                        return getService( ref );
-                    }
+                    bindService( ref );
+                    return ref;
                 }
-            );
+
+
+                public Object getInstance()
+                {
+                    return getService( ref );
+                }
+            }, true );
         }
         else if ( !m_componentManager.getComponentMetadata().isImmediate() )
         {
@@ -1099,7 +1097,7 @@
                 {
                     return getService( ref );
                 }
-            } );
+            }, true );
         }
         else
         {
@@ -1128,21 +1126,19 @@
         // null. This is valid for both immediate and delayed components
         if ( m_componentInstance != null )
         {
-            m_unbind.invoke(
-                m_componentInstance,
-                new BindMethod.Service()
+            m_unbind.invoke( m_componentInstance, new BindMethod.Service()
+            {
+                public ServiceReference getReference()
                 {
-                    public ServiceReference getReference()
-                    {
-                        return ref;
-                    }
-
-                    public Object getInstance()
-                    {
-                        return getService( ref );
-                    }
+                    return ref;
                 }
-            );
+
+
+                public Object getInstance()
+                {
+                    return getService( ref );
+                }
+            }, true );
         }
         else
         {
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
index d7ea67b..be42530 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
@@ -224,7 +224,7 @@
 
         // 4. Call the activate method, if present
         if ( !m_activateMethod.invoke( implementationObject,
-            new ActivateMethod.ActivatorParameter( componentContext, 1 ) ) )
+            new ActivateMethod.ActivatorParameter( componentContext, 1 ), false ) )
         {
             // 112.5.8 If the activate method throws an exception, SCR must log an error message
             // containing the exception with the Log Service and activation fails
@@ -258,7 +258,7 @@
         // method throws an exception, SCR must log an error message containing the
         // exception with the Log Service and continue) has already been logged
         m_deactivateMethod.invoke( implementationObject, new ActivateMethod.ActivatorParameter( componentContext,
-            reason ) );
+            reason ), true );
 
         // 2. Unbind any bound services
         Iterator it = getDependencyManagers();
@@ -415,6 +415,7 @@
         }
         else if ( !modify() )
         {
+            // SCR 112.7.1 - deactivate if configuration is deleted or no modified method declared
             log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure from configuration", null );
             int reason = ( configuration == null ) ? ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED
                 : ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_MODIFIED;
@@ -467,10 +468,11 @@
         // invariant: modify method existing and no static bound service changes
 
         // 4. call method (nothing to do when failed, since it has already been logged)
-        if ( !m_modifyMethod.invoke( getInstance(), new ActivateMethod.ActivatorParameter( m_componentContext, -1 ) ) )
+        if ( !m_modifyMethod.invoke( getInstance(), new ActivateMethod.ActivatorParameter( m_componentContext, -1 ),
+            true ) )
         {
             // log an error if the declared method cannot be found
-            log( LogService.LOG_ERROR, "Declared modify method '{0}' cannot be found, configuring by reactivation",
+            log( LogService.LOG_ERROR, "Declared modify method ''{0}'' cannot be found, configuring by reactivation",
                 new Object[]
                     { getComponentMetadata().getModified() }, null );
             return false;
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
index d4c7dae..13f7639 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
@@ -230,7 +230,7 @@
         };
         ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
         ActivateMethod am = new ActivateMethod( icm, methodName, methodName != null, obj.getClass() );
-        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ) );
+        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ), false );
         Method m = get(am, "m_method");
         assertNotNull( m );
         assertEquals( methodName, m.getName() );
@@ -258,7 +258,7 @@
         };
         ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
         ActivateMethod am = new ActivateMethod( icm, methodName, methodName != null, obj.getClass() );
-        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ) );
+        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ), false );
         assertNull( get( am, "m_method" ) );
         assertNull( obj.getCalledMethod() );
     }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
index 2938bf3..0a9aead 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
@@ -441,7 +441,7 @@
         ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
         BindMethod bm = new BindMethod( icm, methodName, component.getClass(), "reference",
             FakeService.class.getName() );
-        bm.invoke( component, m_service );
+        bm.invoke( component, m_service, true );
         assertEquals( expectCallPerformed, component.callPerformed );
     }
 }