Hi Henrik, Yes, give it a try please. Happy Christmas to you too :-) Sergey
-----Original Message----- From: Henrik Martin [mailto:[email protected]] Sent: 23 December 2009 18:54 To: [email protected] 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 > > > > >
