WSO2Con 2013 CFP Banner

Using SOAP with Attachments in Apache Axis2

Discuss this article on Stack Overflow
By WSO2 Inc
  • 4 May, 2007
  • Level:  Introductory
  • Reads: 60340

Apache Axis2 has excellent support for sending and receiving binary payloads with SOAP using several standard mechanisms such as Base64 encoded binary, SOAP Message Transmission Optimization Mechanism (MTOM), and SOAP with Attachments (SwA). This article by Thilina Gunarathne will walk you through the SwA support in Apache Axis2.

Why Binary Data with SOAP?

There are a variety of binary formats like images, executable files, and movies, which people use in their day-to-day activities. A good part of the data exchanged in today's Web are binary content like images. Even though we can gain many advantages like flexibility, interoperability, and structure by using XML data formats, people are still reluctant to abandon the use of binary data formats. On the other hand, they often want to use raw binary data together with XML. Also, it does not always make sense to serialize all the binary data into XML, especially data like large MPEG movies, large images, etc.

Similarly, Web services users often want to transmit various attachments such as images, movies, and audio, together with SOAP messages. This data is often in binary format. For example, a nationwide patient data storage system that wants to store the patients images, and pictures of their important reports together with the patients health record, a company that wants to send the encrypted payload of a SOAP message as a binary attachment, or a stock information service that wants to send a graph of the stock data to a client.

SOAP with Attachments

SOAP with Attachments (SwA) [2] is a Note submitted to the W3C by Microsoft and HP Labs. The objective of the SwA note is to describe a standard way of associating one or more binary attachments with a SOAP message in their original formats. SwA utilizes the Multipart/Related MIME [3] packaging to package the SOAP message together with the binary attachments, and utilizes URI based mechanisms to reference the MIME parts.

Note: The SOAP with Attachments note is superseded by the MTOM/XOP specifications.

SOAP with Attachments allow referring the attachment content (MIME parts) from the SOAP body elements as well as from the SOAP header elements. This mechanism facilitates the delivery of SOAP messages with attachments in any protocol that is capable of delivering MIME content. Most communication protocols used on the Internet supports MIME content. According to the SwA note, users can use either Content-ID based referencing or Content-Location based referencing to refer to the attached resources from the SOAP payload. Users can have attachments, which are not referenced from the SOAP Envelope, inside the MIME package.

Note: Apache Axis2 supports Content-ID based referencing of MIME parts only. Axis2 does not support Content-Location based referencing of MIME parts. Even the Web Service Security SOAP with Attachments profile limits the references to attachments to content-ID based referencing.

Content-ID based referencing uses the URL scheme "cid:" to refer to the corresponding MIME part. This URL scheme is defined in the RFC 2392 [4]. For example, a MIME part with a value of the Content-ID header as "MyImage1@wso2.org" can be referred from the SOAP message as follows.

e.g.,
    <foo:myattachment href="cid:MyImage1@wso2.org">

This note also defines the HTTP binding for the SOAP with Attachment type messages. According to this HTTP Binding, SwA type messages are required to have a content-type HTTP header with its value set to "multipart/related". Also, the value of the "type" parameter of the content-type HTTP header is required to be set to the content type of the MIME part containing the SOAP message. It needs to be "text/xml" if the version of the SOAP message is SOAP 1.1 and needs to be "application/soap+xml" if the version of the SOAP message is SOAP 1.2. The MIME part which carries the SOAP message is usually referred to as the root MIME part. When the root MIME part is not the first MIME part, the content-ID or the content-location of the root must be specified as the value of the "start" parameter of the content-type HTTP header.

SOAP with Attachments Message Format

SOAP with Attachments Implementation in Apache Axis2

Receiving SOAP with Attachments Messages

Apache Axis2 does not require any configurations to receive SwA type messages. Axis2 identifies incoming SwA messages based on the Content-Type HTTP header, when the Content-Type is "multipart/related" and the "type" parameter of the Content-Type is either "text/xml" or "application/soap+xml". Incoming messages include receiving messages by an Axis2 server as well as receiving a response by an Axis2 client.

Apache Axis2 uses a lazy attachments (MIME) parser to process the attachments. The Axis2 MIME parser reads the attachments from the incoming stream only if and when the user needs them. Let's think of a scenario where Axis2 receives a SwA type message with three binary attachments. Axis2 deffers reading the attachments until the user requests for it. When the user requests the first attachment, Axis2 will only read up to the end of the first attachment. Axis2 also preserves the order of the received attachments when storing them in the MessageContext by using a TreeMap underneath as the AttachmentsMap. Users can use the attachments API of the MessageContext to access the attachments in the messages.

Axis2 also provides a file caching mechanism for incoming attachments to enable the users to receive very large attachments without buffering them in the memory. After processing the MIME part headers, the Axis2 file caching mechanism directly pumps the incoming MIME part stream directly into a temporary file when that MIME part exceeds a given size threshold value. Smaller attachments will remain in the memory increasing the performance, while larger attachments will be stored in temporary files increasing the scalability. Users can configure this size threshold value (in bytes) as well as the attachment temporary file location as follows.

 Using axis2.xml or services.xml, 
<parameter name="cacheAttachments" locked="false">true</parameter>
<parameter name="attachmentDIR" locked="false">temp directory</parameter>
<parameter name="sizeThreshold" locked="false">4000</parameter>
 Programmatically in the client side, 
options.setProperty(Constants.Configuration.CACHE_ATTACHMENTS,
Constants.VALUE_TRUE);
options.setProperty(Constants.Configuration.ATTACHMENT_TEMP_DIR,TempDir);
options.setProperty(Constants.Configuration.FILE_SIZE_THRESHOLD, "4000");

 

Note: Axis2 does not clean the temporary attachment files. Users are expected to clean that directory from time to time.

 

Sending SOAP with Attachments Messages

To send SOAP with Attachments type messages, users should explicitly enable the SOAP with Attachments support in the outflow as shown below. Sending messages include sending a SwA type request message from an Axis2 client as well as sending a SwA type response from an Axis2 server. Users can use the attachments API of the MessageContext to add attachments to the messages.

 Using axis2.xml or services.xml, 
<parameter name="enableSwA" locked="false">true</parameter>
 Programmatically in the client side, 
options.setProperty(Constants.Configuration.ENABLE_SwA,
Constants.VALUE_TRUE);

Attachments API in Apache Axis2

Apache Axis2 exposes the attachment handling functionality through the MessageContext API. You can attach, access, or remove attachments belonging to a message using the org.apache.axis2.context.MessageContext in this API. Alternatively, you can also get a reference to the attachment map to directly manipulate the attachments. All the attachments that you have added and presented in the attachments map will get serialized as MIME attachments when sending the message, provided that you have enabled the SOAP with Attachments for the particular message.

To add an attachment to the message, you have to first create a javax.activation.DataHandler out of your data. You can get the help of javax.activation.DataSource to create the DataHandler. The following example shows you how to create a DataHandler out of a file.

e.g.,
    FileDataSoure dataSource = new
FileDataSource("/home/thilina/temp/foo.jpg");
DataHandler dataHandler = new DataHandler(dataSource);

You can add the DataHandler object as an attachment to the MessageContext, with or without specifying a Content-ID for the attachment MIME part. The content-ID of an attachment is required to be unique with respect to a message. Apache Axis2 will automatically generate a content-ID if you did not specify it. Apache Axis2 preserves the order of adding the attachments when serializing them.

e.g.,
    messageContext.addAttachment("contentID", dataHandler);
or
String contentId = messageContext.addAttachment(dataHandler);

You can access the DataHandler of an attachment contained in the map by giving the corresponding content ID. If you are retrieving the content ID from an "href" attribute, you need to make sure to take off the "cid" prefix to obtain the content-ID. The following method will return null if an attachment cannot be found by the given content ID.

e.g.,
    messageContext.getAttachment("contentID");

In case you want to remove an attachment from the attachment map, you can do it with the help of the removeAttachment() method by giving the corresponding content ID. This method will not return anything (do nothing) if an attachment cannot be found by the given content ID.

e.g.,
    messageContext.removeAttachment("contentID"); 

You can use the getAttachmentMap() method to directly access the underlying attachments map.

e.g.,
    Attachments attachments = messageContext.getAttachmentMap();

 

Accessing the MessageContext

Accessing the incoming MessageContext from a service implementation can be done using the MessageContext.getCurrentMessageContext() method. This will give a handler to the MessageContext only when the service is invoked by Apache Axis2.

   MessageContext incomingContext = MessageContext.getCurrentMessageContext();

Accessing the outgoing MessageContext from the service implementation can be done as follows.

   MessageContext inMessageContext = MessageContext.getCurrentMessageContext();
OperationContext operationContext = inMessageContext.getOperationContext();
MessageContext outMessageContext = operationContext
.getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);

The SwA feature can be used on the client side only with the org.apache.axis2.client.OperationClient API as it deals directly with the MessageContexts. It's not possible to deal with SwA through the org.apache.axis2.client.ServiceClient API as it does not expose the MessageContexts.

 

Summary

Even though the SOAP with Attachments Note is superseded by MTOM/XOP and SwA, it contains some limitations and drawbacks, it still remains as one of the most widely used techniques to send binary attachments with SOAP messages. This is mainly due to the widespread support for SwA from many SOAP stacks, especially by the second generation stacks like Apache Axis1.x. Users will be forced to use SwA on the client side as long as the legacy services, which support only SwA, remain in action.

This article is followed by a tutorial which demonstrates how to download a binary file from a server using SOAP. Please refer to: Downloading a Binary File from a Web Service using Axis2 and SOAP with Attachments

References

  1. MTOM (SOAP Message Transmission Optimization Mechanism)
  2. SwA (SOAP Messages with Attachments)
  3. MIME
  4. Content-ID and Message-ID Uniform Resource Locators
  5. XOP (XML-binary Optimized Packaging)
  6. Downloading a Binary File from a Web Service using Axis2 and SwA

Author

Thilina Gunarathne, Senior Software Engineer, WSO2 Inc. thilina at wso2 dot com