Applied patch (FELIX-131) to fix lookup method and implement enable/disable
component method.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@440786 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
index d2eba74..2b79da7 100644
--- a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
@@ -16,27 +16,13 @@
  */

 package org.apache.felix.scr;

 

-import java.util.Dictionary;

-import java.util.ArrayList;

-import java.util.HashSet;

-import java.util.Iterator;

-import java.util.List;

-import java.util.Set;

+import java.lang.reflect.*;

+import java.util.*;

 

-import org.osgi.framework.Constants;

-import org.osgi.framework.ServiceFactory;

-import org.osgi.framework.ServiceRegistration;

-import org.osgi.framework.BundleContext;

-import org.osgi.framework.ServiceListener;

-import org.osgi.framework.ServiceEvent;

-import org.osgi.framework.ServiceReference;

-import org.osgi.framework.Bundle;

+import org.osgi.framework.*;

 import org.osgi.service.component.ComponentContext;

 import org.osgi.service.component.ComponentInstance;

 

-import java.lang.reflect.Method;

-import java.lang.reflect.InvocationTargetException;

-

 
 /**

  * The default ComponentManager. Objects of this class are responsible for managing

@@ -248,7 +234,7 @@
         {

             // Search for the activate method

         	try {

-        		Method activateMethod = m_implementationObject.getClass().getMethod("activate", new Class[]{ComponentContext.class});

+                Method activateMethod = getMethod(m_implementationObject.getClass(), "activate", new Class[]{ComponentContext.class});

         		activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});

         	}

         	catch(NoSuchMethodException ex) {        		

@@ -322,7 +308,7 @@
 			// is delayed and its service was never requested.

 			if(m_implementationObject != null)

 			{

-				Method activateMethod = m_implementationObject.getClass().getMethod("deactivate", new Class[]{ComponentContext.class});

+				Method activateMethod = getMethod(m_implementationObject.getClass(), "deactivate", new Class[]{ComponentContext.class});

 				activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});				

 			}

 		}

@@ -604,7 +590,7 @@
             try{

             	// Case 1

             	

-                method = targetClass.getMethod(methodname, new Class[]{ServiceReference.class});

+                method = getMethod(targetClass, methodname, new Class[]{ServiceReference.class});

                

                 m_bindUsesServiceReference = true;                

             }

@@ -617,35 +603,50 @@
             		

             		parameterClass = m_activator.getBundleContext().getBundle().loadClass(parameterClassName);

             		

-	                method = targetClass.getMethod(methodname, new Class[]{parameterClass});

+	                method = getMethod(targetClass, methodname, new Class[]{parameterClass});

             	}

-            	catch(NoSuchMethodException ex2) {

+                catch(NoSuchMethodException ex2) {

             		

-            		// Case 3

-            		method = null;

+                    // Case 3

+                    method = null;

             		

-            		// Get all potential bind methods

-            		Method candidateBindMethods[]  = targetClass.getMethods();

-            		

-            		// Iterate over them

-            		for(int i = 0; i < candidateBindMethods.length; i++) {

-            			Method currentMethod = candidateBindMethods[i];

-            			

-            			// Get the parameters for the current method

-            			Class[] parameters = currentMethod.getParameterTypes();

-            			

-            			// Select only the methods that receive a single parameter 

-            			if(parameters.length == 1) {

-            				

-            				// Get the parameter type

-            				Class theParameter = parameters[0];

-            				

-            				// Check if the parameter type is assignable from the type specified by the reference's interface attribute

-            				if(theParameter.isAssignableFrom(parameterClass)) {

-            					method = currentMethod;

-            				}

-            			}            				

-            		}

+                    // iterate on class hierarchy

+                    for ( ; method == null && targetClass != null; targetClass = targetClass.getSuperclass())

+                    {

+                        // Get all potential bind methods

+                        Method candidateBindMethods[]  = targetClass.getDeclaredMethods();

+                       

+                        // Iterate over them

+                        for(int i = 0; method == null && i < candidateBindMethods.length; i++) {

+                            Method currentMethod = candidateBindMethods[i];

+                           

+                            // Get the parameters for the current method

+                            Class[] parameters = currentMethod.getParameterTypes();

+                           

+                            // Select only the methods that receive a single parameter

+                            // and a matching name

+                            if(parameters.length == 1 && currentMethod.getName().equals(methodname)) {

+                               

+                                // Get the parameter type

+                                Class theParameter = parameters[0];

+                               

+                                // Check if the parameter type is assignable from the type specified by the reference's interface attribute

+                                if(theParameter.isAssignableFrom(parameterClass)) {

+                                    

+                                    // Final check: it must be public or protected

+                                    if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers()))

+                                    {

+                                        if (!method.isAccessible())

+                                        {

+                                            method.setAccessible(true);

+                                        }

+                                        method = currentMethod;

+                                        

+                                    }

+                                }

+                            }                           

+                        }

+                    }

             	} 

             	catch(ClassNotFoundException ex2) {

             		GenericActivator.exception("Cannot load class used as parameter "+parameterClassName,m_componentMetadata,ex2);

@@ -1106,20 +1107,22 @@
 	        // 4. Call the activate method, if present

             // Search for the activate method

         	try {

-        		Method activateMethod = m_implementationObject.getClass().getMethod("activate", new Class[]{ComponentContext.class});

+        		Method activateMethod = getMethod(m_implementationObject.getClass(), "activate", new Class[]{ComponentContext.class});

         		activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});

         	}

         	catch(NoSuchMethodException ex) {

-        		// We can safely ignore this one

-        	}

-        	catch(IllegalAccessException ex) {

-        		// TODO: Log this exception?

-        		

-        	}

-        	catch(InvocationTargetException ex) {

-        		// TODO: 112.5.8 If the activate method throws an exception, SCR must log an error message

-        		// containing the exception with the Log Service

-        	}

+                // We can safely ignore this one

+                GenericActivator.trace("activate() method is not implemented", m_componentMetadata);

+            }

+            catch(IllegalAccessException ex) {

+                // Ignored, but should it be logged?

+                GenericActivator.trace("activate() method cannot be called", m_componentMetadata);

+            }

+            catch(InvocationTargetException ex) {

+                // TODO: 112.5.8 If the activate method throws an exception, SCR must log an error message

+                // containing the exception with the Log Service

+                GenericActivator.exception("The activate method has thrown and exception", m_componentMetadata, ex);

+            }

     		

     		return m_implementationObject;

     	}

@@ -1130,6 +1133,61 @@
     	}

     }

 

-

-    

-}

+    /**

+     * 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.

+     */

+    private Method getMethod(Class clazz, String name, Class[] parameterTypes)

+        throws NoSuchMethodException 

+    {

+        // try the default mechanism first, which only yields public methods

+        try

+        {

+            return clazz.getMethod(name, parameterTypes); 

+        }

+        catch (NoSuchMethodException nsme)

+        {

+            // it is ok to not find a public method, try to find a protected now

+        }

+        

+        // now use method declarations, requiring walking up the class

+        // hierarchy manually. this algorithm also returns protected methods

+        // which is, what we need here

+        for ( ; clazz != null; clazz = clazz.getSuperclass()) 

+        {

+            try 

+            {

+                Method method = clazz.getDeclaredMethod(name, parameterTypes);

+                

+                // only accept a protected method, a public method should

+                // have been found above and neither private nor package

+                // protected methods are acceptable here

+                if (Modifier.isProtected(method.getModifiers())) {

+                    method.setAccessible(true);

+                    return method;

+                }

+            }

+            catch (NoSuchMethodException nsme)

+            {

+                // ignore for now

+            }

+        }

+        

+        // walked up the complete super class hierarchy and still not found

+        // anything, sigh ...

+        throw new NoSuchMethodException(name);

+    }    

+}
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/GenericActivator.java b/scr/src/main/java/org/apache/felix/scr/GenericActivator.java
index 03ee4db..165c4b7 100644
--- a/scr/src/main/java/org/apache/felix/scr/GenericActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/GenericActivator.java
@@ -158,8 +158,10 @@
                 		else if(metadata.isEnabled()) {

 		                	// enable the component

 		                	manager.enable();

-		                	m_managers.add(manager);

 		                }

+

+                		// register the manager

+                		m_managers.add(manager);

 	                } catch (Exception e) {

 						// There is a problem with this particular component, we'll log the error

 	                	// and proceed to the next one

@@ -236,6 +238,125 @@
     }

 

     /**

+     * Implements the <code>ComponentContext.enableComponent(String)</code>

+     * method by first finding the component(s) for the <code>name</code> and

+     * then starting a thread to actually enable all components found.

+     * <p>

+     * If no component matching the given name is found the thread is not

+     * started and the method does nothing. 

+     * 

+     * @param name The name of the component to enable or <code>null</code> to

+     *      enable all components.

+     */

+    void enableComponent(String name)

+    {

+        final ComponentManager[] cm = getSelectedComponents(name);

+        if (cm == null)

+        {

+            return;

+        }

+        

+        Thread enabler = new Thread("Component Enabling") 

+        {

+            public void run()

+            {

+                for (int i=0; i < cm.length; i++)

+                {

+                    try

+                    {

+                        cm[i].enable();

+                    }

+                    catch (Throwable t) 

+                    {

+                        exception("Cannot enable component",

+                            cm[i].getComponentMetadata(), t);

+                    }

+                }

+            }

+        };

+        enabler.start();

+    }

+    

+    /**

+     * Implements the <code>ComponentContext.disableComponent(String)</code>

+     * method by first finding the component(s) for the <code>name</code> and

+     * then starting a thread to actually disable all components found.

+     * <p>

+     * If no component matching the given name is found the thread is not

+     * started and the method does nothing. 

+     * 

+     * @param name The name of the component to disable or <code>null</code> to

+     *      disable all components.

+     */

+    void disableComponent(String name)

+    {

+        final ComponentManager[] cm = getSelectedComponents(name);

+        if (cm == null)

+        {

+            return;

+        }

+        

+        Thread disabler = new Thread("Component Disabling")

+        {

+            public void run()

+            {

+                for (int i=0; i < cm.length; i++)

+                {

+                    try

+                    {

+                        cm[i].dispose();

+                    }

+                    catch (Throwable t)

+                    {

+                        exception("Cannot disable component",

+                            cm[i].getComponentMetadata(), t);

+                    }

+                }

+            }

+        };

+        disabler.start();

+    }

+    

+    /**

+     * Returns an array of {@link ComponentManager} instances which match the

+     * <code>name</code>. If the <code>name</code> is <code>null</code> an

+     * array of all currently known component managers is returned. Otherwise

+     * an array containing a single component manager matching the name is

+     * returned if one is registered. Finally, if no component manager with the

+     * given name is registered, <code>null</code> is returned.

+     *  

+     * @param name The name of the component manager to return or

+     *      <code>null</code> to return an array of all component managers.

+     *      

+     * @return An array containing one or more component managers according

+     *      to the <code>name</code> parameter or <code>null</code> if no

+     *      component manager with the given name is currently registered.

+     */

+    private ComponentManager[] getSelectedComponents(String name) {

+        // if all components are selected

+        if (name == null)

+        {

+            return (ComponentManager[]) m_managers.toArray(new ComponentManager[m_managers.size()]);

+        }

+        

+        if (m_componentNames.contains(name))

+        {

+            // otherwise just find it

+            Iterator it = m_managers.iterator();

+            while (it.hasNext())

+            {

+                ComponentManager cm = (ComponentManager) it.next();

+                if (name.equals(cm.getComponentMetadata().getName())) {

+                    return new ComponentManager[]{ cm  };

+                }

+            }

+        }

+        

+        // if the component is not known

+        return null;

+    }

+        

+    /**

      * Method to display traces

      *

      * @param message a string to be displayed