cleaned up request handling
This commit is contained in:
parent
c94f3e5a6b
commit
9a1f750707
1 changed files with 364 additions and 318 deletions
|
@ -121,343 +121,384 @@ public class RequestEvaluator implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* private void startThread () {
|
|
||||||
rtx = new Transactor (this, app.nmgr);
|
|
||||||
evaluator.thread = rtx;
|
|
||||||
rtx.start ();
|
|
||||||
// yield to make sure the transactor thread reaches waiting status before the first
|
|
||||||
// invocation request comes in
|
|
||||||
Thread.yield ();
|
|
||||||
} */
|
|
||||||
|
|
||||||
public void run () {
|
public void run () {
|
||||||
|
|
||||||
int txcount = 0;
|
int txcount = 0;
|
||||||
|
// first, set a local variable to the current transactor thread so we know
|
||||||
|
// when it's time to quit because another thread took over.
|
||||||
|
Transactor localrtx = (Transactor) Thread.currentThread ();
|
||||||
|
|
||||||
|
// evaluators are only initialized as needed, so we need to check that here
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
app.typemgr.initRequestEvaluator (this);
|
app.typemgr.initRequestEvaluator (this);
|
||||||
|
|
||||||
do {
|
try {
|
||||||
|
do {
|
||||||
|
|
||||||
// make sure there is only one thread running per instance of this class
|
// make sure there is only one thread running per instance of this class
|
||||||
Transactor tx = rtx;
|
if (localrtx != rtx) {
|
||||||
if (Thread.currentThread () != tx)
|
localrtx.closeConnections ();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// IServer.getLogger().log ("got request "+reqtype);
|
// IServer.getLogger().log ("got request "+reqtype);
|
||||||
|
|
||||||
switch (reqtype) {
|
switch (reqtype) {
|
||||||
case HTTP:
|
case HTTP:
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
|
|
||||||
current = null;
|
current = null;
|
||||||
currentNode = null;
|
currentNode = null;
|
||||||
reqPath.setSize (0);
|
reqPath.setSize (0);
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
String requestPath = app.getName()+"/"+req.path;
|
|
||||||
// set Timer to get some profiling data
|
|
||||||
tx.timer.reset ();
|
|
||||||
tx.timer.beginEvent (requestPath+" init");
|
|
||||||
tx.begin (requestPath);
|
|
||||||
|
|
||||||
Action action = null;
|
|
||||||
|
|
||||||
root = app.getDataRoot ();
|
|
||||||
|
|
||||||
ESUser esu = (ESUser) getNodeWrapper (user.getNode ());
|
|
||||||
esu.setUser (user);
|
|
||||||
global.putHiddenProperty ("root", getNodeWrapper (root));
|
|
||||||
global.putHiddenProperty("user", esu);
|
|
||||||
global.putHiddenProperty ("req", new ESWrapper (req, evaluator));
|
|
||||||
global.putHiddenProperty ("res", new ESWrapper (res, evaluator));
|
|
||||||
global.putHiddenProperty ("path", reqPath);
|
|
||||||
global.putHiddenProperty ("app", appnode);
|
|
||||||
// set and mount the request data object
|
|
||||||
reqData.setData (req.getReqData());
|
|
||||||
req.data = reqData;
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
if (req.path == null || "".equals (req.path.trim ())) {
|
|
||||||
currentNode = root;
|
|
||||||
current = getNodeWrapper (root);
|
|
||||||
reqPath.putProperty (0, current);
|
|
||||||
Prototype p = app.getPrototype (root);
|
|
||||||
action = p.getActionOrTemplate (null);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// march down request path...
|
|
||||||
|
|
||||||
// is the next path element a subnode or a property of the last one?
|
|
||||||
// currently only used for users node
|
|
||||||
boolean isProperty = false;
|
|
||||||
StringTokenizer st = new StringTokenizer (req.path, "/");
|
|
||||||
int ntokens = st.countTokens ();
|
|
||||||
String next = null;
|
|
||||||
currentNode = root;
|
|
||||||
reqPath.putProperty (0, getNodeWrapper (currentNode));
|
|
||||||
|
|
||||||
// the first token in the path needs to be treated seprerately,
|
|
||||||
// because "/user" is a shortcut to the current user session, while "/users"
|
|
||||||
// is the mounting point for all users.
|
|
||||||
if (ntokens > 1) {
|
|
||||||
next = st.nextToken ();
|
|
||||||
if ("user".equalsIgnoreCase (next)) {
|
|
||||||
currentNode = user.getNode ();
|
|
||||||
ntokens -=1;
|
|
||||||
if (currentNode != null)
|
|
||||||
reqPath.putProperty (1, getNodeWrapper (currentNode));
|
|
||||||
} else if ("users".equalsIgnoreCase (next)) {
|
|
||||||
currentNode = app.getUserRoot ();
|
|
||||||
ntokens -=1;
|
|
||||||
isProperty = true;
|
|
||||||
} else {
|
|
||||||
currentNode = currentNode.getSubnode (next);
|
|
||||||
ntokens -=1;
|
|
||||||
if (currentNode != null)
|
|
||||||
reqPath.putProperty (1, getNodeWrapper (currentNode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=1; i<ntokens; i++) {
|
|
||||||
if (currentNode == null)
|
|
||||||
throw new FrameworkException ("Object not found.");
|
|
||||||
next = st.nextToken ();
|
|
||||||
if (isProperty) // get next element as property
|
|
||||||
currentNode = currentNode.getNode (next, false);
|
|
||||||
else // get next element as subnode
|
|
||||||
currentNode = currentNode.getSubnode (next);
|
|
||||||
isProperty = false;
|
|
||||||
if (currentNode != null && currentNode.getState() != INode.VIRTUAL) // add to reqPath array
|
|
||||||
reqPath.putProperty (reqPath.size(), getNodeWrapper (currentNode));
|
|
||||||
// limit path to < 50 tokens
|
|
||||||
if (i > 50) throw new RuntimeException ("Path too deep");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentNode == null)
|
|
||||||
throw new FrameworkException ("Object not found.");
|
|
||||||
|
|
||||||
Prototype p = app.getPrototype (currentNode);
|
|
||||||
next = st.nextToken ();
|
|
||||||
if (p != null)
|
|
||||||
action = p.getActionOrTemplate (next);
|
|
||||||
|
|
||||||
if (p == null || action == null) {
|
|
||||||
currentNode = currentNode.getSubnode (next);
|
|
||||||
if (currentNode == null)
|
|
||||||
throw new FrameworkException ("Object or Action '"+next+"' not found.");
|
|
||||||
p = app.getPrototype (currentNode);
|
|
||||||
// add to reqPath array
|
|
||||||
if (currentNode != null && currentNode.getState() != INode.VIRTUAL)
|
|
||||||
reqPath.putProperty (reqPath.size(), getNodeWrapper (currentNode));
|
|
||||||
if (p != null)
|
|
||||||
action = p.getActionOrTemplate ("main");
|
|
||||||
}
|
|
||||||
|
|
||||||
current = getNodeWrapper (currentNode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == null)
|
|
||||||
throw new FrameworkException ("Action not found");
|
|
||||||
|
|
||||||
} catch (FrameworkException notfound) {
|
|
||||||
// The path could not be resolved. Check if there is a "not found" action
|
|
||||||
// specified in the property file.
|
|
||||||
String notFoundAction = app.props.getProperty ("notFound", "notfound");
|
|
||||||
Prototype p = app.getPrototype (root);
|
|
||||||
action = p.getActionOrTemplate (notFoundAction);
|
|
||||||
if (action == null)
|
|
||||||
throw new FrameworkException (notfound.getMessage ());
|
|
||||||
current = getNodeWrapper (root);
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.timer.endEvent (requestPath+" init");
|
|
||||||
|
|
||||||
try {
|
|
||||||
tx.timer.beginEvent (requestPath+" execute");
|
|
||||||
current.doIndirectCall (evaluator, current, action.getFunctionName (), new ESValue[0]);
|
|
||||||
tx.timer.endEvent (requestPath+" execute");
|
|
||||||
done = true;
|
|
||||||
} catch (RedirectException redirect) {
|
|
||||||
res.redirect = redirect.getMessage ();
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we're still on track
|
|
||||||
if (tx == rtx)
|
|
||||||
tx.commit ();
|
|
||||||
else
|
|
||||||
throw new TimeoutException ();
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
} catch (ConcurrencyException x) {
|
|
||||||
try { tx.abort (); } catch (Exception ignore) {}
|
|
||||||
res.reset ();
|
|
||||||
if (++tries < 8) {
|
|
||||||
try {
|
try {
|
||||||
// wait a bit longer with each try
|
|
||||||
int base = 500 * tries;
|
|
||||||
Thread.currentThread ().sleep ((long) (base + Math.random ()*base*2));
|
|
||||||
} catch (Exception ignore) {}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
app.errorCount += 1;
|
|
||||||
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>Couldn't complete transaction due to heavy object traffic (tried "+tries+" times).</pre>");
|
|
||||||
done = true;
|
|
||||||
|
|
||||||
} catch (FrameworkException x) {
|
String requestPath = app.getName()+"/"+req.path;
|
||||||
try { tx.abort (); } catch (Exception ignore) {}
|
// set Timer to get some profiling data
|
||||||
app.errorCount += 1;
|
localrtx.timer.reset ();
|
||||||
res.reset ();
|
localrtx.timer.beginEvent (requestPath+" init");
|
||||||
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>" + x.getMessage () + "</pre>");
|
localrtx.begin (requestPath);
|
||||||
if (app.debug)
|
|
||||||
x.printStackTrace ();
|
|
||||||
|
|
||||||
done = true;
|
Action action = null;
|
||||||
} catch (Exception x) {
|
|
||||||
try { tx.abort (); } catch (Exception ignore) {}
|
|
||||||
app.errorCount += 1;
|
|
||||||
System.err.println ("### Exception in "+app.getName()+"/"+req.path+": current = "+currentNode);
|
|
||||||
System.err.println (x);
|
|
||||||
// Dump the profiling data to System.err
|
|
||||||
((Transactor) Thread.currentThread ()).timer.dump (System.err);
|
|
||||||
if (app.debug)
|
|
||||||
x.printStackTrace ();
|
|
||||||
|
|
||||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
root = app.getDataRoot ();
|
||||||
// bother for the error message, just quit.
|
|
||||||
if (rtx != tx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
res.reset ();
|
|
||||||
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>" + x.getMessage () + "</pre>");
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XMLRPC:
|
|
||||||
try {
|
|
||||||
tx.begin (app.getName()+":xmlrpc/"+method);
|
|
||||||
|
|
||||||
root = app.getDataRoot ();
|
|
||||||
|
|
||||||
global.putHiddenProperty ("root", getNodeWrapper (root));
|
|
||||||
global.deleteProperty("user", "user".hashCode());
|
|
||||||
global.deleteProperty ("req", "req".hashCode());
|
|
||||||
global.putHiddenProperty ("res", ESLoader.normalizeValue(new ResponseTrans (), evaluator));
|
|
||||||
global.deleteProperty ("path", "path".hashCode());
|
|
||||||
global.putHiddenProperty ("app", appnode);
|
|
||||||
|
|
||||||
// convert arguments
|
|
||||||
int l = args.size ();
|
|
||||||
current = getNodeWrapper (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 ();
|
|
||||||
try {
|
|
||||||
current = (ESObject) current.getProperty (next, next.hashCode ());
|
|
||||||
} catch (Exception x) {
|
|
||||||
throw new EcmaScriptException ("The property \""+next+"\" is not defined in the remote object.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (current == null)
|
|
||||||
throw new EcmaScriptException ("Method name \""+method+"\" could not be resolved.");
|
|
||||||
method = st.nextToken ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check XML-RPC access permissions
|
|
||||||
String proto = ((ESNode) current).getNode().getPrototype ();
|
|
||||||
app.checkXmlRpcAccess (proto, method);
|
|
||||||
|
|
||||||
ESValue esa[] = new ESValue[l];
|
|
||||||
for (int i=0; i<l; i++) {
|
|
||||||
esa[i] = FesiRpcUtil.convertJ2E (args.elementAt (i), evaluator);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = FesiRpcUtil.convertE2J (current.doIndirectCall (evaluator, current, method, esa));
|
|
||||||
tx.commit ();
|
|
||||||
} catch (Exception wrong) {
|
|
||||||
try { tx.abort (); } catch (Exception ignore) {}
|
|
||||||
|
|
||||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
|
||||||
// bother for the error message, just quit.
|
|
||||||
if (evaluator.thread != Thread.currentThread())
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.exception = wrong;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case INTERNAL:
|
|
||||||
esresult = ESNull.theNull;
|
|
||||||
// Just a human readable descriptor of this invocation
|
|
||||||
String funcdesc = app.getName()+":internal/"+method;
|
|
||||||
try {
|
|
||||||
tx.begin (funcdesc);
|
|
||||||
|
|
||||||
root = app.getDataRoot ();
|
|
||||||
|
|
||||||
global.putHiddenProperty ("root", getNodeWrapper (root));
|
|
||||||
global.deleteProperty("user", "user".hashCode());
|
|
||||||
global.deleteProperty ("req", "req".hashCode());
|
|
||||||
global.putHiddenProperty ("res", ESLoader.normalizeValue(new ResponseTrans (), evaluator));
|
|
||||||
global.deleteProperty ("path", "path".hashCode());
|
|
||||||
global.putHiddenProperty ("app", appnode);
|
|
||||||
|
|
||||||
if (current == null) {
|
|
||||||
if (user == null) {
|
|
||||||
current = global;
|
|
||||||
} else {
|
|
||||||
ESUser esu = (ESUser) getNodeWrapper (user.getNode ());
|
ESUser esu = (ESUser) getNodeWrapper (user.getNode ());
|
||||||
esu.setUser (user);
|
esu.setUser (user);
|
||||||
current = esu;
|
global.putHiddenProperty ("root", getNodeWrapper (root));
|
||||||
|
global.putHiddenProperty("user", esu);
|
||||||
|
global.putHiddenProperty ("req", new ESWrapper (req, evaluator));
|
||||||
|
global.putHiddenProperty ("res", new ESWrapper (res, evaluator));
|
||||||
|
global.putHiddenProperty ("path", reqPath);
|
||||||
|
global.putHiddenProperty ("app", appnode);
|
||||||
|
// set and mount the request data object
|
||||||
|
reqData.setData (req.getReqData());
|
||||||
|
req.data = reqData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (req.path == null || "".equals (req.path.trim ())) {
|
||||||
|
currentNode = root;
|
||||||
|
current = getNodeWrapper (root);
|
||||||
|
reqPath.putProperty (0, current);
|
||||||
|
Prototype p = app.getPrototype (root);
|
||||||
|
action = p.getActionOrTemplate (null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// march down request path...
|
||||||
|
// is the next path element a subnode or a property of the last one?
|
||||||
|
// currently only used for users node
|
||||||
|
boolean isProperty = false;
|
||||||
|
StringTokenizer st = new StringTokenizer (req.path, "/");
|
||||||
|
int ntokens = st.countTokens ();
|
||||||
|
String next = null;
|
||||||
|
currentNode = root;
|
||||||
|
reqPath.putProperty (0, getNodeWrapper (currentNode));
|
||||||
|
|
||||||
|
// the first token in the path needs to be treated seprerately,
|
||||||
|
// because "/user" is a shortcut to the current user session, while "/users"
|
||||||
|
// is the mounting point for all users.
|
||||||
|
if (ntokens > 1) {
|
||||||
|
next = st.nextToken ();
|
||||||
|
if ("user".equalsIgnoreCase (next)) {
|
||||||
|
currentNode = user.getNode ();
|
||||||
|
ntokens -=1;
|
||||||
|
if (currentNode != null)
|
||||||
|
reqPath.putProperty (1, getNodeWrapper (currentNode));
|
||||||
|
} else if ("users".equalsIgnoreCase (next)) {
|
||||||
|
currentNode = app.getUserRoot ();
|
||||||
|
ntokens -=1;
|
||||||
|
isProperty = true;
|
||||||
|
} else {
|
||||||
|
currentNode = currentNode.getSubnode (next);
|
||||||
|
ntokens -=1;
|
||||||
|
if (currentNode != null)
|
||||||
|
reqPath.putProperty (1, getNodeWrapper (currentNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=1; i<ntokens; i++) {
|
||||||
|
if (currentNode == null)
|
||||||
|
throw new FrameworkException ("Object not found.");
|
||||||
|
next = st.nextToken ();
|
||||||
|
if (isProperty) // get next element as property
|
||||||
|
currentNode = currentNode.getNode (next, false);
|
||||||
|
else // get next element as subnode
|
||||||
|
currentNode = currentNode.getSubnode (next);
|
||||||
|
isProperty = false;
|
||||||
|
if (currentNode != null && currentNode.getState() != INode.VIRTUAL) // add to reqPath array
|
||||||
|
reqPath.putProperty (reqPath.size(), getNodeWrapper (currentNode));
|
||||||
|
// limit path to < 50 tokens
|
||||||
|
if (i > 50) throw new RuntimeException ("Path too deep");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentNode == null)
|
||||||
|
throw new FrameworkException ("Object not found.");
|
||||||
|
|
||||||
|
Prototype p = app.getPrototype (currentNode);
|
||||||
|
next = st.nextToken ();
|
||||||
|
if (p != null)
|
||||||
|
action = p.getActionOrTemplate (next);
|
||||||
|
|
||||||
|
if (p == null || action == null) {
|
||||||
|
currentNode = currentNode.getSubnode (next);
|
||||||
|
if (currentNode == null)
|
||||||
|
throw new FrameworkException ("Object or Action '"+next+"' not found.");
|
||||||
|
p = app.getPrototype (currentNode);
|
||||||
|
// add to reqPath array
|
||||||
|
if (currentNode != null && currentNode.getState() != INode.VIRTUAL)
|
||||||
|
reqPath.putProperty (reqPath.size(), getNodeWrapper (currentNode));
|
||||||
|
if (p != null)
|
||||||
|
action = p.getActionOrTemplate ("main");
|
||||||
|
}
|
||||||
|
|
||||||
|
current = getNodeWrapper (currentNode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == null)
|
||||||
|
throw new FrameworkException ("Action not found");
|
||||||
|
|
||||||
|
} catch (FrameworkException notfound) {
|
||||||
|
// The path could not be resolved. Check if there is a "not found" action
|
||||||
|
// specified in the property file.
|
||||||
|
String notFoundAction = app.props.getProperty ("notFound", "notfound");
|
||||||
|
Prototype p = app.getPrototype (root);
|
||||||
|
action = p.getActionOrTemplate (notFoundAction);
|
||||||
|
if (action == null)
|
||||||
|
throw new FrameworkException (notfound.getMessage ());
|
||||||
|
current = getNodeWrapper (root);
|
||||||
|
}
|
||||||
|
|
||||||
|
localrtx.timer.endEvent (requestPath+" init");
|
||||||
|
|
||||||
|
try {
|
||||||
|
localrtx.timer.beginEvent (requestPath+" execute");
|
||||||
|
current.doIndirectCall (evaluator, current, action.getFunctionName (), new ESValue[0]);
|
||||||
|
localrtx.timer.endEvent (requestPath+" execute");
|
||||||
|
done = true;
|
||||||
|
} catch (RedirectException redirect) {
|
||||||
|
res.redirect = redirect.getMessage ();
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we're still the one and only or if the waiting thread has given up on us already
|
||||||
|
commitTransaction ();
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
} catch (ConcurrencyException x) {
|
||||||
|
|
||||||
|
res.reset ();
|
||||||
|
if (++tries < 10) {
|
||||||
|
// try again after waiting some period
|
||||||
|
abortTransaction (true);
|
||||||
|
try {
|
||||||
|
// wait a bit longer with each try
|
||||||
|
int base = 200 * tries;
|
||||||
|
Thread.currentThread ().sleep ((long) (base + Math.random ()*base*2));
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
abortTransaction (false);
|
||||||
|
app.errorCount += 1;
|
||||||
|
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>Couldn't complete transaction due to heavy object traffic (tried "+tries+" times).</pre>");
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (FrameworkException x) {
|
||||||
|
|
||||||
|
abortTransaction (false);
|
||||||
|
|
||||||
|
app.errorCount += 1;
|
||||||
|
res.reset ();
|
||||||
|
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>" + x.getMessage () + "</pre>");
|
||||||
|
if (app.debug)
|
||||||
|
x.printStackTrace ();
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
} catch (Exception x) {
|
||||||
|
|
||||||
|
abortTransaction (false);
|
||||||
|
|
||||||
|
app.errorCount += 1;
|
||||||
|
System.err.println ("### Exception in "+app.getName()+"/"+req.path+": current = "+currentNode);
|
||||||
|
System.err.println (x);
|
||||||
|
// Dump the profiling data to System.err
|
||||||
|
((Transactor) Thread.currentThread ()).timer.dump (System.err);
|
||||||
|
if (app.debug)
|
||||||
|
x.printStackTrace ();
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
break;
|
||||||
|
|
||||||
|
res.reset ();
|
||||||
|
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>" + x.getMessage () + "</pre>");
|
||||||
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
esresult = current.doIndirectCall (evaluator, current, method, new ESValue[0]);
|
break;
|
||||||
tx.commit ();
|
case XMLRPC:
|
||||||
} catch (Throwable wrong) {
|
try {
|
||||||
try { tx.abort (); } catch (Exception ignore) {}
|
localrtx.begin (app.getName()+":xmlrpc/"+method);
|
||||||
|
|
||||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
root = app.getDataRoot ();
|
||||||
// bother for the error message, just quit.
|
|
||||||
if (evaluator.thread != Thread.currentThread())
|
global.putHiddenProperty ("root", getNodeWrapper (root));
|
||||||
return;
|
global.deleteProperty("user", "user".hashCode());
|
||||||
|
global.deleteProperty ("req", "req".hashCode());
|
||||||
|
global.putHiddenProperty ("res", ESLoader.normalizeValue(new ResponseTrans (), evaluator));
|
||||||
|
global.deleteProperty ("path", "path".hashCode());
|
||||||
|
global.putHiddenProperty ("app", appnode);
|
||||||
|
|
||||||
|
// convert arguments
|
||||||
|
int l = args.size ();
|
||||||
|
current = getNodeWrapper (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 ();
|
||||||
|
try {
|
||||||
|
current = (ESObject) current.getProperty (next, next.hashCode ());
|
||||||
|
} catch (Exception x) {
|
||||||
|
throw new EcmaScriptException ("The property \""+next+"\" is not defined in the remote object.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current == null)
|
||||||
|
throw new EcmaScriptException ("Method name \""+method+"\" could not be resolved.");
|
||||||
|
method = st.nextToken ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check XML-RPC access permissions
|
||||||
|
String proto = ((ESNode) current).getNode().getPrototype ();
|
||||||
|
app.checkXmlRpcAccess (proto, method);
|
||||||
|
|
||||||
|
ESValue esa[] = new ESValue[l];
|
||||||
|
for (int i=0; i<l; i++) {
|
||||||
|
esa[i] = FesiRpcUtil.convertJ2E (args.elementAt (i), evaluator);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = FesiRpcUtil.convertE2J (current.doIndirectCall (evaluator, current, method, esa));
|
||||||
|
commitTransaction ();
|
||||||
|
|
||||||
|
} catch (Exception wrong) {
|
||||||
|
|
||||||
|
abortTransaction (false);
|
||||||
|
|
||||||
|
// 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 = wrong;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case INTERNAL:
|
||||||
|
esresult = ESNull.theNull;
|
||||||
|
// Just a human readable descriptor of this invocation
|
||||||
|
String funcdesc = app.getName()+":internal/"+method;
|
||||||
|
try {
|
||||||
|
localrtx.begin (funcdesc);
|
||||||
|
|
||||||
|
root = app.getDataRoot ();
|
||||||
|
|
||||||
|
global.putHiddenProperty ("root", getNodeWrapper (root));
|
||||||
|
global.deleteProperty("user", "user".hashCode());
|
||||||
|
global.deleteProperty ("req", "req".hashCode());
|
||||||
|
global.putHiddenProperty ("res", ESLoader.normalizeValue(new ResponseTrans (), evaluator));
|
||||||
|
global.deleteProperty ("path", "path".hashCode());
|
||||||
|
global.putHiddenProperty ("app", appnode);
|
||||||
|
|
||||||
|
if (current == null) {
|
||||||
|
if (user == null) {
|
||||||
|
current = global;
|
||||||
|
} else {
|
||||||
|
ESUser esu = (ESUser) getNodeWrapper (user.getNode ());
|
||||||
|
esu.setUser (user);
|
||||||
|
current = esu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
esresult = current.doIndirectCall (evaluator, current, method, new ESValue[0]);
|
||||||
|
commitTransaction ();
|
||||||
|
|
||||||
|
} catch (Throwable wrong) {
|
||||||
|
|
||||||
|
abortTransaction (false);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = wrong.getMessage ();
|
||||||
|
if (msg == null || msg.length () == 0)
|
||||||
|
msg = wrong.toString ();
|
||||||
|
IServer.getLogger().log ("Error executing "+funcdesc+": "+msg);
|
||||||
|
this.exception = new Exception (msg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
String msg = wrong.getMessage ();
|
|
||||||
if (msg == null || msg.length () == 0)
|
|
||||||
msg = wrong.toString ();
|
|
||||||
IServer.getLogger().log ("Error executing "+funcdesc+": "+msg);
|
|
||||||
this.exception = new Exception (msg);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
// create a new Thread every 1000 requests. The current one will fade out
|
||||||
reqtype = NONE;
|
if (txcount++ > 1000) {
|
||||||
|
// stop thread - a new one will be created when needed
|
||||||
// create a new Thread every 1000 requests. The current one will fade out
|
localrtx.closeConnections ();
|
||||||
if (txcount++ > 1000) {
|
break;
|
||||||
stopThread (); // stop thread - a new one will be created when needed
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this) {
|
|
||||||
notifyAll ();
|
|
||||||
try {
|
|
||||||
wait ();
|
|
||||||
} catch (InterruptedException ir) {
|
|
||||||
Thread.currentThread ().interrupt ();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} while (evaluator.thread == Thread.currentThread () && evaluator.thread == rtx);
|
notifyAndWait ();
|
||||||
|
|
||||||
|
} while (localrtx == rtx);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
localrtx.closeConnections ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the transactor thread when it has successfully fulfilled a request.
|
||||||
|
*/
|
||||||
|
synchronized void commitTransaction () throws Exception {
|
||||||
|
Transactor localrtx = (Transactor) Thread.currentThread ();
|
||||||
|
if (localrtx == rtx) {
|
||||||
|
reqtype = NONE;
|
||||||
|
localrtx.commit ();
|
||||||
|
} else {
|
||||||
|
throw new TimeoutException ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void abortTransaction (boolean retry) {
|
||||||
|
Transactor localrtx = (Transactor) Thread.currentThread ();
|
||||||
|
if (!retry && localrtx == rtx)
|
||||||
|
reqtype = NONE;
|
||||||
|
try {
|
||||||
|
localrtx.abort ();
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell waiting thread that we're done, then wait for next request
|
||||||
|
*/
|
||||||
|
synchronized void notifyAndWait () {
|
||||||
|
Transactor localrtx = (Transactor) Thread.currentThread ();
|
||||||
|
if (reqtype != NONE)
|
||||||
|
return;
|
||||||
|
notifyAll ();
|
||||||
|
try {
|
||||||
|
wait ();
|
||||||
|
} catch (InterruptedException ir) {
|
||||||
|
localrtx.closeConnections ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized ResponseTrans invoke (RequestTrans req, User user) throws Exception {
|
public synchronized ResponseTrans invoke (RequestTrans req, User user) throws Exception {
|
||||||
|
@ -468,7 +509,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
|
|
||||||
checkThread ();
|
checkThread ();
|
||||||
wait (app.requestTimeout);
|
wait (app.requestTimeout);
|
||||||
if (reqtype > 0) {
|
if (reqtype != NONE) {
|
||||||
IServer.getLogger().log ("Stopping Thread for Request "+app.getName()+"/"+req.path);
|
IServer.getLogger().log ("Stopping Thread for Request "+app.getName()+"/"+req.path);
|
||||||
stopThread ();
|
stopThread ();
|
||||||
res.reset ();
|
res.reset ();
|
||||||
|
@ -489,7 +530,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
|
|
||||||
checkThread ();
|
checkThread ();
|
||||||
wait (app.requestTimeout);
|
wait (app.requestTimeout);
|
||||||
if (reqtype > 0) {
|
if (reqtype != NONE) {
|
||||||
stopThread ();
|
stopThread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +562,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
checkThread ();
|
checkThread ();
|
||||||
wait (60000l*15); // give internal call more time (15 minutes) to complete
|
wait (60000l*15); // give internal call more time (15 minutes) to complete
|
||||||
|
|
||||||
if (reqtype > 0) {
|
if (reqtype != NONE) {
|
||||||
stopThread ();
|
stopThread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +584,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
checkThread ();
|
checkThread ();
|
||||||
wait (app.requestTimeout);
|
wait (app.requestTimeout);
|
||||||
|
|
||||||
if (reqtype > 0) {
|
if (reqtype != NONE) {
|
||||||
stopThread ();
|
stopThread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,17 +600,20 @@ public class RequestEvaluator implements Runnable {
|
||||||
*/
|
*/
|
||||||
public synchronized void stopThread () {
|
public synchronized void stopThread () {
|
||||||
// IServer.getLogger().log ("Stopping Thread");
|
// IServer.getLogger().log ("Stopping Thread");
|
||||||
evaluator.thread = null;
|
|
||||||
Transactor t = rtx;
|
Transactor t = rtx;
|
||||||
|
evaluator.thread = null;
|
||||||
rtx = null;
|
rtx = null;
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
if (reqtype != NONE) {
|
if (reqtype != NONE) {
|
||||||
try { t.abort (); } catch (Exception ignore) {}
|
try {
|
||||||
|
t.abort ();
|
||||||
|
} catch (Exception ignore) {}
|
||||||
t.kill ();
|
t.kill ();
|
||||||
|
reqtype = NONE;
|
||||||
} else {
|
} else {
|
||||||
notifyAll ();
|
notifyAll ();
|
||||||
}
|
}
|
||||||
t.cleanup ();
|
t.closeConnections ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +634,9 @@ public class RequestEvaluator implements Runnable {
|
||||||
* in those places when wrappers have to be updated if they already exist.
|
* in those places when wrappers have to be updated if they already exist.
|
||||||
*/
|
*/
|
||||||
public ESNode getNodeWrapperFromCache (INode n) {
|
public ESNode getNodeWrapperFromCache (INode n) {
|
||||||
return n == null ? null : (ESNode) objectcache.get (n);
|
if (n == null)
|
||||||
|
return null;
|
||||||
|
return (ESNode) objectcache.get (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ESNode getNodeWrapper (INode n) {
|
public ESNode getNodeWrapper (INode n) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue