users@jersey.java.net

Re: [Jersey] Hello World! and Welcome to jersey-multipart

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Thu, 23 Oct 2008 16:51:26 -0700

Jeff Schmidt wrote:
> Thanks Craig! This all sounds good.
>
> I guess my client side question was more generic. Potential clients
> may be using Java, Python, Ruby etc. and whatever related libraries. I
> don't know if issuing multi-part requests is unusual or difficult in
> general for such clients. I don't want to put up anymore barriers to
> entry to use the API then I have to. :)
Agreed -- this is one of the nicest things about REST.
> What has been your experience in this regard? Any complaints from
> clients?
>
Constructing a multipart request is actually very easy, with pretty much
any client language and HTTP framework. From the point of view of such
a framework, it's a single request of type "multipart/mixed" (or
whatever), and the interesting part of the problem is constructing the
message body. For that, it's mostly a matter of alternating between a
bunch of headers and content for each body part, with a little extra
glue for the "boundary" string. In jersey-client, the code that does
this is in MultiPartWriter.java, and as you can see it is pretty
straightforward (assuming your library already has a way to format the
request body for your data entity -- which is the same code you'd need
to send that body part by itself).

Parsing a multipart response, on the other hand, is somewhat more
complicated. In the case of jersey-multipart I punted :-) and used
JavaMail APIs, because systems that understand mail streams already have
to know how to do this. If you use a different Java HTTP library you
can still use JavaMail for this part; in other languages, I'd start by
looking for parsing libraries that already exist, and then just glue
them in to the client.

One of my upcoming tasks will be to create a Ruby client library for
some of the services I'm working on, and that will ultimately include
some multipart processing -- so I'll soon get to practice what I preach
above :-).

Craig
> Cheers,
>
> Jeff
>
> On Oct 23, 2008, at 1:10 PM, Craig McClanahan wrote:
>
>> Jeff Schmidt wrote:
>>> Hi Craig:
>>>
>>> Thanks for your work on jersey-multipart. I have some SOAP based
>>> endpoints where a request can consist of various XML meta data, and
>>> then there is an element of type base64Binary where an arbitrary
>>> file can be 'attached' to the request. I would like to do something
>>> equivalent in a RESTful manner. It seems like a request comprised of
>>> an XML entity and a binary entity would be the way to go. The JAX-RS
>>> resource does not need to understand the binary entity, just make it
>>> available to some server-side code.
>> Yep, that is exactly the sort of thing I use it for.
>>>
>>> Looking at some of the jersey-multipart code, it looks like I can
>>> use BodyPart.getEntityAs(MyMetaData.class) to access the XML meta
>>> data, and BodyPart.getEntity().getInputStream() to access the binary
>>> data. When I'm done, MultiPart.cleanup() will delete the temporary
>>> binary file (if > threshold bytes). Am I reading that right?
>>>
>> That's exactly right.
>>> Also, I don't know if doing this on the server side will make it
>>> difficult for clients. You said the jersey-client can easily work
>>> with jersey-multipart. I've not yet looked into the Commons
>>> HttpClient or other client libraries to see if they have issues with
>>> making multipart requests.
>>>
>> You can also look at the Jersey client code itself. One of the
>> really cool things about jersey-client is you can use the same
>> providers (including the jersey-multipart stuff) on the client just
>> like you can use it on the server. There's some small samples of
>> this in the jersey-multipart unit tests.
>>
>>> Thanks,
>>>
>>> Jeff
>>>
>> Craig
>>
>>> On Oct 17, 2008, at 12:58 AM, Paul Sandoz wrote:
>>>
>>>> Hi Craig,
>>>>
>>>> Welcome to the list of Jersey committers :-)
>>>>
>>>> Thanks very much for the multipart MIME contribution, it looks
>>>> really good. I would like to leverage this to improve the support
>>>> for multipart/form-data and also consider support for Multipart
>>>> Java Beans.
>>>>
>>>> Classes supporting AtomPub support would be great!
>>>>
>>>> Re: the cleanup aspect. I think we need to review Jersey's IoC
>>>> support and integration capabilities with the likes of
>>>> Spring/Guice. It is really hard to be abstract from an IoC
>>>> framework :-( If the returned MultiPart was instantiated in the
>>>> life-cycle of the request then when the response is about to the
>>>> sent a pre destroy method could be called to do the clean up. That
>>>> would not work for the conditions of the client working standalone
>>>> (perhaps cleanup could also be called before being GC'ed although
>>>> that cannot be relied upon).
>>>>
>>>> Paul.
>>>>
>>>>
>>>> On Oct 17, 2008, at 1:00 AM, Craig McClanahan wrote:
>>>>
>>>>> For those who don't know me, I have been around the Java web tier
>>>>> for quite a while, being the original author of the Struts
>>>>> framework (<http://struts.apache.org>), as well as co-spec-lead
>>>>> for JavaServer Faces 1.0 and 1.1. My more recent interests have
>>>>> focused on RESTful web services, which led me naturally towards
>>>>> JAX-RS and the Jersey implementation.
>>>>>
>>>>> I've been one of the folks inside Sun who has been leveraging
>>>>> Jersey for some internal projects over the last few months. We
>>>>> had a particular need to support MIME multipart/* media types, and
>>>>> it made sense to generalize this into a reusable module -- hence,
>>>>> I've just uploaded the "jersey-multipart" module to the "contribs"
>>>>> directory. It relies on 1.0 or later Jersey code, and provides
>>>>> what I hope are found to be elegant solutions to the problems of
>>>>> multipart handling, while leveraging all the nice JAX-RS providers
>>>>> support for dealing with the entity content of body parts, just
>>>>> like we've grown spoiled by on complete message bodies. And, it
>>>>> works both on the server side and the client side, when you use
>>>>> jersey-client.
>>>>>
>>>>> Example server code to build a multipart response might look like
>>>>> this:
>>>>>
>>>>> // I have also provided an appropriate MessageBodyWriter for the
>>>>> MyBean class
>>>>> MyBean bean = ...;
>>>>> return Response.ok(new MultiPart().
>>>>> type(new MediaType("multipart", "mixed").
>>>>> bodyPart("This is the first body part in plain text", new
>>>>> MediaType("text", "plain")).
>>>>> bodyPart(bean, new MediaType("x-application",
>>>>> "x-format"))).build();
>>>>>
>>>>> (Of course, you can do things in a more fine-grained fashion, but
>>>>> the builder pattern utilized all over the JAX-RS and Jersey APIs
>>>>> was so cool that Paul suggested I use it here too, so I did :-).
>>>>>
>>>>> To read a MultiPart entity (produced by code like the previous
>>>>> example) that was uploaded to the server you might do something
>>>>> like this:
>>>>>
>>>>> // I have also provided an appropriate MessageBodyReader for the
>>>>> MyBean class
>>>>> @Path("...")
>>>>> @PUT
>>>>> @Consumes("multipart/mixed")
>>>>> @Produces(...)
>>>>> public Response handler(MultiPart multiPart) {
>>>>> BodyPart part0 = multiPart.getBodyParts().get(0);
>>>>> String text = part0.getEntityAs(String.class);
>>>>> BodyPart part1 = multiPart.getBodyParts().get(1);
>>>>> MyBean bean = part1.getEntityAs(MyBean.class);
>>>>> ...
>>>>> multiPart.cleanup();
>>>>> }
>>>>>
>>>>> The need for cleanup() is because the implementation knows how to
>>>>> buffer "large" body parts to temporary files on disk, so you don't
>>>>> blow away your JVM heap on a multi-gigabyte upload or download.
>>>>> I'm looking for a way to avoid the need for the application to
>>>>> call this, but haven't found one yet -- in the mean time,
>>>>> everything else about dealing with multipart files has seemed
>>>>> pretty easy to deal with.
>>>>>
>>>>> As mentioned above, this module works on the client side as well,
>>>>> if you're using jersey-client. The unit tests have some more
>>>>> worked-out examples of the lower level details.
>>>>>
>>>>> Give it a try and see what you think! And, for sure, if you see
>>>>> anything that needs to be improved, please ask here and/or file an
>>>>> issue in the issue tracking system.
>>>>>
>>>>> Craig McClanahan
>>>>>
>>>>> PS: Among my other interests will be working with the Atom
>>>>> Publishing Protocol support, again with the idea of leveraging
>>>>> JAX-RS providers to do format translations for custom <content>
>>>>> payloads.
>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>> <mailto:users-unsubscribe_at_jersey.dev.java.net>
>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>> <mailto:users-help_at_jersey.dev.java.net>
>>>>>
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> <mailto:users-unsubscribe_at_jersey.dev.java.net>
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>> <mailto:users-help_at_jersey.dev.java.net>
>>>>
>>>
>>>
>>>
>>> --
>>> Jeff Schmidt
>>>
>>>
> --
>
> Jeff Schmidt
>
>
>
>
>
>