JAX-WS Attachment – Enable MTOM for JAX-WS Web services

12 Flares Twitter 1 Facebook 4 Google+ 6 LinkedIn 1 Email -- Filament.io 12 Flares ×

JAX-WS with Attachment – MTOM , XOP and Java Web Service Example using JAX-WS

In this MTOM JAX-WS tutorial, we discuss how to use MTOM (Message Transmission Optimization Mechanism) with JAX-WS Web Services. We also discuss the advantage of using MTOM with web services and how MTOM works with XOP and how the MIME attachments are processed.

What is MTOM?

MTOM (Message Transmission Optimization Mechanism) provides an efficient mechanism for transmitting binary data to and from web services over internet. MTOM uses XML binary Optimized Packaging or XOP to serialize and de-serialize binary part of an XML infoset.
MTOM is a standard that is developed by the World Wide Web Consortium  (W3C) and it is a SOAP Version 1.2 feature (based on the Infoset). Even though SwA (SOAP with Attachments) and MTOM are theoretically similar, and both encode binary data as a MIME attachment in a MIME document, SwA could be replaced by the more powerful MTOM and XOP mechanisms because it solves some of the interoperability issues of SwA. MTOM uses XOP in the context of SOAP and MIME over HTTP to achieve performance improvement.

How Does XOP works?

As we know, the serialization of XML infoset is text based and uses BASE64 binary-to-text encoding scheme, where the binary data represented in an ASCII string format. This increases the size of the XML payload.
An MTOM-enabled web services engine detects the presence of Base64Binary data. XOP packaging process extracts the binary data out of the XML Infoset and the binary data serialized differently. XOP process extracts the binary part of the XML info-set and leaves the XML Infoset 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 raw bytes are appended to the SOAP Message and are separated by a MIME boundary.
The XOP package is created by serializing the XOP infoset and the binary data as a MIME attachment. Once the data is received at the other end, the XOP Package is de-serialized into the XOP Infoset plus the extracted content and the extracted content is placed back in the XML infoset where the corresponding external reference is present.
See and example SOAP response below which uses MTOM. We will see the complete working example as we move on.


   
      
         
            
         
      
   

You can see the reference to the MIME attachment as


If you examine the SOAP header you will something like the below

	
Transfer-encoding  : chunked
Content-type            : multipart/related;start="<rootpart*75292b03-7617-4261-a44f-ac8d9df23382@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:75292b03-7617-4261-a44f-ac8d9df23382";start-info="text/xml"
#status# : HTTP/1.1 200 OK

The attachment details are as below

Name: 40128994-d019-4c2c-a293-49c448772ea7@example.jaxws.sun.com	
Content type: image/png	
Size:431731	
Part: 40128994-d019-4c2c-a293-49c448772ea7@example.jaxws.sun.com	
Type: XOP	
ContentId: 40128994-d019-4c2c-a293-49c448772ea7@example.jaxws.sun.com

The contentId is same as the reference in

Ideal Use case for using MTOM in Web Service

If you have a requirement where the web service has to send and receive large number of documents (images, word documents, pdf etc) to an enterprise system over internet, then using MTOM will save you the bandwidth. You gain efficient network transmission by using MTOM.
Consider you are sending a large PDF document over the wire using a web service With MTOM, the document will be transmitted outside the envelope as a MIME attachment and it is transmitted as binary data. Here there is no XML BASE64 encoding required for the document.

MTOM with JAX-WS Web Service Example

How JAX-WS without MTOM treats binary Data?

Let us create a web service using JAX-WS that offer Image upload and download services. First we will create a service which doesn’t use MTOM and see how the SOAP response when you download an Image.

The SEI (Service Endpoint Interface)

/*
 * @(#)MTOMService.java
 * @author Binu George
 * Globinch.com
 * Visit  http://www.globinch.com. All rights reserved.
 */

package com.ws.mtom;

import java.awt.Image;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;
/**
 * 
 * The MTOMService interface is the SEI  for
 * image download and upload service
 * 
 * 
 * @author Binu George
 * @version 1.0
 * @since MTOMService1.0
 */

@WebService(name = "MTOMService", targetNamespace = "http://globinch.com", wsdlLocation = "http://globinch.com/ws/MTOMService?wsdl")
@SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL)
public interface MTOMService {
	// web method download a image from server
	@WebMethod(operationName = "retrieveImage")
	public Image retrieveImage(String name);

	// Web method to upload the image to server
	@WebMethod(operationName = "uploadImage")
	public String uploadImage(Image image, String name);
}

The SEI Implementation class

/*
 * @(#)MTOMServiceImpl.java
 * @author Binu George
 * Globinch.com
 * Visit  http://www.globinch.com. All rights reserved.
 */

package com.ws.mtom;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.jws.WebService;
import javax.xml.ws.WebServiceException;
/**
 * 
 * The MTOMServiceImpl implementation of   MTOMService SEI  for
 * image download and upload service
 * 
 * 
 * @author Binu George
 * @version 1.0
 * @since MTOMService1.0
 */
@WebService(endpointInterface = "com.ws.mtom.MTOMService", targetNamespace = "http://globinch.com", portName = "MTOMServicePort", serviceName = "MTOMServiceService")
public class MTOMServiceImpl implements MTOMService {
	final static String PATH = "D:\\mtomtest\\upload\\";

	@Override
	public Image retrieveImage(String name) {
		try {
			// Create a file object with file name and read the image
			System.out.println(name);
			File image = new File(PATH + name);
			System.out.println(image.getPath());
			System.out.println(image.getName());
			return ImageIO.read(image);
		} catch (IOException e) {
			e.printStackTrace();
			throw new WebServiceException("Download Failed");
		}
	}

	@Override
	public String uploadImage(Image file, String name) {
		if (file != null) {
			try {
				File image = new File(PATH + name);
				ImageIO.write((BufferedImage) file, "jpg", image);
			} catch (IOException e) {
				e.printStackTrace();
				throw new WebServiceException("Upload Failed");
			}
			return "Upload Successful";
		}
		throw new WebServiceException("No data to upload.");
	}
}

The service endpoint publisher class

/*
 * @(#)MTOMServicePublisher.java
 * @author Binu George
 * Globinch.com
 * Visit  http://www.globinch.com. All rights reserved.
 */
package com.ws.mtom;

import javax.xml.ws.Endpoint;
/**
 *  The MTOMServicePublisher endpoint publisher class  for
 * image download and upload MTOMService service
 * 
 * 
 * @author Binu George
 * @version 1.0
 * @since MTOMService1.0
 */
public class MTOMServicePublisher {
	public static void main(String[] args) {
		  System.out.println("Publish the service");
		  Endpoint.publish("http://192.168.1.201:8088/MTOMService", new MTOMServiceImpl());
		 }
}

Now let us check the WSDL file and the schema file generated for this service.

The Schema file




  

  

  

  

  
    
      
    
  

  
    
      
    
  

  
    
      
      
    
  

  
    
      
    
  


Here you can see that the image in request (uploadImage) and response (retrieveImageResponse) is of type base64Binary.

The WSDL file




  
    
      
    
  
  
    
  
  
    
  
  
    
  
  
    
  
  
    
      
      
    
    
      
      
    
  
  
    
    
      
      
        
      
      
        
      
    
    
      
      
        
      
      
        
      
    
  
  
    
      
    
  


When you run the “retrieveImage” service you will see the SOAP request and response as below.

SOAP request

 

   
   
      
         
         ImageFromClient0.9292193002097403.jpg
      
   

SOAP Response

         

   
      
         iVBORw0KGgoAAAANSUhEUgAAAfQAAAGWCAIAAAABiOaMAACAAElEQVR42uy9Z5QUV5bvq+/vrbfum5m7ZrqnR2oJGQRCwgnvrfAIj7CSEEIgJBBGDgm1DDII4aoon1lVmeUtVZRP70259K4KkNpMd98x685739/b++yMU5F……………………………………………………………………………………………………………………………………………………………………………………….2R/ppZ+VC4+1lae62nNAPMCdXnoKyt3WPdQt/gxwN1Z/BrKL83dkxduKmbvSwnXX6o+W5gNz7T7IdmVxAyQ8KOOB8CIod22hq8xUHZUtgLttqW1dbCmSeevsPMhqc6HA5jIi/zig3Febdy/NyCMTTDZmyKdBuTOZDNDfu1z1VirAa8m4GxQ6MH1kzInbioAPWA8bnBXDP3yVwN2QzenTWTqRUkfj/w+AQhAf1g1PhwAAAABJRU5ErkJggg==
      
   


Here the SOAP response itself has the BASE64 encoded image binary information. I copied only a very small portion of the response string. It has in fact 575646 characters. This means that SOAP XML response will be huge and the transmission time taken will be more. Tools like SoapUI can be used to check the SOAP request and response. See the screen shot below. Also you can see that there is no attachment included as part of response. The entire data is part of SOAP envelop. MTOM-jax-ws-without-attachment

How JAX-WS with MTOM treats binary Data?

Enable MTOM for JAX-WS Web Service

Now let us modify our service to make use of MTOM.
You can follow many different implementation mechanisms to use MTOM.

  1. Enable MTOM on your endpoint implementation class by using annotations. This method is the preferable method for developers. You can use,
    1. @MTOM annotation : The @MTOM annotation has two optional parameters, enabled and threshold. The enabled parameter has a boolean value and indicates if MTOM is enabled for the JAX-WS endpoint. If an attachment is smaller than the size specified in threshold parameter, the runtime will inline the binary data as base64 binary instead of creating an attachment.
    2. @BindingType(value = SOAPBinding.SOAP11HTTP_MTOM_BINDING) (For SOAP version 1.1.)
    3. @BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING) (For SOAP version 1.2.)
    See below example endpoint implementation with annotation

     
    ...........
    @MTOM
    @WebService(endpointInterface = "com.ws.mtom.MTOMService", targetNamespace = "http://globinch.com", portName = "MTOMServicePort", serviceName = "MTOMServiceService")
    public class MTOMServiceImpl implements MTOMService {
    .............
    
     
    ...........
    @BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
    @WebService(endpointInterface = "com.ws.mtom.MTOMService", targetNamespace = "http://globinch.com", portName = "MTOMServicePort", serviceName = "MTOMServiceService")
    public class MTOMServiceImpl implements MTOMService {
    .............
    
  2. By modifying your schema for MTOM
    For example you can change the XML schema element as below

     
     
    Add the “xmime:expectedContentTypes” to the element
    
    
    
    
  3. You can also use the annotation “@XmlMimeType(“application/octet-stream”)” to your POJO to tell JAXB that the field is a candidate for MTOM optimization.
  4. You can modify your endpoint publisher class to support MTOM
    Endpoint ep = Endpoint.publish("http://192.168.1.201:8088/MTOMService", new MTOMServiceImpl());
    SOAPBinding binding = (SOAPBinding) ep.getBinding();
    binding.setMTOMEnabled(true);
  5. If you use XML (When you use Spring and CXF for example) to publish your endpoint then update it as follows.
    
        
          
        
      
    
    

In our example, since we don’t use any JEE container to deploy/run our web service, we use the endpoint publisher class to make our service MTOM enabled.

/*
 * @(#)MTOMServicePublisher.java
 * @author Binu George
 * Globinch.com
 * Visit  http://www.globinch.com. All rights reserved.
 */
package com.ws.mtom;

import javax.xml.ws.Endpoint;
import javax.xml.ws.soap.SOAPBinding;
/**
 * 
 * The MTOMServicePublisher endpoint publisher class  for
 * image download and upload MTOMService service
 * 
 * 
 * @author Binu George
 * @version 1.0
 * @since MTOMService1.0
 */
public class MTOMServicePublisher {
	public static void main(String[] args) {
		  System.out.println("Publish the service");
Endpoint ep = Endpoint.publish("http://192.168.1.201:8088/MTOMService", new MTOMServiceImpl()); 
SOAPBinding binding = (SOAPBinding) ep.getBinding();
		binding.setMTOMEnabled(true);
	 }
}

Now you run the publisher and check the artifacts. You will see the difference in SOAP response while retrieving the image from the server.

SOAP Request

    

   
   
      
         
         ImageFromClient0.9292193002097403.jpg
      
   


SOAP Response


   
      
         
            
         
      
   


As we mentioned earlier now the SOAP message has just the reference. This reference points to the MIME attachment. See the screenshots below. Here the image is send as a MIME attachment. MTOM-jax-ws-with-attachemnt   You can also see the raw SOAP response as below. Notice the three content types.

    1. Content-type: multipart/related;start="<rootpart*75292b03-7617-4261-a44f-ac8d9df23382@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:75292b03-7617-4261-a44f-ac8d9df23382";start-info="text/xml" 
      --uuid:75292b03-7617-4261-a44f-ac8d9df23382
      Content-Id: rootpart*75292b03-7617-4261-a44f-ac8d9df23382@example.jaxws.sun.com
    2. Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
      Content-Transfer-Encoding: binary
      
      --uuid:75292b03-7617-4261-a44f-ac8d9df23382
      Content-Id: 40128994-d019-4c2c-a293-49c448772ea7@example.jaxws.sun.com
    3. Content-Type: image/png
      Content-Transfer-Encoding: binary
      ‰PNG

MTOM-jax-ws-with-attachemnt3

Also note that MTOM is used if the MTOM Feature is set and if either,

  1. Client has already sent an MTOM-request
  2. Client has sent an “Accept” HTTP header indicating that the client supports MTOM

For example if you are using SoapUI to test , you can set “Enable MTOM” and “Force MTOM”. For individual requests you can add an “Accept” header with the value “application/xop+xml;” in SoapUI.

Performance Comparison with and without enabling MTOM in Web Service

Web Service Without enabling MTOM.

The total time taken to get response with image: 155 ms.
The total payload size: 575864 bytes. (562.3671875 KB)

MTOM-payload-without-attachment

Web Service after enabling MTOM

The total time taken to get response with image: 148 ms.
The total payload size: 432558 bytes. (422.4199219KB)

MTOM-payload-with-attachemnt

Conclusion

As we mentioned, if the binary is part of the XML document, it needs to be base64 encoded. Base64Binary encoded data size is around 33% (a factor of 1.33x of the original size) greater than raw byte transmission using MIME. This result in extra CPU time and increase in payload size. Base64 encoding inline tends to enlarge the size of the SOAP message. This introduces performance issues. The MTOM is a solution for this problem. When a service is MTOM enabled, it takes binary data from the XML, and creates a MIME attachment for it. It solves the Drawbacks of embedding binary large data into soap envelop. MTOM data transfer using streaming approach.

Drawbacks of Using MTOM

  1. MTOM is not a preferable method when you have a lot of very small attachments.The overhead of MTOM may outweigh the benefit of binary transfer. In this case you can use the “threshold” parameter of @MTOM annotation to handle it differently as discussed above.
  2. Detecting MTOM messages for dispatch is additional overhead. But usually the benefits of attachments overcomes this drawback.
  3. MTOM works only when all the parties involved in data transfer support MTOM specification. MTOM support is fully interoperable with .NET clients and servers.

References:

  1. SOAP Message Transmission Optimization Mechanism
  2. XML-binary Optimized Packaging
  3. Base64 encoder
  4. Apache Commons Codec (TM)

Incoming search terms:

12 Flares Twitter 1 Facebook 4 Google+ 6 LinkedIn 1 Email -- Filament.io 12 Flares ×

Related Posts

This Post Has 7 Comments

  1. I’m trying to call a webservice with WS-Security authentication (PlainText). The authentication is successful and apparently also the method call that interests me. The method returns a “multipart”:


    ------=_Part_7_416131402.1368626616541
    Content-Type: application/xop+xml; charset=utf-8; type="text/xml"
    Content-Transfer-Encoding: 8bit
    Content-ID:

    0Operazione eseguitaXYZ 0003339455 1.pdfapplication/pdf
    ------=_Part_7_416131402.1368626616541
    Content-Type: application/octet-stream
    Content-Transfer-Encoding: binary
    Content-ID:
    [... following binary part ...]

    From my axis2 standalone clients can not access the part of the non-binary response .. but I have no idea how to be able to save the attachment in the response. I did several tests but failed to solve the problem.

    I also tried to do so:


    DataHandler handler = out.getStreamData();

    File tempFile = File.createTempFile("tempfile", ".pdf");
    FileOutputStream fos = new FileOutputStream(tempFile);
    handler.writeTo(fos);
    fos.flush();
    fos.close();

    This the exception result:


    Exception in thread "main" org.apache.axiom.om.OMException: org.apache.axiom.ext.io.StreamCopyException: Error reading from source
    at org.apache.axiom.attachments.PartContentFactory.createPartContent(PartContentFactory.java:153)
    at org.apache.axiom.attachments.PartImpl.fetch(PartImpl.java:176)
    at org.apache.axiom.attachments.PartImpl.getContent(PartImpl.java:149)
    at org.apache.axiom.attachments.PartImpl.writeTo(PartImpl.java:238)
    at org.apache.axiom.attachments.PartDataHandler.writeTo(PartDataHandler.java:65)
    at TestMyAxis2.main(TestMyAxis2.java:176)
    Caused by: org.apache.axiom.ext.io.StreamCopyException: Error reading from source
    at org.apache.axiom.attachments.utils.BAAOutputStream.readFrom(BAAOutputStream.java:114)
    at org.apache.axiom.attachments.impl.BufferUtils.inputStream2OutputStream(BufferUtils.java:76)
    at org.apache.axiom.attachments.PartContentFactory.createPartContent(PartContentFactory.java:119)
    ... 5 more
    Caused by: java.io.IOException: Attempted read on closed stream.
    at org.apache.commons.httpclient.AutoCloseInputStream.isReadAllowed(AutoCloseInputStream.java:183)
    at org.apache.commons.httpclient.AutoCloseInputStream.read(AutoCloseInputStream.java:107)
    at java.io.FilterInputStream.read(Unknown Source)
    at org.apache.axiom.om.util.DetachableInputStream.read(DetachableInputStream.java:147)
    at org.apache.james.mime4j.io.BufferedLineReaderInputStream.fillBuffer(BufferedLineReaderInputStream.java:111)
    at org.apache.james.mime4j.io.MimeBoundaryInputStream.fillBuffer(MimeBoundaryInputStream.java:223)
    at org.apache.james.mime4j.io.MimeBoundaryInputStream.read(MimeBoundaryInputStream.java:157)
    at org.apache.james.mime4j.io.BufferedLineReaderInputStream.fillBuffer(BufferedLineReaderInputStream.java:111)
    at org.apache.james.mime4j.io.BufferedLineReaderInputStream.read(BufferedLineReaderInputStream.java:158)
    at org.apache.james.mime4j.io.LineReaderInputStreamAdaptor.read(LineReaderInputStreamAdaptor.java:67)
    at org.apache.axiom.attachments.utils.BAAOutputStream.readFrom(BAAOutputStream.java:112)
    ... 7 more

    Can anyone help me … I’m really desperate and frustrated.

  2. @JavaLike, As the error indicates you are trying to read from an already closed stream. “Caused by: java.io.IOException: Attempted read on closed stream”. Check your client code and see how you are reading it.

  3. Hi George,
    thank’s for your reply.

    I have noticed the IO exception, but I do not understand … the returned object should already be consistent (Metadata + Binary).

    out.getStreamData ();

    out or the object returned by the web service.
    I can retrieve the metadata from “out” but not the binary part …

  4. Hi,

    I am trying to display the image in jsp from SOAP response, but i am receiving as attachement encoded data, please find the blow code and help me,

    BBW

    PNG

  5. SoapUI needs set request properties to do the example
    – Enable MTOM = true
    – Force MTOM = true

  6. Hi George,

    Is it possible to rename href (or cid) in xop ?
    So in case of many files, a client can see “friendly” file names

Leave a Reply

Your email address will not be published. Required fields are marked *

Paged comment generated by AJAX Comment Page
© 2024 Globinch Java Forum - Theme by WPEnjoy · Powered by WordPress