Hello Sergey, I added thread local variables cleanup in JAXRSInInterceptor.handleFault() as you suggested on both trunk and 2.2-fixes. It will be available in 2.2.6. Change is tracked in "[CXF-2622] ThreadLocal variables may not be cleared in case of exception" (1).
I will continue to work on the refactoring to get JAXRS monitoring with exception counting for 2.3 and maybe 2.2.7 :-) . Cyrille (1) https://issues.apache.org/jira/browse/CXF-2622 On Mon, Jan 11, 2010 at 12:50 PM, Sergey Beryozkin <sbery...@progress.com> wrote: > > Hi Cyrille > > thanks for your comments. No problems with the delay, you're leading this > thread really well and I'm learning few bits myself too...I'll have to sign > off shortly so will comment later on, I will have some time to think about > what you suggested... > I think it all looks/sounds quite good. May be we also need to modify > JAXRSInInterceptor to add a handleFault method and ensure no leak occurs even > if the fault is thrown by some custom CXF interceptor sitting between > JAXRSInInterceptor and JAXRSInvoker, this fix can be added independently, may > be before 2.2.6... > I'll add more comments later on. > > thanks, Sergey > > -----Original Message----- > From: Cyrille Le Clerc [mailto:clecl...@xebia.fr] > Sent: Sat 1/9/2010 7:16 PM > To: dev@cxf.apache.org > Subject: Re: Questions regarding JAX-RS exception handling > > Hello Sergey, > > Thank you to have taken the time to read my long email. I may not have > been clear enough on the behavior of the exception mapper handling I > suggest in my previous email, I tried to clarify it. > > I add comments prefixed by "CLC:" in the text ; I hope I answered to > all your points. > > I can propose a new version of the patch with the new thread locals > cleanup and an improved exception propagation to the servlet > container. > > Cyrille > > PS : sorry for the delay of my answers but it takes me time to better > understand CXF internals and JAX-RS specs :-) > -- > Cyrille Le Clerc > clecl...@xebia.fr > http://blog.xebia.fr > > ========================== > > * 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, > > > S.B. As you note below, there is a minor possibility of a leak if a given > > chain is aborted earlier on. We can of course warn users to make sure they > > do the cleanup if they try to abort the chain in their custom out/fault > > interceptors, but I'd really like to make sure no leak occurs, no matter > > what users do. So shall we move the cleanup code into > > AbstractJAXRSOutInterceptor and update JAXRSOutInterceptor and > > JAXRSFaultOutInterceptor to clean up in their finally blocks ? > > >> CLC: also convinced that risking to not cleanup thread locals is worrying, > >> CLC: can you confirm my understanding that thread locals are related to > >> @Context and @Resource fields/setters and only apply to RequestHandler, > >> MessageBodyReader, <serviceObject/Resource>, MessageBodyWriter, > >> ResponseHandler and ExceptionMapper ? > >> CLC: if so, almost each thread local is easy to cleanup in a finally block > >> because its scope is limited to one single method : > >> JAXRSInInterceptor.handleMessage(), JAXRSInvoker.invoke(), > >> JAXRSOutInterceptor.handleMessage() and > >> JAXRSFaultOutInterceptor.handleMessage() > >> CLC: the only challenge I see is limited : the <serviceObject/Resource> is > >> injected thread locals in the JAXRSInInterceptors and the cleanup is done > >> in the JAXRSInvoker. I didn't yet figure how the thread locals are cleared > >> if an exception occurs between the two. > > >> CLC: as a general evolution, I would see great benefits in adding a > >> "finally" semantic in the interceptors. I already saw use cases with > >> implementing "circuit breaker patterns" or "invocation concurrency > >> limitations" (with semaphores) ; we do such things on my project with "try > >> {} finally {}" blocks in the service implementation because we fear leaks > >> due to aborted chains executions. > > * 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 > > > S.B this is related to the above comment. I guess I'm slightly nervous > > about postponing the cleanup until later :-). > > * 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 ? > > >S.B : this is what XMLFaultOutInterceptor does by default, and in fact, I > >know that some users would like just this, that is an xml-formatted error > >description, if no ExceptionMappper has been found and if the fault > >propagation to the container (in the form of ServletException) has been > >disabled. > > >> CLC: Understood for the XMLFaultOutInterceptor. > >> CLC: Regarding the exception propagation to the servlet container, would > >> it make sense to add a dedicated mechanism in the PhaseInterceptorChain, I > >> imagine it similar to the invocation suspension with the > >> SuspendedInvocationException. A PropagatedException would hold the > >> underlying exception (ServletException, IOException or RuntimeExcetpion) > >> and it would bubble until the ServletController.invoke() where the actual > >> exception would be thrown. It currently goes throught the step > >> "..AbstractFaultChainInitiatorObserver - Error occurred during error > >> handling, give up!" that seems to be dedicated to abnormal behaviors. > > Why missing writers error message is currently rendered as > plain text and not XML as other faults ? > > > S.B : this is handled by a default WebApplicationExceptionMapper, thus the > > fault does not reach the fault chain > >> CLC: understood. > > * 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. > > > S.B : yes, it is a bit worrying > >> CLC : same feeling. > > 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. > > > S.B. It seems like the logging will occur no matter how we set the fault > > code, though the levels will differ. There is a pending patch for > > PhaseInterceptorChain be able to check for custom FaultLoggers which should > > do the job. > >> CLC : the FaultLogger seem to be the good path. > > > S.B. I'm wondering, should we try to step back a bit and consider more > > seriously your initial idea about explicitly invoking a fault chain if an > > exception mapper has been found ? > The only 2 problems that we need to address are these : if an > (application) fault has been mapped to a Response by ExceptionMapper > then custom in/out interceptors which are registered earlier/later in > the chain will not have their handleFault methods called (1) and the > fault chain will be bypassed (2). I'm not sure if users use custom out > interceptors after JAXRSOutInterceptor has been invoked so the former > problem is less critical but the latter problem prevents JAXRS users > from *fully* utilizing some core CXF features, specifically, > exceptions are not counted/checked properly by the management feature, > but only when they have been converted into JAXRS Response by mappers. > > >> CLC: I may not have been clear enough. If an exception is thrown, I > >> propose to let the PhaseInterceptorChain handle it normally, that is to > >> say unwind the in interceptors chain (calling handleFault()) and to > >> trigger the fault out chain. If the exception is mapped to a response, the > >> fault chain will render this response, otherwise, the fault chain will > >> render the exception in xml or propagate it to the servlet container. > >> CLC: I see one thing you may dislike : custom out interceptors must also > >> be registered as out fault interceptors to be called even if exceptions > >> are thrown ; this is similar to the soap chains behavior. > >> CLC: Do you see problems in handling the ExceptionMapper step as the first > >> step of the fault out chain ? > > > >S.B The solution which which we've discussed so far seems the best one > >technically but there're few bits I'm not feeling comfortable about...JAXRS > >users will need to do extra work which they haven't had to do before if > >they'd like to minimize the logging noise and postponing the cleanup until > >the later stages seems a bit brittle. I forgot to mention that JAXRS users > >can avail of the CXF Continuations API so the runtime SuspendedInvocations > >will occur as a result and no fault chains will be invoked to handle them > >given that it is not a real fault, at some later time some other thread will > >get back and pass through the JAXRSInInterceptor again so this is where we > >can have a leak after the given invocation has been suspended if we do a > >cleanup in the fault chain, possibly a number of times - may be we can fix > >it by updating JAXRSInInterceptor/JAXRSInvoker only if SuspendedInvocation > >has occured. > > >> CLC: the logging concern should be solved by the FaultLogger that has been > >> committed in the trunk. > >> CLC: The resource cleanup concern in the continuations scenario would be > >> fixed by the usage of finally blocks described above. > > > What you've done so far seems very precise and quite perfect but as > you see yourself the refactoring is becoming a bit complicated :-). In > the end of the day, writing a simple FaultLogger which will block the > extra logging or ensuring the cleanup always occurs is not a big deal, > but before we commit to it I'd like us to explore an alternative > solution. > > > S.B So the possible alternative approach is to ensure an in/out fault chain > > is called explicitly even after we have mapped an exception to JAXRS > > Response with a custom ExceptionMapper. I'm not sure how to do it yet, may > > be we can add some method to PhaseInterceptorChain, say, > > getCurrentFaultChain. > Or may we can add a property like > "org.apache.cxf.exception.convertedToResponse" and rethrow the fault > and update XMLOutFaultInterceptor to check this property and not to > write out if it 's been set... > > >> CLC: As I said above, I would see benefits in evolving the > >> PhaseInterceptorChain to handle "propagated exceptions". Adding methods to > >> interact with the fault chain could be tricky as, in case of fault, the > >> PhaseInterceptorChain simply invokes a fault MessageObserver that just > >> happens to hold a fault interceptor chain but the MessageObserver > >> interface doesn't hold such a meaning. More over, the fault chain is > >> created on demand. > > What do you think ? > > thanks, Sergey > > > > 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 > :-) > > > S.B agreed :-) > > 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 > >> > > >