* Handle all HTTP methods (all the same way, this is temporary behaviour

until we find a way to deal with them)
* Add req.getMethod() that returns method name as string
* Add req.getServletRequest() that returns the HttpServletRequest object
   for HTTP requests
* Set up req, path, session... objects for all types of requests
* Restructured helma.framework.core.RequestEvaluator to allow for more
   cleanup in the future
This commit is contained in:
hns 2005-01-25 16:13:04 +00:00
parent 255d6e9812
commit 026dd7faad
4 changed files with 344 additions and 331 deletions

View file

@ -45,6 +45,15 @@ public class RequestBean implements Serializable {
return req.get(name); return req.get(name);
} }
/**
* Return the method of the request. This may either be a HTTP method or
* one of the Helma pseudo methods defined in RequestTrans.
*/
public String getMethod() {
return req.getMethod();
}
/** /**
* *
* *

View file

@ -18,6 +18,8 @@ package helma.framework;
import helma.util.Base64; import helma.util.Base64;
import helma.util.SystemMap; import helma.util.SystemMap;
import javax.servlet.http.HttpServletRequest;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -25,12 +27,26 @@ import java.util.*;
* A Transmitter for a request from the servlet client. Objects of this * A Transmitter for a request from the servlet client. Objects of this
* class are directly exposed to JavaScript as global property req. * class are directly exposed to JavaScript as global property req.
*/ */
public class RequestTrans implements Externalizable { public class RequestTrans implements Serializable {
static final long serialVersionUID = 5398880083482000580L; static final long serialVersionUID = 5398880083482000580L;
public final static byte GET = 0; // HTTP methods
public final static byte POST = 1; public final static String GET = "GET";
public final static String POST = "POST";
public final static String DELETE = "DELETE";
public final static String HEAD = "HEAD";
public final static String OPTIONS = "OPTIONS";
public final static String PUT = "PUT";
public final static String TRACE = "TRACE";
// Helma pseudo-methods
public final static String XMLRPC = "XMLRPC";
public final static String EXTERNAL = "EXTERNAL";
public final static String INTERNAL = "INTERNAL";
// the servlet request, may be null
HttpServletRequest request;
// the uri path of the request // the uri path of the request
public String path; public String path;
@ -40,8 +56,8 @@ public class RequestTrans implements Externalizable {
// the map of form and cookie data // the map of form and cookie data
private Map values; private Map values;
// the request method - 0 for GET, 1 for POST // the HTTP request method
private byte httpMethod = GET; private String method;
// timestamp of client-cached version, if present in request // timestamp of client-cached version, if present in request
private long ifModifiedSince = -1; private long ifModifiedSince = -1;
@ -60,16 +76,18 @@ public class RequestTrans implements Externalizable {
/** /**
* Create a new Request transmitter with an empty data map. * Create a new Request transmitter with an empty data map.
*/ */
public RequestTrans() { public RequestTrans(String method) {
this(GET); this.method = method;
this.request = null;
values = new SystemMap(); values = new SystemMap();
} }
/** /**
* Create a new request transmitter with the given data map. * Create a new request transmitter with the given data map.
*/ */
public RequestTrans(byte method) { public RequestTrans(HttpServletRequest request) {
httpMethod = method; this.method = request.getMethod();
this.request = request;
values = new SystemMap(); values = new SystemMap();
} }
@ -98,6 +116,14 @@ public class RequestTrans implements Externalizable {
return values; return values;
} }
/**
* Returns the Servlet request represented by this RequestTrans instance.
* Returns null for internal and XML-RPC requests.
*/
public HttpServletRequest getServletRequest() {
return request;
}
/** /**
* The hash code is computed from the session id if available. This is used to * The hash code is computed from the session id if available. This is used to
* detect multiple identic requests. * detect multiple identic requests.
@ -121,42 +147,26 @@ public class RequestTrans implements Externalizable {
} }
} }
/**
* Return the method of the request. This may either be a HTTP method or
* one of the Helma pseudo methods defined in this class.
*/
public String getMethod() {
return method;
}
/** /**
* Return true if this object represents a HTTP GET Request. * Return true if this object represents a HTTP GET Request.
*/ */
public boolean isGet() { public boolean isGet() {
return httpMethod == GET; return GET.equalsIgnoreCase(method);
} }
/** /**
* Return true if this object represents a HTTP GET Request. * Return true if this object represents a HTTP GET Request.
*/ */
public boolean isPost() { public boolean isPost() {
return httpMethod == POST; return POST.equalsIgnoreCase(method);
}
/**
* Custom externalization code for quicker serialization.
*/
public void readExternal(ObjectInput s) throws ClassNotFoundException, IOException {
path = s.readUTF();
session = s.readUTF();
values = (Map) s.readObject();
httpMethod = s.readByte();
ifModifiedSince = s.readLong();
etags = (Set) s.readObject();
}
/**
* Custom externalization code for quicker serialization.
*/
public void writeExternal(ObjectOutput s) throws IOException {
s.writeUTF(path);
s.writeUTF(session);
s.writeObject(values);
s.writeByte(httpMethod);
s.writeLong(ifModifiedSince);
s.writeObject(etags);
} }
/** /**

View file

@ -46,7 +46,7 @@ public final class RequestEvaluator implements Runnable {
Object thisObject; Object thisObject;
// the method to be executed // the method to be executed
String method; String functionName;
// the session object associated with the current request // the session object associated with the current request
Session session; Session session;
@ -108,7 +108,7 @@ public final class RequestEvaluator implements Runnable {
Transactor localrtx = (Transactor) Thread.currentThread(); Transactor localrtx = (Transactor) Thread.currentThread();
try { try {
do { do { // while (localrtx == rtx);
// initialize scripting engine, in case it hasn't been initialized yet // initialize scripting engine, in case it hasn't been initialized yet
initScriptingEngine(); initScriptingEngine();
// update scripting prototypes // update scripting prototypes
@ -124,46 +124,37 @@ public final class RequestEvaluator implements Runnable {
requestPath = new RequestPath(app); requestPath = new RequestPath(app);
switch (reqtype) { int tries = 0;
case HTTP: boolean done = false;
String error = null;
int tries = 0; while (!done) {
boolean done = false; currentElement = null;
String error = null;
while (!done) { try {
currentElement = null; // TODO: transaction names are not set for internal/xmlrpc/external requests
// used for logging
StringBuffer txname = new StringBuffer(app.getName());
txname.append("/");
txname.append((error == null) ? req.path : "error");
try { // begin transaction
// used for logging localrtx.begin(txname.toString());
StringBuffer txname = new StringBuffer(app.getName());
txname.append("/"); String action = null;
txname.append((error == null) ? req.path : "error");
// begin transaction root = app.getDataRoot();
localrtx.begin(txname.toString());
String action = null; req.startTime = System.currentTimeMillis();
root = app.getDataRoot(); initGlobals(root);
HashMap globals = new HashMap(); if (error != null) {
res.error = error;
}
globals.put("root", root); switch (reqtype) {
globals.put("session", new SessionBean(session)); case HTTP:
globals.put("req", new RequestBean(req));
globals.put("res", new ResponseBean(res));
globals.put("app", new ApplicationBean(app));
globals.put("path", requestPath);
req.startTime = System.currentTimeMillis();
// enter execution context
scriptingEngine.enterContext(globals);
if (error != null) {
res.error = error;
}
if (session.message != null) { if (session.message != null) {
// bring over the message from a redirect // bring over the message from a redirect
@ -179,7 +170,7 @@ public final class RequestEvaluator implements Runnable {
// do not reset the requestPath so error handler can use the original one // do not reset the requestPath so error handler can use the original one
// get error handler action // get error handler action
String errorAction = app.props.getProperty("error", String errorAction = app.props.getProperty("error",
"error"); "error");
action = getAction(currentElement, errorAction); action = getAction(currentElement, errorAction);
@ -187,7 +178,7 @@ public final class RequestEvaluator implements Runnable {
throw new RuntimeException(error); throw new RuntimeException(error);
} }
} else if ((req.path == null) || } else if ((req.path == null) ||
"".equals(req.path.trim())) { "".equals(req.path.trim())) {
currentElement = root; currentElement = root;
requestPath.add(null, currentElement); requestPath.add(null, currentElement);
@ -199,7 +190,7 @@ public final class RequestEvaluator implements Runnable {
} else { } else {
// march down request path... // march down request path...
StringTokenizer st = new StringTokenizer(req.path, StringTokenizer st = new StringTokenizer(req.path,
"/"); "/");
int ntokens = st.countTokens(); int ntokens = st.countTokens();
// limit path to < 50 tokens // limit path to < 50 tokens
@ -229,12 +220,12 @@ public final class RequestEvaluator implements Runnable {
// try to interpret it as action name. // try to interpret it as action name.
if (i == (ntokens - 1)) { if (i == (ntokens - 1)) {
action = getAction(currentElement, action = getAction(currentElement,
pathItems[i]); pathItems[i]);
} }
if (action == null) { if (action == null) {
currentElement = getChildElement(currentElement, currentElement = getChildElement(currentElement,
pathItems[i]); pathItems[i]);
// add object to request path if suitable // add object to request path if suitable
if (currentElement != null) { if (currentElement != null) {
@ -269,7 +260,7 @@ public final class RequestEvaluator implements Runnable {
res.status = 404; res.status = 404;
String notFoundAction = app.props.getProperty("notfound", String notFoundAction = app.props.getProperty("notfound",
"notfound"); "notfound");
currentElement = root; currentElement = root;
action = getAction(currentElement, notFoundAction); action = getAction(currentElement, notFoundAction);
@ -285,7 +276,7 @@ public final class RequestEvaluator implements Runnable {
int l = requestPath.size(); int l = requestPath.size();
Prototype[] protos = new Prototype[l]; Prototype[] protos = new Prototype[l];
for (int i=0; i<l; i++) { for (int i = 0; i < l; i++) {
Object obj = requestPath.get(i); Object obj = requestPath.get(i);
@ -301,7 +292,7 @@ public final class RequestEvaluator implements Runnable {
// in a second pass, we register path objects with their indirect // in a second pass, we register path objects with their indirect
// (i.e. parent prototype) names, starting at the end and only // (i.e. parent prototype) names, starting at the end and only
// if the name isn't occupied yet. // if the name isn't occupied yet.
for (int i=l-1; i>=0; i--) { for (int i = l - 1; i >= 0; i--) {
if (protos[i] != null) { if (protos[i] != null) {
protos[i].registerParents(macroHandlers, requestPath.get(i)); protos[i].registerParents(macroHandlers, requestPath.get(i));
} }
@ -326,11 +317,11 @@ public final class RequestEvaluator implements Runnable {
// calling the actual action // calling the actual action
try { try {
if (scriptingEngine.hasFunction(currentElement, if (scriptingEngine.hasFunction(currentElement,
"onRequest")) { "onRequest")) {
scriptingEngine.invoke(currentElement, scriptingEngine.invoke(currentElement,
"onRequest", "onRequest",
new Object[0], new Object[0],
ScriptingEngine.ARGS_WRAP_DEFAULT); ScriptingEngine.ARGS_WRAP_DEFAULT);
} }
} catch (RedirectException redir) { } catch (RedirectException redir) {
throw redir; throw redir;
@ -341,235 +332,212 @@ public final class RequestEvaluator implements Runnable {
// do the actual action invocation // do the actual action invocation
scriptingEngine.invoke(currentElement, action, scriptingEngine.invoke(currentElement, action,
new Object[0], new Object[0],
ScriptingEngine.ARGS_WRAP_DEFAULT); ScriptingEngine.ARGS_WRAP_DEFAULT);
} catch (RedirectException redirect) { } catch (RedirectException redirect) {
// res.redirect = redirect.getMessage ();
// if there is a message set, save it on the user object for the next request // if there is a message set, save it on the user object for the next request
if (res.message != null) { if (res.message != null) {
session.message = res.message; session.message = res.message;
} }
done = true;
} }
// check if we're still the one and only or if the waiting thread has given up on us already // check if we're still the one and only or if the waiting thread has given up on us already
commitTransaction(); commitTransaction();
done = true; done = true;
} catch (ConcurrencyException x) {
res.reset();
if (++tries < 8) {
// try again after waiting some period
abortTransaction(true);
try {
// wait a bit longer with each try
int base = 800 * tries;
Thread.sleep((long) (base + (Math.random() * base * 2)));
} catch (Exception ignore) {
}
continue;
} else {
abortTransaction(false);
if (error == null) {
app.errorCount += 1;
// set done to false so that the error will be processed
done = false;
error = "Couldn't complete transaction due to heavy object traffic (tried " +
tries + " times)";
} else {
// error in error action. use traditional minimal error message
res.write("<b>Error in application '" +
app.getName() + "':</b> <br><br><pre>" +
error + "</pre>");
done = true;
}
}
} catch (Exception x) {
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) {
break;
}
res.reset();
// check if we tried to process the error already
if (error == null) {
app.errorCount += 1;
app.logEvent("Exception in " +
Thread.currentThread() + ": " + x);
// Dump the profiling data to System.err
if (app.debug && !(x instanceof ScriptingException)) {
x.printStackTrace ();
}
// set done to false so that the error will be processed
done = false;
error = x.getMessage();
if ((error == null) || (error.length() == 0)) {
error = x.toString();
}
if (error == null) {
error = "Unspecified error";
}
} else {
// error in error action. use traditional minimal error message
res.write("<b>Error in application '" +
app.getName() + "':</b> <br><br><pre>" +
error + "</pre>");
done = true;
}
}
}
break;
case XMLRPC:
case EXTERNAL:
try {
localrtx.begin(app.getName() + ":ext-rpc:" + 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();
}
if (reqtype == XMLRPC) {
// check XML-RPC access permissions
String proto = app.getPrototypeName(currentElement);
app.checkXmlRpcAccess(proto, method);
}
// reset skin recursion detection counter
skinDepth = 0;
result = scriptingEngine.invoke(currentElement, method, args,
ScriptingEngine.ARGS_WRAP_XMLRPC);
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
String funcdesc = app.getName() + ":internal:" + method;
// if thisObject is an instance of NodeHandle, get the node object itself.
if ((thisObject != null) && thisObject instanceof NodeHandle) {
thisObject = ((NodeHandle) thisObject).getNode(app.nmgr.safe);
// see if a valid node was returned
if (thisObject == null) {
reqtype = NONE;
break; break;
}
}
// avoid going into transaction if called function doesn't exist. case XMLRPC:
boolean functionexists = true; case EXTERNAL:
// this only works for the (common) case that method is a plain try {
// method name, not an obj.method path currentElement = root;
if (method.indexOf('.') < 0) {
functionexists = scriptingEngine.hasFunction(thisObject, method);
}
if (!functionexists) { if (functionName.indexOf('.') > -1) {
// function doesn't exist, nothing to do here. StringTokenizer st = new StringTokenizer(functionName, ".");
reqtype = NONE; int cnt = st.countTokens();
} else {
try {
localrtx.begin(funcdesc);
root = app.getDataRoot(); for (int i = 1; i < cnt; i++) {
String next = st.nextToken();
HashMap globals = new HashMap(); currentElement = getChildElement(currentElement,
next);
}
globals.put("root", root); if (currentElement == null) {
globals.put("res", new ResponseBean(res)); throw new FrameworkException("Method name \"" +
globals.put("app", new ApplicationBean(app)); functionName +
"\" could not be resolved.");
}
scriptingEngine.enterContext(globals); functionName = st.nextToken();
}
// reset skin recursion detection counter if (reqtype == XMLRPC) {
skinDepth = 0; // check XML-RPC access permissions
String proto = app.getPrototypeName(currentElement);
result = scriptingEngine.invoke(thisObject, method, args, app.checkXmlRpcAccess(proto, functionName);
ScriptingEngine.ARGS_WRAP_DEFAULT); }
commitTransaction();
} catch (Exception x) {
abortTransaction(false);
app.logEvent("Exception in " + Thread.currentThread() + // reset skin recursion detection counter
": " + x); skinDepth = 0;
// If the transactor thread has been killed by the invoker thread we don't have to result = scriptingEngine.invoke(currentElement, functionName, args,
// bother for the error message, just quit. ScriptingEngine.ARGS_WRAP_XMLRPC);
if (localrtx != rtx) { commitTransaction();
return; } 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;
} }
this.exception = x; done = true;
break;
case INTERNAL:
// TODO: transaction names are not set for internal/xmlrpc/external requests
// Just a human readable descriptor of this invocation
// String funcdesc = app.getName() + ":internal:" + functionName;
// if thisObject is an instance of NodeHandle, get the node object itself.
if ((thisObject != null) && thisObject instanceof NodeHandle) {
thisObject = ((NodeHandle) thisObject).getNode(app.nmgr.safe);
// see if a valid node was returned
if (thisObject == null) {
reqtype = NONE;
break;
}
}
// avoid going into transaction if called function doesn't exist.
boolean functionexists = true;
// this only works for the (common) case that method is a plain
// method name, not an obj.method path
if (functionName.indexOf('.') < 0) {
functionexists = scriptingEngine.hasFunction(thisObject, functionName);
}
if (!functionexists) {
// function doesn't exist, nothing to do here.
reqtype = NONE;
} else {
try {
// reset skin recursion detection counter
skinDepth = 0;
result = scriptingEngine.invoke(thisObject, functionName, args,
ScriptingEngine.ARGS_WRAP_DEFAULT);
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;
}
}
done = true;
break;
} // switch (reqtype)
} catch (ConcurrencyException x) {
res.reset();
if (++tries < 8) {
// try again after waiting some period
abortTransaction(true);
try {
// wait a bit longer with each try
int base = 800 * tries;
Thread.sleep((long) (base + (Math.random() * base * 2)));
} catch (Exception ignore) {
}
continue;
} else {
abortTransaction(false);
if (error == null) {
app.errorCount += 1;
// set done to false so that the error will be processed
done = false;
error = "Couldn't complete transaction due to heavy object traffic (tried " +
tries + " times)";
} else {
// error in error action. use traditional minimal error message
res.write("<b>Error in application '" +
app.getName() + "':</b> <br><br><pre>" +
error + "</pre>");
done = true;
} }
} }
} catch (Throwable x) {
abortTransaction(false);
break; // 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();
// check if we tried to process the error already
if (error == null) {
app.errorCount += 1;
app.logEvent("Exception in " +
Thread.currentThread() + ": " + x);
// Dump the profiling data to System.err
if (app.debug && !(x instanceof ScriptingException)) {
x.printStackTrace();
}
// set done to false so that the error will be processed
done = false;
error = x.getMessage();
if ((error == null) || (error.length() == 0)) {
error = x.toString();
}
if (error == null) {
error = "Unspecified error";
}
} else {
// error in error action. use traditional minimal error message
res.write("<b>Error in application '" +
app.getName() + "':</b> <br><br><pre>" +
error + "</pre>");
done = true;
}
}
} }
// exit execution context // exit execution context
@ -657,10 +625,7 @@ public final class RequestEvaluator implements Runnable {
*/ */
public synchronized ResponseTrans invokeHttp(RequestTrans req, Session session) public synchronized ResponseTrans invokeHttp(RequestTrans req, Session session)
throws Exception { throws Exception {
this.reqtype = HTTP; initObjects(req, session);
this.req = req;
this.session = session;
this.res = new ResponseTrans(req);
app.activeRequests.put(req, this); app.activeRequests.put(req, this);
@ -701,22 +666,18 @@ public final class RequestEvaluator implements Runnable {
/** /**
* *
* *
* @param method ... * @param functionName ...
* @param args ... * @param args ...
* *
* @return ... * @return ...
* *
* @throws Exception ... * @throws Exception ...
*/ */
public synchronized Object invokeXmlRpc(String method, Object[] args) public synchronized Object invokeXmlRpc(String functionName, Object[] args)
throws Exception { throws Exception {
this.reqtype = XMLRPC; initObjects(XMLRPC, RequestTrans.XMLRPC);
this.session = null; this.functionName = functionName;
this.method = method;
this.args = args; this.args = args;
this.res = new ResponseTrans();
result = null;
exception = null;
checkThread(); checkThread();
wait(app.requestTimeout); wait(app.requestTimeout);
@ -740,22 +701,18 @@ public final class RequestEvaluator implements Runnable {
/** /**
* *
* *
* @param method ... * @param functionName ...
* @param args ... * @param args ...
* *
* @return ... * @return ...
* *
* @throws Exception ... * @throws Exception ...
*/ */
public synchronized Object invokeExternal(String method, Object[] args) public synchronized Object invokeExternal(String functionName, Object[] args)
throws Exception { throws Exception {
this.reqtype = EXTERNAL; initObjects(EXTERNAL, RequestTrans.EXTERNAL);
this.session = null; this.functionName = functionName;
this.method = method;
this.args = args; this.args = args;
this.res = new ResponseTrans();
result = null;
exception = null;
checkThread(); checkThread();
wait(); wait();
@ -823,14 +780,10 @@ public final class RequestEvaluator implements Runnable {
public synchronized Object invokeInternal(Object object, String functionName, public synchronized Object invokeInternal(Object object, String functionName,
Object[] args, long timeout) Object[] args, long timeout)
throws Exception { throws Exception {
reqtype = INTERNAL; initObjects(INTERNAL, RequestTrans.INTERNAL);
session = null;
thisObject = object; thisObject = object;
method = functionName; this.functionName = functionName;
this.args = args; this.args = args;
this.res = new ResponseTrans();
result = null;
exception = null;
checkThread(); checkThread();
wait(timeout); wait(timeout);
@ -850,6 +803,65 @@ public final class RequestEvaluator implements Runnable {
} }
/**
* Init this evaluator's objects from a RequestTrans for a HTTP request
*
* @param req
* @param session
*/
private void initObjects(RequestTrans req, Session session) {
this.req = req;
this.reqtype = HTTP;
this.session = session;
res = new ResponseTrans(req);
// result = null;
// exception = null;
}
/**
* Init this evaluator's objects for an internal, external or XML-RPC type
* request.
*
* @param reqtype
* @param reqtypeName
*/
private void initObjects(int reqtype, String reqtypeName) {
this.reqtype = reqtype;
this.req = new RequestTrans(reqtypeName);
session = new Session(functionName, app);
res = new ResponseTrans(req);
result = null;
exception = null;
}
/**
* Initialize the globals in the scripting engine for the current request.
*
* @param root
* @throws ScriptingException
*/
private void initGlobals(Object root) throws ScriptingException {
HashMap globals = new HashMap();
globals.put("root", root);
globals.put("session", new SessionBean(session));
globals.put("req", new RequestBean(req));
globals.put("res", new ResponseBean(res));
globals.put("app", new ApplicationBean(app));
globals.put("path", requestPath);
// enter execution context
scriptingEngine.enterContext(globals);
}
/**
* Get the child element with the given name from the given object.
*
* @param obj
* @param name
* @return
* @throws ScriptingException
*/
private Object getChildElement(Object obj, String name) throws ScriptingException { private Object getChildElement(Object obj, String name) throws ScriptingException {
if (scriptingEngine.hasFunction(obj, "getChildElement")) { if (scriptingEngine.hasFunction(obj, "getChildElement")) {
return scriptingEngine.invoke(obj, "getChildElement", new Object[] {name}, return scriptingEngine.invoke(obj, "getChildElement", new Object[] {name},
@ -864,8 +876,8 @@ public final class RequestEvaluator implements Runnable {
} }
/** /**
* Stop this request evaluator's current thread. If currently active kill the request, otherwise just * Stop this request evaluator's current thread.
* notify. * If currently active kill the request, otherwise just notify.
*/ */
public synchronized void stopThread() { public synchronized void stopThread() {
Transactor t = rtx; Transactor t = rtx;

View file

@ -89,7 +89,7 @@ public abstract class AbstractServletClient extends HttpServlet {
abstract Application getApplication(); abstract Application getApplication();
/** /**
* Handle a GET request. * Handle a request.
* *
* @param request ... * @param request ...
* @param response ... * @param response ...
@ -97,28 +97,10 @@ public abstract class AbstractServletClient extends HttpServlet {
* @throws ServletException ... * @throws ServletException ...
* @throws IOException ... * @throws IOException ...
*/ */
public void doGet(HttpServletRequest request, HttpServletResponse response) protected void service (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
execute(request, response, RequestTrans.GET);
}
/**
* Handle a POST request.
*
* @param request ...
* @param response ...
*
* @throws ServletException ...
* @throws IOException ...
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
execute(request, response, RequestTrans.POST);
}
protected void execute(HttpServletRequest request, HttpServletResponse response, RequestTrans reqtrans = new RequestTrans(request);
byte method) {
RequestTrans reqtrans = new RequestTrans(method);
try { try {
// get the character encoding // get the character encoding