blob: d1841c442467b258febf5a1b005717462cdfcd9b [file] [log] [blame]
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
<meta http-equiv="content-type" content=""/>
<title>Handling Binary data with Axis2 (MTOM/SwA)</title>
<h1>Handling Binary Data with Axis2 (MTOM/SwA)</h1>
<p>This document describes how to use the Axis2 functionality to send/receive
binary data with SOAP.</p>
<li><a href="#1">Introduction</a>
<li><a href="#11">Where Does MTOM Come In?</a></li>
<li><a href="#2">MTOM with Axis2 </a>
<li><a href="#21">Programming Model</a></li>
<li><a href="#22">Enabling MTOM Optimization at Client Side</a></li>
<li><a href="#23">Enabling MTOM Optimization at Server Side</a></li>
<li><a href="#24">Accessing Received Binary Data (Sample Code) </a>
<li><a href="#241">Service</a></li>
<li><a href="#242">Client</a></li>
<li><a href="#25">MTOM Databinding</a>
<li><a href="#251">Using ADB</a></li>
<!--li><a href="#252">Using XMLBeans</a></li-->
<li><a href="#3">SOAP with Attachments with Axis2</a>
<li><a href="#31">Sending SwA Type Attachments</a></li>
<li><a href="#32">Receiving SwA Type Attachments</a></li>
<li><a href="#33">MTOM Backward Compatibility with SwA</a></li>
<li><a href="#4">Advanced Topics </a>
<li><a href="#41">File Caching for Attachments</a></li>
<a name="1"></a>
<p>Despite the flexibility, interoperability, and global acceptance of XML,
there are times when serializing data into XML does not make sense. Web
services users may want to transmit binary attachments of various sorts like
images, drawings, XML docs, etc., together with a SOAP message. Such data is
often in a particular binary format.<br/>
<p>Traditionally, two techniques have been used in dealing with opaque data
in XML;</p>
<li><strong>"By value"</strong></li>
<p>Sending binary data by value is achieved by embedding opaque data (of
course after some form of encoding) as an element or attribute content of
the XML component of data. The main advantage of this technique is that
it gives applications the ability to process and describe data, based
only on the XML component of the data.</p>
<p>XML supports opaque data as content through the use of either base64
or hexadecimal text encoding. Both techniques bloat the size of the data.
For UTF-8 underlying text encoding, base64 encoding increases the size of
the binary data by a factor of 1.33x of the original size, while
hexadecimal encoding expands data by a factor of 2x. The above factors
will be doubled if UTF-16 text encoding is used. Also of concern is the
overhead in processing costs (both real and perceived) for these formats,
especially when decoding back into raw binary.</p>
<li><strong>"By reference"</strong>
<p>Sending binary data by reference is achieved by attaching pure
binary data as external unparsed general entities outside the XML
document and then embedding reference URIs to those entities as
elements or attribute values. This prevents the unnecessary bloating of
data and wasting of processing power. The primary obstacle for using
these unparsed entities is their heavy reliance on DTDs, which impedes
modularity as well as the use of XML namespaces.</p>
<p>There were several specifications introduced in the Web services
world to deal with this binary attachment problem using the "by
reference" technique. <a
href="">SOAP with Attachments</a>
is one such example. Since SOAP prohibits document type declarations
(DTD) in messages, this leads to the problem of not representing data
as part of the message infoset, therefore creating two data models.
This scenario is like sending attachments with an e-mail message. Even
though those attachments are related to the message content they are
not inside the message. This causes the technologies that process and
describe the data based on the XML component of the data to
malfunction. One example is WS-Security.</p>
<a name="11"></a>
<h3>Where Does MTOM Come In?</h3>
<p><a href="">MTOM (SOAP
Message Transmission Optimization Mechanism)</a> is another specification
that focuses on solving the "Attachments" problem. MTOM tries to leverage the
advantages of the above two techniques by trying to merge the two techniques.
MTOM is actually a "by reference" method. The wire format of a MTOM optimized
message is the same as the SOAP with Attachments message, which also makes it
backward compatible with SwA endpoints. The most notable feature of MTOM is
the use of the XOP:Include element, which is defined in the <a
href="">XML Binary Optimized
Packaging (XOP)</a> specification to reference the binary attachments
(external unparsed general entities) of the message. With the use of this
exclusive element, the attached binary content logically becomes inline (by
value) with the SOAP document even though it is actually attached separately.
This merges the two realms by making it possible to work only with one data
model. This allows the applications to process and describe by only looking
at the XML part, making the reliance on DTDs obsolete. On a lighter note,
MTOM has standardized the referencing mechanism of SwA. The following is an
extract from the <a
href="">XOP</a> specification.</p>
<p><em>At the conceptual level, this binary data can be thought of as being
base64-encoded in the XML Document. As this conceptual form might be needed
during some processing of the XML document (e.g., for signing the XML
document), it is necessary to have a one-to-one correspondence between XML
Infosets and XOP Packages. Therefore, the conceptual representation of such
binary data is as if it were base64-encoded, using the canonical lexical form
of the XML Schema base64Binary datatype (see <a href="#XMLSchemaP2">[XML
Schema Part 2: Datatypes Second Edition] </a> <a
base64Binary</a>). In the reverse direction, XOP is capable of optimizing
only base64-encoded Infoset data that is in the canonical lexical
<p>Apache Axis2 supports <strong>Base64 encoding</strong>, <strong>SOAP with
Attachments</strong> and <strong>MTOM (SOAP Message Transmission Optimization
<a name="2"></a>
<h2>MTOM with Axis2</h2>
<a name="21"></a>
<h3>Programming Model</h3>
<p>AXIOM is (and may be the first) Object Model that has the ability to hold
binary data. It has this ability as OMText can hold raw binary content in the
form of javax.activation.DataHandler. OMText has been chosen for this purpose
with two reasons. One is that XOP (MTOM) is capable of optimizing only
base64-encoded Infoset data that is in the canonical lexical form of XML
Schema base64Binary datatype. Other one is to preserve the infoset in both
the sender and receiver. (To store the binary content in the same kind of
object regardless of whether it is optimized or not).</p>
<p>MTOM allows to selectively encode portions of the message, which allows us
to send base64encoded data as well as externally attached raw binary data
referenced by the "XOP" element (optimized content) to be sent in a SOAP
message. You can specify whether an OMText node that contains raw binary data
or base64encoded binary data is qualified to be optimized at the time of
construction of that node or later. For optimum efficiency of MTOM, a user is
advised to send smaller binary attachments using base64encoding
(non-optimized) and larger attachments as optimized content.</p>
<pre> OMElement imageElement = fac.createOMElement("image", omNs);
// Creating the Data Handler for the file. Any implementation of
// javax.activation.DataSource interface can fit here.
javax.activation.DataHandler dataHandler = new javax.activation.DataHandler(new FileDataSource("SomeFile"));
//create an OMText node with the above DataHandler and set optimized to true
OMText textData = <strong>fac.createOMText(dataHandler, true);</strong>
//User can set optimized to false by using the following
<p>Also, a user can create an optimizable binary content node using a base64
encoded string, which contains encoded binary content, given with the MIME
type of the actual binary representation.</p>
<pre> String base64String = "some_base64_encoded_string";
OMText binaryNode =<strong>fac.createOMText(base64String,"image/jpg",true);</strong></pre>
<p>Axis2 uses javax.activation.DataHandler to handle the binary data. All the
optimized binary content nodes will be serialized as Base64 Strings if "MTOM
is not enabled". You can also create binary content nodes, which will not be
optimized at any case. They will be serialized and sent as Base64 Strings.</p>
<pre> //create an OMText node with the above DataHandler and set "optimized" to false
//This data will be send as Base64 encoded string regardless of MTOM is enabled or not
javax.activation.DataHandler dataHandler = new javax.activation.DataHandler(new FileDataSource("SomeFile"));
OMText textData = fac.createOMText(dataHandler, <strong>false</strong>);
<a name="22"></a>
<h3>Enabling MTOM Optimization on the Client Side</h3>
<p>In Options, set the "enableMTOM" property to True when sending
<pre> ServiceClient serviceClient = new ServiceClient ();
Options options = new Options();
<strong>options.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);</strong>
serviceClient .setOptions(options);</pre>
<p>When this property is set to True, any SOAP envelope, regardless of
whether it contains optimizable content or not, will be serialized as an MTOM
optimized MIME message.</p>
<p>Axis2 serializes all binary content nodes as Base64 encoded strings
regardless of whether they are qualified to be optimized or not</p>
<li>if the "enableMTOM" property is set to False.</li>
<li>if the envelope contains any element information items of the name
xop:Include (see <a href="#XOP">[XML-binary Optimized Packaging] </a><a
href="">3. XOP
Infosets Constructs </a>).</li>
<p>The user does <strong>not</strong> have to specify anything in order for
Axis2 to receive MTOM optimised messages. Axis2 will automatically identify
and de-serialize accordingly, as and when an MTOM message arrives.</p>
<a name="23"></a>
<h3>Enabling MTOM Optimization on the Server Side</h3>
<p>The Axis 2 server automatically identifies incoming MTOM optimized
messages based on the content-type and de-serializes them accordingly. The
user can enableMTOM on the server side for outgoing messages,</p>
<p>To enableMTOM globally for all services, users can set the "enableMTOM"
parameter to True in the Axis2.xml. When it is set, all outgoing messages
will be serialized and sent as MTOM optimized MIME messages. If it is not
set, all the binary data in the binary content nodes will be serialized as
Base64 encoded strings. This configuration can be overriden in services.xml
on the basis of per service and per operation.</p>
<pre>&lt;parameter name="enableMTOM"&gt;true&lt;/parameter&gt;</pre>
<p>You must restart the server after setting this parameter.</p>
<a name="24"></a>
<h3>Accessing Received Binary Data (Sample Code)</h3>
<a name="241"></a>
<pre>public class MTOMService {
public void uploadFileUsingMTOM(OMElement element) throws Exception {
<strong>OMText binaryNode = (OMText) (element.getFirstElement()).getFirstOMChild();
DataHandler actualDH;
actualDH = (DataHandler) binaryNode.getDataHandler();</strong>
... <em>Do whatever you need with the DataHandler</em> ...
<a name="242"></a>
<pre> ServiceClient sender = new ServiceClient();
Options options = new Options();
// enabling MTOM
<strong>options.set(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);</strong>
OMElement result = sender.sendReceive(payload);
OMElement ele = result.getFirstElement();
OMText binaryNode = (OMText) ele.getFirstOMChild();
// Retrieving the DataHandler &amp; then do whatever the processing to the data
DataHandler actualDH;
actualDH = binaryNode.getDataHandler();
<a name="25"></a>
<h3>MTOM Databinding</h3>
<p>You can define a binary element in the schema using the schema
type="xsd:base64Binary". Having an element with the type "xsd:base64Binary"
is enough for the Axis2 code generators to identify possible MTOM
attachments, and to generate code accordingly.</p>
<p>Going a little further, you can use the xmime schema
( to describe the binary content more
precisely. With the xmime schema, you can indicate the type of content in the
element at runtime using an MTOM attribute extension xmime:contentType.
Furthermore, you can identify what type of data might be expected in the
element using the xmime:expectedContentType. Putting it all together, our
example element becomes:</p>
<pre> &lt;element name="MyBinaryData" xmime:expectedContentTypes='image/jpeg' &gt;
&lt;extension base="base64Binary" &gt;
&lt;attribute ref="xmime:contentType" use="required"/&gt;
<p>You can also use the xmime:base64Binary type to express the above
mentioned data much clearly.</p>
<pre> &lt;element name="MyBinaryData" xmime:expectedContentTypes='image/jpeg' type="xmime:base64Binary"/&gt;</pre>
<a name="251"></a>
<h3>MTOM Databinding Using ADB</h3>
<p>Let's define a full, validated doc/lit style WSDL that uses the xmime
schema, has a service that receives a file, and saves it in the server using
the given path.</p>
<pre>&lt;wsdl:definitions xmlns:tns=""
&lt;xsd:schema xmlns=""
attributeFormDefault="qualified" elementFormDefault="qualified"
&lt;xsd:import namespace=""
schemaLocation="" /&gt;
&lt;xsd:complexType name="AttachmentType"&gt;
&lt;xsd:element minOccurs="0" name="fileName"
type="xsd:string" /&gt;
&lt;xsd:element minOccurs="0" name="binaryData"
type="xmime:base64Binary" /&gt;
&lt;xsd:element name="AttachmentRequest" type="tns:AttachmentType" /&gt;
&lt;xsd:element name="AttachmentResponse" type="xsd:string" /&gt;
&lt;wsdl:message name="AttachmentRequest"&gt;
&lt;wsdl:part name="part1" element="tns:AttachmentRequest" /&gt;
&lt;wsdl:message name="AttachmentResponse"&gt;
&lt;wsdl:part name="part1" element="tns:AttachmentResponse" /&gt;
&lt;wsdl:portType name="MTOMServicePortType"&gt;
&lt;wsdl:operation name="attachment"&gt;
&lt;wsdl:input message="tns:AttachmentRequest"
wsaw:Action="attachment" /&gt;
&lt;wsdl:output message="tns:AttachmentResponse"
wsaw:Action="" /&gt;
&lt;wsdl:binding name="MTOMServiceSOAP11Binding"
&lt;soap:binding transport=""
style="document" /&gt;
&lt;wsdl:operation name="attachment"&gt;
&lt;soap:operation soapAction="attachment" style="document" /&gt;
&lt;soap:body use="literal" /&gt;
&lt;soap:body use="literal" /&gt;
&lt;wsdl:binding name="MTOMServiceSOAP12Binding"
&lt;soap12:binding transport=""
style="document" /&gt;
&lt;wsdl:operation name="attachment"&gt;
&lt;soap12:operation soapAction="attachment" style="document" /&gt;
&lt;soap12:body use="literal" /&gt;
&lt;soap12:body use="literal" /&gt;
&lt;wsdl:service name="MTOMSample"&gt;
&lt;wsdl:port name="MTOMSampleSOAP11port_http"
location="http://localhost:8080/axis2/services/MTOMSample" /&gt;
&lt;wsdl:port name="MTOMSampleSOAP12port_http"
location="http://localhost:8080/axis2/services/MTOMSample" /&gt;
<p>The important point here is we import
and define the element 'binaryData' that utilizes MTOM.</p>
<p>The next step is using the Axis2 tool 'WSDL2Java' to generate Java source
files from this WSDL. See the 'Code Generator Tool' guide for more
information. Here, we define an Ant task that chooses ADB (Axis2 Data
Binding) as the databinding implementation. The name we list for the WSDL
above is MTOMSample.wsdl, and we define our package name for our generated
source files to 'sample.mtom.service' . Our Ant task for this example is:</p>
&lt;target name="generate.service"&gt;
&lt;java classname="org.apache.axis2.wsdl.WSDL2Java"&gt;
&lt;arg value="-uri" /&gt;
&lt;arg value="${basedir}/resources/MTOMSample.wsdl" /&gt;
&lt;arg value="-ss" /&gt;
&lt;arg value="-sd" /&gt;
&lt;arg value="-g"/&gt;
&lt;arg value="-p" /&gt;
&lt;arg value="sample.mtom.service" /&gt;
&lt;arg value="-o" /&gt;
&lt;arg value="${service.dir}" /&gt;
&lt;classpath refid="class.path" /&gt;
<p>Now we are ready to code. Let's edit
output/src/sample/mtom/service/ and fill in the
business logic. Here is an example:</p>
<pre> public attachment( param0) throws Exception
AttachmentType attachmentRequest = param0.getAttachmentRequest();
Base64Binary binaryData = attachmentRequest.getBinaryData();
DataHandler dataHandler = binaryData.getBase64Binary();
File file = new File(
FileOutputStream fileOutputStream = new FileOutputStream(file);
AttachmentResponse response = new AttachmentResponse();
response.setAttachmentResponse("File saved succesfully.");
return response;
<p>The code above receives a file and writes it to the disk using the given
file name. It returns a message once it is successful. Now let's define the
<pre> public static void transferFile(File file, String destination)
throws RemoteException {
MTOMSampleStub serviceStub = new MTOMSampleStub();
// Enable MTOM in the client side
Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);
//Increase the time out when sending large attachments
// Populating the code generated beans
AttachmentRequest attachmentRequest = new AttachmentRequest();
AttachmentType attachmentType = new AttachmentType();
Base64Binary base64Binary = new Base64Binary();
// Creating a javax.activation.FileDataSource from the input file.
FileDataSource fileDataSource = new FileDataSource(file);
// Create a dataHandler using the fileDataSource. Any implementation of
// javax.activation.DataSource interface can fit here.
DataHandler dataHandler = new DataHandler(fileDataSource);
AttachmentResponse response = serviceStub.attachment(attachmentRequest);
<p>The last step is to create an AAR with our Skeleton and the services.xml
and then deploy the service. You can find the completed sample in the Axis2
standard binary distribution under the samples/mtom directory</p>
<a name="252"></a> <a name="3"></a>
<h2>SOAP with Attachments (SwA) with Axis2</h2>
<a name="31"></a>
<h3>Receiving SwA Type Attachments</h3>
<p>Axis2 automatically identifies SwA messages based on the content type.
Axis2 stores the references on the received attachment parts (MIME parts) in
the Message Context. Axis2 preserves the order of the received attachments
when storing them in the MessageContext. Users can access binary attachments
using the attachement API given in the Message Context using the content-id
of the mime part as the key. Care needs be taken to rip off the "cid" prefix
when content-id is taken from the "Href" attributes. Users can access the
message context from whithin a service implementation class using the
"setOperationContext()" method as shown in the following example.</p>
<p>Note: Axis2 supports content-id based referencing only. Axis2 does not
support Content Location based referencing of MIME parts.</p>
<li><strong>Sample service which accesses a received SwA type
<pre>public class SwA {
public SwA() {
public void uploadAttachment(OMElement omEle) throws AxisFault {
OMElement child = (OMElement) omEle.getFirstOMChild();
OMAttribute attr = child.getAttribute(new QName("href"));
//Content ID processing
String contentID = attr.getAttributeValue();
contentID = contentID.trim();
if (contentID.substring(0, 3).equalsIgnoreCase("cid")) {
contentID = contentID.substring(4);
MessageContext msgCtx = MessageContext.getCurrentMessageContext();
Attachments attachment = msgCtx.getAttachmentMap();
DataHandler dataHandler = attachment.getDataHandler(contentID);
<a name="32"></a>
<h3>Sending SwA Type Attachments</h3>
<p>The user needs to set the "enableSwA" property to True in order to be able
to send SwA messages. The Axis2 user is <strong>not</strong> expected to
enable MTOM and SwA together. In such a situation, MTOM will get priority
over SwA.</p>
<p>This can be set using the axis2.xml as follows.</p>
&lt;parameter name="enableSwA"&gt;true&lt;/parameter&gt;</pre>
<p>"enableSwA" can also be set using the client side Options as follows</p>
options.setProperty(Constants.Configuration.ENABLE_SwA, Constants.VALUE_TRUE);</pre>
<p>Users are expected to use the attachment API provided in the
MessageContext to specify the binary attachments needed to be attached to the
outgoing message as SwA type attachments. Client side SwA capability can be
used only with the OperationClient api, since the user needs the ability to
access the MessageContext.</p>
<li><strong>Sample client which sends a message with SwA type
<pre> public void uploadFileUsingSwA(String fileName) throws Exception {
Options options = new Options();
options.setProperty(Constants.Configuration.ENABLE_SWA, Constants.VALUE_TRUE);
ServiceClient sender = new ServiceClient(null,null);
OperationClient mepClient = sender.createClient(ServiceClient.ANON_OUT_IN_OP);
MessageContext mc = new MessageContext();
FileDataSource fileDataSource = new FileDataSource("test-resources/mtom/test.jpg");
DataHandler dataHandler = new DataHandler(fileDataSource);
<a name="33"></a>
<h3>MTOM Backward Compatibility with SwA</h3>
<p>MTOM specification is designed to be backward compatible with the SOAP
with Attachments specification. Even though the representation is different,
both technologies have the same wire format. We can safely assume that any
SOAP with Attachments endpoint can accept MTOM optimized messages and treat
them as SOAP with Attachment messages - any MTOM optimized message is a valid
SwA message.</p>
<p>Note : Above backword compatibility was succesfully tested against Axis
<li><strong>A sample SwA message from Axis 1.x</strong></li>
<pre>Content-Type: multipart/related; type="text/xml";
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: &lt;9D645C8EBB837CE54ABD027A3659535D&gt;
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;soapenv:Envelope xmlns:soapenv="...."....&gt;
&lt;source href="cid:3936AE19FBED55AE4620B81C73BDD76E" xmlns="/&gt;
Content-Type: text/plain
Content-Transfer-Encoding: binary
Content-Id: &lt;3936AE19FBED55AE4620B81C73BDD76E&gt;
<em>Binary Data.....</em>
<li><strong>Corresponding MTOM message from Axis2</strong></li>
<pre>Content-Type: multipart/related; boundary=MIMEBoundary4A7AE55984E7438034;
type="application/xop+xml"; start="&lt;;";
start-info="text/xml; charset=utf-8"
content-type: application/xop+xml; charset=utf-8; type="application/soap+xml;"
content-transfer-encoding: binary
content-id: &lt;;
&lt;?xml version='1.0' encoding='utf-8'?&gt;
&lt;soapenv:Envelope xmlns:soapenv="...."....&gt;
&lt;xop:Include href=""
content-type: application/octet-stream
content-transfer-encoding: binary
content-id: &lt;;
<em>Binary Data.....</em>
<a name="4"></a>
<h2>Advanced Topics</h2>
<a name="41"></a>
<h3>File Caching for Attachments</h3>
<p>Axis2 comes handy with a file caching mechanism for incoming attachments,
which gives Axis2 the ability to handle very large attachments without
buffering them in the memory at any time. Axis2 file caching streams the
incoming MIME parts directly into the files, after reading the MIME part
<p>Also, a user can specify a size threshold for the File caching (in bytes).
When this threshold value is specified, only the attachments whose size is
bigger than the threshold value will get cached in the files. Smaller
attachments will remain in the memory.</p>
<p>Note : It is a must to specify a directory to temporarily store the
attachments. Also care should be taken to <strong>clean that
directory</strong> from time to time.</p>
<p>The following parameters need to be set in Axis2.xml in order to enable
file caching.</p>
<pre>&lt;axisconfig name="AxisJava2.0"&gt;
&lt;!-- ================================================= --&gt;
&lt;!-- Parameters --&gt;
&lt;!-- ================================================= --&gt;
&lt;parameter name="cacheAttachments"&gt;true&lt;/parameter&gt;
&lt;parameter name="attachmentDIR"&gt;<em>temp directory</em>&lt;/parameter&gt;
&lt;parameter name="sizeThreshold"&gt;<em>4000</em>&lt;/parameter&gt;
<p>Enabling file caching for client side receiving can be done for the by
setting the Options as follows.</p>
options.setProperty(Constants.Configuration.FILE_SIZE_THRESHOLD, <em>"4000"</em>);</pre>