users@jax-rs-spec.java.net

[jax-rs-spec users] [jsr339-experts] Re: Example 3: Why current ReaderInterceptors are cool.

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Fri, 27 Apr 2012 17:23:46 +0100

Hi Bill
On 27/04/12 17:02, Bill Burke wrote:
>
>
> On 4/27/12 4:35 AM, Sergey Beryozkin wrote:
>> Hi Bill
>>
>> It's a good example,
>>
>> On 26/04/12 23:23, Bill Burke wrote:
>>> Here's "Example 3" where a ClientResponseFilter and a ReaderInterceptor
>>> work beautifully together. This also shows why you might want to allow a
>>> ReaderInterceptor the ability to return a java.lang.Object.
>>>
>>> -- Example 3: Client-side Caching --
>>>
>>> Flow:
>>>
>>> 0. Application code calls:
>>> Response response = target.request().get();
>>>
>>> 1. ClientRequestFilter find that the request URL is cached, but the
>>> cache may have expired
>>> 2. ClientRequestFilter adds If-None-Match, If-Modified-Since headers and
>>> does a conditional GET
>>> 3. ClientResponseFilter processes the response.
>>> 4. ClientResponseFilter finds that cached entity is still valid.
>>> 5. ClientResponseFilter updates cache entry with any new Cache-Control
>>> metadata
>>> 6. ClientResponseFilter sets the response InputStream to the raw
>>> representation of the resource (a gzipped XML document in this case)
>>> 6. ClientResponseFilter adds Content-Type header and changes Response
>>> code to 200.
>>> 7. ClientResponseFilter adds the cache entry to the its context's
>>> property map so that the ReaderInterceptor can reference it.
>>> 7. Application code calls:
>>>
>>> Foo foo = response.getEntity(Foo.class);
>>>
>>> 8. Caching ReaderInterceptor pulls the cache entry from context property
>>> map
>>> 9. Caching ReaderInterceptor asks the cache entry if it has ever
>>> unmarshalled Foo.class. If it has, it returns it. Done. *THIS IS AN
>>> EXAMPLE OF a READER INTERCEPTOR CHANGING THE ENTITY*. In this case, it
>>> totally bypasses the MBR.
>>> 10. Caching ReaderInterceptor just proceeds to the next
>>> ReaderInterceptor
>>> 11. GZIP ReaderInterceptor sees that the cached InputStream is gzip
>>> encoded by seeing a Content-Encoding header. It wraps the InputStream.
>>> 12. MBR unmarshalls the GZIPPED XML Document.
>>>
>>
>> Why steps 8-11 can not be made before response.getEntity() ?
>>
>
> You can't do step #9 because before resposne.getEntity() because you
> don't know the Java type.
>
>> What if at step 7 (actually has to be 8), we have
>> response.getEntity(InputStream.class) ?
>>
>
> Its a special case for the caching interceptor. In that case, it would
> create/return an InputStream pointing to the raw representation bytes of
> the cache entry.
>
Yes, I can see the caching example is convincing.
So at the moment, on the client side we have filters per/post processing
the data before the control is returned to the application.
Next we have Reader interceptors involved between the
Response.getEntity() & MBR. Filters & ReaderInterceptors communicate
with each other by passing the properties around.

In the follow up email I thought that composite MBR (delegating to
individual MBRs) can act effectively as Reader interceptors. May be that
option is too limiting, given I did not implement a client side caching
handler myself :-), but seems it might work with the exception handling
being at the composite MBR level, though this option may be a bit
'coarse-grained'.

I'm not entirely appreciating the original Marek's concerns as I haven't
started implementing, but I think it's worth exploring the possibility
of minimizing the number of handlers. If the current approach of having
both the filters and Reader interceptors wins then I'll be happy with
that too :-)

Cheers, Sergey