FELIX-1443 Unify method selection and invocation mechanisms on the
basis of Alin Dreghiciu's implementation for FELIX 924.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@800496 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
new file mode 100644
index 0000000..70000cd
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ActivateMethod.java
@@ -0,0 +1,243 @@
+/*
+ * 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.impl.helper;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.osgi.service.component.ComponentContext;
+
+
+public class ActivateMethod extends BaseMethod
+{
+
+    public ActivateMethod( final AbstractComponentManager componentManager, String methodName, Class componentClass )
+    {
+        super( componentManager, methodName, componentClass );
+    }
+
+
+    protected Method doFindMethod( Class targetClass, boolean acceptPrivate, boolean acceptPackage )
+        throws SuitableMethodNotAccessibleException, InvocationTargetException
+    {
+
+        boolean suitableMethodNotAccessible = false;
+
+        try
+        {
+            return getSingleParameterMethod( targetClass, acceptPrivate, acceptPackage );
+        }
+        catch ( NoSuchMethodException nsme )
+        {
+            // ignore for now
+        }
+        catch ( SuitableMethodNotAccessibleException smnae )
+        {
+            suitableMethodNotAccessible = true;
+        }
+
+        if ( isDS11() )
+        {
+            // check methods with MethodTester
+            Method[] methods = targetClass.getDeclaredMethods();
+            for ( int i = 0; i < methods.length; i++ )
+            {
+                if ( methods[i].getName().equals( getMethodName() ) && isSuitable( methods[i] ) )
+                {
+                    if ( accept( methods[i], acceptPrivate, acceptPackage ) )
+                    {
+                        // check modifiers etc.
+                        return methods[i];
+                    }
+
+                    // method is suitable but not accessible, flag it
+                    suitableMethodNotAccessible = true;
+                }
+            }
+
+            // finally check method with no arguments
+            if ( acceptEmpty() )
+            {
+                try
+                {
+                    // find the declared method in this class
+                    return getMethod( targetClass, getMethodName(), null, acceptPrivate, acceptPackage );
+                }
+                catch ( NoSuchMethodException nsme )
+                {
+                    // ignore for now
+                }
+                catch ( SuitableMethodNotAccessibleException smnae )
+                {
+                    suitableMethodNotAccessible = true;
+                }
+            }
+        }
+
+        if ( suitableMethodNotAccessible )
+        {
+            throw new SuitableMethodNotAccessibleException();
+        }
+
+        return null;
+    }
+
+
+    protected Object[] getParameters( Method method, Object rawParameter )
+    {
+        final Class[] parameterTypes = method.getParameterTypes();
+        final ActivatorParameter ap = ( ActivatorParameter ) rawParameter;
+        final Object[] param = new Object[parameterTypes.length];
+        for ( int i = 0; i < param.length; i++ )
+        {
+            if ( parameterTypes[i] == COMPONENT_CONTEXT_CLASS )
+            {
+                param[i] = ap.getComponentContext();
+            }
+            else if ( parameterTypes[i] == BUNDLE_CONTEXT_CLASS )
+            {
+                param[i] = ap.getComponentContext().getBundleContext();
+            }
+            else if ( parameterTypes[i] == MAP_CLASS )
+            {
+                // note: getProperties() returns a ReadOnlyDictionary which is a Map
+                param[i] = ap.getComponentContext().getProperties();
+            }
+            else if ( parameterTypes[i] == INTEGER_CLASS || parameterTypes[i] == Integer.TYPE )
+            {
+                param[i] = new Integer( ap.getReason() );
+            }
+        }
+
+        return param;
+    }
+
+
+    private Method getSingleParameterMethod( final Class targetClass, final boolean acceptPrivate,
+        final boolean acceptPackage ) throws SuitableMethodNotAccessibleException, InvocationTargetException,
+        NoSuchMethodException
+    {
+        SuitableMethodNotAccessibleException ex = null;
+        final Class[] acceptedTypes = getAcceptedParameterTypes();
+        for ( int i = 0; i < acceptedTypes.length; i++ )
+        {
+            try
+            {
+                // find the declared method in this class
+                return getMethod( targetClass, getMethodName(), new Class[]
+                    { acceptedTypes[i] }, acceptPrivate, acceptPackage );
+            }
+            catch ( NoSuchMethodException nsme )
+            {
+                // ignore for now
+            }
+            catch ( SuitableMethodNotAccessibleException thrown )
+            {
+                ex = thrown;
+            }
+
+        }
+
+        if ( ex != null )
+        {
+            throw ex;
+        }
+
+        throw new NoSuchMethodException();
+    }
+
+
+    private boolean isSuitable( Method method )
+    {
+        // require two or more arguments
+        final Class[] types = method.getParameterTypes();
+        if ( types.length < 2 )
+        {
+            return false;
+        }
+
+        // check for argument types
+        final Class[] acceptedTypes = getAcceptedParameterTypes();
+        OUTER: for ( int i = 0; i < types.length; i++ )
+        {
+            final Class type = types[i];
+            for ( int j = 0; j < acceptedTypes.length; j++ )
+            {
+                if ( type == acceptedTypes[j] )
+                {
+                    continue OUTER;
+                }
+            }
+
+            // get here if type is not contained in the array
+            return false;
+        }
+
+        // all parameters are acceptable
+        return true;
+    }
+
+
+    protected Class[] getAcceptedParameterTypes()
+    {
+        if ( isDS11() )
+        {
+            return new Class[]
+                { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS };
+        }
+
+        return new Class[]
+            { COMPONENT_CONTEXT_CLASS };
+    }
+
+
+    protected boolean acceptEmpty()
+    {
+        return isDS11();
+    }
+
+    //---------- Helper class for method call parameters
+
+    public static final class ActivatorParameter
+    {
+        private final ComponentContext m_componentContext;
+        private final int m_reason;
+
+
+        public ActivatorParameter( ComponentContext componentContext, int reason )
+        {
+            this.m_componentContext = componentContext;
+            this.m_reason = reason;
+        }
+
+
+        public ComponentContext getComponentContext()
+        {
+            return m_componentContext;
+        }
+
+
+        public int getReason()
+        {
+            return m_reason;
+        }
+    }
+}
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
new file mode 100644
index 0000000..99f3596
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -0,0 +1,439 @@
+/*
+ * 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.impl.helper;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.helper.SuitableMethodNotAccessibleException;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * Component method to be invoked on service (un)binding.
+ */
+abstract class BaseMethod
+{
+
+    // class references to simplify parameter checking
+    protected static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class;
+    protected static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class;
+    protected static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class;
+    protected static final Class MAP_CLASS = Map.class;
+    protected static final Class INTEGER_CLASS = Integer.class;
+
+    private final AbstractComponentManager m_componentManager;
+
+    private final String m_methodName;
+    private final Class m_componentClass;
+
+    private Method m_method = null;
+
+    private State m_state;
+
+
+    protected BaseMethod( final AbstractComponentManager componentManager, final String methodName,
+        final Class componentClass )
+    {
+        m_componentManager = componentManager;
+        m_methodName = methodName;
+        m_componentClass = componentClass;
+        if ( m_methodName == null )
+        {
+            m_state = new NotApplicable();
+        }
+        else
+        {
+            m_state = new NotResolved();
+        }
+    }
+
+
+    protected final AbstractComponentManager getComponentManager()
+    {
+        return m_componentManager;
+    }
+
+
+    protected final boolean isDS11()
+    {
+        return getComponentManager().getComponentMetadata().isDS11();
+    }
+
+
+    protected final String getMethodName()
+    {
+        return m_methodName;
+    }
+
+
+    protected final Class getComponentClass()
+    {
+        return m_componentClass;
+    }
+
+
+    /**
+     * Finds the method named in the {@link #m_methodName} field in the given
+     * <code>targetClass</code>. If the target class has no acceptable method
+     * the class hierarchy is traversed until a method is found or the root
+     * of the class hierarchy is reached without finding a method.
+     *
+     * @param targetClass The class in which to look for the method
+     * @param acceptPrivate <code>true</code> if private methods should be
+     *      considered.
+     * @param acceptPackage <code>true</code> if package private methods should
+     *      be considered.
+     * @return The requested method or <code>null</code> if no acceptable method
+     *      can be found in the target class or any super class.
+     * @throws InvocationTargetException If an unexpected Throwable is caught
+     *      trying to find the requested method.
+     */
+    private Method findMethod() throws InvocationTargetException
+    {
+        boolean acceptPrivate = isDS11();
+        boolean acceptPackage = isDS11();
+
+        final Class targetClass = getComponentClass();
+        final ClassLoader targetClasslLoader = targetClass.getClassLoader();
+        final String targetPackage = getPackageName( targetClass );
+
+        for ( Class theClass = targetClass; theClass != null; )
+        {
+
+            try
+            {
+                Method method = doFindMethod( theClass, acceptPrivate, acceptPackage );
+                if ( method != null )
+                {
+                    return method;
+                }
+            }
+            catch ( SuitableMethodNotAccessibleException ex )
+            {
+                // log and return null
+                getComponentManager().log( LogService.LOG_ERROR,
+                    "DependencyManager : Suitable but non-accessible method found in class " + targetClass.getName(),
+                    null, null );
+                break;
+            }
+
+            // if we get here, we have no method, so check the super class
+            theClass = theClass.getSuperclass();
+            if ( theClass == null )
+            {
+                break;
+            }
+
+            // super class method check ignores private methods and accepts
+            // package methods only if in the same package and package
+            // methods are (still) allowed
+            acceptPackage &= targetClasslLoader == theClass.getClassLoader()
+                && targetPackage.equals( getPackageName( theClass ) );
+
+            // private methods will not be accepted any more in super classes
+            acceptPrivate = false;
+        }
+
+        // nothing found after all these years ...
+        return null;
+    }
+
+
+    protected abstract Method doFindMethod( final Class targetClass, final boolean acceptPrivate,
+        final boolean acceptPackage ) throws SuitableMethodNotAccessibleException, InvocationTargetException;
+
+
+    private boolean invokeMethod( final Object componentInstance, final Object rawParameter )
+    {
+        try
+        {
+            final Object[] params = getParameters( m_method, rawParameter );
+            m_method.invoke( componentInstance, params );
+        }
+        catch ( IllegalStateException ise )
+        {
+            getComponentManager().log( LogService.LOG_INFO, ise.getMessage(), null, null );
+            return false;
+        }
+        catch ( IllegalAccessException ex )
+        {
+            // 112.3.1 If the method is not is not declared protected or
+            // public, SCR must log an error message with the log service,
+            // if present, and ignore the method
+            getComponentManager().log( LogService.LOG_DEBUG, "Method " + m_methodName + " cannot be called", null, ex );
+        }
+        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 " + getMethodName() + " method has thrown an exception", null, ex.getCause() );
+            return false;
+        }
+        catch ( Throwable t )
+        {
+            // anything else went wrong, log the message and fail the invocation
+            getComponentManager().log( LogService.LOG_ERROR, "The " + getMethodName() + " method could not be called",
+                null, t );
+
+            // method invocation threw, so it was a failure
+            return false;
+        }
+
+        // assume success (also if the mehotd is not available or accessible)
+        return true;
+    }
+
+
+    /**
+     * Returns the parameter array created from the <code>rawParameter</code>
+     * using the actual parameter type list of the <code>method</code>.
+     * @param method
+     * @param rawParameter
+     * @return
+     * @throws IllegalStateException If the required parameters cannot be
+     *      extracted from the <code>rawParameter</code>
+     */
+    protected abstract Object[] getParameters( Method method, Object rawParameter );
+
+
+    protected String getMethodNamePrefix()
+    {
+        return "";
+    }
+
+
+    //---------- Helpers
+
+    /**
+     * Finds the named public or protected method in the given class or any
+     * super class. If such a method is found, its accessibility is enfored by
+     * calling the <code>Method.setAccessible</code> method if required and
+     * the method is returned. Enforcing accessibility is required to support
+     * invocation of protected methods.
+     *
+     * @param clazz The <code>Class</code> which provides the method.
+     * @param name The name of the method.
+     * @param parameterTypes The parameters to the method. Passing
+     *      <code>null</code> is equivalent to using an empty array.
+     *
+     * @return The named method with enforced accessibility
+     *
+     * @throws NoSuchMethodException If no public or protected method with
+     *      the given name can be found in the class or any of its super classes.
+     * @throws SuitableMethodNotAccessibleException If method with the given
+     *      name taking the parameters is found in the class but the method
+     *      is not accessible.
+     * @throws InvocationTargetException If an unexpected Throwable is caught
+     *      trying to access the desired method.
+     */
+    public static Method getMethod( Class clazz, String name, Class[] parameterTypes, boolean acceptPrivate,
+        boolean acceptPackage ) throws NoSuchMethodException, SuitableMethodNotAccessibleException,
+        InvocationTargetException
+    {
+        try
+        {
+            // find the declared method in this class
+            Method method = clazz.getDeclaredMethod( name, parameterTypes );
+
+            // accept public and protected methods only and ensure accessibility
+            if ( accept( method, acceptPrivate, acceptPackage ) )
+            {
+                return method;
+            }
+        }
+        catch ( NoSuchMethodException nsme )
+        {
+            // forward to caller
+            throw nsme;
+        }
+        catch ( Throwable throwable )
+        {
+            // unexpected problem accessing the method, don't let everything
+            // blow up in this situation, just throw a declared exception
+            throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
+        }
+
+        // suitable method found which is not accessible
+        throw new SuitableMethodNotAccessibleException();
+    }
+
+
+    /**
+     * Returns <code>true</code> if the method is acceptable to be returned from the
+     * {@link #getMethod(Class, String, Class[], boolean, boolean)} and also
+     * makes the method accessible.
+     * <p>
+     * This method returns <code>true</code> iff:
+     * <ul>
+     * <li>The method has <code>void</code> return type</li>
+     * <li>Is not static</li>
+     * <li>Is public or protected</li>
+     * <li>Is private and <code>acceptPrivate</code> is <code>true</code></li>
+     * <li>Is package private and <code>acceptPackage</code> is <code>true</code></li>
+     * </ul>
+     * <p>
+     * This method is package private for unit testing purposes. It is not
+     * meant to be called from client code.
+     *
+     * @param method The method to check
+     * @param acceptPrivate Whether a private method is acceptable
+     * @param acceptPackage Whether a package private method is acceptable
+     * @return
+     */
+    protected static boolean accept( Method method, boolean acceptPrivate, boolean acceptPackage )
+    {
+        // method must be void
+        if ( Void.TYPE != method.getReturnType() )
+        {
+            return false;
+        }
+
+        // check modifiers now
+        int mod = method.getModifiers();
+
+        // no static method
+        if ( Modifier.isStatic( mod ) )
+        {
+            return false;
+        }
+
+        // accept public and protected methods
+        if ( Modifier.isPublic( mod ) || Modifier.isProtected( mod ) )
+        {
+            method.setAccessible( true );
+            return true;
+        }
+
+        // accept private if accepted
+        if ( Modifier.isPrivate( mod ) )
+        {
+            if ( acceptPrivate )
+            {
+                method.setAccessible( acceptPrivate );
+                return true;
+            }
+
+            return false;
+        }
+
+        // accept default (package)
+        if ( acceptPackage )
+        {
+            method.setAccessible( true );
+            return true;
+        }
+
+        // else don't accept
+        return false;
+    }
+
+
+    /**
+     * Returns the name of the package to which the class belongs or an
+     * empty string if the class is in the default package.
+     */
+    public static String getPackageName( Class clazz )
+    {
+        String name = clazz.getName();
+        int dot = name.lastIndexOf( '.' );
+        return ( dot > 0 ) ? name.substring( 0, dot ) : "";
+    }
+
+
+    //---------- State management  ------------------------------------
+
+    public boolean invoke( final Object componentInstance, final Object rawParameter )
+    {
+        return m_state.invoke( componentInstance, rawParameter );
+    }
+
+    private static interface State
+    {
+
+        boolean invoke( final Object componentInstance, final Object rawParameter );
+    }
+
+    private static class NotApplicable implements State
+    {
+
+        public boolean invoke( final Object componentInstance, final Object rawParameter )
+        {
+            return true;
+        }
+    }
+
+    private class NotResolved implements State
+    {
+
+        public boolean invoke( final Object componentInstance, final Object rawParameter )
+        {
+            getComponentManager().log( LogService.LOG_DEBUG,
+                "getting " + getMethodNamePrefix() + "bind: " + m_methodName, null, null );
+            try
+            {
+                m_method = findMethod();
+                m_state = ( m_method == null ) ? ( State ) new NotFound() : new Resolved();
+                return m_state.invoke( componentInstance, rawParameter );
+            }
+            catch ( InvocationTargetException ex )
+            {
+                m_state = new NotFound();
+                // We can safely ignore this one
+                getComponentManager().log( LogService.LOG_WARNING, getMethodName() + " cannot be found", null,
+                    ex.getTargetException() );
+            }
+            return true;
+        }
+    }
+
+    private class NotFound implements State
+    {
+
+        public boolean invoke( final Object componentInstance, final Object rawParameter )
+        {
+            // 112.3.1 If the method is not found , SCR must log an error
+            // message with the log service, if present, and ignore the
+            // method
+            getComponentManager().log( LogService.LOG_ERROR,
+                getMethodNamePrefix() + "bind method [" + m_methodName + "] not found", null, null );
+            return true;
+        }
+    }
+
+    private class Resolved implements State
+    {
+
+        public boolean invoke( final Object componentInstance, final Object rawParameter )
+        {
+            getComponentManager().log( LogService.LOG_DEBUG,
+                "invoking " + getMethodNamePrefix() + "bind: " + m_methodName, null, null );
+            return invokeMethod( componentInstance, rawParameter );
+        }
+    }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
similarity index 70%
rename from scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
rename to scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
index 384d101..209255c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
@@ -16,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scr.impl.manager;
+package org.apache.felix.scr.impl.helper;
 
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import org.apache.felix.scr.impl.helper.ReadOnlyDictionary;
-import org.apache.felix.scr.impl.helper.ReflectionHelper;
-import org.apache.felix.scr.impl.helper.SuitableMethodNotAccessibleException;
-import org.osgi.framework.Constants;
+
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
 
@@ -32,37 +30,19 @@
 /**
  * Component method to be invoked on service (un)binding.
  */
-class BindMethod
+public class BindMethod extends BaseMethod
 {
 
-    private final boolean m_isDS11;
-    private final String m_methodName;
-    private final Class m_componentClass;
     private final String m_referenceName;
     private final String m_referenceClassName;
-    private final Logger m_logger;
-
-    private Method m_method = null;
-    private State m_state;
 
 
-    BindMethod( final boolean isDS11, final String methodName, final Class componentClass, final String referenceName,
-        final String referenceClassName, final Logger logger )
+    public BindMethod( final AbstractComponentManager componentManager, final String methodName,
+        final Class componentClass, final String referenceName, final String referenceClassName )
     {
-        m_isDS11 = isDS11;
-        m_methodName = methodName;
-        m_componentClass = componentClass;
+        super( componentManager, methodName, componentClass );
         m_referenceName = referenceName;
         m_referenceClassName = referenceClassName;
-        m_logger = logger;
-        if ( m_methodName == null )
-        {
-            m_state = new NotApplicable();
-        }
-        else
-        {
-            m_state = new NotResolved();
-        }
     }
 
 
@@ -82,8 +62,8 @@
      * @throws InvocationTargetException If an unexpected Throwable is caught
      *      trying to find the requested method.
      */
-    private Method findMethod( final Class targetClass, final boolean acceptPrivate, final boolean acceptPackage )
-        throws InvocationTargetException
+    protected Method doFindMethod( Class targetClass, boolean acceptPrivate, boolean acceptPackage )
+        throws SuitableMethodNotAccessibleException, InvocationTargetException
     {
         // 112.3.1 The method is searched for using the following priority
         // 1 - Service reference parameter
@@ -144,7 +124,7 @@
             }
 
             // signatures taking a map are only supported starting with DS 1.1
-            if ( m_isDS11 )
+            if ( isDS11() )
             {
 
                 // Case 4 - same as case 2, but + Map param (DS 1.1 only)
@@ -182,25 +162,16 @@
 
         // if at least one suitable method could be found but none of
         // the suitable methods are accessible, we have to terminate
-        if (suitableMethodNotAccessible )
+        if ( suitableMethodNotAccessible )
         {
-            m_logger.log( LogService.LOG_ERROR,
-                "DependencyManager : Suitable but non-accessible method found in class " + targetClass.getName() );
-            return null;
+            getComponentManager().log( LogService.LOG_ERROR,
+                "DependencyManager : Suitable but non-accessible method found in class " + targetClass.getName(), null,
+                null );
+            throw new SuitableMethodNotAccessibleException();
         }
 
-        // if we get here, we have no method, so check the super class
-        final Class superClass = targetClass.getSuperclass();
-        if (superClass == null) {
-            return null;
-        }
-
-        // super class method check ignores private methods and accepts
-        // package methods only if in the same package and package
-        // methods are (still) allowed
-        final boolean withPackage = acceptPackage && targetClass.getClassLoader() == superClass.getClassLoader()
-            && ReflectionHelper.getPackageName( targetClass ).equals( ReflectionHelper.getPackageName( superClass ) );
-        return findMethod( superClass, false, withPackage);
+        // no method found
+        return null;
     }
 
 
@@ -264,8 +235,8 @@
     {
         try
         {
-            return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
-                { ReflectionHelper.SERVICE_REFERENCE_CLASS }, acceptPrivate, acceptPackage );
+            return getMethod( targetClass, getMethodName(), new Class[]
+                { SERVICE_REFERENCE_CLASS }, acceptPrivate, acceptPackage );
         }
         catch ( NoSuchMethodException e )
         {
@@ -299,7 +270,7 @@
     {
         try
         {
-            return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
+            return getMethod( targetClass, getMethodName(), new Class[]
                 { parameterClass }, acceptPrivate, acceptPackage );
         }
         catch ( NoSuchMethodException nsme )
@@ -346,7 +317,7 @@
             // Select only the methods that receive a single
             // parameter
             // and a matching name
-            if ( parameters.length == 1 && method.getName().equals( m_methodName ) )
+            if ( parameters.length == 1 && method.getName().equals( getMethodName() ) )
             {
 
                 // Get the parameter type
@@ -357,7 +328,7 @@
                 // reference's interface attribute
                 if ( theParameter.isAssignableFrom( parameterClass ) )
                 {
-                    if ( ReflectionHelper.accept( method, acceptPrivate, acceptPackage ) )
+                    if ( accept( method, acceptPrivate, acceptPackage ) )
                     {
                         return method;
                     }
@@ -404,8 +375,8 @@
     {
         try
         {
-            return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
-                { parameterClass, ReflectionHelper.MAP_CLASS }, acceptPrivate, acceptPackage );
+            return getMethod( targetClass, getMethodName(), new Class[]
+                { parameterClass, MAP_CLASS }, acceptPrivate, acceptPackage );
         }
         catch ( NoSuchMethodException nsme )
         {
@@ -446,13 +417,13 @@
         {
             final Method method = candidateBindMethods[i];
             final Class[] parameters = method.getParameterTypes();
-            if ( parameters.length == 2 && method.getName().equals( m_methodName ) )
+            if ( parameters.length == 2 && method.getName().equals( getMethodName() ) )
             {
 
                 // parameters must be refclass,map
-                if ( parameters[0].isAssignableFrom( parameterClass ) && parameters[1] == ReflectionHelper.MAP_CLASS )
+                if ( parameters[0].isAssignableFrom( parameterClass ) && parameters[1] == MAP_CLASS )
                 {
-                    if ( ReflectionHelper.accept( method, acceptPrivate, acceptPackage ) )
+                    if ( accept( method, acceptPrivate, acceptPackage ) )
                     {
                         return method;
                     }
@@ -475,17 +446,18 @@
     }
 
 
-    private boolean invokeMethod( final Object componentInstance, final Service service )
+    protected Object[] getParameters( Method method, Object rawParameter )
     {
-        final Class[] paramTypes = m_method.getParameterTypes();
+        final Service service = ( Service ) rawParameter;
+        final Class[] paramTypes = method.getParameterTypes();
         final Object[] params = new Object[paramTypes.length];
         for ( int i = 0; i < params.length; i++ )
         {
-            if ( paramTypes[i] == ReflectionHelper.SERVICE_REFERENCE_CLASS )
+            if ( paramTypes[i] == SERVICE_REFERENCE_CLASS )
             {
                 params[i] = service.getReference();
             }
-            else if ( paramTypes[i] == ReflectionHelper.MAP_CLASS )
+            else if ( paramTypes[i] == MAP_CLASS )
             {
                 params[i] = new ReadOnlyDictionary( service.getReference() );
             }
@@ -494,34 +466,13 @@
                 params[i] = service.getInstance();
                 if ( params[i] == null )
                 {
-                    m_logger.log( LogService.LOG_INFO, "Dependency Manager: Service " + service.getReference()
+                    throw new IllegalStateException( "Dependency Manager: Service " + service.getReference()
                         + " has already gone, not " + getMethodNamePrefix() + "binding" );
-                    return false;
                 }
             }
         }
-        try
-        {
-            m_method.invoke( componentInstance, params );
-            m_logger.log( LogService.LOG_DEBUG, getMethodNamePrefix() + "bound: " + m_referenceName + "/"
-                + service.getReference().getProperty( Constants.SERVICE_ID ) );
-        }
-        catch ( IllegalAccessException ex )
-        {
-            // 112.3.1 If the method is not is not declared protected or
-            // public, SCR must log an error message with the log service,
-            // if present, and ignore the method
-            m_logger.log( LogService.LOG_ERROR, getMethodNamePrefix() + "bind method " + m_methodName + "] cannot be called",
-                ex );
-        }
-        catch ( InvocationTargetException ex )
-        {
-            // 112.5.7 If a bind method throws an exception, SCR must log an
-            // error message containing the exception [...]
-            m_logger.log( LogService.LOG_ERROR, "DependencyManager : exception while invoking " + m_methodName + "()",
-                ex.getCause() );
-        }
-        return true;
+
+        return params;
     }
 
 
@@ -530,88 +481,9 @@
         return "";
     }
 
-
-    //---------- State management  ------------------------------------
-
-    boolean invoke( final Object componentInstance, final Service service )
-    {
-        return m_state.invoke( componentInstance, service );
-    }
-
-    private static interface State
-    {
-
-        boolean invoke( final Object componentInstance, final Service service );
-    }
-
-    private static class NotApplicable implements State
-    {
-
-        public boolean invoke( final Object componentInstance, final Service service )
-        {
-            return true;
-        }
-    }
-
-    private class NotResolved implements State
-    {
-
-        public boolean invoke( final Object componentInstance, final Service service )
-        {
-            m_logger.log( LogService.LOG_DEBUG, "getting " + getMethodNamePrefix() + "bind: " + m_methodName );
-            try
-            {
-                // if the owning component is declared with the DS 1.1 namespace
-                // (or newer), private and package private methods are accepted
-                m_method = findMethod( m_componentClass, m_isDS11, m_isDS11 );
-                if ( m_method == null )
-                {
-                    m_state = new NotFound();
-                }
-                else
-                {
-                    m_state = new Resolved();
-                }
-                return m_state.invoke( componentInstance, service );
-            }
-            catch ( InvocationTargetException ex )
-            {
-                m_state = new NotFound();
-                // 112.5.7 If a bind method throws an exception, SCR must log an
-                // error message containing the exception [...]
-                m_logger.log( LogService.LOG_ERROR, "DependencyManager : exception while finding " + m_methodName
-                    + "()", ex.getCause() );
-            }
-            return true;
-        }
-    }
-
-    private class NotFound implements State
-    {
-
-        public boolean invoke( final Object componentInstance, final Service service )
-        {
-            // 112.3.1 If the method is not found , SCR must log an error
-            // message with the log service, if present, and ignore the
-            // method
-            m_logger.log( LogService.LOG_ERROR, getMethodNamePrefix() + "bind method [" + m_methodName + "] not found" );
-            return true;
-        }
-    }
-
-    private class Resolved implements State
-    {
-
-        public boolean invoke( final Object componentInstance, final Service service )
-        {
-            m_logger.log( LogService.LOG_DEBUG, "invoking " + getMethodNamePrefix() + "bind: " + m_methodName );
-            return invokeMethod( componentInstance, service );
-        }
-    }
-
     //---------- Service abstraction ------------------------------------
 
-    static interface Service
+    public static interface Service
     {
 
         ServiceReference getReference();
@@ -621,16 +493,4 @@
 
     }
 
-    //---------- Logger ------------------------------------
-
-    static interface Logger
-    {
-
-        void log( int level, String message );
-
-
-        void log( int level, String message, Throwable ex );
-
-    }
-
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java
new file mode 100644
index 0000000..2d88d28
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/DeactivateMethod.java
@@ -0,0 +1,45 @@
+/*
+ * 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.impl.helper;
+
+
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+
+
+public class DeactivateMethod extends ActivateMethod
+{
+
+    public DeactivateMethod( final AbstractComponentManager componentManager, String methodName, Class componentClass )
+    {
+        super( componentManager, methodName, componentClass );
+    }
+
+
+    protected Class[] getAcceptedParameterTypes()
+    {
+        if ( isDS11() )
+        {
+            return new Class[]
+                { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS, Integer.TYPE, INTEGER_CLASS };
+        }
+
+        return new Class[]
+            { COMPONENT_CONTEXT_CLASS };
+    }
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/MethodNameException.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ModifiedMethod.java
similarity index 66%
rename from scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/MethodNameException.java
rename to scr/src/main/java/org/apache/felix/scr/impl/helper/ModifiedMethod.java
index 8745490..3e954f1 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/MethodNameException.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ModifiedMethod.java
@@ -16,17 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scr.impl.metadata.instances;
+package org.apache.felix.scr.impl.helper;
 
 
-public final class MethodNameException extends RuntimeException
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+
+
+public class ModifiedMethod extends ActivateMethod
 {
 
-    private static final long serialVersionUID = 1L;
-
-
-    public MethodNameException( String message )
+    public ModifiedMethod( final AbstractComponentManager componentManager, String methodName, Class componentClass )
     {
-        super( message );
+        super( componentManager, methodName, componentClass );
+    }
+
+
+    protected boolean acceptEmpty()
+    {
+        return false;
     }
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java
deleted file mode 100644
index 9bdf532..0000000
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * 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.impl.helper;
-
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.component.ComponentContext;
-
-
-/**
- * The <code>ReflectionHelper</code> class provides utility methods to find out
- * about binding and activation methods in components.
- */
-public final class ReflectionHelper
-{
-
-    // Method instance to implement tristate behaviour on method fields:
-    // unchecked (SENTINEL), no method (null), valid method (method object)
-    public static final Method SENTINEL;
-
-    // class references to simplify parameter checking
-    public static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class;
-    public static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class;
-    public static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class;
-    public static final Class MAP_CLASS = Map.class;
-    public static final Class INTEGER_CLASS = Integer.class;
-
-    // Helper used to find the best matching activate and modified methods (DS 1.1 and newer)
-    public static final MethodTester ACTIVATE_ACCEPTED_PARAMETERS = new ActivatorMethodTester( new Class[]
-        { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS } );
-
-    // Helper used to find the best matching deactivate method (DS 1.1 and newer)
-    public static final MethodTester DEACTIVATE_ACCEPTED_PARAMETERS = new ActivatorMethodTester( new Class[]
-        { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS, Integer.TYPE, INTEGER_CLASS } );
-
-    // Helper used to find the best matching activate/deactivate method (DS 1.0)
-    public static final MethodTester ACTIVATOR_10_ACCEPTED_PARAMETERS = new ActivatorMethodTester10();
-
-    static
-    {
-        Method tmpSentinel = null;
-        try
-        {
-            tmpSentinel = ReflectionHelper.class.getDeclaredMethod( "sentinel", null );
-        }
-        catch ( Throwable t )
-        {
-            // don't care for the reason
-        }
-
-        SENTINEL = tmpSentinel;
-    }
-
-
-    // sentinel method used to assign to the SENTINEL field
-    private static final void sentinel()
-    {
-    }
-
-
-    /**
-     * Finds the named public or protected method in the given class or any
-     * super class. If such a method is found, its accessibility is enfored by
-     * calling the <code>Method.setAccessible</code> method if required and
-     * the method is returned. Enforcing accessibility is required to support
-     * invocation of protected methods.
-     *
-     * @param objectClass The <code>Class</code> at which to start looking for
-     *      a matching method
-     * @param name The name of the method.
-     * @param parameterTypes The list of suitable parmameters. Each class is
-     *      is asked for a declared method of the given name with parameters
-     *      from this list.
-     * @param only Whether to only look at the declared methods of the given
-     *      class or also inspect the super classes.
-     *
-     * @return The named method with enforced accessibility
-     *
-     * @throws NoSuchMethodException If no public or protected method with
-     *      the given name can be found in the class or any of its super classes.
-     * @throws InvocationTargetException If an unexpected Throwable is caught
-     *      trying to access the desired method.
-     */
-    public static Method getMethod( final Class objectClass, final String name, final MethodTester tester )
-        throws NoSuchMethodException, InvocationTargetException
-    {
-        // whether we accept package private methods
-        boolean acceptPackage = tester.acceptPackage();
-        final String packageName = getPackageName( objectClass );
-        final Class[] parameterTypesList = tester.getParameterLists();
-
-        // flag indicating a suitable but inaccessible method has been found
-        boolean suitableMethodNotAccessible = false;
-
-        // lookup methods until there is no more super class or a class would
-        // have at least one suitable method but none is accessible
-        for ( Class clazz = objectClass; clazz != null && !suitableMethodNotAccessible; clazz = clazz.getSuperclass() )
-        {
-            // turns false on first package not equal to the package of objectClass (or different class loader)
-            acceptPackage &= packageName.equals( getPackageName( clazz ) )
-                && clazz.getClassLoader() == objectClass.getClassLoader();
-            final boolean acceptPrivate = tester.acceptPrivate() && clazz == objectClass;
-
-
-            // check parameter types first
-            for ( int i = 0; i < parameterTypesList.length; i++ )
-            {
-                Class[] parameterTypes = new Class[]
-                    { parameterTypesList[i] };
-
-                try
-                {
-                    // find the declared method in this class
-                    return getMethod( clazz, name, parameterTypes, acceptPrivate, acceptPackage );
-                }
-                catch ( NoSuchMethodException nsme )
-                {
-                    // ignore for now
-                }
-                catch ( SuitableMethodNotAccessibleException smnae )
-                {
-                    suitableMethodNotAccessible = true;
-                }
-                catch ( Throwable throwable )
-                {
-                    // unexpected problem accessing the method, don't let everything
-                    // blow up in this situation, just throw a declared exception
-                    throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
-                }
-            }
-
-            // check methods with MethodTester
-            Method[] methods = clazz.getDeclaredMethods();
-            for ( int i = 0; i < methods.length; i++ )
-            {
-                if ( methods[i].getName().equals( name ) && tester.isSuitable( methods[i] ) )
-                {
-                    if ( accept( methods[i], acceptPrivate, acceptPackage ) )
-                    {
-                        // check modifiers etc.
-                        return methods[i];
-                    }
-
-                    // method is suitable but not accessible, flag it
-                    suitableMethodNotAccessible = true;
-                }
-            }
-
-            // finally check method with no arguments
-            if ( tester.acceptEmpty() )
-            {
-                try
-                {
-                    // find the declared method in this class
-                    return getMethod( clazz, name, null, acceptPrivate, acceptPackage );
-                }
-                catch ( NoSuchMethodException nsme )
-                {
-                    // ignore for now
-                }
-                catch ( SuitableMethodNotAccessibleException smnae )
-                {
-                    suitableMethodNotAccessible = true;
-                }
-                catch ( Throwable throwable )
-                {
-                    // unexpected problem accessing the method, don't let everything
-                    // blow up in this situation, just throw a declared exception
-                    throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
-                }
-            }
-        }
-
-        // walked up the complete super class hierarchy and still not found
-        // anything, sigh ...
-        throw new NoSuchMethodException( name );
-    }
-
-
-    /**
-     * Finds the named public or protected method in the given class or any
-     * super class. If such a method is found, its accessibility is enfored by
-     * calling the <code>Method.setAccessible</code> method if required and
-     * the method is returned. Enforcing accessibility is required to support
-     * invocation of protected methods.
-     *
-     * @param clazz The <code>Class</code> which provides the method.
-     * @param name The name of the method.
-     * @param parameterTypes The parameters to the method. Passing
-     *      <code>null</code> is equivalent to using an empty array.
-     *
-     * @return The named method with enforced accessibility
-     *
-     * @throws NoSuchMethodException If no public or protected method with
-     *      the given name can be found in the class or any of its super classes.
-     * @throws SuitableMethodNotAccessibleException If method with the given
-     *      name taking the parameters is found in the class but the method
-     *      is not accessible.
-     * @throws InvocationTargetException If an unexpected Throwable is caught
-     *      trying to access the desired method.
-     */
-    public static Method getMethod( Class clazz, String name, Class[] parameterTypes, boolean acceptPrivate,
-        boolean acceptPackage ) throws NoSuchMethodException, SuitableMethodNotAccessibleException,
-        InvocationTargetException
-    {
-        try
-        {
-            // find the declared method in this class
-            Method method = clazz.getDeclaredMethod( name, parameterTypes );
-
-            // accept public and protected methods only and ensure accessibility
-            if ( accept( method, acceptPrivate, acceptPackage ) )
-            {
-                return method;
-            }
-        }
-        catch ( NoSuchMethodException nsme )
-        {
-            // forward to caller
-            throw nsme;
-        }
-        catch ( Throwable throwable )
-        {
-            // unexpected problem accessing the method, don't let everything
-            // blow up in this situation, just throw a declared exception
-            throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
-        }
-
-        // suitable method found which is not accessible
-        throw new SuitableMethodNotAccessibleException();
-    }
-
-
-    /**
-     * Returns <code>true</code> if the method is acceptable to be returned from the
-     * {@link #getMethod(Class, String, Class[], boolean, boolean)} and also
-     * makes the method accessible.
-     * <p>
-     * This method returns <code>true</code> iff:
-     * <ul>
-     * <li>The method has <code>void</code> return type</li>
-     * <li>Is not static</li>
-     * <li>Is public or protected</li>
-     * <li>Is private and <code>acceptPrivate</code> is <code>true</code></li>
-     * <li>Is package private and <code>acceptPackage</code> is <code>true</code></li>
-     * </ul>
-     * <p>
-     * This method is package private for unit testing purposes. It is not
-     * meant to be called from client code.
-     *
-     * @param method The method to check
-     * @param acceptPrivate Whether a private method is acceptable
-     * @param acceptPackage Whether a package private method is acceptable
-     * @return
-     */
-    public static boolean accept( Method method, boolean acceptPrivate, boolean acceptPackage )
-    {
-        // method must be void
-        if ( Void.TYPE != method.getReturnType() )
-        {
-            return false;
-        }
-
-        // check modifiers now
-        int mod = method.getModifiers();
-
-        // no static method
-        if ( Modifier.isStatic( mod ) )
-        {
-            return false;
-        }
-
-        // accept public and protected methods
-        if ( Modifier.isPublic( mod ) || Modifier.isProtected( mod ) )
-        {
-            method.setAccessible( true );
-            return true;
-        }
-
-        // accept private if accepted
-        if ( Modifier.isPrivate( mod ) )
-        {
-            if ( acceptPrivate )
-            {
-                method.setAccessible( acceptPrivate );
-                return true;
-            }
-
-            return false;
-        }
-
-        // accept default (package)
-        if ( acceptPackage )
-        {
-            method.setAccessible( true );
-            return true;
-        }
-
-        // else don't accept
-        return false;
-    }
-
-
-    /**
-     * Returns the name of the package to which the class belongs or an
-     * empty string if the class is in the default package.
-     */
-    public static String getPackageName( Class clazz )
-    {
-        String name = clazz.getName();
-        int dot = name.lastIndexOf( '.' );
-        return ( dot > 0 ) ? name.substring( 0, dot ) : "";
-    }
-
-    //---------- inner classes
-
-    public static interface MethodTester
-    {
-
-        /**
-         * Returns <code>true</code> if methods without arguments are acceptable.
-         */
-        boolean acceptEmpty();
-
-        /**
-         * Returns <code>true</code> if private methods are allowed at all.
-         */
-        boolean acceptPrivate();
-
-        /**
-         * Returns <code>true</code> if package private methods are allowed at all.
-         */
-        boolean acceptPackage();
-
-        /**
-         * Returns <code>true</code> if the method <code>m</code> is suitable for
-         * this tester.
-         */
-        boolean isSuitable( Method m );
-
-
-        /**
-         * Returns an array of parameters which are acceptable as single parameter
-         * arguments to methods.
-         */
-        Class[] getParameterLists();
-    }
-
-    /**
-     * The <code>ActivatorMethodTester</code> class implements the {@link MethodTester}
-     * interface to test methods applicable for Components declared with the
-     * SCR 1.1 (or newer) specification namespace.
-     */
-    public static final class ActivatorMethodTester implements ReflectionHelper.MethodTester
-    {
-        private final Class[] parameterLists;
-        private final Set methods;
-
-
-        ActivatorMethodTester( Class[] acceptedParameters )
-        {
-            parameterLists = acceptedParameters;
-            methods = new HashSet();
-            methods.addAll( Arrays.asList( acceptedParameters ) );
-        }
-
-
-        public boolean acceptEmpty()
-        {
-            return true;
-        }
-
-
-        public boolean acceptPrivate()
-        {
-            return true;
-        }
-
-
-        public boolean acceptPackage()
-        {
-            return true;
-        }
-
-
-        public boolean isSuitable( Method m )
-        {
-            Class[] types = m.getParameterTypes();
-
-            // require two or more arguments
-            if ( types.length < 2 )
-            {
-                return false;
-            }
-
-            // check for argument types
-            for ( int i = 0; i < types.length; i++ )
-            {
-                if ( !methods.contains( types[i] ) )
-                {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-
-        public Class[] getParameterLists()
-        {
-            return parameterLists;
-        }
-
-    }
-
-
-    /**
-     * The <code>ActivatorMethodTester10</code> class implements the
-     * {@link MethodTester} interface to test methods applicable for Components
-     * declared with the original SCR 1.0 specification namespace.
-     */
-    public static final class ActivatorMethodTester10 implements ReflectionHelper.MethodTester
-    {
-
-        private static final Class[] PARAMETER_LIST =
-            { COMPONENT_CONTEXT_CLASS };
-
-
-        public boolean acceptEmpty()
-        {
-            // DS 1.0 activator methods only accept ComponentContext
-            return false;
-        }
-
-
-        public boolean acceptPrivate()
-        {
-            // DS 1.0 activator methods may only be public or protected
-            return true;
-        }
-
-
-        public boolean acceptPackage()
-        {
-            // DS 1.0 activator methods may only be public or protected
-            return true;
-        }
-
-
-        public boolean isSuitable( Method m )
-        {
-            // DS 1.0 activator methods only accept ComponentContext
-            Class[] types = m.getParameterTypes();
-            return types.length == 1 && types[0] == COMPONENT_CONTEXT_CLASS;
-        }
-
-
-        public Class[] getParameterLists()
-        {
-            return PARAMETER_LIST;
-        }
-    }
-
-}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
similarity index 68%
rename from scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java
rename to scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
index e091f4e..1b5ea93 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/UnbindMethod.java
@@ -16,19 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scr.impl.manager;
+package org.apache.felix.scr.impl.helper;
+
+
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
 
 
 /**
  * Component method to be invoked on service unbinding.
  */
-class UnbindMethod extends BindMethod
+public class UnbindMethod extends BindMethod
 {
 
-    UnbindMethod( final boolean isDS11, final String methodName, final Class componentClass,
-        final String referenceName, final String referenceClassName, final Logger logger )
+    public UnbindMethod( final AbstractComponentManager componentManager, final String methodName,
+        final Class componentClass, final String referenceName, final String referenceClassName )
     {
-        super( isDS11, methodName, componentClass, referenceName, referenceClassName, logger );
+        super( componentManager, methodName, componentClass, referenceName, referenceClassName );
     }
 
 
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 afca9fc..4015d08 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
@@ -774,7 +774,7 @@
     }
 
 
-    void log( int level, String message, ComponentMetadata metadata, Throwable ex )
+    public void log( int level, String message, ComponentMetadata metadata, Throwable ex )
     {
         BundleComponentActivator activator = getActivator();
         if ( activator != 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 0328fc5..14c7174 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
@@ -27,6 +27,8 @@
 import java.util.Map;
 
 import org.apache.felix.scr.Reference;
+import org.apache.felix.scr.impl.helper.BindMethod;
+import org.apache.felix.scr.impl.helper.UnbindMethod;
 import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -115,32 +117,17 @@
      */
     private void initBindingMethods()
     {
-        BindMethod.Logger logger = new BindMethod.Logger()
-        {
-
-            public void log( int level, String message )
-            {
-                log( level, message, null );
-            }
-
-            public void log( int level, String message, Throwable ex )
-            {
-                m_componentManager.log( level, message, m_componentManager.getComponentMetadata(), ex );
-            }
-        };
-        m_bind = new BindMethod( m_componentManager.getComponentMetadata().isDS11(),
+        m_bind = new BindMethod( m_componentManager,
                                  m_dependencyMetadata.getBind(),
                                  m_componentInstance.getClass(),
                                  m_dependencyMetadata.getName(),
-                                 m_dependencyMetadata.getInterface(),
-                                 logger
+                                 m_dependencyMetadata.getInterface()
         );
-        m_unbind = new UnbindMethod( m_componentManager.getComponentMetadata().isDS11(),
+        m_unbind = new UnbindMethod( m_componentManager,
                                      m_dependencyMetadata.getUnbind(),
                                      m_componentInstance.getClass(),
                                      m_dependencyMetadata.getName(),
-                                     m_dependencyMetadata.getInterface(),
-                                     logger
+                                     m_dependencyMetadata.getInterface()
         );
     }
 
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 3b2a17e..bcd5d4a 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
@@ -19,14 +19,14 @@
 package org.apache.felix.scr.impl.manager;
 
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.Dictionary;
 import java.util.Iterator;
 import java.util.List;
 
 import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.helper.ReflectionHelper;
+import org.apache.felix.scr.impl.helper.ActivateMethod;
+import org.apache.felix.scr.impl.helper.DeactivateMethod;
+import org.apache.felix.scr.impl.helper.ModifiedMethod;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
 import org.osgi.framework.ServiceRegistration;
@@ -49,13 +49,13 @@
     private ComponentContext m_componentContext;
 
     // the activate method
-    private Method activateMethod = ReflectionHelper.SENTINEL;
+    private ActivateMethod m_activateMethod;
 
     // the deactivate method
-    private Method deactivateMethod = ReflectionHelper.SENTINEL;
+    private DeactivateMethod m_deactivateMethod;
 
     // the modify method
-    private Method modifyMethod = ReflectionHelper.SENTINEL;
+    private ModifiedMethod m_modifyMethod;
 
     // optional properties provided in the ComponentFactory.newInstance method
     private Dictionary m_factoryProperties;
@@ -139,7 +139,8 @@
 
     protected Object createImplementationObject( ComponentContext componentContext )
     {
-        Object implementationObject;
+        final Class implementationObjectClass;
+        final Object implementationObject;
 
         // 1. Load the component implementation class
         // 2. Create the component instance and component context
@@ -147,12 +148,12 @@
         try
         {
             // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
-            Class c = getActivator().getBundleContext().getBundle().loadClass(
+            implementationObjectClass = getActivator().getBundleContext().getBundle().loadClass(
                 getComponentMetadata().getImplementationClassName() );
 
             // 112.4.4 The class must be public and have a public constructor without arguments so component instances
             // may be created by the SCR with the newInstance method on Class
-            implementationObject = c.newInstance();
+            implementationObject = implementationObjectClass.newInstance();
         }
         catch ( Exception ex )
         {
@@ -188,23 +189,14 @@
         }
 
         // get the method
-        if ( activateMethod == ReflectionHelper.SENTINEL )
+        if ( m_activateMethod == null)
         {
-            // FELIX-1437: New signatures only with DS 1.1 namespace declaration
-            if ( getComponentMetadata().isDS11() )
-            {
-                activateMethod = getMethod( implementationObject, getComponentMetadata().getActivate(),
-                    ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
-            }
-            else
-            {
-                activateMethod = getMethod( implementationObject, getComponentMetadata().getActivate(),
-                    ReflectionHelper.ACTIVATOR_10_ACCEPTED_PARAMETERS );
-            }
+            m_activateMethod = new ActivateMethod( this, getComponentMetadata().getActivate(), implementationObjectClass );
         }
 
         // 4. Call the activate method, if present
-        if ( activateMethod != null && !invokeMethod( activateMethod, implementationObject, componentContext, -1 ) )
+        if ( !m_activateMethod.invoke( implementationObject,
+            new ActivateMethod.ActivatorParameter( componentContext, 1 ) ) )
         {
             // 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
@@ -215,7 +207,7 @@
                 dm.close();
             }
 
-            implementationObject = null;
+            return null;
         }
 
         return implementationObject;
@@ -227,29 +219,18 @@
     {
 
         // get the method
-        if ( deactivateMethod == ReflectionHelper.SENTINEL )
+        if ( m_deactivateMethod == null )
         {
-            // FELIX-1437: New signatures only with DS 1.1 namespace declaration
-            if ( getComponentMetadata().isDS11() )
-            {
-                deactivateMethod = getMethod( implementationObject, getComponentMetadata().getDeactivate(),
-                    ReflectionHelper.DEACTIVATE_ACCEPTED_PARAMETERS );
-            }
-            else
-            {
-                deactivateMethod = getMethod( implementationObject, getComponentMetadata().getDeactivate(),
-                    ReflectionHelper.ACTIVATOR_10_ACCEPTED_PARAMETERS );
-            }
+            m_deactivateMethod = new DeactivateMethod( this, getComponentMetadata().getDeactivate(), implementationObject
+                .getClass() );
         }
 
         // 1. Call the deactivate method, if present
         // don't care for the result, the error (acccording to 112.5.12 If the deactivate
         // method throws an exception, SCR must log an error message containing the
         // exception with the Log Service and continue) has already been logged
-        if ( deactivateMethod != null )
-        {
-            invokeMethod( deactivateMethod, implementationObject, componentContext, reason );
-        }
+        m_deactivateMethod.invoke( implementationObject, new ActivateMethod.ActivatorParameter( componentContext,
+            reason ) );
 
         // 2. Unbind any bound services
         Iterator it = getDependencyManagers();
@@ -410,13 +391,9 @@
         // invariant: we have a modified method name
 
         // 2. get and check configured method
-        Method modifyMethod = getModifyMethod();
-        if ( modifyMethod == null )
+        if ( m_modifyMethod == null )
         {
-            // log an error if the declared method cannot be found
-            log( LogService.LOG_ERROR, "Declared modify method '" + getComponentMetadata().getModified()
-                + "' cannot be found, configuring by reactivation", getComponentMetadata(), null );
-            return false;
+            m_modifyMethod = new ModifiedMethod( this, getComponentMetadata().getModified(), getInstance().getClass() );
         }
         // invariant: modify method is configured and found
 
@@ -438,7 +415,13 @@
         // invariant: modify method existing and no static bound service changes
 
         // 4. call method (nothing to do when failed, since it has already been logged)
-        invokeMethod( modifyMethod, m_implementationObject, m_componentContext, -1 );
+        if ( !m_modifyMethod.invoke( getInstance(), new ActivateMethod.ActivatorParameter( m_componentContext, -1 ) ) )
+        {
+            // log an error if the declared method cannot be found
+            log( LogService.LOG_ERROR, "Declared modify method '" + getComponentMetadata().getModified()
+                + "' cannot be found, configuring by reactivation", getComponentMetadata(), null );
+            return false;
+        }
 
         // 5. update the target filter on the services now, this may still
         // result in unsatisfied dependencies, in which case we abort
@@ -481,139 +464,4 @@
         // 7. everything set and done, the component has been udpated
         return true;
     }
-
-
-    /**
-     * Returns the configured modify method or <code>null</code> if the
-     * configured method cannot be found.
-     */
-    private Method getModifyMethod()
-    {
-        // ensure the method object is known
-        if ( modifyMethod == ReflectionHelper.SENTINEL )
-        {
-            modifyMethod = getMethod( m_implementationObject, getComponentMetadata().getModified(),
-                ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
-        }
-
-        return modifyMethod;
-    }
-
-
-    /**
-     * Find the method with the given name in the class hierarchy of the
-     * implementation object's class. This method looks for methods which have
-     * one of the parameter lists of the {@link #ACTIVATE_PARAMETER_LIST} array.
-     *
-     * @param implementationObject The object whose class (and its super classes)
-     *      may provide the method
-     * @param methodName Name of the method to look for
-     * @param methodTester The {@link ReflectionHelper.MethodTester} instance
-     *      used to select the actual method.
-     * @return The named method or <code>null</code> if no such method is available.
-     */
-    private Method getMethod( final Object implementationObject, final String methodName,
-        final ReflectionHelper.MethodTester methodTester )
-    {
-        try
-        {
-            return ReflectionHelper.getMethod( implementationObject.getClass(), methodName, methodTester );
-        }
-        catch ( InvocationTargetException ite )
-        {
-            // We can safely ignore this one
-            log( LogService.LOG_WARNING, methodName + " cannot be found", getComponentMetadata(), ite
-                .getTargetException() );
-        }
-        catch ( NoSuchMethodException ex )
-        {
-            // We can safely ignore this one
-            log( LogService.LOG_DEBUG, methodName + " method is not implemented", getComponentMetadata(), null );
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Invokes the given method on the <code>implementationObject</code> using
-     * the <code>componentContext</code> as the base to create method argument
-     * list.
-     *
-     * @param method The method to call. This method must already have been
-     *      made accessible by calling
-     *      <code>Method.setAccessible(boolean)</code>.
-     * @param implementationObject The object on which to call the method.
-     * @param componentContext The <code>ComponentContext</code> used to
-     *      build the argument list
-     * @param reason The deactivation reason code. This should be one of the
-     *      values in the {@link ComponentConstants} interface. This parameter
-     *      is only of practical use for calling deactivate methods, which may
-     *      take a numeric argument indicating the deactivation reason.
-     *
-     * @return <code>true</code> if the method should be considered invoked
-     *      successfully. <code>false</code> is returned if the method threw
-     *      an exception.
-     *
-     * @throws NullPointerException if any of the parameters is <code>null</code>.
-     */
-    private boolean invokeMethod( final Method method, final Object implementationObject,
-        final ComponentContext componentContext, int reason )
-    {
-        final String methodName = method.getName();
-        try
-        {
-            // build argument list
-            Class[] paramTypes = method.getParameterTypes();
-            Object[] param = new Object[paramTypes.length];
-            for ( int i = 0; i < param.length; i++ )
-            {
-                if ( paramTypes[i] == ReflectionHelper.COMPONENT_CONTEXT_CLASS )
-                {
-                    param[i] = componentContext;
-                }
-                else if ( paramTypes[i] == ReflectionHelper.BUNDLE_CONTEXT_CLASS )
-                {
-                    param[i] = componentContext.getBundleContext();
-                }
-                else if ( paramTypes[i] == ReflectionHelper.MAP_CLASS )
-                {
-                    // note: getProperties() returns a ReadOnlyDictionary which is a Map
-                    param[i] = componentContext.getProperties();
-                }
-                else if ( paramTypes[i] == ReflectionHelper.INTEGER_CLASS || paramTypes[i] == Integer.TYPE)
-                {
-                    param[i] = new Integer(reason);
-                }
-            }
-
-            method.invoke( implementationObject, param );
-        }
-        catch ( IllegalAccessException ex )
-        {
-            // Ignored, but should it be logged?
-            log( LogService.LOG_DEBUG, methodName + " method cannot be called", getComponentMetadata(), null );
-        }
-        catch ( InvocationTargetException ex )
-        {
-            // 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
-            log( LogService.LOG_ERROR, "The " + methodName + " method has thrown an exception", getComponentMetadata(),
-                ex.getCause() );
-
-            // method threw, so it was a failure
-            return false;
-        }
-        catch ( Throwable t )
-        {
-            // anything else went wrong, log the message and fail the invocation
-            log( LogService.LOG_ERROR, "The " + methodName + " method could not be called", getComponentMetadata(), t );
-
-            // method invocation threw, so it was a failure
-            return false;
-        }
-
-        // assume success (also if the method is not available or accessible)
-        return true;
-    }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
similarity index 74%
rename from scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java
rename to scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
index e9212b5..bc7faa8 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/ActivateMethodTest.java
@@ -19,25 +19,30 @@
 package org.apache.felix.scr.impl.helper;
 
 
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
 
-import org.apache.felix.scr.impl.helper.ReflectionHelper;
+import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.apache.felix.scr.impl.metadata.instances.AcceptMethod;
 import org.apache.felix.scr.impl.metadata.instances.BaseObject;
 import org.apache.felix.scr.impl.metadata.instances.Level1Object;
 import org.apache.felix.scr.impl.metadata.instances.Level3Object;
-import org.apache.felix.scr.impl.metadata.instances.MethodNameException;
 import org.apache.felix.scr.impl.metadata.instances2.Level2Object;
+import org.easymock.EasyMock;
+import org.osgi.service.component.ComponentContext;
 
 
-public class ReflectionHelperTest extends TestCase
+public class ActivateMethodTest extends TestCase
 {
 
     private static final Class ACCEPT_METHOD_CLASS = AcceptMethod.class;
 
+    private ComponentContext m_ctx;
+
     BaseObject base = new BaseObject();
 
     Level1Object level1 = new Level1Object();
@@ -46,10 +51,15 @@
 
     Level3Object level3 = new Level3Object();
 
-
-    public void test_sentinel() throws Exception
+    protected void setUp() throws Exception
     {
-        assertNotNull( "Sentinel is null", ReflectionHelper.SENTINEL );
+        super.setUp();
+
+        m_ctx = ( ComponentContext ) EasyMock.createNiceMock( ComponentContext.class );
+        EasyMock.expect( m_ctx.getProperties() ).andReturn( new Hashtable() ).anyTimes();
+        EasyMock.replay( new Object[]
+            { m_ctx } );
+
     }
 
 
@@ -138,9 +148,9 @@
     public void test_getPackage() throws Exception
     {
         Class dpc = getClass().getClassLoader().loadClass( "DefaultPackageClass" );
-        assertEquals( "", ReflectionHelper.getPackageName( dpc ) );
+        assertEquals( "", BaseMethod.getPackageName( dpc ) );
 
-        assertEquals( "org.apache.felix.scr.impl.metadata.instances", ReflectionHelper.getPackageName( base.getClass() ) );
+        assertEquals( "org.apache.felix.scr.impl.metadata.instances", BaseMethod.getPackageName( base.getClass() ) );
     }
 
 
@@ -195,13 +205,7 @@
 
         // this must fail to find a method, since Level2Object's activate_suitable
         // is private and terminates the search for Level3Object
-        try {
-            checkMethod( level3, "activate_suitable" );
-            fail("Level3Object must not find activate_suitable method");
-        } catch (NoSuchMethodException nsme) {
-            // expecting method lookup abort on suitable private
-            // method in Level2Object class
-        }
+        ensureMethodNotFoundMethod( level3, "activate_suitable" );
     }
 
 
@@ -215,22 +219,22 @@
      * @param obj
      * @param methodName
      */
-    private void checkMethod( Object obj, String methodName ) throws NoSuchMethodException, InvocationTargetException,
-        IllegalAccessException
+    private void checkMethod( BaseObject obj, String methodName )
     {
-        Method method = ReflectionHelper.getMethod( obj.getClass(), methodName,
-            ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
-        try
+        ComponentMetadata metadata = new ComponentMetadata( 0 )
         {
-            method.invoke( obj, new Object[method.getParameterTypes().length] );
-            fail( "Expected MethodNameException being thrown" );
-        }
-        catch ( InvocationTargetException ite )
-        {
-            Throwable target = ite.getTargetException();
-            assertTrue( "Expected MethodNameException", target instanceof MethodNameException );
-            assertEquals( methodName, target.getMessage() );
-        }
+            public boolean isDS11()
+            {
+                return true;
+            }
+        };
+        ImmediateComponentManager icm = new ImmediateComponentManager( null, metadata );
+        ActivateMethod am = new ActivateMethod( icm, methodName, obj.getClass() );
+        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ) );
+        Method m = get(am, "m_method");
+        assertNotNull( m );
+        assertEquals( methodName, m.getName() );
+        assertEquals( methodName, obj.getCalledMethod() );
     }
 
 
@@ -243,18 +247,20 @@
      * @throws InvocationTargetException
      * @throws IllegalAccessException
      */
-    private void ensureMethodNotFoundMethod( Object obj, String methodName ) throws InvocationTargetException,
-        IllegalAccessException
+    private void ensureMethodNotFoundMethod( BaseObject obj, String methodName )
     {
-        try
+        ComponentMetadata metadata = new ComponentMetadata( 0 )
         {
-            checkMethod( obj, methodName );
-            fail( "Expected to not find method " + methodName + " for " + obj.getClass() );
-        }
-        catch ( NoSuchMethodException nsme )
-        {
-            // expected not to find a method
-        }
+            public boolean isDS11()
+            {
+                return true;
+            }
+        };
+        ImmediateComponentManager icm = new ImmediateComponentManager( null, metadata );
+        ActivateMethod am = new ActivateMethod( icm, methodName, obj.getClass() );
+        am.invoke( obj, new ActivateMethod.ActivatorParameter( m_ctx, -1 ) );
+        assertNull( get( am, "m_method" ) );
+        assertNull( obj.getCalledMethod() );
     }
 
 
@@ -262,7 +268,30 @@
         throws NoSuchMethodException
     {
         Method method = ACCEPT_METHOD_CLASS.getDeclaredMethod( methodName, null );
-        boolean accepted = ReflectionHelper.accept( method, acceptPrivate, acceptPackage );
+        boolean accepted = BaseMethod.accept( method, acceptPrivate, acceptPackage );
         assertEquals( expected, accepted );
     }
+
+
+    private static Method get( final BaseMethod baseMethod, final String fieldName )
+    {
+        try
+        {
+            Field field = BaseMethod.class.getDeclaredField( fieldName );
+            field.setAccessible( true );
+            Object value = field.get( baseMethod );
+            if ( value == null || value instanceof Method )
+            {
+                return ( Method ) value;
+            }
+            fail( "Field " + field + " is not of type Method" );
+        }
+        catch ( Throwable t )
+        {
+            fail( "Failure accessing field " + fieldName + " in " + baseMethod + ": " + t );
+        }
+
+        // Compiler does not know about fail()
+        return null;
+    }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
similarity index 94%
rename from scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java
rename to scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
index 6d4ae02..e09ef07 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
@@ -16,16 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.felix.scr.impl.manager;
+package org.apache.felix.scr.impl.helper;
 
 
 import junit.framework.TestCase;
 
+import org.apache.felix.scr.impl.helper.BindMethod;
+import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
 import org.apache.felix.scr.impl.manager.components.FakeService;
 import org.apache.felix.scr.impl.manager.components.T1;
 import org.apache.felix.scr.impl.manager.components.T1a;
 import org.apache.felix.scr.impl.manager.components.T3;
 import org.apache.felix.scr.impl.manager.components2.T2;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.easymock.EasyMock;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
@@ -431,33 +434,15 @@
     private void testMethod( final String methodName, final T1 component, final boolean isDS11,
         final String expectCallPerformed )
     {
-        BindMethod bm = new BindMethod( isDS11, methodName, component.getClass(), "reference", FakeService.class
-            .getName(), new SysOutLogger() );
+        ComponentMetadata metadata = new ComponentMetadata( 0 ) {
+            public boolean isDS11() {
+                return isDS11;
+            }
+        };
+        ImmediateComponentManager icm = new ImmediateComponentManager( null, metadata );
+        BindMethod bm = new BindMethod( icm, methodName, component.getClass(), "reference",
+            FakeService.class.getName() );
         bm.invoke( component, m_service );
         assertEquals( expectCallPerformed, component.callPerformed );
     }
-
-    private static class SysOutLogger implements BindMethod.Logger
-    {
-
-        private static final String[] LEVELS = new String[]
-            { "ERROR", "WARNING", "INFO", "DEBUG" };
-
-
-        public void log( int level, String message )
-        {
-            log( level, message, null );
-        }
-
-
-        public void log( int level, String message, Throwable ex )
-        {
-            System.out.println( LEVELS[level - 1] + " - " + message );
-            if ( ex != null )
-            {
-                System.out.println( ex.getClass().getName() + "-" + ex.getMessage() );
-            }
-        }
-    }
-
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
index 59fd9fa..7c8dd0f 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
@@ -31,26 +31,41 @@
 public class BaseObject
 {
 
+    private String m_calledMethod;
+
+
+    public String getCalledMethod()
+    {
+        String cm = m_calledMethod;
+        m_calledMethod = null;
+        return cm;
+    }
+
+
+    protected void setCalledMethod(String calledMethod) {
+        m_calledMethod = calledMethod;
+    }
+
     private void activate_no_arg()
     {
-        throw new MethodNameException( "activate_no_arg" );
+        setCalledMethod( "activate_no_arg" );
     }
 
 
     protected void activate_comp( ComponentContext ctx )
     {
-        throw new MethodNameException( "activate_comp" );
+        setCalledMethod( "activate_comp" );
     }
 
 
     void activate_comp_bundle( ComponentContext ctx, BundleContext bundle )
     {
-        throw new MethodNameException( "activate_comp_bundle" );
+        setCalledMethod( "activate_comp_bundle" );
     }
 
 
     protected void activate_suitable( ComponentContext ctx )
     {
-        throw new MethodNameException( "activate_suitable" );
+        setCalledMethod( "activate_suitable" );
     }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level1Object.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level1Object.java
index 4082b3e..199ca7f 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level1Object.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level1Object.java
@@ -29,13 +29,13 @@
 
     private void activate_level1_bundle( BundleContext ctx )
     {
-        throw new MethodNameException("activate_level1_bundle");
+        setCalledMethod("activate_level1_bundle");
     }
 
 
     protected void activate_level1_map( Map props )
     {
-        throw new MethodNameException("activate_level1_map");
+        setCalledMethod("activate_level1_map");
     }
 
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level3Object.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level3Object.java
index 72c3236..27efc6a 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level3Object.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/Level3Object.java
@@ -30,7 +30,7 @@
 
     private void activate_comp_map( ComponentContext ctx, Map map )
     {
-        throw new MethodNameException("activate_comp_map");
+        setCalledMethod("activate_comp_map");
     }
 
 
@@ -38,12 +38,12 @@
     // Map has higher precedence
     public void activate_collision()
     {
-        throw new MethodNameException("not_expected_to_be_found");
+        setCalledMethod("not_expected_to_be_found");
     }
 
 
     public void activate_collision( Map map )
     {
-        throw new MethodNameException("activate_collision");
+        setCalledMethod("activate_collision");
     }
 }
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
index 510f941..64a24ba 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
@@ -22,7 +22,6 @@
 import java.util.Map;
 
 import org.apache.felix.scr.impl.metadata.instances.Level1Object;
-import org.apache.felix.scr.impl.metadata.instances.MethodNameException;
 import org.osgi.service.component.ComponentContext;
 
 
@@ -31,7 +30,7 @@
 
     private void activate_comp_map( ComponentContext ctx, Map map )
     {
-        throw new MethodNameException( "activate_comp_map" );
+        setCalledMethod( "activate_comp_map" );
     }
 
 
@@ -39,18 +38,18 @@
     // Map has higher precedence
     public void activate_collision()
     {
-        throw new MethodNameException( "not_expected_to_be_found" );
+        setCalledMethod( "not_expected_to_be_found" );
     }
 
 
     public void activate_collision( Map map )
     {
-        throw new MethodNameException( "activate_collision" );
+        setCalledMethod( "activate_collision" );
     }
 
 
     private void activate_suitable( Map map )
     {
-        throw new MethodNameException( "activate_suitable" );
+        setCalledMethod( "activate_suitable" );
     }
 }