diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java
index 4acd46a5..617d1d1d 100644
--- a/src/helma/framework/RequestTrans.java
+++ b/src/helma/framework/RequestTrans.java
@@ -59,7 +59,7 @@ public class RequestTrans implements Serializable {
private final Map values;
// the HTTP request method
- private final String method;
+ private String method;
// timestamp of client-cached version, if present in request
private long ifModifiedSince = -1;
@@ -70,9 +70,6 @@ public class RequestTrans implements Serializable {
// when was execution started on this request?
private final long startTime;
- // true if this might be an XML-RPC request
- private boolean isXmlRpc;
-
// the name of the action being invoked
private String action;
private String httpUsername;
@@ -101,9 +98,6 @@ public class RequestTrans implements Serializable {
this.path = path;
values = new SystemMap();
startTime = System.currentTimeMillis();
- if ("POST".equals(method) && "text/xml".equals(request.getContentType())) {
- isXmlRpc = true;
- }
}
/**
@@ -111,17 +105,19 @@ public class RequestTrans implements Serializable {
*
* @return true if this might be an XML-RPC request.
*/
- public synchronized boolean isXmlRpc() {
- return isXmlRpc;
+ public synchronized boolean checkXmlRpc() {
+ return "POST".equals(method) && "text/xml".equals(request.getContentType());
}
/**
- * Set the isXmlRpc flag
+ * Return true if this request is in fact handled as XML-RPC request.
+ * This implies that {@link #checkXmlRpc()} returns true and a matching
+ * XML-RPC action was found.
*
- * @param xmlrpc true if this is infact an XML-RPC request
+ * @return true if this request is handled as XML-RPC request.
*/
- public synchronized void setXmlRpc(boolean xmlrpc) {
- isXmlRpc = xmlrpc;
+ public synchronized boolean isXmlRpc() {
+ return XMLRPC.equals(method);
}
/**
@@ -195,10 +191,19 @@ public class RequestTrans implements Serializable {
* 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() {
+ public synchronized String getMethod() {
return method;
}
+ /**
+ * Set the method of this request.
+ *
+ * @param method the method.
+ */
+ public synchronized void setMethod(String method) {
+ this.method = method;
+ }
+
/**
* Return true if this object represents a HTTP GET Request.
*/
diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java
index 8691c3e6..6d19b904 100644
--- a/src/helma/framework/ResponseTrans.java
+++ b/src/helma/framework/ResponseTrans.java
@@ -25,6 +25,8 @@ import java.io.*;
import java.security.*;
import java.util.*;
+import org.apache.xmlrpc.XmlRpcResponseProcessor;
+
/**
* A Transmitter for a response to the servlet client. Objects of this
* class are directly exposed to JavaScript as global property res.
@@ -118,7 +120,7 @@ public final class ResponseTrans implements Serializable {
// the res.meta map for meta response data
private transient Map meta = new SystemMap();
-
+
// the request trans for this response
private transient RequestTrans reqtrans;
@@ -129,13 +131,6 @@ public final class ResponseTrans implements Serializable {
Application app;
- /**
- * Creates a new ResponseTrans object.
- */
- public ResponseTrans(Application app) {
- this.app = app;
- }
-
/**
* Creates a new ResponseTrans object.
*
@@ -170,7 +165,7 @@ public final class ResponseTrans implements Serializable {
public Map getMacroHandlers() {
return handlers;
}
-
+
/**
* Get the meta info map for this response transmitter.
*/
@@ -462,12 +457,39 @@ public final class ResponseTrans implements Serializable {
* @param message the error message
*/
public void writeErrorReport(String appName, String message) {
- write("
");
- write("Error in application ");
- write(appName);
- write("
");
- write(message);
- write("");
+ if (reqtrans.isXmlRpc()) {
+ writeXmlRpcError(new RuntimeException(message));
+ } else {
+ write("");
+ write("Error in application ");
+ write(appName);
+ write("
");
+ write(message);
+ write("");
+ }
+ }
+
+ public void writeXmlRpcResponse(Object result) {
+ try {
+ reset();
+ contentType = "text/xml";
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+ XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor();
+ writeBinary(xresproc.encodeResponse(result, charset));
+ } catch (Exception x) {
+ writeXmlRpcError(x);
+ }
+ }
+
+ public void writeXmlRpcError(Exception x) {
+ contentType = "text/xml";
+ if (charset == null) {
+ charset = "UTF-8";
+ }
+ XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor();
+ writeBinary(xresproc.encodeException(x, charset));
}
/**
diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java
index b0d03324..a825b761 100644
--- a/src/helma/framework/core/RequestEvaluator.java
+++ b/src/helma/framework/core/RequestEvaluator.java
@@ -25,7 +25,6 @@ import java.util.*;
import org.apache.xmlrpc.XmlRpcRequestProcessor;
import org.apache.xmlrpc.XmlRpcServerRequest;
-import org.apache.xmlrpc.XmlRpcResponseProcessor;
/**
* This class does the work for incoming requests. It holds a transactor thread
@@ -194,7 +193,7 @@ public final class RequestEvaluator implements Runnable {
String errorAction = app.props.getProperty("error",
"error");
- action = getAction(currentElement, errorAction, null);
+ action = getAction(currentElement, errorAction, req);
if (action == null) {
throw new RuntimeException(error);
@@ -284,7 +283,7 @@ public final class RequestEvaluator implements Runnable {
"notfound");
currentElement = root;
- action = getAction(currentElement, notFoundAction, null);
+ action = getAction(currentElement, notFoundAction, req);
if (action == null) {
throw new FrameworkException(notfound.getMessage());
@@ -352,14 +351,11 @@ public final class RequestEvaluator implements Runnable {
XmlRpcRequestProcessor xreqproc = new XmlRpcRequestProcessor();
XmlRpcServerRequest xreq = xreqproc.decodeRequest(req.getServletRequest()
.getInputStream());
- System.err.println("ARGUMENTS: " + xreq.getParameters());
Vector args = xreq.getParameters();
args.add(0, xreq.getMethodName());
result = scriptingEngine.invoke(currentElement, action,
args.toArray(), ScriptingEngine.ARGS_WRAP_XMLRPC);
- res.reset();
- XmlRpcResponseProcessor xresproc = new XmlRpcResponseProcessor();
- res.writeBinary(xresproc.encodeResponse(result, "UTF-8"));
+ res.writeXmlRpcResponse(result);
} else {
scriptingEngine.invoke(currentElement, action,
new Object[0],
@@ -533,7 +529,8 @@ public final class RequestEvaluator implements Runnable {
res.reset();
- // check if we tried to process the error already
+ // check if we tried to process the error already,
+ // or if this is an XML-RPC request
if (error == null) {
app.errorCount += 1;
@@ -555,6 +552,15 @@ public final class RequestEvaluator implements Runnable {
app.logError(txname + ": " + error, x);
+ if (req.isXmlRpc()) {
+ // if it's an XML-RPC exception immediately generate error response
+ if (!(x instanceof Exception)) {
+ // we need an exception to pass to XML-RPC responder
+ x = new Exception(x.toString(), x);
+ }
+ res.writeXmlRpcError((Exception) x);
+ done = true;
+ }
} else {
// error in error action. use traditional minimal error message
res.writeErrorReport(app.getName(), error);
@@ -983,13 +989,15 @@ public final class RequestEvaluator implements Runnable {
// afterwards for GET, POST, HEAD requests
int length = buffer.length();
- if (req.isXmlRpc()) {
+ if (req.checkXmlRpc()) {
// append _methodname
buffer.append("_xmlrpc");
- if (scriptingEngine.hasFunction(obj, buffer.toString()))
+ if (scriptingEngine.hasFunction(obj, buffer.toString())) {
+ // handle as XML-RPC request
+ req.setMethod(RequestTrans.XMLRPC);
return buffer.toString();
+ }
// cut off method in case it has been appended
- req.setXmlRpc(false);
buffer.setLength(length);
}