You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Henrik Martin <he...@rovicorp.com> on 2009/12/23 05:24:03 UTC

Need some more help on error handling

Greetings. I'm thoroughly confused about the gazillion ways of handling
errors in CXF/JAX-RS. I've read whatever documentation I've found on the
wiki, and have followed the many posts to the mailing list on this
subject, and I still can't figure out how to cover all corner cases
without hacking the CXF source code (a situation I don't want to get
into). 

I need to capture 100% of all possible errors that can ever happen
inside CXF, the web container (Tomcat 6.X), and any possible CXF
application running in the container (we ONLY use REST based services
using CXF), and stream the errors/exceptions out as XML (we use XStream
for that). That's the requirement. 

Here's what I've done:

1) I wrote a piece of code that implements the ResponseHandler
interface. I do quite a bit of analysis inside that code, and return a
custom response called an ErrorResponse. This eventually gets streamed
out to XML. This ResponseHandler is configured as a provider with the
<jaxrs:providers> mechanism in our Spring config file. It seems to cover
the cases where the error condition is wrapped inside a Response object.

2) I implemented a bunch of ExceptionMapper classes for the most common
exceptions, as well as a "catch-all" for other exceptions. This seems to
cover the cases where a service is throwing an exception. My mappers
convert the exception to XML and stuffs that in a Response object. The
mappers are also configured using the <jaxrs:providers> mechanism. 

3) I wrote an a piece of code that extends the
AbstractOutDatabindingInterceptor class (based on the CXF example that
Sergey posted a while back). This is configured using the following
mechanism:
    
<cxf:bus>
  <cxf:outFaultInterceptors>
    <ref bean="XMLOutFault.Interceptor"/>
  </cxf:outFaultInterceptors>
</cxf:bus> 

4) I wrote a Servlet Filter (implementing the javax.servlet.Filter
interface), that catches any exception and streams it out as XML. The
problem is that nothing downstream seems to throw any exceptions, so the
doFilter() method always returns normally. 

I need to know what I have to do to cover 100% of all possible error
cases, and stream the error out using our custom XStream transcode back
to the client. Some code samples or fairly detailed info about how to
write the code, and how to wire it up would be fantastic. One of the
corner cases NOT covered by any of the above mentioned mechanisms is
when I specify a URL that is not mapped by CXF. In this case, the
org.apache.cxf.transport.servlet.ServletController's invoke() method
will call generateNotFound(), which sets the HTTP status code to 404,
and writes an error message directly to the HttpServletResponse. How can
I override this? 

I don't want ANY component other than my code, writing ANYTHING to the
servlet's OutputStream in case something goes wrong. I absolutely have
to control 100% of all error handling. Any tips, tricks, and pointers to
examples are greatly appreciated. Thanks much,

/Henrik



RE: Need some more help on error handling

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi Henrik,

Yes, give it a try please.
Happy Christmas to you too :-)
Sergey 

-----Original Message-----
From: Henrik Martin [mailto:henrik.martin@rovicorp.com] 
Sent: 23 December 2009 18:54
To: users@cxf.apache.org
Subject: Re: Need some more help on error handling

Thanks Sergey. I think I'll try to subclass the CXFServlet + the
controller and override the necessary methods. Kudos to you and the rest
of the CXF team for excellent support! Happy holidays to y'all. 

/Henrik

On Wed, 2009-12-23 at 13:16 +0000, Sergey Beryozkin wrote:
> Hi
> 
> > Greetings. I'm thoroughly confused about the gazillion ways of
handling
> > errors in CXF/JAX-RS. I've read whatever documentation I've found on
the
> > wiki, and have followed the many posts to the mailing list on this
> > subject, and I still can't figure out how to cover all corner cases
> > without hacking the CXF source code (a situation I don't want to get
> > into).
> 
> Ok :-).
> As far as JAX-RS itself is concerned, there are 3 ways to deal with
errors (marked as JAXRS1, etc).
> 
> JAXRS1. Return a JAXRS Response directly from a resource method, with
this Response containing the appropriate status code
> 
> JAXRS2. Create as many ExceptionMappers as needed which will capture
exceptions and convert them into appropriate Responses. One 
> might have a single mapper capturing all the exceptions or a number of
mappers capturing seperate exceptions...CXF JAXRS ships a 
> default WebApplicationExceptionMapper but one can register a custom
WebApplicationExceptionMapper if the responses produced by the 
> default mapper are not satisfactory in some specific cases.
> 
> JAXRS3. Have Servlet Filter capturing ServletExceptions - all the
exceptions which have been not mapped by the mappers earlier on 
> will be visible to Servlet Filter.
> 
> These options should give you a 100% coverage.
> Next, CXF JAX-RS and CXF offers few more options (marked as CXF1,
etc).
> 
> CXF1. As noted in JAXRS2, one can override responses produced by
default mapper by registering a custom 
> WebApplicationExceptionMapper but the CXF JAXRS specifc option is to
register a ResponseHandler filter instead and override the 
> Response there
> 
> CXF2. One can configure CXF JAXRS to block the propagation of the
unmapped execptions to the Servlet filter in which case CXF XML 
> Binding (which CXF JAX-RS depends upon) will wrap the exception in its
xml-specific format
> 
> CXF3. One can register CXF fault interceptors and handle all the
exceptions in these interceptors.
> 
> That is probably it, does it clarify things a bit ?
> 
> >
> > I need to capture 100% of all possible errors that can ever happen
> > inside CXF, the web container (Tomcat 6.X), and any possible CXF
> > application running in the container (we ONLY use REST based
services
> > using CXF), and stream the errors/exceptions out as XML (we use
XStream
> > for that). That's the requirement.
> >
> > Here's what I've done:
> >
> > 1) I wrote a piece of code that implements the ResponseHandler
> > interface. I do quite a bit of analysis inside that code, and return
a
> > custom response called an ErrorResponse. This eventually gets
streamed
> > out to XML. This ResponseHandler is configured as a provider with
the
> > <jaxrs:providers> mechanism in our Spring config file. It seems to
cover
> > the cases where the error condition is wrapped inside a Response
object.
> 
> Yes, it is option CXF1 but also see option JAXRS2. I'm not sure when
this code even executes for you given that you
> say in 2) below that you capture all the exceptions with exception
mappers.
> 
> >
> > 2) I implemented a bunch of ExceptionMapper classes for the most
common
> > exceptions, as well as a "catch-all" for other exceptions. This
seems to
> > cover the cases where a service is throwing an exception. My mappers
> > convert the exception to XML and stuffs that in a Response object.
The
> > mappers are also configured using the <jaxrs:providers> mechanism.
> 
> OK
> 
> >
> > 3) I wrote an a piece of code that extends the
> > AbstractOutDatabindingInterceptor class (based on the CXF example
that
> > Sergey posted a while back). This is configured using the following
> > mechanism:
> >
> > <cxf:bus>
> >  <cxf:outFaultInterceptors>
> >    <ref bean="XMLOutFault.Interceptor"/>
> >  </cxf:outFaultInterceptors>
> > </cxf:bus>
> 
> You probably do not need it if you already do 1) and 2) unless you
also do JAXWS. If both JAXWS & JAXRS are involved then relying on 
> fault interceptors can be quite an attractive option...
> 
> >
> > 4) I wrote a Servlet Filter (implementing the javax.servlet.Filter
> > interface), that catches any exception and streams it out as XML.
The
> > problem is that nothing downstream seems to throw any exceptions, so
the
> > doFilter() method always returns normally.
> 
> This is expected because in 2) you've captured all the exceptions.
Only those exceptions which have not been mapped will be 
> propagated
> 
> >
> > I need to know what I have to do to cover 100% of all possible error
> > cases, and stream the error out using our custom XStream transcode
back
> > to the client. Some code samples or fairly detailed info about how
to
> > write the code, and how to wire it up would be fantastic. One of the
> > corner cases NOT covered by any of the above mentioned mechanisms is
> > when I specify a URL that is not mapped by CXF. In this case, the
> > org.apache.cxf.transport.servlet.ServletController's invoke() method
> > will call generateNotFound(), which sets the HTTP status code to
404,
> > and writes an error message directly to the HttpServletResponse. How
can
> > I override this?
> 
> Perhaps you can extend CXFServlet and override its protected
createServletController and then override generateNotFound() on your 
> custom controller ?
> 
> Another, possibly a more awkward workaround is to use your custom
ServletFilter and pass along an HttpResponse filter ? Please see 
> HttpServletResponseFilter and ServletOutputStreamFilter in the CXF
JAXRS source for some basic example...Ex, given
> 
> protected void generateNotFound(HttpServletRequest request,
HttpServletResponse res) throws IOException {
> 
> res.setStatus(404);
> 
> res.setContentType("text/html");
> 
> res.getWriter().write("<html><body>No service was
found.</body></html>");
> 
> }
> 
> you can override in your HttpResponse filter  setContentType() and
setStatus() and if you get "text/html" and "404" (CXF JAXRS can 
> also reply with 404 but it won't set text/html) then it is that edge
case you're dealing with and if it is the case then in 
> getWriter() your return a StringWriter buffer instead to block the
default response....
> 
> >
> > I don't want ANY component other than my code, writing ANYTHING to
the
> > servlet's OutputStream in case something goes wrong. I absolutely
have
> > to control 100% of all error handling. Any tips, tricks, and
pointers to
> > examples are greatly appreciated. Thanks much,
> 
> At the moment I think that given the above, you can get a 100%
coverage...
> 
> thanks, Sergey
> 
> >
> > /Henrik
> >
> > 
> 

Re: Need some more help on error handling

Posted by Henrik Martin <he...@rovicorp.com>.
Thanks Sergey. I think I'll try to subclass the CXFServlet + the
controller and override the necessary methods. Kudos to you and the rest
of the CXF team for excellent support! Happy holidays to y'all. 

/Henrik

On Wed, 2009-12-23 at 13:16 +0000, Sergey Beryozkin wrote:
> Hi
> 
> > Greetings. I'm thoroughly confused about the gazillion ways of handling
> > errors in CXF/JAX-RS. I've read whatever documentation I've found on the
> > wiki, and have followed the many posts to the mailing list on this
> > subject, and I still can't figure out how to cover all corner cases
> > without hacking the CXF source code (a situation I don't want to get
> > into).
> 
> Ok :-).
> As far as JAX-RS itself is concerned, there are 3 ways to deal with errors (marked as JAXRS1, etc).
> 
> JAXRS1. Return a JAXRS Response directly from a resource method, with this Response containing the appropriate status code
> 
> JAXRS2. Create as many ExceptionMappers as needed which will capture exceptions and convert them into appropriate Responses. One 
> might have a single mapper capturing all the exceptions or a number of mappers capturing seperate exceptions...CXF JAXRS ships a 
> default WebApplicationExceptionMapper but one can register a custom WebApplicationExceptionMapper if the responses produced by the 
> default mapper are not satisfactory in some specific cases.
> 
> JAXRS3. Have Servlet Filter capturing ServletExceptions - all the exceptions which have been not mapped by the mappers earlier on 
> will be visible to Servlet Filter.
> 
> These options should give you a 100% coverage.
> Next, CXF JAX-RS and CXF offers few more options (marked as CXF1, etc).
> 
> CXF1. As noted in JAXRS2, one can override responses produced by default mapper by registering a custom 
> WebApplicationExceptionMapper but the CXF JAXRS specifc option is to register a ResponseHandler filter instead and override the 
> Response there
> 
> CXF2. One can configure CXF JAXRS to block the propagation of the unmapped execptions to the Servlet filter in which case CXF XML 
> Binding (which CXF JAX-RS depends upon) will wrap the exception in its xml-specific format
> 
> CXF3. One can register CXF fault interceptors and handle all the exceptions in these interceptors.
> 
> That is probably it, does it clarify things a bit ?
> 
> >
> > I need to capture 100% of all possible errors that can ever happen
> > inside CXF, the web container (Tomcat 6.X), and any possible CXF
> > application running in the container (we ONLY use REST based services
> > using CXF), and stream the errors/exceptions out as XML (we use XStream
> > for that). That's the requirement.
> >
> > Here's what I've done:
> >
> > 1) I wrote a piece of code that implements the ResponseHandler
> > interface. I do quite a bit of analysis inside that code, and return a
> > custom response called an ErrorResponse. This eventually gets streamed
> > out to XML. This ResponseHandler is configured as a provider with the
> > <jaxrs:providers> mechanism in our Spring config file. It seems to cover
> > the cases where the error condition is wrapped inside a Response object.
> 
> Yes, it is option CXF1 but also see option JAXRS2. I'm not sure when this code even executes for you given that you
> say in 2) below that you capture all the exceptions with exception mappers.
> 
> >
> > 2) I implemented a bunch of ExceptionMapper classes for the most common
> > exceptions, as well as a "catch-all" for other exceptions. This seems to
> > cover the cases where a service is throwing an exception. My mappers
> > convert the exception to XML and stuffs that in a Response object. The
> > mappers are also configured using the <jaxrs:providers> mechanism.
> 
> OK
> 
> >
> > 3) I wrote an a piece of code that extends the
> > AbstractOutDatabindingInterceptor class (based on the CXF example that
> > Sergey posted a while back). This is configured using the following
> > mechanism:
> >
> > <cxf:bus>
> >  <cxf:outFaultInterceptors>
> >    <ref bean="XMLOutFault.Interceptor"/>
> >  </cxf:outFaultInterceptors>
> > </cxf:bus>
> 
> You probably do not need it if you already do 1) and 2) unless you also do JAXWS. If both JAXWS & JAXRS are involved then relying on 
> fault interceptors can be quite an attractive option...
> 
> >
> > 4) I wrote a Servlet Filter (implementing the javax.servlet.Filter
> > interface), that catches any exception and streams it out as XML. The
> > problem is that nothing downstream seems to throw any exceptions, so the
> > doFilter() method always returns normally.
> 
> This is expected because in 2) you've captured all the exceptions. Only those exceptions which have not been mapped will be 
> propagated
> 
> >
> > I need to know what I have to do to cover 100% of all possible error
> > cases, and stream the error out using our custom XStream transcode back
> > to the client. Some code samples or fairly detailed info about how to
> > write the code, and how to wire it up would be fantastic. One of the
> > corner cases NOT covered by any of the above mentioned mechanisms is
> > when I specify a URL that is not mapped by CXF. In this case, the
> > org.apache.cxf.transport.servlet.ServletController's invoke() method
> > will call generateNotFound(), which sets the HTTP status code to 404,
> > and writes an error message directly to the HttpServletResponse. How can
> > I override this?
> 
> Perhaps you can extend CXFServlet and override its protected createServletController and then override generateNotFound() on your 
> custom controller ?
> 
> Another, possibly a more awkward workaround is to use your custom ServletFilter and pass along an HttpResponse filter ? Please see 
> HttpServletResponseFilter and ServletOutputStreamFilter in the CXF JAXRS source for some basic example...Ex, given
> 
> protected void generateNotFound(HttpServletRequest request, HttpServletResponse res) throws IOException {
> 
> res.setStatus(404);
> 
> res.setContentType("text/html");
> 
> res.getWriter().write("<html><body>No service was found.</body></html>");
> 
> }
> 
> you can override in your HttpResponse filter  setContentType() and setStatus() and if you get "text/html" and "404" (CXF JAXRS can 
> also reply with 404 but it won't set text/html) then it is that edge case you're dealing with and if it is the case then in 
> getWriter() your return a StringWriter buffer instead to block the default response....
> 
> >
> > I don't want ANY component other than my code, writing ANYTHING to the
> > servlet's OutputStream in case something goes wrong. I absolutely have
> > to control 100% of all error handling. Any tips, tricks, and pointers to
> > examples are greatly appreciated. Thanks much,
> 
> At the moment I think that given the above, you can get a 100% coverage...
> 
> thanks, Sergey
> 
> >
> > /Henrik
> >
> > 
> 

Re: Need some more help on error handling

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi

> Greetings. I'm thoroughly confused about the gazillion ways of handling
> errors in CXF/JAX-RS. I've read whatever documentation I've found on the
> wiki, and have followed the many posts to the mailing list on this
> subject, and I still can't figure out how to cover all corner cases
> without hacking the CXF source code (a situation I don't want to get
> into).

Ok :-).
As far as JAX-RS itself is concerned, there are 3 ways to deal with errors (marked as JAXRS1, etc).

JAXRS1. Return a JAXRS Response directly from a resource method, with this Response containing the appropriate status code

JAXRS2. Create as many ExceptionMappers as needed which will capture exceptions and convert them into appropriate Responses. One 
might have a single mapper capturing all the exceptions or a number of mappers capturing seperate exceptions...CXF JAXRS ships a 
default WebApplicationExceptionMapper but one can register a custom WebApplicationExceptionMapper if the responses produced by the 
default mapper are not satisfactory in some specific cases.

JAXRS3. Have Servlet Filter capturing ServletExceptions - all the exceptions which have been not mapped by the mappers earlier on 
will be visible to Servlet Filter.

These options should give you a 100% coverage.
Next, CXF JAX-RS and CXF offers few more options (marked as CXF1, etc).

CXF1. As noted in JAXRS2, one can override responses produced by default mapper by registering a custom 
WebApplicationExceptionMapper but the CXF JAXRS specifc option is to register a ResponseHandler filter instead and override the 
Response there

CXF2. One can configure CXF JAXRS to block the propagation of the unmapped execptions to the Servlet filter in which case CXF XML 
Binding (which CXF JAX-RS depends upon) will wrap the exception in its xml-specific format

CXF3. One can register CXF fault interceptors and handle all the exceptions in these interceptors.

That is probably it, does it clarify things a bit ?

>
> I need to capture 100% of all possible errors that can ever happen
> inside CXF, the web container (Tomcat 6.X), and any possible CXF
> application running in the container (we ONLY use REST based services
> using CXF), and stream the errors/exceptions out as XML (we use XStream
> for that). That's the requirement.
>
> Here's what I've done:
>
> 1) I wrote a piece of code that implements the ResponseHandler
> interface. I do quite a bit of analysis inside that code, and return a
> custom response called an ErrorResponse. This eventually gets streamed
> out to XML. This ResponseHandler is configured as a provider with the
> <jaxrs:providers> mechanism in our Spring config file. It seems to cover
> the cases where the error condition is wrapped inside a Response object.

Yes, it is option CXF1 but also see option JAXRS2. I'm not sure when this code even executes for you given that you
say in 2) below that you capture all the exceptions with exception mappers.

>
> 2) I implemented a bunch of ExceptionMapper classes for the most common
> exceptions, as well as a "catch-all" for other exceptions. This seems to
> cover the cases where a service is throwing an exception. My mappers
> convert the exception to XML and stuffs that in a Response object. The
> mappers are also configured using the <jaxrs:providers> mechanism.

OK

>
> 3) I wrote an a piece of code that extends the
> AbstractOutDatabindingInterceptor class (based on the CXF example that
> Sergey posted a while back). This is configured using the following
> mechanism:
>
> <cxf:bus>
>  <cxf:outFaultInterceptors>
>    <ref bean="XMLOutFault.Interceptor"/>
>  </cxf:outFaultInterceptors>
> </cxf:bus>

You probably do not need it if you already do 1) and 2) unless you also do JAXWS. If both JAXWS & JAXRS are involved then relying on 
fault interceptors can be quite an attractive option...

>
> 4) I wrote a Servlet Filter (implementing the javax.servlet.Filter
> interface), that catches any exception and streams it out as XML. The
> problem is that nothing downstream seems to throw any exceptions, so the
> doFilter() method always returns normally.

This is expected because in 2) you've captured all the exceptions. Only those exceptions which have not been mapped will be 
propagated

>
> I need to know what I have to do to cover 100% of all possible error
> cases, and stream the error out using our custom XStream transcode back
> to the client. Some code samples or fairly detailed info about how to
> write the code, and how to wire it up would be fantastic. One of the
> corner cases NOT covered by any of the above mentioned mechanisms is
> when I specify a URL that is not mapped by CXF. In this case, the
> org.apache.cxf.transport.servlet.ServletController's invoke() method
> will call generateNotFound(), which sets the HTTP status code to 404,
> and writes an error message directly to the HttpServletResponse. How can
> I override this?

Perhaps you can extend CXFServlet and override its protected createServletController and then override generateNotFound() on your 
custom controller ?

Another, possibly a more awkward workaround is to use your custom ServletFilter and pass along an HttpResponse filter ? Please see 
HttpServletResponseFilter and ServletOutputStreamFilter in the CXF JAXRS source for some basic example...Ex, given

protected void generateNotFound(HttpServletRequest request, HttpServletResponse res) throws IOException {

res.setStatus(404);

res.setContentType("text/html");

res.getWriter().write("<html><body>No service was found.</body></html>");

}

you can override in your HttpResponse filter  setContentType() and setStatus() and if you get "text/html" and "404" (CXF JAXRS can 
also reply with 404 but it won't set text/html) then it is that edge case you're dealing with and if it is the case then in 
getWriter() your return a StringWriter buffer instead to block the default response....

>
> I don't want ANY component other than my code, writing ANYTHING to the
> servlet's OutputStream in case something goes wrong. I absolutely have
> to control 100% of all error handling. Any tips, tricks, and pointers to
> examples are greatly appreciated. Thanks much,

At the moment I think that given the above, you can get a 100% coverage...

thanks, Sergey

>
> /Henrik
>
>