users@jersey.java.net

Re: [Jersey] Error Handling...and forwarding

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Wed, 14 Jan 2009 10:01:20 -0500

Another (portable) workaround is to add an exception mapper for
WebApplicationException:

@Provider
public class BackstopExceptionHandler implements
ExceptionMapper<WebApplicationException> {
   public Response toResponse(WebApplicationException exception) {
     WebServiceFault f = MapToFault(exception);
     return
Response.fromResponse(exception.getResponse()).entity(f).type("text/
plain").build();
   }
}

If a resource can't be found then a JAX-RS impl throws a
WebApplicationException with just a status code set, see:

https://jsr311.dev.java.net/nonav/releases/1.0/spec/
spec3.html#x3-360003.7.2 step 1.d

This exception is then processed the same as one thrown by a resource
method, see section 3.3.4:

https://jsr311.dev.java.net/nonav/releases/1.0/spec/
spec3.html#x3-280003.3.4

HTH,
Marc.

On Jan 14, 2009, at 7:55 AM, Paul Sandoz wrote:

> I think there may also be a workaround in the interim of fixing this.
>
> Register a ContainerResponseFilter implementation that has
> HttpServletResponse injected. Check the status, headers and entity
> of the ContainerResponse. If only the status is set and >=400 then
> call HttpServletResponse.sendError() with the status.
>
> Paul.
>
> On Jan 14, 2009, at 1:45 PM, Paul Sandoz wrote:
>
>> HI Jorge,
>>
>> Thanks for doing this investigating it helps me a lot to
>> investigate further. Note that i tried asking on the GF users list
>> but got no response :-(
>>
>> So in the bad-resource case the behavior for the Jersey Web app
>> should be as follows:
>>
>> 1) Jersey returns a 404 to the URL path "/rest/bla"
>>
>> 2) The servlet container redirects the 404 to /rest/error"
>>
>> And i presume it should be the same for a servlet implemented
>> equivalently to that of the Jersey servlet.
>>
>> So... I modified the servlet test case. The web.xml was modified as
>> follows:
>>
>> <servlet-mapping>
>> <servlet-name>ErrorServlet</servlet-name>
>> <url-pattern>/servlet/*</url-pattern>
>> </servlet-mapping>
>> <error-page>
>> <error-code>404</error-code>
>> <location>/servlet/error</location>
>> </error-page>
>>
>> and the ErrorServlet was modified as follows:
>>
>> if (req.getPathInfo().equals("/error")) {
>> PrintWriter out;
>>
>> res.setContentType("text/plain");
>> out = res.getWriter();
>>
>> out.printf("The error has been caught by the error
>> servlet!\n\n");
>> out.printf("Error : %d\n" +
>> "Message : %s\n" +
>> "Exception Type: %s\n",
>>
>> req.getAttribute("javax.servlet.error.status_code"),
>> req.getAttribute("javax.servlet.error.message"),
>>
>> req.getAttribute("javax.servlet.error.exception_type"));
>> } else {
>> res.setStatus(404);
>> }
>>
>> Thus the above models what Jersey does. In such cases the same
>> behavior results as the Jersey deployed JAX-RS test case.
>>
>> I think i now know what it is. If i change:
>>
>> res.setStatus(404);
>>
>> to
>>
>> res.sendError(404);
>>
>> then it works. And then i read this:
>>
>> Sets the status code for this response. This method is used to set
>> the return status code when there is no error (for example, for the
>> status codes SC_OK or SC_MOVED_TEMPORARILY). If there is an error,
>> and the caller wishes to invoke an error-page defined in the
>> web application, the sendError method should be used instead.
>>
>> Hmm... i am wondering what to do here. The following rule could
>> apply:
>>
>> - if the response status is an error >= 400 and there is no
>> response entity and no response headers set (the application has
>> not set
>> anything other than the status code or Jersey has set just the
>> status code) then the servlet response mapping calls sendError.
>>
>> IMHO this is something we need to clarify in the JAX-RS
>> specification.
>>
>> Paul.
>>
>> On Jan 14, 2009, at 9:23 AM, Jorge L. Williams wrote:
>>
>>> -----BEGIN PGP SIGNED MESSAGE-----
>>> Hash: SHA1
>>>
>>> Hi Paul,
>>>
>>> Wow, I can't believe it took me a month to get back to you. Sorry,
>>> holiday, deadlines, you know how it is.
>>>
>>> Anyway, I did put together a simple app for you. I noticed while
>>> testing it that the behavior is slightly different between
>>> application servers. To rule out an application server problem vs a
>>> jersey problem I also tested my approach with the RestEasy JAX-RS
>>> implementation (no offense guys :-) I'm sending the source for the
>>> ear file.
>>>
>>> There are three web modules:
>>>
>>> 1. error-servlet : Our old approach of catching errors
>>> using a
>>> servlet as an error page.
>>> 2. error-jaxrs : The Jersey implementation
>>> 3. error-resteasy : The Rest-easy implementation
>>>
>>> I tested with three application servers
>>>
>>> 1. glassfish : 9.1_02 (build b04-fcs)
>>> 2. jboss : 5.0.0.GA
>>> 3. weblogic : 10.3
>>>
>>> Each webapp is setup to forward a 404 to a resource (or servlet). If
>>> you visit context root of each of the web apps you'll see a couple
>>> of
>>> links
>>>
>>> 1. direct : A direct link to the error resource (just to make sure
>>> we're getting to it)
>>> 2. bad : A bad link within the context root (this should generate
>>> 404 and forward to the error resource)
>>> 3. bad-resource : A bad link within the JAX-RS servlet mapping
>>> (this should should also forward to the error resource)
>>>
>>> Here's the results I get for Jersey
>>>
>>> glassfish (direct : works, bad : works, bad-resource : wrong error
>>> page )
>>> jboss (direct : works, bad: works, bad-resource: wrong error
>>> page)
>>> weblogic (direct: works, bad : empty result, bad-resource: empty
>>> result)
>>>
>>> I use weblogic which displays the behavior I described in my initial
>>> email. I'm guessing the behavior there may indeed be an application
>>> server issue. None the less, Jersey doesn't seem to be behaving
>>> correctly with the other app servers. The RestEasy implementation
>>> handles all three cases correctly -- in JBoss, I couldn't get it
>>> deployed on the other app servers though I didn't spend too much
>>> time
>>> fighting with it :-)
>>>
>>> Hope this helps...It would be really nice if I could get this
>>> feature
>>> to work or if there were at least an alternative to it.
>>>
>>> Let me know,
>>>
>>> jOrGe W.
>>>
>>>> Hi Jorge,
>>>>
>>>> Would it be possible to create a simple example application. That
>>>> would help me understand better your use-case and help debug what
>>>> is
>>>> going on.
>>>>
>>>> My suspicion is the error resource is deployed at a URL that is
>>>> different to what you expect.
>>>>
>>>> What is the error resource class you are using, specifically the
>>>> @Path
>>>> value? and what is the URL pattern for the error servlet?
>>>>
>>>> Paul.
>>>>
>>>> On Dec 12, 2008, at 12:32 AM, Jorge L Williams wrote:
>>>>
>>>>>
>>>>> Hey guys,
>>>>>
>>>>> I know we covered this topic earlier, but I have a slightly
>>>>> different question, I think.
>>>>>
>>>>> We want to make sure that regardless of what sort of error
>>>>> condition
>>>>> occurs (whether it's generated by one of our JAX-RS resources or
>>>>> whether it's an internal server error of some kind) that we
>>>>> return a
>>>>> correct entity. In our case we have a JAXB object called
>>>>> WebserviceFault that our clients expect should anything go wrong.
>>>>>
>>>>> To catch every case we created an ErrorServlet that mapped to
>>>>> say /
>>>>> error and setup our web.xml...
>>>>>
>>>>> <error-page>
>>>>> <error-code>400</error-code>
>>>>> <location>/error</location>
>>>>> </error-page>
>>>>> .
>>>>> .
>>>>> .
>>>>> <error-page>
>>>>> <error-code>500</error-code>
>>>>> <location>/error</location>
>>>>> </error-page>
>>>>>
>>>>> The error servlet itself simply gets details from the request...
>>>>>
>>>>> Integer code = (Integer) request.getAttribute
>>>>> ("javax.servlet.error.status_code");
>>>>> Exception e = (Exception) request.getAttribute
>>>>> ("javax.servlet.error.exception");
>>>>> String msg = (String) request.getAttribute
>>>>> ("javax.servlet.error.message");
>>>>>
>>>>> and wraps it around a WebserviceFault which it serializes to the
>>>>> response.
>>>>>
>>>>> Very tedious and maybe a little goofy (If there's a better way
>>>>> I'll
>>>>> take it), but it's been working well for us thus far and this
>>>>> method
>>>>> allows us to catch absolutely all error conditions including 401s
>>>>> etc..that I don't think make it into Jersey.
>>>>>
>>>>> We've been transitioning our ReST services from using vanilla
>>>>> servlets to Jersey over the last couple of months. I decided to
>>>>> replace the ErrorServlet that we've been using with an error
>>>>> resource since we've become interested in receiving error
>>>>> conditions
>>>>> not just in XML but also in JSON and I figured converting the
>>>>> Error
>>>>> servlet would be the easiest way to accomplish this.
>>>>>
>>>>> One problem: it doesn't work. When an error condition hits and
>>>>> the
>>>>> application server forwards to the error resource, I get nothing
>>>>> but
>>>>> a blank request no entity at all -- though the Error code is
>>>>> correctly transmitted ie:
>>>>>
>>>>>
>>>>> HTTP/1.x 404 Not Found
>>>>> Date: Thu, 11 Dec 2008 22:34:21 GMT
>>>>> Content-Length: 0
>>>>>
>>>>> I suspect that this is because the request is being forwarded and
>>>>> the URI is not what Jersey is expecting(?).
>>>>> For example we get...
>>>>>
>>>>> GET /bla/bla/bla
>>>>>
>>>>> but something goes wrong and the application server forwards to
>>>>>
>>>>> /error
>>>>>
>>>>> probably via a request dispatcher(?). I believe the request URI
>>>>> in
>>>>> this case should be /bla/bla/bla and not /error -- is this what's
>>>>> confusing things?
>>>>>
>>>>> So, should I stick with my error servlet? If so what's the best
>>>>> way to utilize Jersey to handle the request -- parse the Accept
>>>>> header myself and get a MessageBodyWriter from MessageBodyWorkers?
>>>>>
>>>>> Thanks,
>>>>>
>>>>> jOrGe W.
>>> -----BEGIN PGP SIGNATURE-----
>>> Version: GnuPG v2.0.9 (GNU/Linux)
>>>
>>> iEYEARECAAYFAkltoQEACgkQ72r0i/n44hPv9wCfdrRjk7MmDJe8TucA4c3oA4rD
>>> 3ioAoJjrOsE2mtMqJFzzOpCgUz+Q3Xml
>>> =GtV5
>>> -----END PGP SIGNATURE-----
>>>
>>> <error-test.tgz><error-
>>> test
>>> .tgz
>>> .sig
>>> >
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>

---
Marc Hadley <marc.hadley at sun.com>
CTO Office, Sun Microsystems.