JAX-WS Binary Data passing: using MTOM

The preferred way of binary data passing in the JAX-WS is MTOM. In the previous blog (JAX-WS Binary Data Passing: using base64binary), binary data has been passed in the body of the SOAP. But in the MTOM, binary data is passed as a attachment. See the web service (which is modified from the previous blog).

package org.ojitha.wsex4;

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

import javax.imageio.ImageIO;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import javax.xml.ws.soap.MTOM;
import javax.xml.ws.soap.SOAPBinding;


@WebService(serviceName="ImageService", wsdlLocation="org/ojitha/wsex4/ImageService.wsdl")
@MTOM
public class ImageService {
	
	@WebMethod
	public Image getImage(String imgName) throws IOException{
		System.out.println("Image name "+imgName);
		return ImageIO.read(new File(imgName));
	}
	
	public static void main(String[] args){
		Endpoint endpoint = Endpoint.create(new ImageService());
		SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
		binding.setMTOMEnabled(true);
		int port = 9875;
		String url = "http://localhost:" + port + "/image";
		endpoint.publish(url);
		System.out.println(url);
	}

}

Line number 27 and 28 is very important because in 27 you get the SOAP binding to enable the MTOM in line number 28. In the line 16, you need to add the @MTOM annotation. However, you need to do modifications to Schema data type file as shown in the following. Therefore, modified WSDL is provided in the line number 15.

<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. 
	RI's version is JAX-WS RI 2.1.6 in JDK 6. -->
<xs:schema xmlns:tns="http://wsex4.ojitha.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
	version="1.0" targetNamespace="http://wsex4.ojitha.org/">

	<xs:element name="IOException" type="tns:IOException"></xs:element>

	<xs:element name="getImage" type="tns:getImage"></xs:element>

	<xs:element name="getImageResponse" type="tns:getImageResponse"></xs:element>

	<xs:complexType name="getImage">
		<xs:sequence>
			<xs:element name="arg0" type="xs:string" minOccurs="0"></xs:element>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="getImageResponse">
		<xs:sequence>
			<xs:element name="return" type="xs:base64Binary"
				minOccurs="0" xmime:expectedContentTypes="application/octet-stream"   xmlns:xmime="http://www.w3.org/2005/05/xmlmime">
				</xs:element>
		</xs:sequence>
	</xs:complexType>

	<xs:complexType name="IOException">
		<xs:sequence>
			<xs:element name="message" type="xs:string" minOccurs="0"></xs:element>
		</xs:sequence>
	</xs:complexType>
</xs:schema>

In the line umber 21, you need to provide the expected content type for the MTOM (This is the only modification). You have to run the following command to create the client code from the WSDL because data type schema is changed as shown in the above code.

image

In the generated code you need to provide the new WSDL file location as shown in the following code. The generated code should be copied to the relevant package where Client can access. In the following generated ImageService_Service.java, line number 19, 32 and 34 should be changed to the proper location of the WSDL.

package org.ojitha.wsex5.client;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;


/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.1.6 in JDK 6
 * Generated source version: 2.1
 * 
 */
@WebServiceClient(name = "ImageService", targetNamespace = "http://wsex4.ojitha.org/", wsdlLocation = "file:../../wsex4/ImageService.wsdl")
public class ImageService_Service
    extends Service
{

    private final static URL IMAGESERVICE_WSDL_LOCATION;
    private final static Logger logger = Logger.getLogger(org.ojitha.wsex5.client.ImageService_Service.class.getName());

    static {
        URL url = null;
        try {
            URL baseUrl;
            baseUrl = org.ojitha.wsex5.client.ImageService_Service.class.getResource(".");
            url = new URL(baseUrl, "file:../../wsex4/ImageService.wsdl");
        } catch (MalformedURLException e) {
            logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/test/ImageService.wsdl', retrying as a local file");
            logger.warning(e.getMessage());
        }
        IMAGESERVICE_WSDL_LOCATION = url;
    }

    public ImageService_Service(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    public ImageService_Service() {
        super(IMAGESERVICE_WSDL_LOCATION, new QName("http://wsex4.ojitha.org/", "ImageService"));
    }

    /**
     * 
     * @return
     *     returns ImageService
     */
    @WebEndpoint(name = "ImageServicePort")
    public ImageService getImageServicePort() {
        return super.getPort(new QName("http://wsex4.ojitha.org/", "ImageServicePort"), ImageService.class);
    }

    /**
     * 
     * @param features
     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
     * @return
     *     returns ImageService
     */
    @WebEndpoint(name = "ImageServicePort")
    public ImageService getImageServicePort(WebServiceFeature... features) {
        return super.getPort(new QName("http://wsex4.ojitha.org/", "ImageServicePort"), ImageService.class, features);
    }

}

The client code is as follows

package org.ojitha.wsex5.client;

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

import javax.activation.DataHandler;
import javax.imageio.ImageIO;

public class Client {

	/**
	 * @param args
	 * @throws IOException_Exception 
	 */
	public static void main(String[] args) throws IOException_Exception {
		 ImageService_Service service = new ImageService_Service();
	       ImageService port = service.getImageServicePort();

	       DataHandler image = port.getImage("rainbow.jpg");
	       dump(image);


	}
	 private static void dump(DataHandler dh) {
	       System.out.println();
	       try {
	          System.out.println("MIME type: " + dh.getContentType());
	          System.out.println("Content:   " + dh.getContent());
	          InputStream in = dh.getInputStream();
	          BufferedImage buffferedImage = ImageIO.read(in);
	          ImageIO.write(buffferedImage, "jpg", new File("test.jpg"));
	       }
	       catch(IOException e) { System.err.println(e); }
	    }


}

Before run client, run the service. When you execute, the test.jpg file should be in your root.  I used apache tcpmon to trace the response.

image

As shown in the above picture, attachment is going after the SOAPEnvelop.

image

Above picture shows the output of the SoaoUI. You can download the source.

Comments

Popular posts from this blog

How To: GitHub projects in Spring Tool Suite

Spring 3 Part 7: Spring with Databases

Parse the namespace based XML using Python