Hello, Here is an updated version of the refactoring of the server side handling of exceptions. It passes most of the systests, there is a message format issue if no writer is found, all there other tests seem to pass. Here are the details :
* Message serialization is mutualized in a AbstractJAXRSOutInterceptor from which both JAXRSOutInterceptor and JAXRSFaultOutInterceptor inherit, there is no longer the weird concept of a third interceptor chain, * Thread locals and reserved resources release are moved in a JAXRSResourceCleanerOutInterceptor that is added to both the out and faultOut interceptors chain, * JAXRSInvoker and JAXRSInInterceptor lose all their exception handling and resource cleanup (thread local, etc) logic, they just rethrow to let the PhaseInterceptorChain invoke the adhoc interceptors * JAXRSOutInterceptor gives most of its business logic to the AbstractJAXRSOutInterceptor (all the message serialization), * JAXRSFaultOutInterceptor handles all the exception handling logic (ExceptionMapper) : ** TODO : why the default fault is render in XML ? why not plain text ? Why missing writers error message is currently rendered as plain text and not XML as other faults ? * XMLFaultOutInterceptor and StaxOutInterceptor are no longer invoked in the faultOut chain, see JAXRSFaultOutInterceptor * JAXRSResourceCleanerOutInterceptor is associated both with the out and the faultOut interceptor chains. Clean the thread locals and the the reserved resource (resourceProvider.releaseInstance ). ** TODO : should we deal with ContextClassLoader ? ** TODO : should we cleanup both on handleMessage and handleFault ? ** there is a problem if someone wants to abort the fault chain (see testcase 1), it would bypass the cleanup. Regarding your question about the noisy logging of application exception by the PhaseInterceptorChain, I feel that the concept of checked application fault should do the job ; I didn't verify. Regarding your question about the client, I didn't touch the WebClient yet, it is on my todo list there should not be problems with it. I would prefer to focus on the server side right now and postpone the client side refactoring as the server side work is already pretty big :-) Please tell me if it makes sense to continue to work on this, Cyrille (1) see org.apache.cxf.systest.jaxrs.CustomOutFaultInterceptor in jaxrs systest On Tue, Dec 29, 2009 at 12:48 PM, Sergey Beryozkin <sbery...@progress.com> wrote: > > Hi Cyrille > > Thanks for posting this proposal/analysis, please see some comments > prefixed with S.B. below... > > cheers, Sergey > > Hello all, > > Here is a proposal of refactoring of both the JAXRS client-side and > server-side, these refactoring could be separated one from the other. > > Please, let me know if it worth continuing this work. > > SERVER SIDE > ============ > > Move the ExceptionMapper handling from the JAXRSInvoker to a new > JAXRSFaultOutInterceptor. > > Description : If an exception is associated with a Response via an > ExceptionMapper, the fault interceptors chain is aborted and a new > chain is triggered to render the Response. > > Pros : consistency between the JAXRS and JAXWS interceptor chains, for > example, the ResponseTimeFeature can now count exceptions mapped to > responses. > > Cons : a third interceptors chain is introduced for exceptions that > are mapped to Response. It is a bit weird :-) > > S.B : > It looks like the right approach going forward from a technical perspective. > Note that at the moment JAXRSInvoker, in JAXRSInInterceptor and out > JAXRSOutInterceptor are all trying to map exceptions to Responses given that > the exceptions may be thrown from the application code (JAXRSInvoker > mapping), from JAXRS message body readers or custom in filters > (JAXRSInInterceptor mapping) or from JAXRS message body writers > (JAXRSOutInterceptor mapping). > > Perhaps, the ExceptionMapper handling can indeed be moved from the > JAXRSInvoker and JAXRSInInterceptor to the fault interceptor, but this fault > interceptor should basically reuse the JAXRSOutInterceptor if/after it has > managed to map a fault to the Response given that a Response created by a > given ExceptionMapper still has to go through the chain of custom out filters > and JAXRS writers. But there are few more things to consider : > > - JAXRSInInterceptor/JAXRInvoker in its final block clears thread local > proxies (representing UriInfo/etc) which may've been injected into custom > providers, including exception mappers, so these proxies will need to be > available for these mappers and for JAXRS writers/outFilters (in case they > need to handle the exception mapper Responses) if they will be invoked from > the fault interceptors. So the fault interceptor will need to take care of > clearing all the proxies injected into various providers in the end. > > - At the moment PhaseInterceptorChain will log all the faults which are > coming through it. This is something which users may not always want. For > example, a JAXRS application code might've logged the fact that a certain > resource is not available and throw BookNotFoundException and expect a custom > mapper to quietly turn it into 404. At the moment it will work as expected > but if we move the mapping code from JAXRSInvoker and JAXRSInInterceptor to > the fault one then more runtime logging will get done. I think one of CXF > users was thinking of customizing PhaseInterceptorChain so that 'quiet' > loggers can be plugged in but nothing has been done yet there AFAIK. > > So it all should work quite well, but we need to do a bit more analysis of > what it would take to complete this refactoring on the server side... > > CLIENT SIDE > =========== > > Extract the marshalling and exception processing logic from the jaxrs > client to interceptors ; I only worked on the ClientProxyImpl, the > work on the WebClient is still to do. > > Description : > * the JAXRSResponseInterceptor builds the Response object (currently > with the inputstream object). Remaining : complete the Response > processing with the unmarshalling of the inputstream > >> S.B. I guess this one should probably be handling both proxy and WebClient >> responses ? > > * the JAXRSCheckFaultInterceptor handles faults and the > ResponseExceptionMapper processing > >> S.B : one thing to be aware of here is that if either a code using proxy or >> WebClient explicitly expects a JAXRS Response object then it should get >> Response... > > Pros : consistency betwen JAXRS and JAXWS interceptor chains, for > example, the ResponseTimeFeature can now count exceptions mapped to > responses. > > Cons : I didn't find any :-) > > S.B : sounds good :-) > > Todo : complete the cleanup of the client > > Note : the ClientFaultConverter should NOT be declared as an "In Fault > Interceptor" for JAXRS endpoints (specially important for the client) > as the ClientFaultConverter tries to unmarshall a SOAP XML exception. > > Cyrille > > -- > Cyrille Le Clerc > clecl...@xebia.fr > http://blog.xebia.fr > > On Mon, Dec 21, 2009 at 6:54 PM, Sergey Beryozkin <sbery...@progress.com> > wrote: >> >> Hi Cyrille >> >> Please see comments inline >> >>> >>> Dear all, >>> >>> I am looking at the consistency of exception handling among JAX-WS >>> and JAX-RS. My primary goal is to ensure cxf management metrics (JMX) >>> are consistent. >>> >>> Here are few questions : >>> >>> SERVER SIDE JAXRS EXCEPTION MAPPER >>> ==================================== >>> >>> If an ExceptionMapper handles the exception : >>> >>> 1) The JAXRSInvoker returns a Response instead of throwing an Exception >> >> Yes, this is for JAXRS message body writers be able to handle whatever >> Response entity a given mapper might've set up. >> >>> >>> 2) Thus PhaseInterceptorChain does NOT see that an exception occurred >>> during the invocation >> >> Yes >> >>> >>> 3) Thus the "Out Interceptors" are not replaced by the "Out Fault >>> Interceptors" and these "Out Interceptors" are called on >>> #handleMessage() with the outMessage (ie the response created by the >>> ExceptionMapper) instead of being called on #handleFaultMessage() with >>> the inMessage when information like the FaultMode is still holded by >>> the inMessage >> >> Yes >> >>> >>> 4) Interceptors like the ResponseTimeMessageOutInterceptor who rely on >>> the faultMode attribute located on the Message that is being passed to >>> handleMessage/handleFault are lost, they don't find the information >>> they look for >> >> I see... >> >>> >>> Questions : >>> * Wouldn't it make sense to call the "Out Fault Interceptors" if a >>> JAX-RS exception is mapped to a custom response ? >> >> Now that you suggested it, perhaps, one alternative in mapping exceptions to >> exception mappers would be to >> register JAX-RS specific fault interceptors which will do the mapping, >> instead of doing it in the JAXRSInInterceptor or JAXRSInvoker... >> So other registered fault interceptors will get their chance as well... >> >> What complicates things a bit is that JAXRS users can have ResponseHandler >> filteres registered which can override the ExceptionMapper responses... >> >>> * which message should be given to the handleFaultMessage() ? The >>> inMessage that caused the exception and that holds the exception as an >>> attribute (it would be consistent with JAX-WS) or the outMessage as >>> currently done ? >> >> Perhaps we should consider introducing JAXRS fault interceptors ? They will >> do Exception Mapping and abort the chain if the mapping has been found ? I'm >> not yet sure how feasible and/or sensitive such a change might be, but may >> be it will be the right step forward >> >>> >>> CLIENT SIDE JAXRS EXCEPTION HANDLING >>> ============================================= >>> >>> ClientProxyImpl handles exceptions after calling the interceptors >>> when, with JAX-WS, exception handling (CheckFaultInterceptor) is >>> performed in the POST_PROTOCOL phase. >>> >>> Due to this, the "In Interceptors Chain" is called instead of the "In >>> Fault Interceptors Chain" and interceptors like >>> ResponseTimeMessageInInterceptor don't see the Response as an >>> exception. >>> >>> Question : >>> Can we imagine to refactor jaxrs client side exception handling as a >>> post protocol interceptor ? >> >> The client side needs some refactoring going forward....Some of its code >> would definitely need to be moved to some isolated interceptors. However, >> please see JAXRSSoapBookTest, Eamonn did quite a few tests with faulty >> features/interceptors/server faults... >> >>> >>> >>> I hope this email was not too long ; it took me few hours to check all >>> these use cases and figure out how it worked :-) >> >> No problems :-), please type as long a message as you'd like to :-), thanks >> for starting this thread >> >> cheers, Sergey >> >>> >>> Cyrille >>> -- >>> Cyrille Le Clerc >>> clecl...@xebia.fr >> >