Threads and evaluators are now started in lazy mode - only when needed. Halleluja!
This commit is contained in:
parent
73bcc24ffc
commit
6d0491e2de
12 changed files with 396 additions and 235 deletions
|
@ -8,6 +8,13 @@ import java.io.*;
|
|||
import helma.framework.*;
|
||||
import helma.objectmodel.IServer;
|
||||
import FESI.Data.*;
|
||||
import FESI.Parser.*;
|
||||
import FESI.AST.ASTFormalParameterList;
|
||||
import FESI.AST.ASTStatementList;
|
||||
import FESI.AST.EcmaScriptTreeConstants;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -20,34 +27,40 @@ import FESI.Data.*;
|
|||
public class Action {
|
||||
|
||||
String name;
|
||||
String functionName;
|
||||
Prototype prototype;
|
||||
Application app;
|
||||
File file;
|
||||
long lastmod;
|
||||
|
||||
|
||||
ParsedFunction pfunc;
|
||||
|
||||
|
||||
public Action (File file, String name, Prototype proto) {
|
||||
this.prototype = proto;
|
||||
this.app = proto.app;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
update (file);
|
||||
}
|
||||
|
||||
|
||||
public void update (File f) {
|
||||
|
||||
long fmod = f.lastModified ();
|
||||
this.file = f;
|
||||
long fmod = file.lastModified ();
|
||||
if (lastmod == fmod)
|
||||
return;
|
||||
|
||||
try {
|
||||
FileReader reader = new FileReader (f);
|
||||
char cbuf[] = new char[(int)f.length ()];
|
||||
FileReader reader = new FileReader (file);
|
||||
char cbuf[] = new char[(int) file.length ()];
|
||||
reader.read (cbuf);
|
||||
reader.close ();
|
||||
String content = new String (cbuf);
|
||||
update (content);
|
||||
} catch (Exception filex) {
|
||||
IServer.getLogger().log ("*** Error reading template file "+f+": "+filex);
|
||||
IServer.getLogger().log ("*** Error reading action file "+file+": "+filex);
|
||||
}
|
||||
lastmod = fmod;
|
||||
}
|
||||
|
@ -57,13 +70,13 @@ public class Action {
|
|||
public void update (String content) throws Exception {
|
||||
// IServer.getLogger().log ("Reading text template " + name);
|
||||
|
||||
functionName = name+"_hop_action";
|
||||
String fname = name+"_hop_action";
|
||||
|
||||
try {
|
||||
app.typemgr.readFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content, prototype.getName ());
|
||||
pfunc = parseFunction (fname, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
app.typemgr.generateErrorFeedback (functionName, message, prototype.getName ());
|
||||
app.typemgr.generateErrorFeedback (fname, message, prototype.getName ());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,9 +87,97 @@ public class Action {
|
|||
}
|
||||
|
||||
public String getFunctionName () {
|
||||
return functionName;
|
||||
return pfunc.functionName;
|
||||
}
|
||||
|
||||
protected ParsedFunction parseFunction (String funcname, String params, String body) throws EcmaScriptException {
|
||||
|
||||
// ESObject fp = app.eval.evaluator.getFunctionPrototype();
|
||||
// ConstructedFunctionObject function = null;
|
||||
ASTFormalParameterList fpl = null;
|
||||
ASTStatementList sl = null;
|
||||
FunctionEvaluationSource fes = null;
|
||||
|
||||
if (body == null || "".equals (body.trim()))
|
||||
body = ";\r\n";
|
||||
else
|
||||
body = body + "\r\n";
|
||||
if (params == null) params = "";
|
||||
else params = params.trim ();
|
||||
|
||||
String fulltext = "function "+funcname+" (" + params + ") {\n" + body + "\n}";
|
||||
|
||||
EcmaScript parser;
|
||||
StringReader is;
|
||||
|
||||
// Special case for empty parameters
|
||||
if (params.length()==0) {
|
||||
fpl = new ASTFormalParameterList(EcmaScriptTreeConstants.JJTFORMALPARAMETERLIST);
|
||||
} else {
|
||||
is = new java.io.StringReader(params);
|
||||
parser = new EcmaScript(is);
|
||||
try {
|
||||
fpl = (ASTFormalParameterList) parser.FormalParameterList();
|
||||
is.close();
|
||||
} catch (ParseException x) {
|
||||
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null));
|
||||
}
|
||||
}
|
||||
// this is very very very strange: without the toString, lots of obscure exceptions
|
||||
// deep inside the parser...
|
||||
is = new java.io.StringReader(body.toString ());
|
||||
try {
|
||||
parser = new EcmaScript (is);
|
||||
sl = (ASTStatementList) parser.StatementList();
|
||||
is.close();
|
||||
} catch (ParseException x) {
|
||||
IServer.getLogger().log ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x);
|
||||
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null));
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger().log ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x);
|
||||
throw new RuntimeException (x.getMessage ());
|
||||
}
|
||||
|
||||
fes = new FunctionEvaluationSource (new StringEvaluationSource(fulltext, null), funcname);
|
||||
return new ParsedFunction (fpl, sl, fes, fulltext, funcname);
|
||||
}
|
||||
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
if (pfunc != null)
|
||||
pfunc.updateRequestEvaluator (reval);
|
||||
}
|
||||
|
||||
class ParsedFunction {
|
||||
|
||||
ASTFormalParameterList fpl = null;
|
||||
ASTStatementList sl = null;
|
||||
FunctionEvaluationSource fes = null;
|
||||
String fullFunctionText = null;
|
||||
String functionName;
|
||||
|
||||
public ParsedFunction (ASTFormalParameterList fpl, ASTStatementList sl, FunctionEvaluationSource fes,
|
||||
String fullFunctionText, String functionName) {
|
||||
this.fpl = fpl;
|
||||
this.sl = sl;
|
||||
this.fes = fes;
|
||||
this.fullFunctionText = fullFunctionText;
|
||||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
|
||||
EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor();
|
||||
Vector vnames = vdvisitor.processVariableDeclarations(sl, fes);
|
||||
|
||||
FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction (
|
||||
reval.evaluator, functionName, fes,
|
||||
fullFunctionText, fpl.getArguments(), vnames, sl);
|
||||
op.putHiddenProperty (functionName, fp);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, Runn
|
|||
TypeManager typemgr;
|
||||
|
||||
RequestEvaluator eval;
|
||||
private Stack freeThreads;
|
||||
protected Stack freeThreads;
|
||||
protected Vector allThreads;
|
||||
|
||||
Hashtable sessions;
|
||||
|
@ -154,7 +154,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, Runn
|
|||
if (allThreads != null) {
|
||||
for (Enumeration e=allThreads.elements (); e.hasMoreElements (); ) {
|
||||
RequestEvaluator ev = (RequestEvaluator) e.nextElement ();
|
||||
ev.stop ();
|
||||
ev.stopThread ();
|
||||
}
|
||||
}
|
||||
allThreads.removeAllElements ();
|
||||
|
@ -166,20 +166,49 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, Runn
|
|||
}
|
||||
}
|
||||
|
||||
public synchronized RequestEvaluator getEvaluator () {
|
||||
protected RequestEvaluator getEvaluator () {
|
||||
if (freeThreads == null)
|
||||
throw new ApplicationStoppedException ();
|
||||
if (freeThreads.empty ())
|
||||
try {
|
||||
return (RequestEvaluator) freeThreads.pop ();
|
||||
} catch (EmptyStackException nothreads) {
|
||||
throw new RuntimeException ("Maximum Thread count reached.");
|
||||
RequestEvaluator ev = (RequestEvaluator) freeThreads.pop ();
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void releaseEvaluator (RequestEvaluator ev) {
|
||||
protected void releaseEvaluator (RequestEvaluator ev) {
|
||||
if (ev != null)
|
||||
freeThreads.push (ev);
|
||||
}
|
||||
|
||||
protected boolean setNumberOfEvaluators (int n) {
|
||||
if (n < 1 || n > 512)
|
||||
return false;
|
||||
int current = allThreads.size();
|
||||
synchronized (allThreads) {
|
||||
if (n > current) {
|
||||
int toBeCreated = n - current;
|
||||
for (int i=0; i<toBeCreated; i++) {
|
||||
RequestEvaluator ev = new RequestEvaluator (this);
|
||||
freeThreads.push (ev);
|
||||
allThreads.addElement (ev);
|
||||
}
|
||||
} else if (n < current) {
|
||||
int toBeDestroyed = current - n;
|
||||
for (int i=0; i<toBeDestroyed; i++) {
|
||||
try {
|
||||
RequestEvaluator re = (RequestEvaluator) freeThreads.pop ();
|
||||
allThreads.removeElement (re);
|
||||
re.stopThread ();
|
||||
} catch (EmptyStackException empty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public ResponseTrans execute (RequestTrans req) {
|
||||
|
||||
requestCount += 1;
|
||||
|
@ -243,8 +272,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, Runn
|
|||
}
|
||||
|
||||
public Prototype getPrototype (String str) {
|
||||
if (debug)
|
||||
IServer.getLogger().log ("retrieving prototype for name "+str);
|
||||
return typemgr.getPrototype (str);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ package helma.framework.core;
|
|||
import helma.objectmodel.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Interpreter.Evaluator;
|
||||
|
||||
/**
|
||||
* ESApp represents the app node of an application, providing an app-wide transient shared
|
||||
|
@ -17,10 +18,15 @@ public class ESAppNode extends ESNode {
|
|||
private Application app;
|
||||
private DatePrototype createtime;
|
||||
|
||||
public ESAppNode (INode node, RequestEvaluator eval) {
|
||||
public ESAppNode (INode node, RequestEvaluator eval) throws EcmaScriptException {
|
||||
super (eval.esNodePrototype, eval.evaluator, node, eval);
|
||||
app = eval.app;
|
||||
createtime = new DatePrototype (eval.evaluator, node.created());
|
||||
FunctionPrototype fp = (FunctionPrototype) eval.evaluator.getFunctionPrototype();
|
||||
putHiddenProperty("countEvaluators", new AppCountEvaluators ("countEvaluators", evaluator, fp));
|
||||
putHiddenProperty("countFreeEvaluators", new AppCountFreeEvaluators ("countFreeEvaluators", evaluator, fp));
|
||||
putHiddenProperty("countBusyEvaluators", new AppCountBusyEvaluators ("countBusyEvaluators", evaluator, fp));
|
||||
putHiddenProperty("setNumberOfEvaluators", new AppSetNumberOfEvaluators ("setNumberOfEvaluators", evaluator, fp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,6 +49,47 @@ public class ESAppNode extends ESNode {
|
|||
}
|
||||
|
||||
|
||||
class AppCountEvaluators extends BuiltinFunctionObject {
|
||||
AppCountEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.allThreads.size());
|
||||
}
|
||||
}
|
||||
|
||||
class AppCountFreeEvaluators extends BuiltinFunctionObject {
|
||||
AppCountFreeEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.freeThreads.size());
|
||||
}
|
||||
}
|
||||
|
||||
class AppCountBusyEvaluators extends BuiltinFunctionObject {
|
||||
AppCountBusyEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.allThreads.size() - app.freeThreads.size());
|
||||
}
|
||||
}
|
||||
|
||||
class AppSetNumberOfEvaluators extends BuiltinFunctionObject {
|
||||
AppSetNumberOfEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
RequestEvaluator ev = new RequestEvaluator (app);
|
||||
if (arguments.length != 1)
|
||||
return ESBoolean.makeBoolean (false);
|
||||
return ESBoolean.makeBoolean (app.setNumberOfEvaluators (arguments[0].toInt32()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String toString () {
|
||||
return ("AppNode "+node.getNameOrID ());
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@ package helma.framework.core;
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.objectmodel.IServer;
|
||||
import FESI.Data.ObjectPrototype;
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
import FESI.Interpreter.*;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -18,24 +22,51 @@ public class FunctionFile {
|
|||
String name;
|
||||
Prototype prototype;
|
||||
Application app;
|
||||
File file;
|
||||
long lastmod;
|
||||
|
||||
public FunctionFile (File file, String name, Prototype proto) {
|
||||
this.prototype = proto;
|
||||
this.app = proto.app;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
update (file);
|
||||
}
|
||||
|
||||
|
||||
public void update (File f) {
|
||||
|
||||
long fmod = f.lastModified ();
|
||||
this.file = f;
|
||||
|
||||
long fmod = file.lastModified ();
|
||||
if (lastmod == fmod)
|
||||
return;
|
||||
|
||||
lastmod = fmod;
|
||||
app.typemgr.readFunctionFile (f, prototype.getName ());
|
||||
// app.typemgr.readFunctionFile (file, prototype.getName ());
|
||||
}
|
||||
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) {
|
||||
|
||||
EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
|
||||
FileReader fr = null;
|
||||
|
||||
try {
|
||||
fr = new FileReader(file);
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
reval.evaluator.evaluate(fr, op, es, false);
|
||||
} catch (IOException e) {
|
||||
IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
||||
} catch (EcmaScriptException e) {
|
||||
IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
||||
} finally {
|
||||
if (fr!=null) {
|
||||
try {
|
||||
fr.close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.*;
|
|||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -119,6 +120,24 @@ public class Prototype {
|
|||
}
|
||||
|
||||
|
||||
public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
for (Enumeration en = functions.elements(); en.hasMoreElements(); ) {
|
||||
FunctionFile ff = (FunctionFile) en.nextElement ();
|
||||
ff.updateRequestEvaluator (reval);
|
||||
}
|
||||
for (Enumeration en = templates.elements(); en.hasMoreElements(); ) {
|
||||
Template tmp = (Template) en.nextElement ();
|
||||
try {
|
||||
tmp.updateRequestEvaluator (reval);
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
for (Enumeration en = actions.elements(); en.hasMoreElements(); ) {
|
||||
Action act = (Action) en.nextElement ();
|
||||
try {
|
||||
act.updateRequestEvaluator (reval);
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ public class RequestEvaluator implements Runnable {
|
|||
this.objectcache = new LruHashtable (100, .80f);
|
||||
this.prototypes = new Hashtable ();
|
||||
initEvaluator ();
|
||||
startThread ();
|
||||
// startThread ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,30 +119,25 @@ public class RequestEvaluator implements Runnable {
|
|||
}
|
||||
|
||||
|
||||
private void startThread () {
|
||||
/* 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 () {
|
||||
|
||||
int txcount = 0;
|
||||
|
||||
while (evaluator.thread == Thread.currentThread () && evaluator.thread == rtx) {
|
||||
if (prototypes.size() == 0)
|
||||
app.typemgr.initRequestEvaluator (this);
|
||||
|
||||
synchronized (this) {
|
||||
notifyAll ();
|
||||
try {
|
||||
wait ();
|
||||
} catch (InterruptedException ir) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
do {
|
||||
|
||||
// make sure there is only one thread running per instance of this class
|
||||
if (Thread.currentThread () != rtx)
|
||||
return;
|
||||
|
||||
|
@ -166,11 +161,6 @@ public class RequestEvaluator implements Runnable {
|
|||
rtx.timer.beginEvent (requestPath+" init");
|
||||
rtx.begin (requestPath);
|
||||
|
||||
if (app.debug) {
|
||||
IServer.getLogger().log ("request transactor = "+this);
|
||||
IServer.getLogger().log ("user = "+user);
|
||||
}
|
||||
|
||||
Action action = null;
|
||||
|
||||
root = app.getDataRoot ();
|
||||
|
@ -187,11 +177,6 @@ public class RequestEvaluator implements Runnable {
|
|||
reqData.setData (req.getReqData());
|
||||
req.data = reqData;
|
||||
|
||||
if (app.debug) {
|
||||
IServer.getLogger().log ("root = "+root);
|
||||
IServer.getLogger().log ("usernode = "+esu);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (req.path == null || "".equals (req.path.trim ())) {
|
||||
|
@ -454,33 +439,35 @@ public class RequestEvaluator implements Runnable {
|
|||
|
||||
// create a new Thread every 1000 requests. The current one will fade out
|
||||
if (txcount++ > 1000) {
|
||||
rtx.cleanup (); // close sql connections held by this thread
|
||||
startThread ();
|
||||
stopThread (); // stop thread - a new one will be created when needed
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// IServer.getLogger().log (this+ " exiting.");
|
||||
synchronized (this) {
|
||||
notifyAll ();
|
||||
try {
|
||||
wait ();
|
||||
} catch (InterruptedException ir) {
|
||||
Thread.currentThread ().interrupt ();
|
||||
}
|
||||
}
|
||||
|
||||
} while (evaluator.thread == Thread.currentThread () && evaluator.thread == rtx);
|
||||
}
|
||||
|
||||
public synchronized ResponseTrans invoke (RequestTrans req, User user) throws Exception {
|
||||
checkThread ();
|
||||
this.reqtype = HTTP;
|
||||
this.req = req;
|
||||
this.user = user;
|
||||
this.res = new ResponseTrans ();
|
||||
|
||||
notifyAll ();
|
||||
checkThread ();
|
||||
wait (app.requestTimeout);
|
||||
if (reqtype > 0) {
|
||||
IServer.getLogger().log ("Stopping Thread for Request "+app.getName()+"/"+req.path);
|
||||
evaluator.thread = null;
|
||||
rtx.kill ();
|
||||
stopThread ();
|
||||
res.reset ();
|
||||
res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>Request timed out.</pre>");
|
||||
rtx = new Transactor (this, app.nmgr);
|
||||
evaluator.thread = rtx;
|
||||
rtx.start ();
|
||||
Thread.yield ();
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -488,7 +475,6 @@ public class RequestEvaluator implements Runnable {
|
|||
|
||||
|
||||
public synchronized Object invokeXmlRpc (String method, Vector args) throws Exception {
|
||||
checkThread ();
|
||||
this.reqtype = XMLRPC;
|
||||
this.user = null;
|
||||
this.method = method;
|
||||
|
@ -496,16 +482,10 @@ public class RequestEvaluator implements Runnable {
|
|||
result = null;
|
||||
exception = null;
|
||||
|
||||
notifyAll ();
|
||||
checkThread ();
|
||||
wait (app.requestTimeout);
|
||||
if (reqtype > 0) {
|
||||
IServer.getLogger().log ("Stopping Thread");
|
||||
evaluator.thread = null;
|
||||
rtx.kill ();
|
||||
rtx = new Transactor (this, app.nmgr);
|
||||
evaluator.thread = rtx;
|
||||
rtx.start ();
|
||||
Thread.yield ();
|
||||
stopThread ();
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
|
@ -525,7 +505,6 @@ public class RequestEvaluator implements Runnable {
|
|||
|
||||
public synchronized ESValue invokeFunction (ESObject obj, String functionName, ESValue[] args)
|
||||
throws Exception {
|
||||
checkThread ();
|
||||
this.reqtype = INTERNAL;
|
||||
this.user = null;
|
||||
this.current = obj;
|
||||
|
@ -534,17 +513,11 @@ public class RequestEvaluator implements Runnable {
|
|||
esresult = ESNull.theNull;
|
||||
exception = null;
|
||||
|
||||
notifyAll ();
|
||||
checkThread ();
|
||||
wait (60000l*15); // give internal call more time (15 minutes) to complete
|
||||
|
||||
if (reqtype > 0) {
|
||||
IServer.getLogger().log ("Stopping Thread");
|
||||
evaluator.thread = null;
|
||||
rtx.kill ();
|
||||
rtx = new Transactor (this, app.nmgr);
|
||||
evaluator.thread = rtx;
|
||||
rtx.start ();
|
||||
Thread.yield ();
|
||||
stopThread ();
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
|
@ -554,7 +527,6 @@ public class RequestEvaluator implements Runnable {
|
|||
|
||||
public synchronized ESValue invokeFunction (User user, String functionName, ESValue[] args)
|
||||
throws Exception {
|
||||
checkThread ();
|
||||
this.reqtype = INTERNAL;
|
||||
this.user = user;
|
||||
this.current = null;
|
||||
|
@ -563,17 +535,11 @@ public class RequestEvaluator implements Runnable {
|
|||
esresult = ESNull.theNull;
|
||||
exception = null;
|
||||
|
||||
notifyAll ();
|
||||
checkThread ();
|
||||
wait (app.requestTimeout);
|
||||
|
||||
if (reqtype > 0) {
|
||||
IServer.getLogger().log ("Stopping Thread");
|
||||
evaluator.thread = null;
|
||||
rtx.kill ();
|
||||
rtx = new Transactor (this, app.nmgr);
|
||||
evaluator.thread = rtx;
|
||||
rtx.start ();
|
||||
Thread.yield ();
|
||||
stopThread ();
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
|
@ -583,24 +549,32 @@ public class RequestEvaluator implements Runnable {
|
|||
|
||||
|
||||
/**
|
||||
* Stop this request evaluator. If currently active kill the request, otherwise just
|
||||
* Stop this request evaluator's current thread. If currently active kill the request, otherwise just
|
||||
* notify.
|
||||
*/
|
||||
public synchronized void stop () {
|
||||
public synchronized void stopThread () {
|
||||
// IServer.getLogger().log ("Stopping Thread");
|
||||
evaluator.thread = null;
|
||||
if (reqtype != NONE) {
|
||||
rtx.kill ();
|
||||
} else {
|
||||
notifyAll ();
|
||||
Transactor t = rtx;
|
||||
rtx = null;
|
||||
if (t != null) {
|
||||
if (reqtype != NONE) {
|
||||
t.kill ();
|
||||
} else {
|
||||
notifyAll ();
|
||||
}
|
||||
t.cleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkThread () {
|
||||
private synchronized void checkThread () throws InterruptedException {
|
||||
if (rtx == null || !rtx.isAlive()) {
|
||||
// IServer.getLogger().log ("Starting Thread");
|
||||
rtx = new Transactor (this, app.nmgr);
|
||||
evaluator.thread = rtx;
|
||||
rtx.start ();
|
||||
Thread.yield ();
|
||||
} else {
|
||||
notifyAll ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.*;
|
|||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -22,6 +23,9 @@ import FESI.Data.*;
|
|||
|
||||
public class Template extends Action {
|
||||
|
||||
ParsedFunction psfunc;
|
||||
|
||||
|
||||
public Template (File file, String name, Prototype proto) {
|
||||
super (file, name, proto);
|
||||
}
|
||||
|
@ -128,25 +132,21 @@ public class Template extends Action {
|
|||
}
|
||||
// templateBody.append ("\r\nreturn null;\r\n");
|
||||
|
||||
|
||||
functionName = name;
|
||||
String fname = name+"_as_string";
|
||||
String body = templateBody.toString ();
|
||||
|
||||
try {
|
||||
app.typemgr.readFunction (name,
|
||||
pfunc = parseFunction (name,
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
body+"\r\nreturn null;\r\n",
|
||||
prototype.getName ());
|
||||
body+"\r\nreturn null;\r\n");
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
app.typemgr.generateErrorFeedback (name, message, prototype.getName ());
|
||||
}
|
||||
try {
|
||||
app.typemgr.readFunction (fname,
|
||||
psfunc = parseFunction (fname,
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
"res.pushStringBuffer(); "+body+"\r\nreturn res.popStringBuffer();\r\n",
|
||||
prototype.getName ());
|
||||
"res.pushStringBuffer(); "+body+"\r\nreturn res.popStringBuffer();\r\n");
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
app.typemgr.generateErrorFeedback (fname, message, prototype.getName ());
|
||||
|
@ -154,6 +154,12 @@ public class Template extends Action {
|
|||
|
||||
}
|
||||
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
if (pfunc != null)
|
||||
pfunc.updateRequestEvaluator (reval);
|
||||
if (psfunc != null)
|
||||
psfunc.updateRequestEvaluator (reval);
|
||||
}
|
||||
|
||||
class Part {
|
||||
|
||||
|
|
|
@ -151,34 +151,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
public void registerPrototype (String name, File dir, Prototype proto) {
|
||||
// IServer.getLogger().log ("registering prototype "+name);
|
||||
|
||||
int size = app.allThreads.size ();
|
||||
for (int i=0; i<size; i++) {
|
||||
RequestEvaluator reval = (RequestEvaluator) app.allThreads.elementAt (i);
|
||||
ObjectPrototype op = null;
|
||||
if ("user".equalsIgnoreCase (name))
|
||||
op = reval.esUserPrototype;
|
||||
else if ("global".equalsIgnoreCase (name))
|
||||
op = reval.global;
|
||||
else if ("hopobject".equalsIgnoreCase (name))
|
||||
op = reval.esNodePrototype;
|
||||
else {
|
||||
op = new ObjectPrototype (reval.esNodePrototype, reval.evaluator);
|
||||
try {
|
||||
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
reval.putPrototype (name, op);
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a node and then call the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase (name)) {
|
||||
try {
|
||||
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
|
||||
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
// show the type checker thread that there has been type activity
|
||||
idleSeconds = 0;
|
||||
|
||||
|
@ -202,7 +174,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
ntemp.put (tmpname, t);
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error creating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
|
||||
} else if (list[i].endsWith (app.scriptExtension) && tmpfile.length () > 0) {
|
||||
|
@ -211,7 +182,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
nfunc.put (tmpname, ff);
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error creating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
} else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
|
||||
try {
|
||||
|
@ -219,7 +189,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
nact.put (tmpname, af);
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error creating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +226,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error updating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
ntemp.put (tmpname, t);
|
||||
|
||||
|
@ -273,7 +241,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error updating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
nfunc.put (tmpname, ff);
|
||||
|
||||
|
@ -289,7 +256,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
// broadcaster.broadcast ("Error updating prototype "+list[i]+":<br>"+x+"<br><hr>");
|
||||
}
|
||||
nact.put (tmpname, af);
|
||||
|
||||
|
@ -309,100 +275,6 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
proto.actions = nact;
|
||||
}
|
||||
|
||||
protected void readFunctionFile (File f, String protoname) {
|
||||
|
||||
EvaluationSource es = new FileEvaluationSource(f.getPath(), null);
|
||||
FileReader fr = null;
|
||||
|
||||
int size = app.allThreads.size ();
|
||||
for (int i=0; i<size; i++) {
|
||||
RequestEvaluator reval = (RequestEvaluator) app.allThreads.elementAt (i);
|
||||
|
||||
try {
|
||||
fr = new FileReader(f);
|
||||
ObjectPrototype op = reval.getPrototype (protoname);
|
||||
reval.evaluator.evaluate(fr, op, es, false);
|
||||
} catch (IOException e) {
|
||||
IServer.getLogger().log ("*** Error reading function file "+f+": "+e);
|
||||
} catch (EcmaScriptException e) {
|
||||
IServer.getLogger().log ("*** Error reading function file "+f+": "+e);
|
||||
} finally {
|
||||
if (fr!=null) {
|
||||
try {
|
||||
fr.close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void readFunction (String funcname, String params, String body, String protoname)
|
||||
throws EcmaScriptException {
|
||||
|
||||
// ESObject fp = app.eval.evaluator.getFunctionPrototype();
|
||||
ConstructedFunctionObject function = null;
|
||||
ASTFormalParameterList fpl = null;
|
||||
ASTStatementList sl = null;
|
||||
|
||||
if (body == null || "".equals (body.trim()))
|
||||
body = ";\r\n";
|
||||
else
|
||||
body = body + "\r\n";
|
||||
if (params == null) params = "";
|
||||
else params = params.trim ();
|
||||
|
||||
String fullFunctionText = "function "+funcname+" (" + params + ") {\n" + body + "\n}";
|
||||
|
||||
EcmaScript parser;
|
||||
StringReader is;
|
||||
|
||||
// Special case for empty parameters
|
||||
if (params.length()==0) {
|
||||
fpl = new ASTFormalParameterList(JJTFORMALPARAMETERLIST);
|
||||
} else {
|
||||
is = new java.io.StringReader(params);
|
||||
parser = new EcmaScript(is);
|
||||
try {
|
||||
fpl = (ASTFormalParameterList) parser.FormalParameterList();
|
||||
is.close();
|
||||
} catch (ParseException x) {
|
||||
throw new EcmaScriptParseException (x, new StringEvaluationSource(fullFunctionText, null));
|
||||
}
|
||||
}
|
||||
// this is very very very strange: without the toString, lots of obscure exceptions
|
||||
// deep inside the parser...
|
||||
is = new java.io.StringReader(body.toString ());
|
||||
try {
|
||||
parser = new EcmaScript (is);
|
||||
sl = (ASTStatementList) parser.StatementList();
|
||||
is.close();
|
||||
} catch (ParseException x) {
|
||||
x.printStackTrace ();
|
||||
throw new EcmaScriptParseException (x, new StringEvaluationSource(fullFunctionText, null));
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace ();
|
||||
throw new RuntimeException (x.getMessage ());
|
||||
}
|
||||
|
||||
FunctionEvaluationSource fes = new FunctionEvaluationSource (
|
||||
new StringEvaluationSource(fullFunctionText,null), funcname);
|
||||
|
||||
DbMapping dbmap = null;
|
||||
|
||||
int size = app.allThreads.size ();
|
||||
for (int i=0; i<size; i++) {
|
||||
RequestEvaluator reval = (RequestEvaluator) app.allThreads.elementAt (i);
|
||||
|
||||
ObjectPrototype op = reval.getPrototype (protoname);
|
||||
|
||||
EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor();
|
||||
Vector vnames = vdvisitor.processVariableDeclarations(sl, fes);
|
||||
|
||||
FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction(reval.evaluator, funcname, fes, fullFunctionText, fpl.getArguments(), vnames, sl);
|
||||
op.putHiddenProperty (funcname, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void generateErrorFeedback (String funcname, String message, String protoname)
|
||||
|
@ -413,6 +285,7 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
RequestEvaluator reval = (RequestEvaluator) app.allThreads.elementAt (i);
|
||||
|
||||
ObjectPrototype op = reval.getPrototype (protoname);
|
||||
if (op == null) return;
|
||||
|
||||
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype ();
|
||||
FunctionPrototype func = new ThrowException (funcname, reval.evaluator, fp, message);
|
||||
|
@ -435,6 +308,38 @@ public class TypeManager implements Runnable, EcmaScriptTreeConstants {
|
|||
}
|
||||
}
|
||||
|
||||
public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
for (Enumeration en = prototypes.elements(); en.hasMoreElements(); ) {
|
||||
Prototype p = (Prototype) en.nextElement ();
|
||||
String name = p.getName ();
|
||||
ObjectPrototype op = null;
|
||||
if ("user".equalsIgnoreCase (name))
|
||||
op = reval.esUserPrototype;
|
||||
else if ("global".equalsIgnoreCase (name))
|
||||
op = reval.global;
|
||||
else if ("hopobject".equalsIgnoreCase (name))
|
||||
op = reval.esNodePrototype;
|
||||
else {
|
||||
op = new ObjectPrototype (reval.esNodePrototype, reval.evaluator);
|
||||
try {
|
||||
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
reval.putPrototype (name, op);
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a node and then call the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase (name)) {
|
||||
try {
|
||||
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
|
||||
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
|
||||
p.initRequestEvaluator (reval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ public class Transactor extends Thread {
|
|||
// The thread is told to stop by setting the thread flag in the EcmaScript
|
||||
// evaluator, so we can hope that it stops without doing anything else.
|
||||
try {
|
||||
join (1000);
|
||||
join (500);
|
||||
} catch (InterruptedException ir) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
@ -222,6 +222,7 @@ public class Transactor extends Thread {
|
|||
}
|
||||
|
||||
public void cleanup () {
|
||||
// IServer.getLogger().log("Cleaning up Transactor thread");
|
||||
if (sqlCon != null) {
|
||||
for (Iterator i=sqlCon.values().iterator(); i.hasNext(); ) {
|
||||
try {
|
||||
|
|
|
@ -101,4 +101,4 @@ public class Benchmark implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,10 +76,6 @@ public class XmlRpcClient implements XmlRpcHandler {
|
|||
return retval;
|
||||
} finally {
|
||||
worker.reset ();
|
||||
if (workers < 20 && !worker.fault)
|
||||
pool.push (worker);
|
||||
else
|
||||
workers -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +149,8 @@ public class XmlRpcClient implements XmlRpcHandler {
|
|||
} catch (Exception x) {
|
||||
if (callback != null)
|
||||
callback.handleError (x, url, method);
|
||||
} finally {
|
||||
reset ();
|
||||
}
|
||||
System.err.println ("GOT: "+result);
|
||||
}
|
||||
|
@ -255,6 +253,11 @@ public class XmlRpcClient implements XmlRpcHandler {
|
|||
result = null;
|
||||
params = null;
|
||||
callback = null;
|
||||
if (workers < 20 && !fault)
|
||||
pool.push (this);
|
||||
else
|
||||
workers -= 1;
|
||||
|
||||
}
|
||||
|
||||
} // end of inner class Worker
|
||||
|
@ -274,7 +277,7 @@ public class XmlRpcClient implements XmlRpcHandler {
|
|||
} catch (NumberFormatException nfx) {
|
||||
v.addElement (args[i]);
|
||||
}
|
||||
XmlRpcClient client = new XmlRpcClient (url);
|
||||
XmlRpcClient client = new XmlRpcClientLite (url);
|
||||
try {
|
||||
/* System.err.println (*/client.executeAsync (method, v, null);
|
||||
} catch (Exception ex) {
|
||||
|
|
|
@ -75,19 +75,52 @@ public class XmlRpcClientLite extends XmlRpcClient {
|
|||
}
|
||||
|
||||
|
||||
class Worker extends XmlRpc {
|
||||
class Worker extends XmlRpc implements Runnable {
|
||||
|
||||
boolean fault;
|
||||
Object result = null;
|
||||
HttpClient client = null;
|
||||
StringBuffer strbuf;
|
||||
|
||||
String method;
|
||||
Vector params;
|
||||
AsyncCallback callback = null;
|
||||
|
||||
public Worker () {
|
||||
super ();
|
||||
}
|
||||
|
||||
|
||||
public Object execute (String method, Vector params) throws XmlRpcException, IOException {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
return executeCall ();
|
||||
}
|
||||
|
||||
public void executeAsync (String method, Vector params, AsyncCallback callback) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.callback = callback;
|
||||
Thread t = new Thread (this);
|
||||
t.start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
Object res = null;
|
||||
try {
|
||||
res = executeCall ();
|
||||
// notify callback object
|
||||
if (callback != null)
|
||||
callback.handleResult (res, url, method);
|
||||
} catch (Exception x) {
|
||||
if (callback != null)
|
||||
callback.handleError (x, url, method);
|
||||
} finally {
|
||||
reset ();
|
||||
}
|
||||
System.err.println ("GOT: "+result);
|
||||
}
|
||||
|
||||
private Object executeCall () throws XmlRpcException, IOException {
|
||||
long now = System.currentTimeMillis ();
|
||||
fault = false;
|
||||
try {
|
||||
|
@ -196,6 +229,20 @@ public class XmlRpcClientLite extends XmlRpcClient {
|
|||
super.startElement (name, atts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release possibly big per-call object references to allow them to be garbage collected
|
||||
*/
|
||||
public void reset () {
|
||||
result = null;
|
||||
params = null;
|
||||
callback = null;
|
||||
if (workers < 20 && !fault)
|
||||
pool.push (this);
|
||||
else
|
||||
workers -= 1;
|
||||
|
||||
}
|
||||
|
||||
} // end of class Worker
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue