users@jersey.java.net

Re: [Jersey] Fixed <was> Re: [Jersey] MIMEParsingException (IOException: Stream closed) when accessing a multipart form from a filter

From: Igor Minar <iiminar_at_gmail.com>
Date: Thu, 16 Jul 2009 10:45:01 -0700

Paul,

You are awesome!

I have to admit that I completely failed to realize that I could
create a wrapper for the request and return it back to Jersey. What an
elegant solution!

Thanks so much for being super responsive and helpful.

Jersey and JAX-RS is the first piece of java web technology that got
me excited after a long time. You guys did a great job and deserve a
lot of praise and respect for what you are doing. Keep up the good work!

As a contribution from me to the Jersey community, I'd like to
highlight my project grizzly-sendfile[1] (soon to become an official
part of grizzly). I'm currently using it to delivere (large) files
from my jersey app in a very efficient manner. Once the project is
part of grizzly, maybe we could work together on tighter integration
with jersey.

Thanks again.

/i


[1] http://grizzly-sendfile.kenai.com/


On Jul 16, 2009, at 4:19 AM, Paul Sandoz wrote:

> Hi,
>
> I have fixed this in the trunk. A filter can do, for example:
>
> public static class CachedEntityFilter implements
> ContainerRequestFilter {
> public ContainerRequest filter(ContainerRequest request) {
> request = new CachedEntityContainerRequest(request);
> Form f = request.getEntity(Form.class);
> f.add("z", "z");
> return request;
> }
> }
>
> The instance of Form "f" will be cached in the
> CachedEntityContainerRequest. If subsequent calls to getEntity are
> called with Form.class the same instance will be returned, otherwise
> a ClassCastException will be thrown.
>
> It should be possible to easily adapt ContainerRequest to your own
> requirements.
>
> Paul.
>
> On Jul 16, 2009, at 9:29 AM, Paul Sandoz wrote:
>
>>
>> On Jul 15, 2009, at 11:10 PM, Igor Minar wrote:
>>
>>>
>>> On Jul 15, 2009, at 12:59 AM, Paul Sandoz wrote:
>>>
>>>>
>>>> On Jul 15, 2009, at 1:02 AM, Igor Minar wrote:
>>>>
>>>>> Hi Paul,
>>>>>
>>>>> Thanks for the answer, but I'm afraid that due to the expected
>>>>> size of the requests handled in this way, I don't think that
>>>>> buffering things in the memory will be feasible.
>>>>>
>>>>> If I read the jersey multipart docs/emails on the list correctly
>>>>> then the multipart implementation buffers large requests on the
>>>>> disk, which is something that I'd like to take advantage of.
>>>>>
>>>>
>>>> That is the problem, the filter may not necessarily process the
>>>> same Java type as required by the resource method.
>>>
>>> Do you mean the case where filter would want to process the
>>> request as FormDataMultiPart and resource would instead be
>>> interested in for example the raw inputstream?
>>
>> Yes.
>>
>>
>>> I can see that being a problem, but that's not what we are doing.
>>>
>>
>> Right, but i am searching for generic solutions to the problem.
>>
>>
>>>>
>>>> Are you using a resource filter and specifically associating it
>>>> with the resource method or a container request filter that would
>>>> apply to all resource methods?
>>>
>>> Currently it's a container request filter. It applies to all
>>> resource methods, but we don't process the request in the filter
>>> if the request doesn't have multipart media type (which is most of
>>> the time).
>>>
>>
>> You could make this a resource specific filter, based on an
>> annotation a resource method is annotated with (or say what the
>> resource method consumes, if you want to be more generic). This
>> more closely ties the entity processing functionality between the
>> filter and the resource method and also modularizes functionality.
>>
>>
>>> The filter is a generic authentication filter, which is capable
>>> extracting credentials via several different ways and one of them
>>> is an authentication mechanism which uses tokens and multipart
>>> form fields - similar to how S3 browser based uploads work.
>>>
>>>>
>>>>
>>>>> In the meantime I did implement a workaround where I pass the
>>>>> FormDataMultiPart instance from filter to my resource via a
>>>>> thread local class, but I still would like to see a nicer
>>>>> solution to this problem.
>>>>>
>>>>
>>>> Yes, this of course does not work for @FormDataParam though.
>>>
>>> FormDataMultiPart object contains all the FormDataParam objects,
>>> so if I pass it around, I can get access to the individual
>>> FormDataParam objects too. It's not ideal, but it works.
>>>
>>
>> Right.
>>
>>
>>>>
>>>>
>>>>>> In general when using Jersey filters one should not assume that
>>>>>> the Java type the filter wants for an entity is the same as the
>>>>>> Java type for the resource method. But there is probably some
>>>>>> way i could optimize this, for the case of when it is. Could
>>>>>> you log an enhancement issue?
>>>>>
>>>>> You mean that you would cache the entity within the provider, so
>>>>> that when it is requested the second time provider just
>>>>> retrieves the entity from the cache? Or are you thinking of
>>>>> something else?
>>>>>
>>>>
>>>> Cache it within the ContainerRequest. But this will not work if
>>>> one requests a different Java type for the entity the second time.
>>>
>>> As I mentioned we extract the same java type from the request.
>>>
>>
>> I know, but i have to cover the cases for developers where this may
>> not be the case. Hence i think the solution is to allow extension
>> of ContainerRequest to support your use-case.
>>
>>
>>>>
>>>> The right way to do this would i think be for the filter to
>>>> extend ContainerRequest with such functionality by overriding the
>>>> getEntity method. Then the filter can adapt the ContainerRequest
>>>> passed in and return the adapted instance. Unfortunately the
>>>> ContainerRequest class is currently set up to easily do this so
>>>> we need to modify this class so it can adapted (likewise for
>>>> ContainerResponse). Could you log an issue?
>>>
>>> done: https://jersey.dev.java.net/issues/show_bug.cgi?id=330
>>>
>>
>> Thanks.
>>
>>
>>>>
>>>>
>>>>> As an alternative to thread local hack, I also looked for an api
>>>>> similar to servlet's request.setAttribute but I didn't find
>>>>> anything like that in jersey. Am I just not looking hard enough
>>>>> or there really isn't anything like that in Jersey.
>>>>>
>>>>
>>>> See:
>>>>
>>>> https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/api/core/HttpContext.html
>>>> #getProperties()
>>>> See:
>>>>
>>>> and you can inject HttpContext e.g. @Context HttpContext hc.
>>>>
>>>> Note that the same properties are accessible that
>>>> ContainerRequest as well:
>>>>
>>>> https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/spi/container/ContainerRequest.html
>>>> #getProperties()
>>>>
>>>> So in your filter you do not need to inject HttpContext.
>>>
>>> ahhh.. sweet! I was looking for setters and missed the properties
>>> getter which returns a mutable Properties object.
>>>
>>> thanks! I'll use this in the meantime to transport the extracted
>>> FormDataMultiPart object from our filter to the resource instead
>>> of the thread local hack we use now.
>>>
>>
>> Great!
>>
>> Paul.
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>