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
> >
> >
>