views:

100

answers:

4

We would like to implement a "fault barrier" strategy for managing exceptions in our applications. One thing our applications have is the concept of a "passback" response, basically a no-op, which we'd like to return in preference to throwing 500, 400, etc. HTTP status codes - e.g. our external facing applications should always return a valid response, even if an underlying exception was thrown - we'd like to handle that internal to the application, and still return a valid noop response.

Our first implementation was a Servlet Filter which would wrap all requests in a try/catch block, and return the default return from the catch, e.g.:

try{
  chain.doFilter()
} catch (Throwable t) {
  generatePassbackResponse(HttpServletRequest req, HttpServletResponse res)
}

While this mostly works, and feels nice and clean (we can return nice text, set the content/type appropriately, etc.) the one problem seems to be that when an Exception is thrown the response still comes through with Status-Code: 500.

HttpServletResponse.setStatus(200) doesn't have an effect, and the javadoc does say it only applies on normal requests.

Our second implementation thought is we may have to forward to another page, or plug an errorPage into web.xml and manually sendError to that page - though we're interested in whether anyone has a specific recommendation.

A: 

Can you not just use the standard web.xml configuration:

<error-page>
    <error-code>500</error-code>
    <location>/error.jsp</location>
</error-page>

<error-page>
    <location>/error.jsp</location>
    <exception-type>java.lang.Exception</exception-type>
</error-page>

I cant see what else you're trying to do that this doesn't already cater for? If it's just the error code, then I think that you can set this using the response object.

Steve Neal
The default error-page handler (which we tried) doesn't appear to allow us to override the status code.The status code is a big part of what we're trying to handle, and at least in Glassfish, the response object does not seem to allow you to set the status code on an error response. Since these are server-to-server responses (and not user browser in most cases) the status code can be pretty significant for RESTful responses.
jayshao
A: 

If I remember correctly, you should not be calling chain.doFilter() if you do not want anything else to process the request. The filter will get executed in every case, but chain.doFilter() will ensure that all other filters are called. In order to properly block an exception from getting to the user, you need to stop the request/response handling.

You could take a different route as well by using a framework like Spring and its Interceptors (just like a Filter). Spring gives you a lot of control over the Interceptors and how responses get handled. Granted, this is a bit heavy of a solution to your question.

In response to the comment, according to http://java.sun.com/products/servlet/Filters.html:

The most important method in the Filter interface is the doFilter method...This method usually performs some of the following actions:

If the current filter is the last filter in the chain that ends with the target servlet, the next entity is the resource at the end of the chain; otherwise, it is the next filter that was configured in the WAR. It invokes the next entity by calling the doFilter method on the chain object (passing in the request and response it was called with, or the wrapped versions it may have created). Alternatively, it can choose to block the request by not making the call to invoke the next entity. In the latter case, the filter is responsible for filling out the response.

The idea being that this "fault barrier" needs to stop all other filters from executing, and just handle the request/response in the manner it deems necessary.

Robert Diana
You should not call `FilterChain#doFilter()` whenever you've called `RequestDispatcher#forward()` or `HttpServletResponse#sendRedirect()` before in the `Filter#doFilter()` method. This is not the case here.
BalusC
Since the goal is to catch the exception being thrown, but have a generic filter, we definitely need to call doFilter - this got kind of backburnered though, so for now we're looking to see if a abstract/dispatcher servlet gets us what we want.
jayshao
A: 

The RESTEasy framework allows you to select what your response code will be using ExceptionMappers. It may be that you're reluctant to use it, but I've found it to be very quick and efficient.

The JBoss documentation covering ExceptionMappers http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html_single/index.html#ExceptionMappers

My blog article showing a snippet of general purpose RESTEasy code http://gary-rowe.com/agilestack/2010/08/22/my-current-development-stack/

Gary Rowe
I don't know if I'd describe us as being reluctant to use it, though it does seem like overkill in this one case to think about switching dev frameworks.
jayshao
I wouldn't go changing a dev framework that everyone is familiar with unless there is a compelling reason (hence "reluctant to use it") but it may be that the transition is relatively painless.
Gary Rowe
+1  A: 

There are two methods form setting the HTTP status of a response:

  • setStatus() will just set the status
  • sendError() will set the status and trigger the <error-page> mechanism

Javadoc for sendError says the response should be considered to be committed after calling sendError (this could explain the behavior of your appserver).

Implementing a custom HttpServletResponseWrapper would allow you to enforce the behavior you need for sendError (and maybe buffer the whole request in memory, so that you can send "passbacks" for exceptions occurring after the point the request would be usually committed).

giorgiga