| <html>
|
| <head>
|
| <meta http-equiv="content-type" content="">
|
| <title>Handling Binary data with Axis2 (MTOM/SwA)</title>
|
| </head>
|
|
|
| <body>
|
| <h1>Handling Binary data with Axis2 (MTOM/SwA)</h1>
|
|
|
| <p>This document will describe how to use Axis2 functionality to send/receive binary data
|
| with SOAP.</p>
|
|
|
| <h2>Content</h2>
|
| <ul>
|
| <li><a href="#1">Introduction</a>
|
| <ul>
|
| <li><a href="#11">Where Does MTOM Come In?</a></li>
|
| </ul>
|
| </li>
|
| <li><a href="#2">MTOM with Axis2 </a>
|
| <ul>
|
| <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>
|
| <ul>
|
| <li><a href="#241">Service</a></li>
|
| <li><a href="#242">Client</a></li>
|
| </ul>
|
| </li>
|
| <li><a href="#25">MTOM Databinding</a>
|
| </ul>
|
| </li>
|
| <li><a href="#3">SOAP with Attachments with Axis2</a></li> |
| <ul>
|
| <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>
|
| </ul>
|
| <li><a href="#4">Advanced Topics </a>
|
| <ul>
|
| <li><a href="#41">File Caching for Attachments</a></li>
|
| </ul>
|
| </li>
|
| </ul>
|
| <a name="1"></a>
|
|
|
| <h2>Introduction</h2>
|
|
|
| <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 need to transmit binary attachments of various sorts like
|
| images, drawings, xml docs, etc together with SOAP message. Such data are
|
| often in a particular binary format.<br>
|
| </p>
|
|
|
| <p>Traditionally, two techniques have been used in dealing with opaque data
|
| in XML;</p>
|
| <ol>
|
| <li><strong>"By value"</strong></li>
|
|
|
| <blockquote>
|
| <p>Sending binary data by value is achieved by embedding opaque data (of
|
| course after some form of encoding) as 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 and
|
| looking only on XML component of the data.</p>
|
|
|
| <p>XML supports opaque data as content through the use of either base64
|
| or hexadecimal text encoding. Both these 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. 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>
|
| </blockquote>
|
| <li><strong>"By reference"</strong>
|
|
|
| <blockquote>
|
| <p>Sending binary data by reference is achieved by attaching pure
|
| binary data as external unparsed general entities outside of the XML
|
| document and then embedding reference URI's 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 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="http://www.w3.org/TR/SOAP-attachments">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, 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 for processing and description
|
| of data based on XML component of the data, to malfunction. One example
|
| is WS-Security.</p>
|
| </blockquote>
|
| </li>
|
| </ol>
|
| <a name="11"></a>
|
|
|
| <h3>Where Does MTOM Come In?</h3>
|
|
|
| <p><a href="http://www.w3.org/TR/2004/PR-soap12-mtom-20041116/">MTOM (SOAP
|
| Message Transmission Optimization Mechanism)</a> is another specification
|
| which focuses on solving the "Attachments" problem. MTOM tries to leverage
|
| the advantages of above two techniques by trying to merge the two techniques.
|
| MTOM is actually a "by reference" method. Wire format of a MTOM optimized
|
| message is 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 XOP:Include element, which is defined in <a
|
| href="http://www.w3.org/TR/2004/PR-xop10-20041116/">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 become inline (by
|
| value) with the SOAP document even though actually it is 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 XML part making reliance on DTDs obsolete. On a lighter note MTOM has
|
| standardized the referencing mechanism of SwA. Following is an extract from
|
| the <a href="http://www.w3.org/TR/2004/PR-xop10-20041116/">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 XML Schema base64Binary datatype (see <a href="#XMLSchemaP2">[XML Schema
|
| Part 2: Datatypes Second Edition] </a><a
|
| href="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#base64Binary">3.2.16
|
| base64Binary</a>). In the reverse direction, XOP is capable of optimizing
|
| only base64-encoded Infoset data that is in the canonical lexical
|
| form.</em></p>
|
|
|
| <p>Apache Axis2 supports <strong>Base64 encoding</strong>, <strong>SOAP with
|
| Attachments</strong> & <strong>MTOM (SOAP Message Transmission
|
| Optimization Mechanism).</strong></p>
|
| <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 which has the ability to hold
|
| binary data. It has been given this ability by allowing OMText to 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 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 "XOP" element (optimized content) to be send in a SOAP message.
|
| User can specify whether an OMText node which contains raw binary data or
|
| base64encoded binary data is qualified to be optimized or not at the
|
| construction time of that node or later. To take the optimum efficiency of
|
| MTOM a user is advised to send smaller binary attachments using
|
| base64encoding (None optimized) and larger attachments as optimized
|
| content.</p>
|
| <source><pre> OMElement imageElement = fac.createOMElement("image", omNs);
|
|
|
| // Creating the Data Handler for the image.
|
| // User has the option to use a FileDataSource or a ImageDataSource
|
| // in this scenario...
|
| Image image;
|
| image = new ImageIO()
|
| .loadImage(new FileInputStream(inputImageFileName));
|
| ImageDataSource dataSource = new ImageDataSource("test.jpg",image);
|
| DataHandler dataHandler = new DataHandler(dataSource);
|
|
|
| //create an OMText node with the above DataHandler and set optimized to true
|
| OMText textData = <strong>fac.createOMText(dataHandler, true);</strong>
|
| imageElement.addChild(textData);
|
|
|
| //User can set optimized to false by using the following
|
| //textData.doOptimize(false);</pre>
|
| </source>
|
| <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>
|
| <source><pre> String base64String = "some_base64_encoded_string";
|
| OMText binaryNode =<strong>fac.createOMText(base64String,"image/jpg",true);</strong></pre>
|
| </source>
|
| <p>Axis2 uses javax.activation.DataHandler to handle the binary data. All
|
| optimized binary content nodes will be serialized as Base64 Strings if "MTOM
|
| is not enabled". One can also create binary content nodes which will not be
|
| optimized at any case. They will be serialized and send as Base64 Strings.</p>
|
| <source><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("someLocation"));
|
| OMText textData = fac.createOMText(dataHandler, <strong>false</strong>);
|
| image.addChild(textData);</pre>
|
| </source><a name="22"></a>
|
|
|
| <h3>Enabling MTOM Optimization at Client Side</h3>
|
|
|
| <p>Set the "enableMTOM" property in the Options to true, when sending
|
| messages.</p>
|
| <source><pre> ServiceClient serviceClient = new ServiceClient ();
|
| Options options = new Options();
|
| options.setTo(targetEPR);
|
| <strong>options.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);</strong>
|
| serviceClient .setOptions(options);</pre>
|
| </source>
|
| <p>When this property is set to true any SOAP envelope, regardless whether it contains optimisable content or not, |
| will be serialized as a MTOM optimized MIME message. |
|
|
| <p>Axis2 serializes all binary content nodes as Base64 encoded strings
|
| regardless of they are qualified to be optimize or not, if,</p>
|
| <ul>
|
| <li>"enableMTOM" property is set to false.</li>
|
| <li>If envelope contains any element information items of name xop:Include
|
| (see <a href="#XOP">[XML-binary Optimized Packaging] </a><a
|
| href="http://www.w3.org/TR/2005/REC-xop10-20050125/#xop_infosets">3. XOP
|
| Infosets Constructs </a>).</li>
|
| </ul>
|
|
|
| <p>User do <strong>not</strong> have to specifiy anything inoder for Axis2 to receive MTOM optimised messages.
|
| Axis2 will automatically identify and de-serialize accordingly as and when a MTOM message arrives.</p>
|
|
|
| <p><a name="23"></a></p>
|
|
|
| <h3>Enabling MTOM Optimization at Server Side</h3>
|
|
|
| <p>Axis 2 server automatically identifies incoming MTOM optimized messages
|
| based on the content-type and de-serializes accordingly. User can enableMTOM
|
| in the server side for outgoing messages,</p>
|
| <blockquote>
|
| <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 send as MTOM optimized MIME messages. |
| If it is not set all the binary data in binary content nodes will be
|
| serialized as Base64 encoded strings. This configuration can be overriden in services.xml for per service and per operation |
| basis.</p>
|
| </blockquote>
|
|
|
| <p><source></p>
|
| <pre><parameter name="enableMTOM" locked="false">true</parameter></pre>
|
| </source>
|
| <p>User must restart the server after setting this parameter.</p>
|
|
|
| <a name="24"></a>
|
|
|
| <h3>Accessing Received Binary Data (Sample Code)</h3>
|
| <ul>
|
| <li><strong><a name="241"></a>Service</strong></li>
|
| </ul>
|
| <source><pre>public class MTOMService {
|
| public void uploadFileUsingMTOM(OMElement element) throws Exception { |
| |
| Iterator itr = element.getChildElements(); |
| folder = (OMElement) itr.next(); |
| .... |
| |
| images = (OMElement) itr.next(); |
| itr = images.getChildElements(); |
| |
| int i = 1; |
| String picName; |
| while (itr.hasNext()) { |
| picture = (OMElement) itr.next(); |
| if (picture == null) throw new AxisFault("Picture " + i + " is null"); |
| |
| <strong>OMText binaryNode = (OMText) picture.getFirstOMChild(); |
| DataHandler actualDH; |
| actualDH = (DataHandler) binaryNode.getDataHandler();</strong> |
| |
| ... <em>Do whatever you need with the DataHandler</em> ... |
| } |
| } |
| }
|
| </pre>
|
| </source><ul>
|
| <ul>
|
| <li><a name="242"><strong>Client</strong></a></li>
|
| </ul>
|
| </ul>
|
| <source><pre>
|
| ServiceClient sender = new ServiceClient();
|
| Options options = new Options();
|
| options.setTo(targetEPR);
|
| // 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 & then do whatever the processing to the data
|
| DataHandler actualDH;
|
| actualDH = binaryNode.getDataHandler();
|
| .............</pre>
|
| </source>
|
|
|
| <p><a name="25"></a></p>
|
|
|
| <h3>MTOM Databinding</h3>
|
|
|
| <p>When using MTOM, you simply define the binary file as part of your SOAP message as
|
| type="xsd:base64Binary" or type="xsd:hexBinary. You 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>
|
|
|
| <source><pre>
|
| <element name="MyBinaryData" xmime:expectedContentTypes='image/jpeg' >
|
| <complexType>
|
| <simpleContent>
|
| <extension base="base64Binary" >
|
| <attribute ref="xmime:contentType" use="required"/>
|
| </extension>
|
| </simpleContent>
|
| </complexType>
|
| </element></pre>
|
| </source>
|
| <p>Lets define a full, validated doc / lit style WSDL that imports the xmime schema, has a service that
|
| receives a jpeg and returns a pass / fail status to the client:</p>
|
|
|
| <source><pre>
|
| <?xml version="1.0" encoding="UTF-8"?>
|
|
|
| <definitions name="MyMTOMService" targetNamespace="http://myMtomNS" xmlns:tns="http://myMtomNS" xmlns="http://schemas.xmlsoap.org/wsdl/"
|
| xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns2="http://myMtomNS/types">
|
| <types>
|
| <schema targetNamespace="http://myMtomNS/types" elementFormDefault="qualified" xmlns:tns="http://myMtomNS/types"
|
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"
|
| xmlns:xmime="http://www.w3.org/2005/05/xmlmime">
|
| <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
|
| <import namespace="http://www.w3.org/2005/05/xmlmime"
|
| schemaLocation="http://www.w3.org/2005/05/xmlmime"/>
|
| <complexType name="ReturnWebBase">
|
| <sequence>
|
| <element name="errorMessage" type="xsd:string"/>
|
| <element name="successErrorCode" type="xsd:int"/>
|
| </sequence>
|
| </complexType>
|
| <element name="MyBinaryData" xmime:expectedContentTypes='image/jpeg' >
|
| <complexType>
|
| <simpleContent>
|
| <extension base="base64Binary" >
|
| <attribute ref="xmime:contentType" use="required"/>
|
| </extension>
|
| </simpleContent>
|
| </complexType>
|
| </element>
|
| <element name="sendData">
|
| <complexType>
|
| <sequence>
|
| <element ref='tns:MyBinaryData' minOccurs="1" maxOccurs="1" />
|
| </sequence>
|
| </complexType>
|
| </element>
|
| <element name="sendDataResponse">
|
| <complexType>
|
| <sequence>
|
| <element minOccurs="1" maxOccurs="1" name="sendDataResult" type="tns:ReturnWebBase" />
|
| </sequence>
|
| </complexType>
|
| </element>
|
| </schema>
|
| </types>
|
| <message name="MyMTOMEndpoint_sendData">
|
| <part name="parameters" element="ns2:sendData"/>
|
| </message>
|
| <message name="MyMTOMEndpoint_sendDataResponse">
|
| <part name="result" element="ns2:sendDataResponse"/>
|
| </message>
|
| <portType name="MyMTOMEndpoint">
|
| <operation name="sendData">
|
| <input message="tns:MyMTOMEndpoint_sendData" name="MyMTOMEndpoint_sendData"/>
|
| <output message="tns:MyMTOMEndpoint_sendDataResponse" name="MyMTOMEndpoint_sendDataResponse"/>
|
| </operation>
|
| </portType>
|
| <binding name="MyMTOMEndpointBinding" type="tns:MyMTOMEndpoint">
|
| <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
|
| <operation name="sendData">
|
| <soap:operation soapAction="sendData"/>
|
| <input name="MyMTOMEndpoint_sendData">
|
| <soap:body use="literal"/>
|
| </input>
|
| <output name="MyMTOMEndpoint_sendDataResponse">
|
| <soap:body use="literal"/>
|
| </output>
|
| </operation>
|
| </binding>
|
| <service name="MyMTOMService">
|
| <port name="MyMTOMEndpointPort" binding="tns:MyMTOMEndpointBinding">
|
| <soap:address location="http://localhost:8080/axis2/services/MyMTOMService"/></port></service></definitions>
|
| </pre>
|
| </source>
|
| <p>The important point here is we import http://www.w3.org/2005/05/xmlmime and define an element, 'MyBinaryData' , 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
|
| info. Here, we define an ant task that chooses XMLBeans as the databinding implementation. We also choose to generate an interface which our
|
| Skeleton will implement. The name we list for the WSDL above is mtomExample.wsdl, and we define our package name for our generated source files to be
|
| 'org.apache.axis2.samples.mtomDatabinding.endpoint' . Our ant task for this example is:
|
| </p>
|
|
|
| <source><pre><target name="wsdl2java" depends="clean,prepare">
|
| <delete dir="output" />
|
| <java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true">
|
| <classpath refid="axis.classpath"/>
|
| <arg value="-d"/>
|
| <arg value="xmlbeans"/>
|
| <arg value="-uri"/>
|
| <arg file="wsdl/mtomExample.wsdl"/>
|
| <arg value="-ss"/>
|
| <arg value="-ssi"/>
|
| <arg value="-g"/>
|
| <arg value="-sd"/>
|
| <arg value="-o"/>
|
| <arg file="output"/>
|
| <arg value="-p"/>
|
| <arg value="org.apache.axis2.samples.mtomDatabinding.endpoint"/>
|
| </java>
|
|
|
| <!-- Move the schema folder to classpath-->
|
| <move todir="${build.classes}">
|
| <fileset dir="output/resources">
|
| <include name="*schema*/**/*.class"/>
|
| <include name="*schema*/**/*.xsb"/>
|
| </fileset>
|
| </move>
|
|
|
| </target></pre>
|
| </source>
|
| <p>Now we are ready to code. Lets edit output/src/org/apache/axis2/samples/mtomDatabinding/endpoint/MyMTOMServiceSkeleton.java
|
| and fill in the business logic. The end result becomes: </p>
|
|
|
| <source><pre>/**
|
| * MyMTOMServiceSkeleton.java
|
| *
|
| * This file was auto-generated from WSDL
|
| * by the Apache Axis2 version: SNAPSHOT Jul 19, 2006 (03:46:19 BRT)
|
| */
|
| package org.apache.axis2.samples.mtomDatabinding.endpoint;
|
|
|
| import java.io.File;
|
| import java.io.FileOutputStream;
|
|
|
| import org.apache.commons.logging.Log;
|
| import org.apache.commons.logging.LogFactory;
|
|
|
| import mymtomns.types.ReturnWebBase;
|
| import mymtomns.types.SendDataDocument;
|
| import mymtomns.types.SendDataResponseDocument;
|
| import mymtomns.types.MyBinaryDataDocument.MyBinaryData;
|
| import mymtomns.types.SendDataDocument.SendData;
|
| import mymtomns.types.SendDataResponseDocument.SendDataResponse;
|
|
|
| /**
|
| * MyMTOMServiceSkeleton java skeleton for the axisService
|
| */
|
| public class MyMTOMServiceSkeleton implements MyMTOMServiceSkeletonInterface {
|
|
|
| /** commons logging declaration. * */
|
| private static Log logger = LogFactory
|
| .getLog(MyMTOMServiceSkeleton.class);
|
|
|
| /** Put file received here - change path for your system. */
|
| private static final String MY_DIR = "/home/myuser/example_dir/output";
|
| /** Success code. */
|
| public static final Integer SUCCESS = new Integer(0);
|
| /** Failure / Exception code. */
|
| public static final Integer FAILURE = new Integer(-1);
|
|
|
| /**
|
| * Auto generated method signature.
|
| *
|
| * @param sendDataDocument
|
| * input complex object
|
| * @return SendDataResponseDocument complex object return values
|
| */
|
| public SendDataResponseDocument sendData (SendDataDocument sendDataDocument) {
|
|
|
| // prepare output
|
| SendDataResponseDocument retDoc = SendDataResponseDocument.Factory
|
| .newInstance();
|
|
|
| SendDataResponse retElement = SendDataResponse.Factory
|
| .newInstance();
|
|
|
| ReturnWebBase returnWebBase = ReturnWebBase.Factory
|
| .newInstance();
|
|
|
| try {
|
| if (logger.isDebugEnabled()) {
|
| logger.debug("Reached mtomExample on the server side...");
|
| }
|
| SendData sendData = sendDataDocument.getSendData();
|
| MyBinaryData myBinaryData = sendData.getMyBinaryData();
|
| byte [] myJpegBytes = myBinaryData.getByteArrayValue();
|
|
|
| File jpegFile = new File(MY_DIR+"myJpeg.jpg");
|
| FileOutputStream fos = new FileOutputStream(jpegFile);
|
| fos.write( myJpegBytes );
|
| fos.flush();
|
| fos.close();
|
|
|
| returnWebBase.setSuccessErrorCode(SUCCESS);
|
| returnWebBase.setErrorMessage("SUCCESS");
|
|
|
| } catch (Exception ex) {
|
| logger.error("MyMTOMServiceSkeleton.sendData error:"
|
| + ex.getMessage(), ex);
|
| returnWebBase.setErrorMessage(ex.getMessage());
|
| returnWebBase.setSuccessErrorCode(FAILURE);
|
| }
|
| retElement.setSendDataResult(returnWebBase);
|
| retDoc.setSendDataResponse(retElement);
|
| return retDoc;
|
| }
|
|
|
| }</pre>
|
| </source>
|
|
|
| <p>The code above receives a jpeg file and writes it to disk.
|
| It returns zero on success and in the case of an error, returns -1 along with a stacktrace. Now lets define the client:</p>
|
|
|
| <source><pre>package client;
|
|
|
| import java.io.File;
|
| import java.io.FileOutputStream;
|
| import java.io.FileInputStream;
|
|
|
| import mymtomns.types.ReturnWebBase;
|
| import mymtomns.types.SendDataDocument;
|
| import mymtomns.types.SendDataResponseDocument;
|
| import mymtomns.types.MyBinaryDataDocument.MyBinaryData;
|
| import mymtomns.types.SendDataDocument.SendData;
|
| import mymtomns.types.SendDataResponseDocument.SendDataResponse;
|
| import org.apache.axis2.samples.mtomDatabinding.endpoint.MyMTOMServiceStub;
|
|
|
| public class MTOMXMLBeansClient {
|
|
|
| /** Read file from here - change path for your system. */
|
| private static final String MY_DIR = "/home/myuser/example_dir/input/";
|
|
|
| public static void main(String [] args) throws Exception {
|
|
|
| try {
|
| SendData sendData
|
| = SendData.Factory
|
| .newInstance();
|
| SendDataDocument doc
|
| = SendDataDocument.Factory
|
| .newInstance();
|
| MyBinaryData myBinaryData
|
| = MyBinaryData.Factory
|
| .newInstance();
|
|
|
| File file=new File(MY_DIR + "axis.jpg");
|
| FileInputStream stream=new FileInputStream(file);
|
| int size=stream.available();
|
| byte[] bytes=new byte[size];
|
| stream.read(bytes);
|
|
|
| myBinaryData.setByteArrayValue(bytes);
|
| sendData.setMyBinaryData(myBinaryData);
|
| doc.setSendData(sendData);
|
|
|
| MyMTOMServiceStub stub = new MyMTOMServiceStub();
|
| SendDataResponseDocument responseDoc = stub
|
| .sendData(doc);
|
| SendDataResponse response = responseDoc
|
| .getSendDataResponse();
|
| ReturnWebBase result = response.getSendDataResult();
|
| // test for errors
|
| if (result.getSuccessErrorCode() ==-1) {
|
| System.out.println("ERROR: " + result.getErrorMessage());
|
| }
|
|
|
| } catch (Exception e) {
|
| e.printStackTrace();
|
| }
|
| }
|
| }</pre>
|
| </source>
|
|
|
| <p>The last step is to create an AAR with our Skeleton and the generated interface and services.xml, and then deploy the service. See the user guide for more info. </p>
|
| |
| <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 |
| to 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 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 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>
|
| <ul>
|
| <li><strong>Sample service which accesses a received SwA type attachment</strong></li>
|
| </ul>
|
| <source><pre>
|
| public class SwA { |
| private OperationContext operationContext; |
| |
| public SwA() { |
| } |
| |
| public void setOperationContext(OperationContext oc) throws AxisFault { |
| operationContext = oc; |
| } |
| |
| 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); |
| } |
| |
| Attachments attachment = (Attachments) (operationContext.getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE)).getAttachmentMap(); |
| DataHandler dataHandler = attachment.getDataHandler(contentID); |
| ........... |
| } |
| }
|
| </pre>
|
| </source> |
| <a name="32"></a> |
| <h3>Sending SwA type attachments</h3>
|
| <p>User need to set the "enableSwA" property to true in order to be able to send SwA
|
| messages. Axis2 user is <strong>not</strong> expected to enable MTOM & 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> |
| <source><pre>
|
| <parameter name="enableSwA" locked="false">true</parameter> |
| </pre></source> |
| |
| <p>"enableSwA" can also be set using the client side Options as follows</p> |
| <source><pre>
|
| options.setProperty(Constants.Configuration.ENABLE_SwA, Constants.VALUE_TRUE); |
| </pre></source> |
| |
| <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>
|
| <ul>
|
| <li><strong>Sample client which sends a message with SwA type attachments</strong></li>
|
| </ul>
|
| <source><pre>
|
| public void uploadFileUsingSwA(String fileName) throws Exception { |
| |
| Options options = new Options(); |
| options.setTo(targetEPR); |
| options.setProperty(Constants.Configuration.ENABLE_SWA, Constants.VALUE_TRUE); |
| options.setTransportInProtocol(Constants.TRANSPORT_HTTP); |
| options.setSoapVersionURI(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI); |
| options.setTo(targetEPR); |
| |
| ServiceClient sender = new ServiceClient(null,null); |
| sender.setOptions(options); |
| OperationClient mepClient = sender.createClient(ServiceClient.ANON_OUT_IN_OP); |
| |
| MessageContext mc = new MessageContext(); |
| mc.setEnvelope(createEnvelope()); |
| FileDataSource fileDataSource = new FileDataSource("test-resources/mtom/test.jpg"); |
| DataHandler dataHandler = new DataHandler(fileDataSource); |
| mc.addAttachment("FirstAttachment",dataHandler); |
| |
| mepClient.addMessageContext(mc); |
| mepClient.execute(true); |
| }
|
| </pre>
|
| </source> |
| |
| <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 a 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 1.x</p>
|
| <ul>
|
| <li><strong>A sample SwA message from Axis 1.x</strong></li>
|
| </ul>
|
| <source><pre>Content-Type: multipart/related; type="text/xml";
|
| start="<9D645C8EBB837CE54ABD027A3659535D>";
|
| boundary="----=_Part_0_1977511.1123163571138"
|
|
|
| ------=_Part_0_1977511.1123163571138
|
| Content-Type: text/xml; charset=UTF-8
|
| Content-Transfer-Encoding: binary
|
| Content-Id: <9D645C8EBB837CE54ABD027A3659535D>
|
|
|
| <?xml version="1.0" encoding="UTF-8"?>
|
| <soapenv:Envelope xmlns:soapenv="...."....>
|
| ........
|
| <source href="cid:3936AE19FBED55AE4620B81C73BDD76E" xmlns="/>
|
| ........
|
| </soapenv:Envelope>
|
| ------=_Part_0_1977511.1123163571138
|
| Content-Type: text/plain
|
| Content-Transfer-Encoding: binary
|
| Content-Id: <3936AE19FBED55AE4620B81C73BDD76E>
|
|
|
| <em>Binary Data.....</em>
|
| ------=_Part_0_1977511.1123163571138--</pre>
|
| </source><ul>
|
| <li><strong>Corresponding MTOM message from Axis2</strong></li>
|
| </ul>
|
| <source><pre>Content-Type: multipart/related; boundary=MIMEBoundary4A7AE55984E7438034;
|
| type="application/xop+xml"; start="<0.09BC7F4BE2E4D3EF1B@apache.org>";
|
| start-info="text/xml; charset=utf-8"
|
|
|
| --MIMEBoundary4A7AE55984E7438034
|
| content-type: application/xop+xml; charset=utf-8; type="application/soap+xml;"
|
| content-transfer-encoding: binary
|
| content-id: <0.09BC7F4BE2E4D3EF1B@apache.org>
|
|
|
| <?xml version='1.0' encoding='utf-8'?>
|
| <soapenv:Envelope xmlns:soapenv="...."....>
|
| ........
|
| <xop:Include href="cid:1.A91D6D2E3D7AC4D580@apache.org"
|
| xmlns:xop="http://www.w3.org/2004/08/xop/include">
|
| </xop:Include>
|
| ........
|
| </soapenv:Envelope>
|
| --MIMEBoundary4A7AE55984E7438034
|
| content-type: application/octet-stream
|
| content-transfer-encoding: binary
|
| content-id: <1.A91D6D2E3D7AC4D580@apache.org>
|
|
|
| <em>Binary Data.....</em>
|
| --MIMEBoundary4A7AE55984E7438034--</pre>
|
| </source><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 memory at any time. Axis2 file caching streams the incoming
|
| MIME parts directly in to files, after reading the MIME part headers.</p>
|
|
|
| <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 files. Smaller attachments will remain
|
| in Memory.</p>
|
|
|
| <p><em>NOTE</em> : It is a must to specify a directory to temporary 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>
|
| <source><pre><axisconfig name="AxisJava2.0">
|
| <!-- ================================================= -->
|
| <!-- Parameters -->
|
| <!-- ================================================= -->
|
| <parameter name="cacheAttachments" locked="false">true</parameter>
|
| <parameter name="attachmentDIR" locked="false"><em>temp directory</em></parameter>
|
| <parameter name="sizeThreshold" locked="false"><em>4000</em></parameter>
|
| .........
|
| .........
|
| </axisconfig></pre>
|
| </source> |
| <p>Enabling file caching for client side receiving can be done for the by setting the Options as follows.</p>
|
| <source><pre> |
| options.setProperty(Constants.Configuration.CACHE_ATTACHMENTS,Constants.VALUE_TRUE); |
| options.setProperty(Constants.Configuration.ATTACHMENT_TEMP_DIR,<em>TempDir</em>); |
| options.setProperty(Constants.Configuration.FILE_SIZE_THRESHOLD, <em>"4000"</em>); |
|
|
| </pre>
|
| </source> |
| </body>
|
| </html>
|