You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2009/09/25 10:19:19 UTC

svn commit: r818764 - in /myfaces/extensions/scripting/trunk/core/core/src: main/java/org/apache/myfaces/scripting/core/ main/java/org/apache/myfaces/scripting/core/util/ test/java/org/apache/myfaces/scripting/core/util/

Author: werpu
Date: Fri Sep 25 08:19:19 2009
New Revision: 818764

URL: http://svn.apache.org/viewvc?rev=818764&view=rev
Log:
overhaul of the reflection code for the next big features

Added:
    myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java   (with props)
Modified:
    myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ConstructorLevelReloadingHandler.java
    myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/MethodLevelReloadingHandler.java
    myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/util/ReflectUtil.java
    myfaces/extensions/scripting/trunk/core/core/src/test/java/org/apache/myfaces/scripting/core/util/ReflectUtilTest.java

Modified: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ConstructorLevelReloadingHandler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ConstructorLevelReloadingHandler.java?rev=818764&r1=818763&r2=818764&view=diff
==============================================================================
--- myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ConstructorLevelReloadingHandler.java (original)
+++ myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ConstructorLevelReloadingHandler.java Fri Sep 25 08:19:19 2009
@@ -39,21 +39,10 @@
  * @Deprecated not used anymore since we have to do most
  * of our object instantiation brute force we cannot use proxies here
  */
-public class ConstructorLevelReloadingHandler implements InvocationHandler, Serializable, Decorated {
+public class ConstructorLevelReloadingHandler extends ReloadingInvocationHandler implements Serializable, Decorated {
 
-    Class _loadedClass = null;
     ScriptingWeaver _weaver = null;
-
-
-    public Object getDelegate() {
-        return _delegate;
-    }
-
-    transient Object _delegate = null;
-
-    public Class getLoadedClass() {
-        return _loadedClass;
-    }
+ 
 
     public void setLoadedClass(Class loadedClass) {
         _loadedClass = loadedClass;

Modified: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/MethodLevelReloadingHandler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/MethodLevelReloadingHandler.java?rev=818764&r1=818763&r2=818764&view=diff
==============================================================================
--- myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/MethodLevelReloadingHandler.java (original)
+++ myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/MethodLevelReloadingHandler.java Fri Sep 25 08:19:19 2009
@@ -22,6 +22,7 @@
 import org.apache.myfaces.scripting.api.Decorated;
 import org.apache.myfaces.scripting.api.ScriptingWeaver;
 import org.apache.myfaces.scripting.core.util.ProxyUtils;
+import org.apache.myfaces.scripting.core.util.ReflectUtil;
 
 import java.io.Serializable;
 import java.lang.reflect.InvocationHandler;
@@ -34,16 +35,14 @@
  * all interfacable artefacts which
  * only have reloading logic
  * and can cope with reloading on method level
- *
+ * <p/>
  * Note this works only for a minority of the artefacts
  * the reason, most artefacts do not rely on interfaces but
  * on base classes
  *
  * @author Werner Punz
  */
-public class MethodLevelReloadingHandler implements InvocationHandler, Serializable, Decorated {
-    Class _loadedClass = null;
-    transient Object _delegate = null;
+public class MethodLevelReloadingHandler extends ReloadingInvocationHandler implements  Serializable {
     ScriptingWeaver _weaver = null;
 
     public MethodLevelReloadingHandler(Object rootObject) {
@@ -52,18 +51,6 @@
     }
 
 
-    public Object getDelegate() {
-        return _delegate;
-    }
-
-    public Class getLoadedClass() {
-        return _loadedClass;
-    }
-
-    public void setLoadedClassName(Class loadedClass) {
-        this._loadedClass = loadedClass;
-    }
-
     /**
      * outside interface to the invoke method
      * which gets called every time a method
@@ -102,6 +89,10 @@
         } else {
             //if we are stateful only a tainted artefact is reloaded
             _delegate = _weaver.reloadScriptingInstance(_delegate);
+
+            //we work our way through all proxies and fetch the class for further reference
+            Object delegate = ProxyUtils.getDelegateFromProxy(_delegate);
+            _loadedClass = delegate.getClass();
         }
         //check for proxies and unproxy them before calling the methods
         //to avoid unneccessary cast problems

Added: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java?rev=818764&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java (added)
+++ myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java Fri Sep 25 08:19:19 2009
@@ -0,0 +1,52 @@
+package org.apache.myfaces.scripting.core;
+
+import org.apache.myfaces.scripting.api.Decorated;
+import org.apache.myfaces.scripting.core.util.ProxyUtils;
+import org.apache.myfaces.scripting.core.util.ReflectUtil;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationHandler;
+import java.util.Collection;
+
+/**
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ *
+ * We set our own invocation handler
+ * here to allow reflection utils directly targetting our
+ * _delegate.
+ */
+public abstract class ReloadingInvocationHandler implements InvocationHandler, Decorated {
+    Class _loadedClass = null;
+    Object _delegate = null;
+
+    /**
+     * simplified invoke for more dynamic upon invocation
+     * on our reloading objects
+     * @param o
+     * @param m
+     * @param args
+     * @return
+     */
+    public Object invoke(Object o, String m, Object ... args) {
+        return ReflectUtil.executeMethod(o, m, args);
+    }
+    
+   
+    public Class getLoadedClass() {
+        return _loadedClass;
+    }
+
+    public Object getDelegate() {
+        return _delegate;
+    }
+
+    public void setDelegate(Object delegate) {
+        _delegate = delegate;
+    }
+
+    public void setLoadedClassName(Class loadedClass) {
+        this._loadedClass = loadedClass;
+    }
+
+}

Propchange: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/ReloadingInvocationHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/util/ReflectUtil.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/util/ReflectUtil.java?rev=818764&r1=818763&r2=818764&view=diff
==============================================================================
--- myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/util/ReflectUtil.java (original)
+++ myfaces/extensions/scripting/trunk/core/core/src/main/java/org/apache/myfaces/scripting/core/util/ReflectUtil.java Fri Sep 25 08:19:19 2009
@@ -18,9 +18,16 @@
  */
 package org.apache.myfaces.scripting.core.util;
 
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.InvocationHandler;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 
 /**
  * @author Werner Punz (latest modification by $Author$)
@@ -28,10 +35,20 @@
  */
 
 public class ReflectUtil {
+
+    static Log log = LogFactory.getLog(ReflectUtil.class);
+
     public static Object instantiate(String clazz, Object... varargs) {
         return instantiate(ClassUtils.forName(clazz), varargs);
     }
 
+    /**
+     * A simplified instantiation over reflection
+     *
+     * @param clazz   the class to be istantiated
+     * @param varargs the instantiation parameters
+     * @return the instantiated object
+     */
     public static Object instantiate(Class clazz, Object... varargs) {
         Class[] classes = new Class[varargs.length];
         for (int cnt = 0; cnt < varargs.length; cnt++) {
@@ -68,38 +85,28 @@
     }
 
 
+    /**
+     * Generic execute method which simplifies the reflection api
+     * down to a usable system
+     *
+     * @param obj        the target object the method has to be executed upon
+     * @param methodName the method name
+     * @param varargs    the arguments which have to be passed to the method
+     * @return the return value of the method
+     */
     public static Object executeStaticMethod(Class obj, String methodName, Object... varargs) {
 
-        Method[] methods = obj.getDeclaredMethods();
-
-         for (Method m : methods) {
+        Collection<Method> methods = getMethods(obj, methodName, varargs.length);
 
-            if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) {
-                continue;
-            }
-            try {
-                return m.invoke(obj, varargs);
-            } catch (IllegalAccessException e) {
-                //expected, we do it that way for speed reasons
-                //because it is faster on most cases than looping over the param types
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException(e);
-            }
+        Object retVal = handleStaticMethod(obj, methodName, methods, varargs);
+        if (!methodNotFound(retVal)) {
+            return retVal;
         }
 
-        methods = obj.getMethods();
-        for (Method m : methods) {
-            if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) {
-                continue;
-            }
-            try {
-                return m.invoke(obj, varargs);
-            } catch (IllegalAccessException e) {
-                //expected, we do it that way for speed reasons
-                //because it is faster on most cases than looping over the param types
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException(e);
-            }
+        methods = getAllMethods(obj, methodName, varargs.length);
+        retVal = handleStaticMethod(obj, methodName, methods, varargs);
+        if (!methodNotFound(retVal)) {
+            return retVal;
         }
 
         throw new RuntimeException("Static Method of :" + methodName + " from class " + obj.getClass().getName() + " not found");
@@ -107,47 +114,196 @@
     }
 
 
+    public static Collection<Method> getAllMethods(Class clazz, String methodName, int varargLength) {
+        ArrayList<Method> retVal = new ArrayList<Method>(30);
+        while (clazz.equals(java.lang.Object.class)) {
+            for (Method m : clazz.getDeclaredMethods()) {
+                if (m.getParameterTypes().length == varargLength && m.getName().equals(methodName)) {
+                    retVal.add(m);
+                }
+            }
+            clazz = clazz.getSuperclass();
+        }
 
+        return retVal;
+    }
 
 
+    public static Collection<Method> getMethods(Class clazz, String methodName, int varargLength) {
+        ArrayList<Method> retVal = new ArrayList<Method>(30);
+        for (Method m : clazz.getDeclaredMethods()) {
+            if (m.getParameterTypes().length == varargLength && m.getName().equals(methodName)) {
+                retVal.add(m);
+            }
+        }
+
+        return retVal;
+    }
 
 
+    /**
+     * Generic execute method which simplifies the reflection api
+     * down to a usable system
+     *
+     * @param obj        the target object the method has to be executed upon
+     * @param methodName the method name
+     * @param varargs    the arguments which have to be passed to the method
+     * @return the return value of the method
+     * @throws a generic runtime exception in case of a failure
+     *           we use unmanaged exceptions here to get a behavior similar to scripting
+     *           language execution where failures can happen but method executions
+     *           should not enforce exception handling
+     */
     public static Object executeMethod(Object obj, String methodName, Object... varargs) {
+
+        Collection<Method> methods = null;
+        //if we have an invocationHandler here we
+        //can work over the generic invoke interface
+        //That way we can cover more dynamic stuff
+        //our reload invocation handler is treated differently here
+
+        if (obj instanceof InvocationHandler) {
+            InvocationHandler objToInvoke = (InvocationHandler) obj;
+
+            Object realTarget = ProxyUtils.getDelegateFromProxy(objToInvoke);
+
+            //first we try only the public because they are the most likely ones
+            //to be accessed
+            methods = getMethods(realTarget.getClass(), methodName, varargs.length);
+            Object retVal = handleInvHandlerMethod(objToInvoke, methodName, methods, varargs);
+            if (!methodNotFound(retVal)) {
+                return retVal;
+            }
+            //if not we try all of them until we have a match
+            methods = getAllMethods(realTarget.getClass(), methodName, varargs.length);
+            retVal = handleInvHandlerMethod(objToInvoke, methodName, methods, varargs);
+            if (!(methodNotFound(retVal))) {
+                return retVal;
+            }
+
+            throw new RuntimeException("Method of :" + methodName + " from class " + obj.getClass().getName() + " not found");
+        }
+
         Class clazz = obj.getClass();
-        Method[] methods = clazz.getDeclaredMethods();
+
+        //first we try only the public because they are the most likely ones
+        //to be accessed
+        methods = getMethods(clazz, methodName, varargs.length);
+        Object retVal = handleObjMethod(obj, methodName, methods, varargs);
+        if (!methodNotFound(retVal)) {
+            return retVal;
+        }
+
+        //if not we try all of them until we have a match
+        methods = getAllMethods(clazz, methodName, varargs.length);
+        retVal = handleObjMethod(obj, methodName, methods, varargs);
+        if (!methodNotFound(retVal)) {
+            return retVal;
+        }
+
+        throw new RuntimeException("Method of :" + methodName + " from class " + obj.getClass().getName() + " not found");
+    }
+
+    /**
+     * special marker class which is a special return value indicating
+     * that not method has been found which can be executed
+     */
+    static class _MethodNotFound {
+    }
+
+
+    /**
+     * check if the return vaue is a method not found return val which
+     * indicates we have to follow the next workflow step
+     *
+     * @param retVal
+     * @return
+     */
+    private static boolean methodNotFound(Object retVal) {
+        return retVal instanceof _MethodNotFound;
+    }
+
+
+    /**
+     * executes a method in an invocation handler
+     *
+     * @param objToInvoke
+     * @param methodName
+     * @param methods
+     * @param varargs
+     * @return
+     */
+    static private Object handleInvHandlerMethod(InvocationHandler objToInvoke, String methodName, Collection<Method> methods, Object... varargs) {
+        for (Method m : methods) {
+            if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) {
+                continue;
+            }
+            try {
+                return objToInvoke.invoke(objToInvoke, m, varargs);
+            } catch (Throwable e) {
+                handleException(e);
+            }
+        }
+        return new _MethodNotFound();
+    }
+
+    /**
+     * executes a method on an object
+     *
+     * @param objToInvoke
+     * @param methodName
+     * @param methods
+     * @param varargs
+     * @return
+     */
+    static private Object handleObjMethod(Object objToInvoke, String methodName, Collection<Method> methods, Object... varargs) {
         for (Method m : methods) {
             if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) {
                 continue;
             }
             try {
-                return m.invoke(obj, varargs);
-            } catch (IllegalAccessException e) {
-                //expected, we do it that way for speed reasons
-                //because it is faster on most cases than looping over the param types
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException(e);
+                return m.invoke(objToInvoke, varargs);
+            } catch (Throwable e) {
+                handleException(e);
             }
         }
+        return new _MethodNotFound();
+    }
+
 
-        methods = clazz.getMethods();
+    /**
+     * executes a static method on a class
+     *
+     * @param objToInvoke
+     * @param methodName
+     * @param methods
+     * @param varargs
+     * @return
+     */
+    static private Object handleStaticMethod(Class objToInvoke, String methodName, Collection<Method> methods, Object... varargs) {
         for (Method m : methods) {
             if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) {
                 continue;
             }
             try {
-                return m.invoke(obj, varargs);
-            } catch (IllegalAccessException e) {
-                //expected, we do it that way for speed reasons
-                //because it is faster on most cases than looping over the param types
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException(e);
+                return m.invoke(objToInvoke, varargs);
+            } catch (Throwable e) {
+                handleException(e);
             }
         }
-        throw new RuntimeException("Method of :" + methodName + " from class " + obj.getClass().getName() + " not found");
+        return new _MethodNotFound();
     }
 
 
-   
+    private static void handleException(Throwable e) {
+        if (e instanceof IllegalAccessException) {
+            //do nothing
+        } else if (e instanceof IllegalArgumentException) {
+           //do nothing
+        } else {
+            throw new RuntimeException(e);
+        }
+    }
 
 
     /**
@@ -187,8 +343,20 @@
     }
 
 
+    /**
+     * faster reflection call
+     * if we know the data types excactly we can
+     * trigger a direct call instead of walking through all methods
+     *
+     * @param obj
+     * @param methodName
+     * @param classes
+     * @return
+     * @throws NoSuchMethodException
+     */
     public static Method fastGetMethod(Object obj, String methodName, Class[] classes) throws NoSuchMethodException {
         Method m = null;
+        //TODO add inheritance handling here
         try {
             m = obj.getClass().getDeclaredMethod(methodName, classes);
         } catch (NoSuchMethodException e) {

Modified: myfaces/extensions/scripting/trunk/core/core/src/test/java/org/apache/myfaces/scripting/core/util/ReflectUtilTest.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/core/core/src/test/java/org/apache/myfaces/scripting/core/util/ReflectUtilTest.java?rev=818764&r1=818763&r2=818764&view=diff
==============================================================================
--- myfaces/extensions/scripting/trunk/core/core/src/test/java/org/apache/myfaces/scripting/core/util/ReflectUtilTest.java (original)
+++ myfaces/extensions/scripting/trunk/core/core/src/test/java/org/apache/myfaces/scripting/core/util/ReflectUtilTest.java Fri Sep 25 08:19:19 2009
@@ -50,13 +50,11 @@
         try {
             executeMethod(probe, "testMethod3");
         } catch (RuntimeException e) {
-
         }
 
         try {
             executeMethod(probe, "testMethod3", 10);
         } catch (RuntimeException e) {
-
         }
 
         boolean retVal = (Boolean) executeMethod(probe, "testMethod3", "hello world");