users@jersey.java.net

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

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 16 Jul 2009 13:19:11 +0200

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
>