users@jersey.java.net

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

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Wed, 14 Jan 2009 16:44:21 +0100

Good point!

Paul.

On Jan 14, 2009, at 4:01 PM, Marc Hadley wrote:

> 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.
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>