Friday, August 15, 2014

MTOM/XOP example using JAX-WS / SOA Suite & OSB - 1

Binary data sent using SOAP across the wire needs to be encoded using base64Encoding to convert it as text. This process will increase the size of data by 33%. Thus to optimize the transmission of xml data of type xs:base64Binary and xs:hexBinary in SOAP messages, W3C recommends usage of MTOM/XOP (Message Transmission Optimization Mechanism / XML Optimized Packaging). When the transport protocol is HTTP, MIME attachments are used to carry that data while at the same time allowing both the sender and the receiver direct access to the XML data in the SOAP message without having to be aware that any MIME artefacts were used to marshal the base64Binary or hexBinary data. MTOM primarily provides the following:
  • Encoding of the binary data
  • Removal the binary data from the SOAP Envelope
  • Compression of the Binary data
  • Attach the binary data to the MIME package
  • Pointer to the MIME package in the SOAP Envelope
JAX-WS provides annotations support for MTOM/XOP through annotations.

JAVA - XML Type conversion for MTOM

The java types/classes javax.activation.DataHandler, java.awt.Image, java.xml.transform.Source are by default converted to xs:base64Binary or xs:hexBinary XML types. While the XML types xs:base64Binary or xs:hexBinary are converted to byte[] by default.

One of the highlights of the MTOM specification is that, it doesn't mandate that always the data will be sent as attachments by default. It allows us to specify the threshold limit after which the data needs to sent as attachment. This way for lesser data need not be passed as attachment and thus can avoid unnecessary overhead.

@MTOM(threshold=<Threshold Value>)

Steps to Enable MTOM
  • Annotate the datatype that needs to be sent as attachment
  • Enable MTOM on both the Web Service & its client
Example (Start with Java)

Lets create the class 'DocumentManager' and define a method to archive the incoming document into the disc... The document sent across the wire will use MTOM providing an optimized transmission.


public class DocumentManager {
    public DocumentManager() {
        super();
    }
    
    public void archiveDocument(javax.activation.DataHandler _pDocumentHandler) {
        try
        {
            //Hardcoding stuff here...you can get the content type to set the extension dynamically....
            File fileToArchive = new File("/tmp/"+"test.pdf");             
            FileOutputStream outputStream = new FileOutputStream(fileToArchive);
            _pDocumentHandler.writeTo(outputStream); //Writes the stream into the disk.
            outputStream.flush();
            outputStream.close();
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        
    }

Now lets expose the class as a JAX-WS web service and enable MTOM for the same:

 









The generated service would look something like below:
package fmw.techsamples.java.ws.mtom;

import java.io.File;
import java.io.FileOutputStream;

import javax.jws.WebService;

import javax.xml.ws.soap.MTOM;

@WebService(endpointInterface = "fmw.techsamples.java.ws.mtom.DocumentManagerPortType")
@MTOM(enabled=true,threshold=1024)
public class DocumentManager {
    public DocumentManager() {
        super();
    }
    
    public void archiveDocument(javax.activation.DataHandler _pDocumentHandler) {
        try
        {
            //you can get the content type to set the extension dynamically....
            File fileToArchive = new File("/tmp/"+"test.pdf"); 
            
         FileOutputStream outputStream = new FileOutputStream(fileToArchive);
         _pDocumentHandler.writeTo(outputStream);
         outputStream.flush();
         outputStream.close();
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        
    }
}

I have set the threshold  to 1024 bytes, which means till that threshold is reached MTOM will not be used. The below image shows the WSDL & XSD definition generated after deploying the web service.
The WSDL would contain the WS policy definition for MTOM/XOP. Also, note that the XSD definition shows the input as 'base64Binary'



Ok now to testing. We will use SOAP UI to do the testing, but to trap the http request that is sent through the wire to the server(to show that the request has been optimized through MTOM), we will make use of HttpAnalyzer in the jdeveloper. First we start  the HttpAnalyzer to listen in port 8099 and then set the same as the proxy in SOAP UI (via preferences as shown below).

This would mean that all the request flows through HttpAnalyzer and we can trap the request sent across the wire. In the SOAPUI, we can use the Insert file as Base64 option to convert a pdf to base64binary (or you could use openssl or base64 command to do that easily in a mac). Also, we need to set the 'Enable MTOM' to true (equivalent to setting new MTOMFeature() in a java client)



After executing the request, lets see the request sent via HttpAnalyzer. The below SOAP request shows the XOP-include element having the reference to binary data sent separately as MIME attachments.
Also, the end pdf is shown written to the /tmp directory in the server. 


In the next instalment I will show a quick sample on how to access the MTOM enabled service through Oracle SOA Suite / OSB.

No comments:

Post a Comment