* Add boolean resolve argument to ScriptingEngine.invoke() to tell the engine if
functionName argument should be resolved as member expression. Use this feature to allow calling nested/deep functions in internal invocations (e.g. scheduler calls). Fixes bug 290.
This commit is contained in:
		
							parent
							
								
									f4eb8a9735
								
							
						
					
					
						commit
						cb92ec8469
					
				
					 6 changed files with 96 additions and 33 deletions
				
			
		|  | @ -330,8 +330,6 @@ public final class RequestEvaluator implements Runnable { | |||
| 
 | ||||
|                                     // set the req.action property, cutting off the _action suffix | ||||
|                                     req.setAction(action); | ||||
|                                     // make sure we have a valid function name by replacing dots with underscores | ||||
|                                     action = action.replace('.', '_'); | ||||
| 
 | ||||
|                                     // reset skin recursion detection counter | ||||
|                                     skinDepth = 0; | ||||
|  | @ -344,7 +342,8 @@ public final class RequestEvaluator implements Runnable { | |||
|                                             scriptingEngine.invoke(currentElement, | ||||
|                                                     "onRequest", | ||||
|                                                     new Object[0], | ||||
|                                                     ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|                                                     ScriptingEngine.ARGS_WRAP_DEFAULT, | ||||
|                                                     false); | ||||
|                                         } | ||||
|                                     } catch (RedirectException redir) { | ||||
|                                         throw redir; | ||||
|  | @ -360,13 +359,18 @@ public final class RequestEvaluator implements Runnable { | |||
|                                                 .getInputStream()); | ||||
|                                         Vector args = xreq.getParameters(); | ||||
|                                         args.add(0, xreq.getMethodName()); | ||||
|                                         result = scriptingEngine.invoke(currentElement, action, | ||||
|                                             args.toArray(), ScriptingEngine.ARGS_WRAP_XMLRPC); | ||||
|                                         result = scriptingEngine.invoke(currentElement, | ||||
|                                                 action, | ||||
|                                                 args.toArray(), | ||||
|                                                 ScriptingEngine.ARGS_WRAP_XMLRPC, | ||||
|                                                 false); | ||||
|                                         res.writeXmlRpcResponse(result); | ||||
|                                     } else { | ||||
|                                         scriptingEngine.invoke(currentElement, action, | ||||
|                                             new Object[0], | ||||
|                                             ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|                                         scriptingEngine.invoke(currentElement, | ||||
|                                                 action, | ||||
|                                                 new Object[0], | ||||
|                                                 ScriptingEngine.ARGS_WRAP_DEFAULT, | ||||
|                                                 false); | ||||
|                                     } | ||||
|                                 } catch (RedirectException redirect) { | ||||
|                                     // if there is a message set, save it on the user object for the next request | ||||
|  | @ -420,8 +424,10 @@ public final class RequestEvaluator implements Runnable { | |||
|                                     // reset skin recursion detection counter | ||||
|                                     skinDepth = 0; | ||||
| 
 | ||||
|                                     result = scriptingEngine.invoke(currentElement, functionName, args, | ||||
|                                             ScriptingEngine.ARGS_WRAP_XMLRPC); | ||||
|                                     result = scriptingEngine.invoke(currentElement, | ||||
|                                             functionName, args, | ||||
|                                             ScriptingEngine.ARGS_WRAP_XMLRPC, | ||||
|                                             false); | ||||
|                                     commitTransaction(); | ||||
|                                 } catch (Exception x) { | ||||
|                                     abortTransaction(); | ||||
|  | @ -475,8 +481,11 @@ public final class RequestEvaluator implements Runnable { | |||
|                                         // reset skin recursion detection counter | ||||
|                                         skinDepth = 0; | ||||
| 
 | ||||
|                                         result = scriptingEngine.invoke(thisObject, functionName, args, | ||||
|                                                 ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|                                         result = scriptingEngine.invoke(thisObject, | ||||
|                                                 functionName, | ||||
|                                                 args, | ||||
|                                                 ScriptingEngine.ARGS_WRAP_DEFAULT, | ||||
|                                                 true); | ||||
|                                         commitTransaction(); | ||||
|                                     } catch (Exception x) { | ||||
|                                         abortTransaction(); | ||||
|  | @ -836,7 +845,8 @@ public final class RequestEvaluator implements Runnable { | |||
|      */ | ||||
|     public Object invokeDirectFunction(Object obj, String functionName, Object[] args) | ||||
|                                 throws Exception { | ||||
|         return scriptingEngine.invoke(obj, functionName, args, ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|         return scriptingEngine.invoke(obj, functionName, args, | ||||
|                 ScriptingEngine.ARGS_WRAP_DEFAULT, false); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -961,7 +971,7 @@ public final class RequestEvaluator implements Runnable { | |||
|     private Object getChildElement(Object obj, String name) throws ScriptingException { | ||||
|         if (scriptingEngine.hasFunction(obj, "getChildElement")) { | ||||
|             return scriptingEngine.invoke(obj, "getChildElement", new Object[] {name}, | ||||
|                                           ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|                                           ScriptingEngine.ARGS_WRAP_DEFAULT, false); | ||||
|         } | ||||
| 
 | ||||
|         if (obj instanceof IPathElement) { | ||||
|  |  | |||
|  | @ -88,12 +88,14 @@ public interface ScriptingEngine { | |||
|      *                   one of <code>ARGS_WRAP_NONE</code>, | ||||
|      *                          <code>ARGS_WRAP_DEFAULT</code>, | ||||
|      *                          <code>ARGS_WRAP_XMLRPC</code> | ||||
|      * @param resolve indicates whether functionName may contain an object path | ||||
|      *                   or just the plain function name | ||||
|      * @return the return value of the function | ||||
|      * @throws ScriptingException to indicate something went wrong | ||||
|      *                   with the invocation | ||||
|      */ | ||||
|     public Object invoke(Object thisObject, String functionName, | ||||
|                          Object[] args, int argsWrapMode) | ||||
|                          Object[] args, int argsWrapMode, boolean resolve) | ||||
|             throws ScriptingException; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -147,7 +147,10 @@ public class HopObject extends ScriptableObject implements Wrapper, PropertyReco | |||
| 
 | ||||
|             hobj.init(core, node); | ||||
|             if (proto != null) { | ||||
|                 engine.invoke(hobj, "__constructor__", args, ScriptingEngine.ARGS_WRAP_NONE); | ||||
|                 engine.invoke(hobj, | ||||
|                         "__constructor__", | ||||
|                         args, ScriptingEngine.ARGS_WRAP_NONE, | ||||
|                         false); | ||||
|             } | ||||
| 
 | ||||
|             return hobj; | ||||
|  |  | |||
|  | @ -28,11 +28,27 @@ import helma.scripting.ScriptingException; | |||
|  * @see helma.main.launcher.FilteredClassLoader | ||||
|  */ | ||||
| public final class PhantomEngine extends RhinoEngine { | ||||
| 
 | ||||
|     /** | ||||
|      * Invoke a function on some object, using the given arguments and global vars. | ||||
|      * XML-RPC calls require special input and output parameter conversion. | ||||
|      * | ||||
|      * @param thisObject the object to invoke the function on, or null for | ||||
|      *                   global functions | ||||
|      * @param functionName the name of the function to be invoked | ||||
|      * @param args array of argument objects | ||||
|      * @param argsWrapMode indicated the way to process the arguments. Must be | ||||
|      *                   one of <code>ARGS_WRAP_NONE</code>, | ||||
|      *                          <code>ARGS_WRAP_DEFAULT</code>, | ||||
|      *                          <code>ARGS_WRAP_XMLRPC</code> | ||||
|      * @param resolve indicates whether functionName may contain an object path | ||||
|      *                   or just the plain function name | ||||
|      * @return the return value of the function | ||||
|      * @throws ScriptingException to indicate something went wrong | ||||
|      *                   with the invocation | ||||
|      */ | ||||
|     public Object invoke(Object thisObject, String functionName, Object[] args, | ||||
|                          int argsWrapMode) throws ScriptingException { | ||||
|         return super.invoke(thisObject, functionName, args, argsWrapMode); | ||||
|                          int argsWrapMode, boolean resolve) throws ScriptingException { | ||||
|         return super.invoke(thisObject, functionName, args, argsWrapMode, resolve); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -678,7 +678,8 @@ public final class RhinoCore implements ScopeProvider { | |||
|                     try { | ||||
|                         result = engine.invoke(handler, hrefFunction, | ||||
|                                                new Object[] { basicHref }, | ||||
|                                                ScriptingEngine.ARGS_WRAP_DEFAULT); | ||||
|                                                ScriptingEngine.ARGS_WRAP_DEFAULT, | ||||
|                                                false); | ||||
|                     } catch (ScriptingException x) { | ||||
|                         throw new EvaluatorException("Error in hrefFunction: " + x); | ||||
|                     } | ||||
|  |  | |||
|  | @ -255,16 +255,24 @@ public class RhinoEngine implements ScriptingEngine { | |||
| 
 | ||||
|     /** | ||||
|      * Invoke a function on some object, using the given arguments and global vars. | ||||
|      * XML-RPC calls require special input and output parameter conversion. | ||||
|      * | ||||
|      * @param thisObject the object to invoke the function on, or null for | ||||
|      *                   global functions | ||||
|      * @param functionName the name of the function to be invoked | ||||
|      * @param args array of argument objects | ||||
|      * @param argsWrapMode indicated the way to process the arguments. Must be | ||||
|      *                   one of <code>ARGS_WRAP_NONE</code>, | ||||
|      *                          <code>ARGS_WRAP_DEFAULT</code>, | ||||
|      *                          <code>ARGS_WRAP_XMLRPC</code> | ||||
|      * @param resolve indicates whether functionName may contain an object path | ||||
|      *                   or just the plain function name | ||||
|      * @return the return value of the function | ||||
|      * @throws ScriptingException to indicate something went wrong | ||||
|      *                   with the invocation | ||||
|      */ | ||||
|     public Object invoke(Object thisObject, String functionName, Object[] args, | ||||
|                          int argsWrapMode) throws ScriptingException { | ||||
|         Scriptable eso = null; | ||||
| 
 | ||||
|         if (thisObject == null) { | ||||
|             eso = global; | ||||
|         } else { | ||||
|             eso = Context.toObject(thisObject, global); | ||||
|         } | ||||
|                          int argsWrapMode, boolean resolve) throws ScriptingException { | ||||
|         try { | ||||
|             for (int i = 0; i < args.length; i++) { | ||||
|                 switch (argsWrapMode) { | ||||
|  | @ -279,15 +287,37 @@ public class RhinoEngine implements ScriptingEngine { | |||
|                         args[i] = core.processXmlRpcArgument(args[i]); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Object f = ScriptableObject.getProperty(eso, functionName.replace('.', '_')); | ||||
|             } | ||||
|             Scriptable obj = thisObject == null ? global : Context.toObject(thisObject, global); | ||||
| 
 | ||||
|             // if function name should be resolved interpret it as member expression, | ||||
|             // otherwise replace dots with underscores. | ||||
|             if (resolve) { | ||||
|                 if (functionName.indexOf('.') > 0) { | ||||
|                     StringTokenizer st = new StringTokenizer(functionName, "."); | ||||
|                     for (int i=0; i<st.countTokens()-1; i++) { | ||||
|                         String propName = st.nextToken(); | ||||
|                         Object propValue = ScriptableObject.getProperty(obj, propName); | ||||
|                         if (propValue instanceof Scriptable) { | ||||
|                             obj = (Scriptable) propValue; | ||||
|                         } else { | ||||
|                             throw new RuntimeException("Can't resolve function name " + | ||||
|                                     functionName + " in " + thisObject); | ||||
|                         } | ||||
|                     } | ||||
|                     functionName = st.nextToken(); | ||||
|                 } | ||||
|             } else { | ||||
|                 functionName = functionName.replace('.', '_'); | ||||
|             } | ||||
|             Object f = ScriptableObject.getProperty(obj, functionName); | ||||
| 
 | ||||
|             if ((f == ScriptableObject.NOT_FOUND) || !(f instanceof Function)) { | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             Object retval = ((Function) f).call(context, global, eso, args); | ||||
|             Object retval = ((Function) f).call(context, global, obj, args); | ||||
| 
 | ||||
|             if (retval instanceof Wrapper) { | ||||
|                 retval = ((Wrapper) retval).unwrap(); | ||||
|  | @ -372,16 +402,18 @@ public class RhinoEngine implements ScriptingEngine { | |||
|      * is a java object) with that name. | ||||
|      */ | ||||
|     public boolean hasFunction(Object obj, String fname) { | ||||
|         // Convert '.' to '_' in function name | ||||
|         fname = fname.replace('.', '_'); | ||||
|         // Treat HopObjects separately - otherwise we risk to fetch database | ||||
|         // references/child objects just to check for function properties. | ||||
|         if (obj instanceof INode) { | ||||
|             String protoname = ((INode) obj).getPrototype(); | ||||
|             return core.hasFunction(protoname, fname.replace('.', '_')); | ||||
|             return core.hasFunction(protoname, fname); | ||||
|         } | ||||
| 
 | ||||
|         Scriptable op = obj == null ? global : Context.toObject(obj, global); | ||||
| 
 | ||||
|         Object func = ScriptableObject.getProperty(op, fname.replace('.', '_')); | ||||
|         Object func = ScriptableObject.getProperty(op, fname); | ||||
| 
 | ||||
|         if (func != null && func != Undefined.instance && func instanceof Function) { | ||||
|             return true; | ||||
|  | @ -395,7 +427,6 @@ public class RhinoEngine implements ScriptingEngine { | |||
|      * is a java object) with that name. | ||||
|      */ | ||||
|     public Object get(Object obj, String propname) { | ||||
|         // System.err.println ("GET: "+propname); | ||||
|         if ((obj == null) || (propname == null)) { | ||||
|             return null; | ||||
|         } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue