First some definitions:
You set a global error handler like this:
dwr.engine.setErrorHandler(handler);
You can also specify call or batch level error or warning handlers. For example, in the call meta-data:
Remote.method(params, { callback:function(data) { ... }, errorHandler:function(errorString, exception) { ... } });or, in batch meta-data:
dwr.engine.beginBatch(); Remote.method(params, function(data) { ... }); // Other remote calls dwr.engine.endBatch({ errorHandler:function(errorString, exception) { ... } });
DWR can marshall exceptions, and they will become errors in JavaScript land (they can't be thrown since this will probably be happening asynchronously).
For example, if we remote the following Java class:
public class Remote { public String getData() { throw new NullPointerException("message"); } }
Then in Javascript we will see the following:
function errh(msg) { alert(msg); } dwr.engine.setErrorHandler(errh); Remote.getData(function(data) { alert(data); });
The result will be an alert dialog from the errh()
error handler.
Exceptions are subject to the usual marshaling rules - that is nothing is converted without express permission. However, there is one deviation from this rule. If there is no marshaller in place for an exception, then a default MinimalistExceptionConverter is used. The MinimalistExceptionConverter tells the client that something has gone wrong (which the client could guess anyway, since the call did not work) but for security reasons, it does not say what broke - so exception types are converted to a java.lang.Throwable.
When there is no exception converter specified for an exception, the exception object passed to the client looks like this:
{ javaClassName:'java.lang.Throwable', message:'Error' }
You can enable a more verbose exception handler with the following in dwr.xml:
<convert match="java.lang.Exception" converter="exception"/>
By default, this will attempt to convert everything that is part of the exception, so the converted exception might look like this:
{ javaClassName:'org.xml.sax.SAXParseException', lineNumber:42, publicId:'somePublicId', message:'Missing >' }
Clearly, permission will be needed to convert nested properties, which includes the stack trace. By default, there is no permission to convert StackTrace elements. It is a good idea to either expose only the information that you wish to expose (better for a live environment):
<convert match="java.lang.Exception" converter="exception"> <param name='include' value='message,lineNumber'/> </convert>
Or allow stack traces too, (which can be useful in development):
<convert match="java.lang.StackTraceElement" converter="bean"/>
Aside from the fact that this is obviously insecure, it can also be quite verbose, so it might be best to use this technique only when the browser and web-server are close together in network terms.
The primary purpose of textHtmlHandler is to allow you to cope with the server expiring your session and sending a login page in response to a DWR request without letting DWR handle the response at all.
The standard usage goes something like this:
dwr.engine.setTextHtmlHandler(function() { window.alert("Your session has expired, please login again." ); document.location = '/mycontext/login'; });
It is possible to show the login page using a pop-up div, keeping the user on the current page. The textHtmlHandler function is passed a parameter which contains information about the failure. The data passed in the parameter is:
Example usage might be something like this:
dwr.engine.setTextHtmlHandler(function(pageData) { // display pageData.responseText in a Lightbox });
A fully working example would need to post the login from inside an iframe to allow the user to remain on the same page.
There is currently a limitation in setTextHtmlHandler where it will not be called as a result of fileUpload requests. Future versions of DWR should correct this issue.