jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Need clarification on Section 6.7

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Fri, 1 Feb 2013 16:24:31 +0000

Hi Marek, and Santiago
On 01/02/13 13:06, Marek Potociar wrote:
>
> On Feb 1, 2013, at 1:10 PM, Sergey Beryozkin<sberyozkin_at_talend.com> wrote:
>
>> On 01/02/13 12:02, Marek Potociar wrote:
>>>
>>> On Feb 1, 2013, at 12:55 PM, Sergey Beryozkin<sberyozkin_at_talend.com> wrote:
>>>
>>>> On 01/02/13 11:38, Marek Potociar wrote:
>>>>>
>>>>> On Jan 31, 2013, at 6:29 PM, Sergey Beryozkin<sberyozkin_at_talend.com> wrote:
>>>>>
>>>>>> On 31/01/13 16:57, Marek Potociar wrote:
>>>>>>> Hi Bill,
>>>>>>> I'm forwarding my recent reply to a similar question we received from
>>>>>>> TCK team:
>>>>>>>
>>>>>>> Global and globally name-bound filters and interceptors should be
>>>>>>> invoked for all responses. Resource and method name-bound interceptors
>>>>>>> should be invoked only for responses originated from the bound resource
>>>>>>> or resource method.
>>>>>>>
>>>>>>> I.e. if we define 2 groups of filters and interceptors based on their
>>>>>>> binding:
>>>>>>>
>>>>>>> G1: Global and globally name-bound (i.e. name-bound to the Application
>>>>>>> sub-class) response filters and interceptors
>>>>>>> - IMO the user intention with these is clearly to invoke them for ALL
>>>>>>> responses
>>>>>>>
>>>>>>> G2: Resource and method name-bound response filters and interceptors
>>>>>>> - IMO the user intention with these is to invoke them only for responses
>>>>>>> originated from a particular resource or method
>>>>>>>
>>>>>>
>>>>>> What are resource-bound filters, is it:
>>>>>>
>>>>>> @SomeName
>>>>>> class MyFilter...
>>>>>>
>>>>>> @SomeName
>>>>>> @Path("/root")
>>>>>> public class RootResource {
>>>>>> }
>>>>>>
>>>>>> Effectively MyFilter applies to all RootResource methods ?
>>>>>
>>>>> Yes, exactly.
>>>>>
>>>>>>
>>>>>>> With the groups defined above, here's what I think it should work
>>>>>>> (Santiago, please correct me if you think otherwise):
>>>>>>>
>>>>>>> UC1: Response returned from pre-matching filter:
>>>>>>> - G1 gets invoked
>>>>>>>
>>>>>>> UC2: Response produced by an ExceptionMapper from an exception that
>>>>>>> originated in a pre-matching filter:
>>>>>>> - G1 gets invoked
>>>>>>>
>>>>>>> UC3: Response returned from post-matching filter:
>>>>>>> - G2 + G1 gets invoked
>>>>>>>
>>>>>>> UC4: Response returned from matched resource method:
>>>>>>> - G2 + G1 gets invoked
>>>>>>>
>>>>>>> UC5: Response produced by an ExceptionMapper from an exception that
>>>>>>> originated in a matched resource method:
>>>>>>> - G2 + G1 gets invoked
>>>>>>>
>>>>>>> UC6: Response produced by an ExceptionMapper from an exception that
>>>>>>> originated in a response filter or interceptor processing a response to
>>>>>>> a matched request:
>>>>>>> - G2 + G1 gets invoked
>>>>>>>
>>>>>>> UC7: Response produced by an ExceptionMapper from an exception that
>>>>>>> originated in a response filter or interceptor processing a response to
>>>>>>> an unmatched request:
>>>>>>> - G1 gets invoked
>>>>>>>
>>>>>>> Additionally, there is a condition in the spec that prevents infinite
>>>>>>> loops for UC6 and UC7 (see 2nd paragraph in section 6.7 of the spec).
>>>>>>> So, to sum-up, here's the conceptual algorithm I have in mind:
>>>>>>>
>>>>>>> start request processing
>>>>>>> store G1 response filters and interceptors into the request context
>>>>>>> try {
>>>>>>> invoke pre-matching request filters
>>>>>>> match request
>>>>>>> if (request matched) {
>>>>>>> store G2 response filters and interceptors into the request context
>>>>>>> invoke global and bound post-matching request filters
>>>>>>> invoke resource method
>>>>>>> }
>>>>>>> invoke all response filters stored to the request context
>>>>>>> } catch (Exception ex) {
>>>>>>> try {
>>>>>>> map exception to response
>>>>>>> invoke all response filters stored to the request context
>>>>>>> } catch (Exception ex) {
>>>>>>> propagate exception to the hosting container
>>>>>>> }
>>>>>>> }
>>>>>>> exit request processing
>>>>>>>
>>>>>> I think it basically says that in Bill's (2) case all response filters are executed,
>>>>>> What about his case 3 though, I think it is UC6, UC7 points, still not clear what if the mapped response has to run through remaining filters or not, for example,
>>>>>>
>>>>>> A->B, A throws the exception, is B still given a chance to handle the mapped response ?
>>>>>
>>>>> I thought the algorithm above is also clear on that. For a mapped exception response, ALL applicable response filters are invoked (not only "remaining ones"). So, both, A and B are invoked.
>>>>>
>>>>> FWIW, throwing an exception from a filter is IMO not the programming model we should optimize for. Such exceptions should mostly indicate that there is a problem with the filter implementation as such.
>>>>>
>>>>
>>>> Hmm..., both A and B are response filters, they are processing some Response, A is first to process it and decides to throw an exception (intentionally) - what I don't quite get is whether it means we have an immediate 500, or, we try to map this A-originated exception and if the mapping was successful, then let B a chance to handle this mapped response, even though A thought it was an exception case...
>>>>
>>>> I'm sorry if I'm slow :-), but I'm still a bit unclear.
>>>
>>> If A throws an exception that gets mapped, then both A and B will be invoked on the mapped response. If A throws an exception again, then the exception is going to be propagated to the hosting container.
>>>
>>> Hope it's crystal clear now,
>>
>> Definitely is, thanks Marek. The fact that A can be re-entered twice was definitely something I was not getting.
>>
>> Are we sure it is correct though to allow re-entrance into A and indeed all the response filters before A if A throws the exception intentionally, effectively saying 'I've had enough with processing this current response' ? Not really sure whether it is right or not, I guess it is interesting to imagine a bit the possible pros and cons
>
> I'm not 100% sure, but as I wrote earlier, I believe that we should not promote programming models where a filter throws an exception in a "stateful" way, i.e. in a way that it would not expect to be applied to the mapped response.
>
> My main motivation factors for promoting this approach are:
>
> 1. it's based on simple rules and JAX-RS users will be able to grasp these rules without too much confusion
> 2. a response filters should be invoked for any response to which they are applicable.
> 3. in general it's better to give all response filters involved in the given request processing a chance to react and process a mapped exception response that to ignore them for such responses.
>
> In general, it means that global filters should be invoked for all responses and bound filters to responses originating from a component. Note here that a response to a mapped exception (thrown anyway in the req/resp processing) should not deviate from this rule IMO. While it may not be obvious with 2 response filters, consider scenario with 3 filters:
>
> A->B->C; B throws exception that gets mapped to a response R(ex).
>
> IMO the A should be given a chance to process the new R(ex) response.

Yes, I agree it makes sense in most cases to support it.
I think there could be some issues though like double logging or
similar, etc, when the response filter which throws the exception has
been prioritized to be after such filters like logging one, etc.
The user might see for example from the in & out loggers:

Request: a
Response: aResponse
Response: aResponse2 or even aResponse

May be it is negligible this issue. Perhaps it can make sense to
consider adding an annotation like @NonReentrant or similar either for
2.0 or 2.1 if the group agrees it can be warranted. I'm easy either way

Cheers. Sergey

>
> Cheers,
> Marek
>
>>
>> Cheers, Sergey
>>
>>
>>> Marek
>>>
>>>>
>>>> thanks, Sergey
>>>>
>>>>> HTH,
>>>>> Marek
>>>>>
>>>>>>
>>>>>> Thanks, Sergey
>>>>>>
>>>>>>
>>>>>>
>>>>>>> HTH,
>>>>>>> Marek
>>>>>>>
>>>>>>>
>>>>>>> On Jan 30, 2013, at 4:29 PM, Bill Burke<bburke_at_redhat.com
>>>>>>> <mailto:bburke_at_redhat.com>> wrote:
>>>>>>>
>>>>>>>> The section on filters and exception handling is unclear.
>>>>>>>>
>>>>>>>> if an exception is thrown from a resource method:
>>>>>>>>
>>>>>>>> 1. An exception mapper is found
>>>>>>>> 2. bound and global filters are executed on the response
>>>>>>>>
>>>>>>>> If an exception is thrown from a request filter:
>>>>>>>>
>>>>>>>> 1. An exception mapper is found and executed
>>>>>>>> 2. response filters are executed. BOund response filters only executed
>>>>>>>> if this is not prematch
>>>>>>>>
>>>>>>>> If an exception is thrown from a response filter:
>>>>>>>>
>>>>>>>> 1. An exception maper is found and executed
>>>>>>>> 2. ??? I assume no response filters are then executed?
>>>>>>>> --
>>>>>>>> Bill Burke
>>>>>>>> JBoss, a division of Red Hat
>>>>>>>> http://bill.burkecentral.com
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>