Architecting Technology, Systems and Security solutions

Rizwan Ahmed

Subscribe to Rizwan Ahmed: eMailAlertsEmail Alerts
Get Rizwan Ahmed: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: SOA Best Practices Digest, SOA & WOA Magazine, Java Developer Magazine

Article

Implementing RESTful Services

Using Multipart Data Content

The RESTful architectural style [1], with its URL addressable, resource oriented approach allows you to define Web services which can have multiple runtime representation in a variety of different media types. You define a Web resource, encapsulating the desired functionality within a business method, accessible via a URI over the HTTP protocol and its different "verbs": GET, POST, PUT, DELETE [2]. The transferred content may be either HTML, XML, binary data or images, which, depending on the business use case often require to be embedded within the same message. The Multipurpose Internet Mail Extensions (MIME) is an internet standard that is frequently used for describing content type in communication protocols like HTTP and specifies standard formats for encapsulating multiple pieces of data into a single message. In this article, I demonstrate RESTful services created by the RESTEasy open source framework to work with multipart data content typical in a real-world service scenario.

Introduction
The JAX-RS specification defines a Java API to create RESTful Web services [3] and allows you to build custom RESTful applications consisting of Web resources and providers. A JAX-RS Web resource is the server-side implementation of the business functionality of potential interest, the parameter/result content which is serializable into an entity representation. JAX-RS providers supply mapping services (via the javax.ws.rs.ext.MessageBodyReader and MessageBodyWriter interfaces) between the representations and their associated Java types. The JAX-RS runtime performs the actual selection of the appropriate MessageBodyReader(Writer) by matching up the media type in the request (or response) header to the declared media type within the resource (using the @Consumes and @Produces annotation) and then iterating through the selected subset of media type supported providers to narrow down on the one that supports the desired Java type.  The readFrom method is then called on the selected MessageBodyReader (writeTo for MessageBodyWriter) to map the entity body to its Java type.

RESTEasy is an open source reference implementation of the JAX-RS specification [4] and provides a developer friendly API, with annotations that facilitate a declarative style of programming, to create RESTful information-driven Web resources [5]. RESTEasy includes a rich set of built-in providers that support content (un)marshalling on a variety of different representations (including XML, JSON, FastInfoSet, Multipart, XOP, ATOM) with the selection of the appropriate provider invisible to the developers. RESTEasy comes with an easy-to-use client framework that allows you to create/bind the entity body and invoke HTTP requests mapped to the server resource via an interface proxy. RESTEasy also supports the multipart/mixed, multipart/form-data and multipart/related MIME types that allows the RESTful resource to work with multipart messages.

A Real-World Service Scenario
Figure 1 shows the component diagram for a sample use case [6]. ScrsCommon is a centralized online system managing customer-specific information (name, address, demographics and the like). The PAC (Integrated Payments and Claims) online system needs to obtain account-centric information pertaining to a specific customer (which is best represented using XML) along with prior transactional history of that customer (tax forms, 1099s, written communication), represented as Portable Document Format (PDF), indexed for easy retrieval and archived away into an Imaging system. Therefore, the Forms system would need to define Web resources (available using REST) that access the respective services on ScrsCommon and Imaging to create a heterogeneous multipart message consisting of aggregations of XML and PDF media-type content which can then be consumed by a RESTful PAC resource.  This leads to streamlined interaction between the different systems resulting in better servicing for that customer's account.

Multipart Messages
There are two general ways of creating or presenting multipart electronic messages: as a main document with a list of separate attachments, or as a single document with the various parts expanded and displayed inline. Inline message components are generally easier to work with as they do not require any action on part of the recipient to view the message parts.

Through the use of the multipart type, as the name suggests, MIME allows messages to have multiple parts that consist of attachments arranged inline in a linear tree like structure with support for various media content such as application/xml, application/octet-stream, application/msword, image/jpg, audio/mp3, etc. A multipart message contains a boundary defined in the top level "Content-Type" header that is placed between the parts and at the beginning and end of the body of the message (refer to Example 1). (The code examples and listings can be downloaded here.)The top level "Content-Type" header for the multipart message indicates the media type of the message content and could be one of the following subtypes: multipart/mixed, multipart/form-data and multipart/related. Each part of a multipart message has its own unique identity consisting of a "Content-Type" header indicating its wrapped media type, the "Content-Disposition" header indicating presentational information, and finally the message body encapsulating the message content. The mixed subtype of the multipart MIME type is the most basic and arguably the easiest way of sending heterogeneous media content.  Its intended for use when the individual body parts are independent of each other and do not need to be bundled in any particular order (see Example 1) [8].

Defining a JAX-RS Service to Work with Multipart/Mixed
RESTEasy provides an easy-to-use mechanism that allows you to read in and write out inlined multipart/mixed MIME type [4]. The primary interfaces provided are org.jboss.resteasy.plugins.providers.MultipartInput and org.jboss.resteasy.plugins.providers.MultipartOutput for multipart input/output, respectively (please refer to Listings 1 and 2). If your message consists of XML body parts, as in the following example, you would first need to define JAXB annotated value classes (either generated using the JAXB schema compiler [7] or simply annotated with @XmlRootElement) representing the individual message part entities and then either read from or add to the afore mentioned Multipart classes which encapsulate the multipart message. The RESTEasy runtime will automatically find a MessageBodyReader to unmarshall and  MessageBodyWriter to marshall your entity objects from the multipart/mixed message.

Listing 3 shows a RESTful Web resource that returns a multipart/mixed message wrapped within MultipartOutput. The multipart message being returned consists of product details: name, cost, description, the purchase order PDF form (represented as binary data) and customer information as JAXB annotated classes for automatic marshalling by the RESTEasy JAXB Providers. The ProductDetailType, Product and Customer objects are JAXB schema derived (annotated with @XmlType) classes representing the individual part entities. It's worthwhile to keep in mind that the JAXB implementation will create an ObjectFactory class that is used by the RESTEasy runtime JAXBXmlTypeProvider to create a JAXBElement represention of the ProductDetailType, Customer and Product entities [5]. A sample multipart/mixed output for the HTTP request GET /rest-services/multipart/mixed HTTP/1.1 is shown in Example 1.

The Multipart/form-data MIME Format
This MIME type [9], widely implemented in various web browsers, is typically used when you need to work with field data supplied by a user who fills out forms that are presented in various runtime representations: HTML, Speadsheets or PDF (a likely use case is also if you need to pre-fill HTML or PDF with form-field data). In each form, there are a series of fields each having a unique name. The multipart/form-data message contains a series of inline parts, demarcated by a boundary, with each part containing a "Content-Disposition" header where the disposition type is "form-data" and contains an additional parameter called "name" whose value is the original INPUT field name in the form (please refer to Example 2 for a listing of the multipart/form-data message format).  As with all multipart MIME types, each part has an optional "Content-Type" that defaults to text/plain and that may be labeled with the appropriate media type (Listing 4 shows application/xml and application/octet-stream to represent XML and binary data respectively). Each field of the form is sent, in the order defined by the sending application and form, as a part of the multipart stream.

Defining a JAX-RS Service and Client to Work with Multipart/form-data
As with multipart/mixed, RESTEasy provides a similar mechanism that allows you to read in and write out inlined multipart/form-data messages. The interfaces are org.jboss.resteasy.plugins.providers.MultipartFormDataInput and org.jboss.resteasy.plugins.providers.MultipartFormDataOutput that extend MultipartInput and MultipartOutput with added convenience methods to work with (extract and add) form-data parts represented as key/entity pairs (Listings 4 and 5). If your message consists of XML body parts you would first need to define JAXB annotated value classes that represent the individual message part entities and then either read from or write to the MultipartFormData classes that encapsulate the multipart message. A suitable MessageBodyReader and MessageBodyWriter provider implementation will be automatically found by the RESTEasy runtime to (un)marshall your entity objects from the multipart/form-data message.

An alternate method involves first creating a value class that maps to your multipart/form-data message content. In this example (refer to Listing 6), I have created a POJO annotated with @XmlRootElement that will encapsulate the multipart content returned by a JAX-RS Web resource. As before, the Customer and Product objects are JAXB schema-derived classes representing the individual part entities. If posting from an online HTML form whose action is mapped to the RESTful resource that can handle multipart form-data (similar to MultipartFormResponseType), the @FormParam annotation on each multipart element is used to inject individual form parameters from the request body into the method. You may, alternately, choose to have your web resource declaratively voice its parameter preference of application/x-www-form-urlencoded which unmarshalls to a MultivaluedMap<String, String> if the message parts are of uniform content.

In this example, we're creating a resource that generates multipart/form-data (to be sent back for pre-filling the HTML or PDF form), therefore, the @FormParam is used to bind the values of form-field data onto the response. The @PartType annotation is used to represent the media type of the individual parts.

Listing 7 is an example of a RESTful Web resource that returns a multipart/form-data message encapsulated within an instance of MultipartFormResponseType. The @MultipartForm annotation is used to tell RESTEasy that the returned entity has multiple parts annotated with @FormParam and therefore should be marshalled as such.  JAX-RS allows for building custom responses using the javax.ws.rs.core.Response and ResponseBuilder classes. The javax.ws.rs.core.GenericEntity<T> class represents a response entity of a generic type T and is used by the Resource class to wrap the entity representing the multipart message. The javax.ws.rs.core.Response class's ok() convenience method builds the response containing an entity of generic type MultipartFormResponseType and returns an HTTP 200 OK. This generic type is available at runtime and is used by RESTEasy for selection of the appropriate MessageBodyWriter for marshalling.

Once we have a RESTful Web resource defined that outputs multipart data, the next thing we need is a client that can parse out and understand it. RESTEasy has an easy-to-use client proxy framework. You create a Java class proxy that is a mirror interface of the resource class (refer to Listing 8). The client framework builds an HTTP request that is then used to invoke on the remote RESTful Web resource (see Listing 9) and leverages similar providers to unmarshal the response from the server resource. The org.jboss.resteasy.client.ClientResponse is the RESTEasy extension of the javax.ws.rs.core.Response and is typically used if your clients need access to the Response entity as well as status and header information.

A sample output of the response to the following HTTP request GET /rest-services/multipart/form HTTP/1.1 is shown in Example 2.

The Multipart/related MIME Format
A multipart/related media type [10] is used to define inlined message parts referenced as part of an aggregate whole. It is intended for compound objects consisting of several inter-related body parts (a likely use case is when we need to send HTML together with images and audio/video content in a single message). For a multipart/related message, proper display can only be achieved by aggregating the different constituent body parts. The message consists of a root that is the first part of the message body. This root part references, via the "start" parameter, to the body part that contains the object root. The relationships between the other inlined body parts are internally linked via their respective Content-IDs as is shown in the sample listing of a multipart/related message (Example 3), which shows an XML representation with embedded binary data.

Defining a JAX-RS Service to Work with Multipart/related Messages
RESTEasy provides the following interface that allows you to read in and write out inlined multipart/related MIME type messages:  org.jboss.resteasy.plugins.providers.MultipartRelatedInput and org.jboss.resteasy.plugins.providers.MultipartRelatedOutput (please refer to Listings 10 and 11).  As before, for XML body parts you would first need to define JAXB annotated value classes representing the individual message part entities and then either read from or write to the MultipartRelated classes which encapsulate the multipart/related message.

Alternately, you could create a POJO (akin to Listing 6) consisting of JAXB annotated classes for XML media type content, byte array (or the more commonly used javax.activation.DataHandler) for binary content that wraps your multipart message. In Listing 12, I have created a JAX-RS resource that consumes a multipart/related message represented by the class MultipartRelatedType. RESTEasy enables multipart/related messages consisting of binary data to be packaged using the XOP (XML binary Optimized Packaging) mechanism. XOP optimizes the packaging of the binary content without encoding it within Base64 thereby resulting in a faster transport [11]. The @Consumes(MediaType.MULTIPART_RELATED) annotation informs RESTEasy about our intention to pass a multipart/related message as a parameter to the Web service. The annotation @XopWithMultipartRelated tells RESTEasy to unpack and process the message packaged using XOP (the same annotation on the client side interface tells the RESTEasy client framework to pack the message using XOP packaging).

Conclusion
The RESTful web-centric, resource-oriented architecture allows for building flexible systems that can transform information representations in different media formats and amalgamate it into a single MIME supported heterogeneous entity for easy transport across the web to the calling client or system.  All resources built using RESTful principles exhibit the qualities of increased network/user perceived performance and scalability due to lighter message payloads as compared to SOAP.  The JAX-RS reference implemention framework, RESTEasy, has additional convenience features, APIs and annotations to facilitate optimal packaging and faster transport of certain types of data.  It also has rich support for the multipart/* MIME type with built-in interfaces and providers that allows you to create and work with messages consisting of aggregations of different media type content, typical of real-world Web services.

References

  1. Architectural Styles and the Design of Network-based Software Architectures by Roy Thomas Fielding, Doctoral dissertation, University of California, Irvine, http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  2. REST for Java developers: Part 1 by Brian Sletten, JavaWorld.com
  3. JAX-RS: Java API for RESTful Web Services, Java.net
  4. RESTEasy User Documentation, JBoss.org
  5. RESTful SOA with Open Source by Rizwan Ahmed, SOA Magazine August 2009
  6. An SOA Case Study: Integrating Adobe LiveCycle Forms using JBossWS by Rizwan Ahmed, SOA Magazine July 2009
  7. Unofficial JAXB User Guide, Java.net
  8. RFC 2046 - Multipart Internet Mail Extensions: Media Types, IETF Network Working Group
  9. RFC 2388 - Returning Values From Forms: multipart/form-data, IETF Network Working Group
  10. RFC 2387 - The MIME Multipart/Related Content-type, IETF Network Working Group
  11. XML - binary Optimized Packaging, W3C Recommendation

More Stories By Rizwan Ahmed

Rizwan Ahmed is an IT Systems Architect and author. He has about 10 years of experience in the public and private sector architecting technology, systems and security solutions. He holds Bachelor's and Master's degrees from the Indian Institute of Technology and the Florida State University, respectively. Passionate about open source as contributor and evangelist, he is also a frequent speaker at Java user groups, conferences and sponsored workshops. He holds the Sun Certified Java Programmer, Certified Information Systems Security Professional (CISSP), Certified Secure Software Lifecycle Professional (CSSLP) and the Project Management Professional (PMP) credentials. He lives with his wife and two kids in Columbia, SC.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.