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");