Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JAX-WS With MTOM Using Mule

DZone's Guide to

JAX-WS With MTOM Using Mule

Want your XML to stay lightweight? See how to keep it that way to avoid bloated messages.

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

In 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.

Image title

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:

  • Efficient Transmission: Base64 binary encoded data is around 33% larger than raw bytes transmission using MIME. This will result in extra resource utilization such as increases in CPU time and fattening of payload size. With MTOM, it will reduce the data bloat by converting the binary data into raw bytes for transmission, this will significantly save the bandwidth.
  • Processing Simplicity: Security standards such as WS-Encryption and WS-Signatures can directly be applied to the SOAP message as the base64 binary data is represented within the SOAP XML message. Once these such operations are performed, the binary data can be converted to raw bytes for transmission. Therefore, no additional efforts are required to secure the MIME-based attachments within the SOAP XML message.
  • 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

    Image title

    Image title


    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:

    Image title


    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:

    Image title

    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

    Image title


    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.

    Image title


    That’s it, guys! I hope you like this article.

    The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

    Topics:
    mule esb ,mulesoft ,web services ,jax-ws

    Opinions expressed by DZone contributors are their own.

    {{ parent.title || parent.header.title}}

    {{ parent.tldr }}

    {{ parent.urlSource.name }}