FELIX-4918 : Implement searching for event methods according to 112.3.2

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1684588 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
index b563283..d909be9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
@@ -84,19 +84,23 @@
      *      trying to find the requested method.
      */
     @Override
-    protected Method doFindMethod( Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
+    protected Method doFindMethod( final Class<?> targetClass, 
+    		final boolean acceptPrivate, 
+    		final boolean acceptPackage, 
+    		final SimpleLogger logger )
         throws SuitableMethodNotAccessibleException, InvocationTargetException
     {
-        /* 112.3.1 The method is searched for using the following priority
-         1 - ServiceReference single parameter
-         2 - ComponentServiceObjects single parameter (DS 1.3+ only)
-         3 - Service object single parameter
-         4 - Service interface assignment compatible single parameter
-         5 - two parameters, first the type of or assignment compatible with the service, the second Map (DS 1.1, 1.2 only)
-         6 - one or more parameters of types ServiceReference, ServiceObjects, interface type, or assignment compatible to interface type, in any order. (DS 1.3+ only)
-         */
+        // 112.3.1 The method is searched for using the following priority
+        //  1 - ServiceReference single parameter
+        //  2 - DS 1.3+ : ComponentServiceObjects single parameter
+        //  3 - Service object single parameter
+        //  4 - Service interface assignment compatible single parameter
+        //  5 - DS 1.3+ : Single argument with Map
+        //  6 - DS 1.1/DS 1.2 : two parameters, first the type of or assignment compatible with the service, the second Map
+        //  7 - DS 1.3+ : one or more parameters of types ServiceReference, ServiceObjects, interface type, 
+    	//                or assignment compatible to interface type, in any order.
 
-        // flag indicating a suitable but inaccessible method has been found
+    	// flag indicating a suitable but inaccessible method has been found
         boolean suitableMethodNotAccessible = false;
 
         if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
@@ -125,25 +129,28 @@
             suitableMethodNotAccessible = true;
         }
 
-        //case 2 ComponentServiceObjects parameter
-        try
+        // Case 2 - ComponentServiceObjects parameter
+        if ( getDSVersion().isDS13() )
         {
-            method = getComponentObjectsMethod( targetClass, acceptPrivate, acceptPackage, logger );
-            if ( method != null )
-            {
-                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
-                {
-                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
-                }
-                m_paramTypes = Collections.singletonList(ParamType.serviceObjects);
-                return method;
-            }
+	        try
+	        {
+	            method = getComponentObjectsMethod( targetClass, acceptPrivate, acceptPackage, logger );
+	            if ( method != null )
+	            {
+	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+	                {
+	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+	                }
+	                m_paramTypes = Collections.singletonList(ParamType.serviceObjects);
+	                return method;
+	            }
+	        }
+	        catch ( SuitableMethodNotAccessibleException ex )
+	        {
+	            suitableMethodNotAccessible = true;
+	        }
         }
-        catch ( SuitableMethodNotAccessibleException ex )
-        {
-            suitableMethodNotAccessible = true;
-        }
-
+        
         // for further methods we need the class of the service object
         final Class<?> parameterClass = ClassUtils.getClassFromComponentClassLoader( targetClass, m_referenceClassName, logger );
         if ( parameterClass != null )
@@ -157,13 +164,17 @@
                         + parameterClass.getName(), null );
             }
 
-            // Case 2 - Service object parameter
+            // Case 3 - Service object parameter
             try
             {
                 method = getServiceObjectMethod( targetClass, parameterClass, acceptPrivate, acceptPackage, logger );
                 if ( method != null )
                 {
-                    m_paramTypes = Collections.singletonList(ParamType.serviceType);
+	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+	                {
+	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+	                }
+	                m_paramTypes = Collections.singletonList(ParamType.serviceType);
                     return method;
                 }
             }
@@ -172,12 +183,16 @@
                 suitableMethodNotAccessible = true;
             }
 
-            // Case 3 - Service interface assignement compatible methods
+            // Case 4 - Service interface assignment compatible methods
             try
             {
                 method = getServiceObjectAssignableMethod( targetClass, parameterClass, acceptPrivate, acceptPackage, logger );
                 if ( method != null )
                 {
+	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+	                {
+	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+	                }
                     m_paramTypes = Collections.singletonList(ParamType.serviceType);
                     return method;
                 }
@@ -187,16 +202,42 @@
                 suitableMethodNotAccessible = true;
             }
 
+            // Case 5 - DS 1.3+ : Single argument with Map
+            if ( getDSVersion().isDS13() )
+            {
+                try
+                {
+                    method = getMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage, logger );
+                    if ( method != null )
+                    {
+    	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+    	                {
+    	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+    	                }
+                        m_paramTypes = Collections.singletonList(ParamType.map);
+                        return method;
+                    }
+                }
+                catch ( SuitableMethodNotAccessibleException ex )
+                {
+                    suitableMethodNotAccessible = true;
+                }            	
+            }
+            
             // signatures taking a map are only supported starting with DS 1.1
             if ( getDSVersion().isDS11() && !getDSVersion().isDS13() )
             {
 
-                // Case 4 - same as case 2, but + Map param (DS 1.1 only)
+                // Case 6 - same as case 3, but + Map param (DS 1.1 only)
                 try
                 {
                     method = getServiceObjectWithMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage, logger );
                     if ( method != null )
                     {
+    	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+    	                {
+    	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+    	                }
                         List<ParamType> paramTypes = new ArrayList<ParamType>(2);
                         paramTypes.add(ParamType.serviceType);
                         paramTypes.add(ParamType.map);
@@ -209,13 +250,17 @@
                     suitableMethodNotAccessible = true;
                 }
 
-                // Case 5 - same as case 3, but + Map param (DS 1.1 only)
+                // Case 6 - same as case 4, but + Map param (DS 1.1 only)
                 try
                 {
                     method = getServiceObjectAssignableWithMapMethod( targetClass, parameterClass, acceptPrivate,
                         acceptPackage );
                     if ( method != null )
                     {
+    	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+    	                {
+    	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
+    	                }
                         List<ParamType> paramTypes = new ArrayList<ParamType>(2);
                         paramTypes.add(ParamType.serviceType);
                         paramTypes.add(ParamType.map);
@@ -229,6 +274,7 @@
                 }
 
             }
+            // Case 7 - Multiple parameters
             if ( getDSVersion().isDS13() )
             {
                 for (Method m: targetClass.getDeclaredMethods())
@@ -289,6 +335,10 @@
                         {
                             if ( accept( m, acceptPrivate, acceptPackage, returnValue() ) )
                             {
+            	                if ( logger.isLogEnabled( LogService.LOG_DEBUG ) )
+            	                {
+            	                    logger.log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + m, null );
+            	                }
                                 m_paramTypes = paramTypes;
                                 return m;
                             }
@@ -349,13 +399,9 @@
     private Method getComponentObjectsMethod( final Class<?> targetClass, boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger )
         throws SuitableMethodNotAccessibleException, InvocationTargetException
     {
-        if ( m_referenceScope == ReferenceMetadata.ReferenceScope.prototype )
-        {
-            return getMethod(targetClass, getMethodName(),
-                new Class[] { ClassUtils.COMPONENTS_SERVICE_OBJECTS_CLASS }, acceptPrivate, acceptPackage,
-                logger);
-        }
-        return null;
+        return getMethod(targetClass, getMethodName(),
+            new Class[] { ClassUtils.COMPONENTS_SERVICE_OBJECTS_CLASS }, acceptPrivate, acceptPackage,
+            logger);
     }
 
 
@@ -567,6 +613,33 @@
         return null;
     }
 
+    /**
+     * Returns a method taking a single map parameter
+     * or <code>null</code> if no such method exists.
+     *
+     *
+     * @param targetClass The class in which to look for the method. Only this
+     *      class is searched 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.
+     * @param logger
+     * @return The requested method or <code>null</code> if no acceptable method
+     *      can be found in the target class.
+     * @throws SuitableMethodNotAccessibleException If a suitable method was
+     *      found which is not accessible
+     * @throws InvocationTargetException If an unexpected Throwable is caught
+     *      trying to find the requested method.
+     */
+    private Method getMapMethod( final Class<?> targetClass, final Class<?> parameterClass,
+            boolean acceptPrivate, boolean acceptPackage, SimpleLogger logger ) throws SuitableMethodNotAccessibleException,
+        InvocationTargetException
+    {
+        return getMethod( targetClass, getMethodName(), new Class[]
+            { ClassUtils.MAP_CLASS }, acceptPrivate, acceptPackage, logger );
+    }
+
     public <S, T> boolean getServiceObject( ComponentContextImpl<S> key, RefPair<S, T> refPair, BundleContext context, SimpleLogger logger )
     {
         //??? this resolves which we need.... better way?