JAX-WS With MTOM Using Mule
Want your XML to stay lightweight? See how to keep it that way to avoid bloated messages.
Join the DZone community and get the full member experience.
Join For FreeIn this article, we discuss on how to use MTOM – Message Transmission Optimization Mechanism with JAX-WS using Mule.
What Is MTOM?
In a nutshell, MTOM – Message Transmission Optimization Mechanism developed by W3C – is a method of efficiently sending binary data to and from Web services. MTOM is designed for optimizing the electronic transmission of attachments. MTOM is usually used with the XOP — XML-binary Optimized Packaging to serialize and de-serialize the binary part of an XML.
How MTOM (With XOP) Works?
As we know, SOAP is XML, and when sending something other than text, such as PDF files, images, or Word documents, between systems, it has to be converted into a datatype that the XML processor can understand. It must also use base64 encoding, where the binary data is present, and then embed it in the XML document, which will, in turn, increase the size of XML payload.
An MTOM-enabled web services engine detects the presence of base64-encoded binary data types. The XOP packaging process extracts the binary data out of the XML and serializes the binary data differently. The XOP process responsibility is to extract the binary part of the XML data and leaves the XML with the binary parts replaced by external references. This is called XOP infoset and the external reference is added as “xop:Include” element in XML. This makes MTOM actually a “by reference” method. The extracted or separated raw bytes are appended to the SOAP Message and are separated by a MIME boundary.
Once the XML data is received at the receivers end, XOP package will de-serialize the infoset along with the extracted content and replace it in the XML where the corresponding external reference is present.
Below is sample example of SOAP response which uses MTOM and separated by MIME boundary:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
<soap:Body>
<ns2:ByteEcho xmlns:ns2="http://myideas4u.com" >
<ns2:data><xop:Include href=cid:1.633335845875937500@myideas4u.com xmlns:xop="http://www.w3.org/2004/08/xop/include"/></ns2:data>
</ns2:ByteEcho>
</soap:Body>
</soap:Envelope>
--MIMEBoundary000000
content-id: <1.633335845875937500@myideas4u.com>
content-type: application/octet-stream
content-transfer-encoding: binary
MTOM provides two significant advantages:
How do JAX-WS web services treat binary data with MTOM enabled?
Let us create a web service using JAX-WS with the following operations:
- uploadDocument.
- downloadDocument.
Firstly, we will create a web service that doesn’t use MTOM and see how the SOAP response message will look like when “downloadDocument” operation invoked.
As you know, you can develop web services using either “Top-Down” or “Bottom-Up” approach.
In the top-down approach, you start web services development with a contract i.e., WSDL document design and then generate the Java objects to implement services. This approach is also known as the “Contract First” approach. | In the bottom-up approach, you start web services development with Java objects and services enable it using annotations. This approach is also known as “Code First” approach. |
In this article, we follow “Bottom-Up” approach.
Now, it is time to get to the action.
Create a new project viz., "mtom-demo".
Create project in Anypoint Studio, by selecting the top menu bar.
Select File > New > Mule Project
After the project is created, create the SEI – Service Endpoint Interface viz. MTOMDemoService.java.
/**
* @(#)MTOMDemoService.java
* myideas4u.com
*/
package com.webservice.mtom.intf;
import javax.activation.DataHandler;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* MTOMDemoService interface is the Service Endpoint Interface for
* <b>{@code uploadDocument}</b> and <b>{@code downloadDocument}</b> services.
*
* @author Anil Kumar.V
*
*/
@WebService(name = "MTOMService", targetNamespace = "http://myideas4u.com/ws/mtom")
public interface MTOMDemoService {
@WebMethod(action = "uploadDocument")
@XmlMimeType("application/octet-stream")
public String uploadDocument(@WebParam(name = "fileData") DataHandler
fileData);
@WebMethod(action = "downloadDocument")
public DataHandler downloadDocument();
}
Next, create the SEI implementation viz. MTOMDemoServiceImpl.java.
/**
* @(#)MTOMDemoServiceImpl.java
* myideas4u.com
*/
package com.webservice.mtom.impl;
import java.io.IOException;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.xml.ws.WebServiceException;
import com.webservice.mtom.intf.MTOMDemoService;
/**
* MTOMDemoServiceImpl implementation is the Service Endpoint Interface for
* <b>{@code uploadDocument}</b> and <b>{@code downloadDocument}</b> services.
*
* @author Anil Kumar.V
*
*/
public class MTOMDemoServiceImpl implements MTOMDemoService {
@Override
public String uploadDocument(DataHandler fileData) {
try {
System.out.println("File Data received: " +
fileData.getContent().toString());
// code to save the file on the server location....
} catch (IOException e) {
e.printStackTrace();
throw new WebServiceException("Upload Failed");
}
return "File uploaded successfully.";
}
@Override
public DataHandler downloadDocument() {
return new DataHandler(new FileDataSource("c:/tmp/esb.pdf"));
}
}
Now drag and drop the following components from the palette in the same order onto the canvas:
1. HTTP | URL : http://localhost:8081/mtom |
2. CXF | Select the Operation to : JAX-WS service and Service Class to SEI i.e., com.webservice.mtom.intf.MTOMDemoService |
3. Java | Set the Class Name to SEI Implementation i.e., com.webservice.mtom.impl.MTOMDemoServiceImpl |
The flow should look like below:
Now let us check the WSDL contract and the schema generated for the above SEI implementations. To get hold of the WSDL contract, you need to run the mule flow, and type "http://localhost:8081/mtom?wsdl" in the browser.
WSDL File
Here you can see that the “DataHandler” type in service request and response is of type "xsd:base64Binary" in schema.
When you invoke the “downloadDocument” operation using the SOAP UI, you see the request and response as below.
SOAP Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mtom="http://myideas4u.com/ws/mtom">
<soapenv:Header/>
<soapenv:Body>
<mtom:downloadDocument/>
</soapenv:Body>
</soapenv:Envelope>
SOAP Response
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:downloadDocumentResponse xmlns:ns2="http://myideas4u.com/ws/mtom">
<return>/9j/4AAQSkZJRgABAQEBLAEsAAD//eHBhY2tldCBiZWdpbj0n77u/JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkJz8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0nYWRvYmU6bnM6bWV0YS8nPgo8cSlKAUpSgFKUoBSlKAUpSgFKUoBSlKAUpSgFKUoD//2Q==</return>
</ns2:downloadDocumentResponse>
</soap:Body>
</soap:Envelope>
Here, the SOAP response itself has base64-encoded document/image binary information. Please note that it copied only the few portions of the response string. In fact, it has 40,556 characters. This indicates that the SOAP response XML is very huge and will consume enough time to transmit to the client. If you look carefully, the data is part of the SOAP envelop message itself, no attachments are added. See the below picture:
Now, let us enable MTOM for the JAX-WS Service and check how MTOM treats binary data.
We need to make some changes to the services to make use of MTOM. There are many different implementation mechanisms to use MTOM.
- Add @MTOM annotation to the SEI class.
- Use the @XmlMimeType annotation on POJO to make JAXB aware that this candidate is for MTOM optimization.
- Enable at the end point publisher i.e., in the mule "CXF Component".
In our case, enabling MTOM is pretty simple as we are using Mule's “CXF Component”.
Click on the “Advanced” tab in properties of CXF component and Select “MTOM Enabled” option
Now run the flow again and test it again using the SOAP UI. Now you will see the difference in the SOAP response while retrieving the document/image from the server.
SOAP Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mtom="http://myideas4u.com/ws/mtom">
<soapenv:Header/>
<soapenv:Body>
<mtom:downloadDocument/>
</soapenv:Body>
</soapenv:Envelope>
SOAP Response
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:downloadDocumentResponse xmlns:ns2="http://myideas4u.com/ws/mtom">
<return>
<xop:Include href="cid:d92a081c-b475-45f1-8422-5be59d0226b8-3@cxf.apache.org" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</return>
</ns2:downloadDocumentResponse>
</soap:Body>
</soap:Envelope>
As mentioned earlier, now the SOAP message has just the reference(s). This reference points to the MIME attachment. See the screenshots below. Notice, the document/image is sent as a MIME attachment not with in the SOAP envelope.
That’s it, guys! I hope you like this article.
Opinions expressed by DZone contributors are their own.
Comments