* 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:
hns 2003-12-09 16:47:44 +00:00
parent ae1aa70fdf
commit f3a623cf95
2 changed files with 145 additions and 17 deletions

View file

@ -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);
}
}
}

View file

@ -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;
}
/**
*
*