* Adding invokeExternal() code from Stefan Pollach (should later be consolidated
by merging it with invokeXmlRpc() - the only difference is in the XML-RPC access check, so we shouldn't have to duplicate all code.) * Make execution of global onStart() function synchronous in Application.start() * Fix bug where user.onLogout() is called on a released RequestEvaluator
This commit is contained in:
parent
ae1aa70fdf
commit
f3a623cf95
2 changed files with 145 additions and 17 deletions
|
@ -365,6 +365,23 @@ public final class Application implements IPathElement, Runnable {
|
|||
*/
|
||||
public void start() {
|
||||
starttime = System.currentTimeMillis();
|
||||
|
||||
// read in standard prototypes to make first request go faster
|
||||
// typemgr.updatePrototype("root");
|
||||
// typemgr.updatePrototype("global");
|
||||
|
||||
// as first thing, invoke global onStart() function
|
||||
RequestEvaluator eval = getEvaluator();
|
||||
try {
|
||||
eval.invokeInternal(null, "onStart", new Object[0]);
|
||||
} catch (Exception ignore) {
|
||||
logEvent("Error in " + name + "/onStart(): " + ignore);
|
||||
} finally {
|
||||
if (!stopped) {
|
||||
releaseEvaluator(eval);
|
||||
}
|
||||
}
|
||||
|
||||
worker = new Thread(this, "Worker-" + name);
|
||||
worker.setPriority(Thread.NORM_PRIORITY + 1);
|
||||
worker.start();
|
||||
|
@ -626,6 +643,23 @@ public final class Application implements IPathElement, Runnable {
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
public Object executeExternal(String method, Vector args)
|
||||
throws Exception {
|
||||
Object retval = null;
|
||||
RequestEvaluator ev = null;
|
||||
try {
|
||||
// check if the properties file has been updated
|
||||
updateProperties();
|
||||
// get evaluator and invoke
|
||||
ev = getEvaluator();
|
||||
retval = ev.invokeExternal(method, args.toArray());
|
||||
} finally {
|
||||
releaseEvaluator(ev);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the application's object cache, causing all objects to be refetched from
|
||||
* the database.
|
||||
|
@ -1331,22 +1365,6 @@ public final class Application implements IPathElement, Runnable {
|
|||
|
||||
// logEvent ("Starting scheduler for "+name);
|
||||
|
||||
// read in standard prototypes to make first request go faster
|
||||
typemgr.updatePrototype("root");
|
||||
typemgr.updatePrototype("global");
|
||||
|
||||
// as first thing, invoke function onStart in the root object
|
||||
RequestEvaluator eval = getEvaluator();
|
||||
try {
|
||||
eval.invokeInternal(null, "onStart", new Object[0]);
|
||||
} catch (Exception ignore) {
|
||||
logEvent("Error in " + name + "/onStart(): " + ignore);
|
||||
} finally {
|
||||
if (!stopped) {
|
||||
releaseEvaluator(eval);
|
||||
}
|
||||
}
|
||||
|
||||
// loop-local cron job data
|
||||
List cronJobs = null;
|
||||
long lastCronParse = 0;
|
||||
|
@ -1369,8 +1387,12 @@ public final class Application implements IPathElement, Runnable {
|
|||
"30")));
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
RequestEvaluator thisEvaluator = null;
|
||||
|
||||
try {
|
||||
|
||||
thisEvaluator = getEvaluator();
|
||||
|
||||
Hashtable cloned = (Hashtable) sessions.clone();
|
||||
|
||||
for (Enumeration e = cloned.elements(); e.hasMoreElements();) {
|
||||
|
@ -1383,7 +1405,7 @@ public final class Application implements IPathElement, Runnable {
|
|||
try {
|
||||
Object[] param = { session.getSessionID() };
|
||||
|
||||
eval.invokeInternal(userhandle, "onLogout", param);
|
||||
thisEvaluator.invokeInternal(userhandle, "onLogout", param);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
@ -1394,6 +1416,10 @@ public final class Application implements IPathElement, Runnable {
|
|||
} catch (Exception cx) {
|
||||
logEvent("Error cleaning up sessions: " + cx);
|
||||
cx.printStackTrace();
|
||||
} finally {
|
||||
if (!stopped && thisEvaluator != null) {
|
||||
releaseEvaluator(thisEvaluator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
static final int HTTP = 1; // via HTTP gateway
|
||||
static final int XMLRPC = 2; // via XML-RPC
|
||||
static final int INTERNAL = 3; // generic function call, e.g. by scheduler
|
||||
static final int EXTERNAL = 4; // function from script etc
|
||||
public final Application app;
|
||||
protected ScriptingEngine scriptingEngine;
|
||||
public RequestTrans req;
|
||||
|
@ -496,6 +497,68 @@ public final class RequestEvaluator implements Runnable {
|
|||
|
||||
break;
|
||||
|
||||
|
||||
case EXTERNAL:
|
||||
|
||||
try {
|
||||
localrtx.begin(app.getName() + ":external:" + method);
|
||||
|
||||
root = app.getDataRoot();
|
||||
|
||||
HashMap globals = new HashMap();
|
||||
|
||||
globals.put("root", root);
|
||||
globals.put("res", new ResponseBean(res));
|
||||
globals.put("app", new ApplicationBean(app));
|
||||
|
||||
scriptingEngine.enterContext(globals);
|
||||
|
||||
currentElement = root;
|
||||
|
||||
if (method.indexOf('.') > -1) {
|
||||
StringTokenizer st = new StringTokenizer(method, ".");
|
||||
int cnt = st.countTokens();
|
||||
|
||||
for (int i = 1; i < cnt; i++) {
|
||||
String next = st.nextToken();
|
||||
|
||||
currentElement = getChildElement(currentElement,
|
||||
next);
|
||||
}
|
||||
|
||||
if (currentElement == null) {
|
||||
throw new FrameworkException("Method name \"" +
|
||||
method +
|
||||
"\" could not be resolved.");
|
||||
}
|
||||
|
||||
method = st.nextToken();
|
||||
}
|
||||
|
||||
// reset skin recursion detection counter
|
||||
skinDepth = 0;
|
||||
|
||||
result = scriptingEngine.invoke(currentElement, method, args,
|
||||
true);
|
||||
commitTransaction();
|
||||
} catch (Exception x) {
|
||||
abortTransaction(false);
|
||||
|
||||
app.logEvent("Exception in " + Thread.currentThread() + ": " +
|
||||
x);
|
||||
|
||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
||||
// bother for the error message, just quit.
|
||||
if (localrtx != rtx) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.exception = x;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case INTERNAL:
|
||||
|
||||
// Just a human readable descriptor of this invocation
|
||||
|
@ -727,6 +790,45 @@ public final class RequestEvaluator implements Runnable {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param method ...
|
||||
* @param args ...
|
||||
*
|
||||
* @return ...
|
||||
*
|
||||
* @throws Exception ...
|
||||
*/
|
||||
public synchronized Object invokeExternal(String method, Object[] args)
|
||||
throws Exception {
|
||||
this.reqtype = EXTERNAL;
|
||||
this.session = null;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
this.res = new ResponseTrans();
|
||||
result = null;
|
||||
exception = null;
|
||||
|
||||
checkThread();
|
||||
wait();
|
||||
|
||||
if (reqtype != NONE) {
|
||||
stopThread();
|
||||
}
|
||||
|
||||
// reset res for garbage collection (res.data may hold reference to evaluator)
|
||||
res = null;
|
||||
|
||||
if (exception != null) {
|
||||
throw (exception);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue