* Extend ScriptingEngine.invoke() to directly accept JavaScript function objects.

* Make RequestEvaluator.invokeInternal() and RequestEvaluator.invokeDirectFunction()
  accept Javascript function objects as arguments.
This commit is contained in:
hns 2007-03-28 14:32:46 +00:00
parent 900d16654a
commit 05a978e901
3 changed files with 63 additions and 40 deletions

View file

@ -62,9 +62,12 @@ public final class RequestEvaluator implements Runnable {
// the object on which to invoke a function, if specified // the object on which to invoke a function, if specified
private volatile Object thisObject; private volatile Object thisObject;
// the method to be executed // the function to be executed
private volatile String functionName; private volatile String functionName;
// the function or function name to be executed
private volatile Object function;
// the session object associated with the current request // the session object associated with the current request
private volatile Session session; private volatile Session session;
@ -165,7 +168,7 @@ public final class RequestEvaluator implements Runnable {
// avoid going into transaction if called function doesn't exist. // avoid going into transaction if called function doesn't exist.
// this only works for the (common) case that method is a plain // this only works for the (common) case that method is a plain
// method name, not an obj.method path // method name, not an obj.method path
if (reqtype == INTERNAL) { if (reqtype == INTERNAL && functionName != null) {
// if object is an instance of NodeHandle, get the node object itself. // if object is an instance of NodeHandle, get the node object itself.
if (thisObject instanceof NodeHandle) { if (thisObject instanceof NodeHandle) {
thisObject = ((NodeHandle) thisObject).getNode(app.nmgr.safe); thisObject = ((NodeHandle) thisObject).getNode(app.nmgr.safe);
@ -482,12 +485,12 @@ public final class RequestEvaluator implements Runnable {
// reset skin recursion detection counter // reset skin recursion detection counter
skinDepth = 0; skinDepth = 0;
if (!scriptingEngine.hasFunction(thisObject, functionName)) { if (functionName != null && !scriptingEngine.hasFunction(thisObject, functionName)) {
throw new FrameworkException(missingFunctionMessage(thisObject, functionName)); throw new FrameworkException(missingFunctionMessage(thisObject, functionName));
} }
result = scriptingEngine.invoke(thisObject, result = scriptingEngine.invoke(thisObject,
functionName, function,
args, args,
ScriptingEngine.ARGS_WRAP_DEFAULT, ScriptingEngine.ARGS_WRAP_DEFAULT,
true); true);
@ -850,14 +853,14 @@ public final class RequestEvaluator implements Runnable {
* Invoke a function internally and directly, using the thread we're running on. * Invoke a function internally and directly, using the thread we're running on.
* *
* @param obj the object to invoke the function on * @param obj the object to invoke the function on
* @param functionName the name of the function to invoke * @param function the function or name of the function to invoke
* @param args the arguments * @param args the arguments
* @return the result returned by the invocation * @return the result returned by the invocation
* @throws Exception any exception thrown by the invocation * @throws Exception any exception thrown by the invocation
*/ */
public Object invokeDirectFunction(Object obj, String functionName, Object[] args) public Object invokeDirectFunction(Object obj, Object function, Object[] args)
throws Exception { throws Exception {
return scriptingEngine.invoke(obj, functionName, args, return scriptingEngine.invoke(obj, function, args,
ScriptingEngine.ARGS_WRAP_DEFAULT, false); ScriptingEngine.ARGS_WRAP_DEFAULT, false);
} }
@ -866,16 +869,16 @@ public final class RequestEvaluator implements Runnable {
* and waits for it to finish. * and waits for it to finish.
* *
* @param object the object to invoke the function on * @param object the object to invoke the function on
* @param functionName the name of the function to invoke * @param function the function or name of the function to invoke
* @param args the arguments * @param args the arguments
* @return the result returned by the invocation * @return the result returned by the invocation
* @throws Exception any exception thrown by the invocation * @throws Exception any exception thrown by the invocation
*/ */
public synchronized Object invokeInternal(Object object, String functionName, public synchronized Object invokeInternal(Object object, Object function,
Object[] args) Object[] args)
throws Exception { throws Exception {
// give internal call more time (15 minutes) to complete // give internal call more time (15 minutes) to complete
return invokeInternal(object, functionName, args, 60000L * 15); return invokeInternal(object, function, args, 60000L * 15);
} }
/** /**
@ -883,21 +886,27 @@ public final class RequestEvaluator implements Runnable {
* and waits for it to finish. * and waits for it to finish.
* *
* @param object the object to invoke the function on * @param object the object to invoke the function on
* @param functionName the name of the function to invoke * @param function the function or name of the function to invoke
* @param args the arguments * @param args the arguments
* @param timeout the time in milliseconds to wait for the function to return * @param timeout the time in milliseconds to wait for the function to return, or
* -1 to wait indefinitely
* @return the result returned by the invocation * @return the result returned by the invocation
* @throws Exception any exception thrown by the invocation * @throws Exception any exception thrown by the invocation
*/ */
public synchronized Object invokeInternal(Object object, String functionName, public synchronized Object invokeInternal(Object object, Object function,
Object[] args, long timeout) Object[] args, long timeout)
throws Exception { throws Exception {
initObjects(functionName, INTERNAL, RequestTrans.INTERNAL); initObjects(functionName, INTERNAL, RequestTrans.INTERNAL);
thisObject = object; thisObject = object;
this.functionName = functionName; if (function instanceof String)
this.functionName = (String) function;
this.function = function;
this.args = args; this.args = args;
startTransactor(); startTransactor();
if (timeout < 0)
wait();
else
wait(timeout); wait(timeout);
if (reqtype != NONE && stopTransactor()) { if (reqtype != NONE && stopTransactor()) {
@ -997,6 +1006,8 @@ public final class RequestEvaluator implements Runnable {
res = null; res = null;
req = null; req = null;
session = null; session = null;
functionName = null;
function = null;
args = null; args = null;
result = null; result = null;
exception = null; exception = null;

View file

@ -85,7 +85,7 @@ public interface ScriptingEngine {
* *
* @param thisObject the object to invoke the function on, or null for * @param thisObject the object to invoke the function on, or null for
* global functions * global functions
* @param functionName the name of the function to be invoked * @param function the name of the function to be invoked
* @param args array of argument objects * @param args array of argument objects
* @param argsWrapMode indicated the way to process the arguments. Must be * @param argsWrapMode indicated the way to process the arguments. Must be
* one of <code>ARGS_WRAP_NONE</code>, * one of <code>ARGS_WRAP_NONE</code>,
@ -97,7 +97,7 @@ public interface ScriptingEngine {
* @throws ScriptingException to indicate something went wrong * @throws ScriptingException to indicate something went wrong
* with the invocation * with the invocation
*/ */
public Object invoke(Object thisObject, String functionName, public Object invoke(Object thisObject, Object function,
Object[] args, int argsWrapMode, boolean resolve) Object[] args, int argsWrapMode, boolean resolve)
throws ScriptingException; throws ScriptingException;

View file

@ -217,7 +217,7 @@ public class RhinoEngine implements ScriptingEngine {
* *
* @param thisObject the object to invoke the function on, or null for * @param thisObject the object to invoke the function on, or null for
* global functions * global functions
* @param functionName the name of the function to be invoked * @param function the function or name of the function to be invoked
* @param args array of argument objects * @param args array of argument objects
* @param argsWrapMode indicated the way to process the arguments. Must be * @param argsWrapMode indicated the way to process the arguments. Must be
* one of <code>ARGS_WRAP_NONE</code>, * one of <code>ARGS_WRAP_NONE</code>,
@ -229,15 +229,18 @@ public class RhinoEngine implements ScriptingEngine {
* @throws ScriptingException to indicate something went wrong * @throws ScriptingException to indicate something went wrong
* with the invocation * with the invocation
*/ */
public Object invoke(Object thisObject, String functionName, Object[] args, public Object invoke(Object thisObject, Object function, Object[] args,
int argsWrapMode, boolean resolve) throws ScriptingException { int argsWrapMode, boolean resolve) throws ScriptingException {
try { try {
Scriptable obj = thisObject == null ? global : Context.toObject(thisObject, global); Scriptable obj = thisObject == null ? global : Context.toObject(thisObject, global);
Function func;
if (function instanceof String) {
String funcName = (String) function;
// if function name should be resolved interpret it as member expression, // if function name should be resolved interpret it as member expression,
// otherwise replace dots with underscores. // otherwise replace dots with underscores.
if (resolve) { if (resolve) {
if (functionName.indexOf('.') > 0) { if (funcName.indexOf('.') > 0) {
StringTokenizer st = new StringTokenizer(functionName, "."); StringTokenizer st = new StringTokenizer(funcName, ".");
for (int i=0; i<st.countTokens()-1; i++) { for (int i=0; i<st.countTokens()-1; i++) {
String propName = st.nextToken(); String propName = st.nextToken();
Object propValue = ScriptableObject.getProperty(obj, propName); Object propValue = ScriptableObject.getProperty(obj, propName);
@ -245,20 +248,29 @@ public class RhinoEngine implements ScriptingEngine {
obj = (Scriptable) propValue; obj = (Scriptable) propValue;
} else { } else {
throw new RuntimeException("Can't resolve function name " + throw new RuntimeException("Can't resolve function name " +
functionName + " in " + thisObject); funcName + " in " + thisObject);
} }
} }
functionName = st.nextToken(); funcName = st.nextToken();
} }
} else { } else {
functionName = functionName.replace('.', '_'); funcName = funcName.replace('.', '_');
} }
Object f = ScriptableObject.getProperty(obj, functionName); Object funcvalue = ScriptableObject.getProperty(obj, funcName);
if (!(f instanceof Function)) { if (!(funcvalue instanceof Function))
return null; return null;
func = (Function) funcvalue;
} else {
if (function instanceof Wrapper)
function = ((Wrapper) function).unwrap();
if (!(function instanceof Function))
throw new IllegalArgumentException("Not a function or function name: " + function);
func = (Function) function;
} }
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
switch (argsWrapMode) { switch (argsWrapMode) {
case ARGS_WRAP_DEFAULT: case ARGS_WRAP_DEFAULT:
@ -275,7 +287,7 @@ public class RhinoEngine implements ScriptingEngine {
} }
// use Context.call() in order to set the context's factory // use Context.call() in order to set the context's factory
Object retval = Context.call(core.contextFactory, (Function) f, global, obj, args); Object retval = Context.call(core.contextFactory, func, global, obj, args);
if (retval instanceof Wrapper) { if (retval instanceof Wrapper) {
retval = ((Wrapper) retval).unwrap(); retval = ((Wrapper) retval).unwrap();