Search |
||
Exception Handling in Web ApplicationsPosted by crazybob on February 6, 2004 at 1:45 PM PST
If you've ever diagnosed a bug in a web application, you've undoubtedly experienced annoyance digging through a list of fifteen exception stack traces trying to identify the one you're interested in (if it's even present), or a sinking feeling when you tailed the web server log only to find: java.lang.NullPointerException I sure have. The output to the browser client helps even less, typically churning out the de facto, "Cannot display page," message. Avoid these symptoms of exception handling pitfalls and troubleshoot web applications effortlessly with this simple recipe. AntiPattern: T.M.I. (Too Much Information) The first exception throwing antipattern occurs when we repeatedly log or wrap and rethrow an exception every time we catch it:
catch (Exception e) {
e.printStackTrace();
throw new WrappingException(e);
}
The application prints the stack trace and rewraps the exception fifteen times before it finally propagates to the top where we're often subjected to the stack trace for each wrapper exception. Our visual noise filters go into overload as we sift through a proverbial log hay stack in search of the one stack trace we actually care about. AntiPattern: Lie of Omission The second antipattern surfaces when we trash the original stack trace:
catch (Exception e) {
// print message only.
System.err.println(e);
throw new WrapperException(e.getMessage());
}
If we look at the web server log, we'll see our AntiPattern: Head in the Sand This brings us to our final, most evil antipattern, ignoring exceptions:
catch (Exception e) {
e.printStackTrace();
}
Printing the stack trace and going on about your business is on par with trying to drive a car after the wheel has fallen off. Doing so leaves the system in an unpredictable state, often leading to security holes and code that's insanely difficult to debug. It's the modern day incarnation of a segmentation fault. The moral of this story: don't be afraid to throw your hands in the air and refuse to go on. People entrusting you with their credit card numbers may not thank you, but they'll hold on to their identities a little longer. Solution: NestedException Failing early helps avoid these pitfalls. The original stack trace in addition to other pertinent state information (user IDs, primary keys, method arguments, etc.) is a troubleshooter's best friend. I've found that when faced with a checked exception I can't possibly handle, it's best to wrap the exception in a runtime exception (once) and throw it to the top where it can ultimately be thrown to the web container. The exception propagates to the top sans explicit handling until the web container catches and logs it once and only once.
We can accomplish this with a class called
catch (CheckedException e) {
throw NestedException.wrap(e);
}
public class NestedException extends RuntimeException {
Throwable throwable;
private NestedException(Throwable t) {
this.throwable = t;
}
/** Wraps another exeception in a RuntimeException. */
public static RuntimeException wrap(Throwable t) {
if (t instanceof RuntimeException)
return (RuntimeException) t;
return new NestedException(t);
}
public Throwable getCause() {
return this.throwable;
}
public void printStackTrace() {
this.throwable.printStackTrace();
}
...
}
Create a Default Error Page Now that we've scrubbed our logs, we're left with the matter of output to the web browser. From my experience, only the finest of quality assurance testers take time to look at server logs. I often see bugs filed with the following description: Did so and so... Browser said "Error 500: Cannot display page."
Not a lot of help. On the other hand, most testers are willing to cut and paste browser output into an issue tracking system. A simple solution is to configure your web application's default error page in the
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>
Now, when we throw an exception to the container, it forwards the request to
<%@ page isErrorPage="true" import="java.io.PrintWriter" %>
<html><body>
<h1 style="color: red">Error</h1>
<pre>
<%
// unwrap ServletExceptions.
while (exception instanceof ServletException)
exception = ((ServletException) exception).getRootCause();
// print stack trace.
exception.printStackTrace(new PrintWriter(out));
%>
</pre>
</body></html>
The resulting page looks something like this:
Beautify our error page's design a bit, add some logic to show the stack trace to QA users but hide it from customers, and we're ready to go to production! »
Related Topics >>
Programming Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|