Downloading files using SwA (Soap With Attachments)

SOAP based web services over HTTP have the ability to send and receive attachments (aka SwA). In fact there are multiple ways in which attachments can be sent with a web service response. The most simple way is to encode the file data as characters and embed coded characters as body of SOAP message response. Another way is to send a reference to the binary data which is external to SOAP message but is part of the HTTP response. Both these approaches are shown below with the help of example. The corresponding SOAP response clearly shows how does the one differs from other.

SwA code

Without MTOM

Let us first see how to send attachment from server to client without using MTOM:

ImageService

package com.sample;

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

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style=Style.RPC)
public interface ImageService {

	public Image getImage(String name) throws IOException;
}

ImageServiceImpl

package com.sample;

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.soap.MTOM;

@WebService(endpointInterface="com.sample.ImageService")
public class ImageServiceImpl implements ImageService {


	@Override
	public Image getImage(String name) throws IOException {
		BufferedImage bufImage = ImageIO.read(new File("c://images//" + name));
		return bufImage;
	}
}

ImageServicePublisher

package com.sample;

import javax.xml.ws.Endpoint;
import com.sample.ImageServiceImpl;

public class ImageServicePublisher {

	public static void main(String[] args) {
		
		Endpoint.publish("http://localhost:9999/com.sample",new ImageServiceImpl());
	}
}

ImageClient

package com.sample;

import java.io.IOException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class ImageClient {

	public static void main(String[] args) throws IOException {
		URL url = new URL("http://localhost:8080/com.sample?wsdl");
		QName qname = new QName("http://sample.com/","ImageServiceImplService");
		Service service = Service.create(url, qname);
		ImageService sp = service.getPort(ImageService.class);
		System.out.println(sp.getImage("rss.jpg"));
	}
}

SOAP response:

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset="utf-8"

5e
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body>
1000
<ns2:getImageResponse xmlns:ns2="http://sample.com/"><return>iVBORw0KGgoAAAANSUhEUgAAAMkAAACQCAIAAAAtJdhtAACAAElEQVR42uy9B3Rb15W2jck/k0kmTibxTLrtVMdxXBLHdmSrWb13qlAiRYpN7BJ7771TbCIlkmLvKCQaAbD33jsJECR6B9E77ncuQMmynWQyGU+cyW+sd90FXrAB98He7z5nnwOEyQwBmS03yPqFyWiR9T4EZLYIfGUwQxoIUkOQ1gzpwYPgUeNTgftmWODb9JbvsUpvgAz6XRkNsMBPAe3+RbPRIv3H+vL2N7mZ//dviP+SLRiA59jSQjBeOgtOVph2wYJlgr+0nADfoLUcTc9+3GT5rZY7RuPz/wOM18fHL2//MGw9/8VTnna1G1nMu2DtsmWCpbec2WULjl4myKCDjLDMJp0JjlZ6PSyj+TNPyWQyGY3Gj/+O5Wk+DWTmL6/6Pzhbz5/7FHI6g15v1BkMOpNRb4XJIg2kkUNauVmnMBvkJpPCBCmNkNIExzjDs7AGRzGz0WQywGwBYp/7tQZo986Xt38ctp46HmtK2r196sI/kyWuaD92UyYVZFBCBjksjQTSSiC9FDJKIGgHgmQQJLUclZYfsQqYNDiqGc0G658wWNAzWCyawfLll3T9w7L11LibnyUsq54GMZ0FFzEsoxjSCSAVF1JwzXIWJGNBCiakYkM6DmTgQWYeBAEJIKMQMkkg047ZLIcFqSz1AGDL+Awv/VMBvL5k6x+ILZMe1ifZMjyVhQAjHFbgIk4HmRWQmgEp1807yxrhgpwzK96a4lMnuOtjks1pcF/KnJKxp5S8aZ1wVi+a0UsX9EqqXkXXa5lGwBzgzCy1RjJLADNa/taXbP2jswU7oU+AZaVKB9eFZpVFCsgkUrJHVYy+HVoXb4W8NUtcG8ctDrXO9aPWxgnrE3jqNB6cZC0QeEsEwQpRsE7SSWY1Owt6xYpJQ4P0DMgssORKBfwLIY31jz7LjF+y9Y/F1m5xZwAW2wLT7giEzqC2hBK1WS8xawVmDVslWOWt91JH6zZHnix0lawN1c731WzPtW/Nk7irffz1AfpcO3+tZ3GgbnO8aXO0hjZUsT5YLljFcteI/HWycLN7hz2ilSyY1XQ4aRpFkHEHMqrMJq3lT5t3BzQsN4PlBlt+eAzt/4/X+Iti6HNkEbE7avBJtkAEMRiVFsMuM6qYMs6saHOQOU/aGKlf6S6iDxbTh8uXekrme56sjjQx5kms5U6TZEXNmVIwhrmLeOZk82JHwWpXPn+6hjtby5mr58418pfR4o12OaNPy5/UiRf00g2DkgHpRZYUqX7q9PXQ0zLVZLn9w49K/COzZTJqrWyB9PTcgIDWcsllIMAo2BP06dalvspZUuFUW/pye9oKOZXWXzRLfgBiGAhd0921lJbC+uK4TmTBCPExa6ZVvNTGGH6y2VMgmiznjJSwRoEescfLudN1goVmySpOskHZ2R5U86ZNcipk5D+tKK2J0gD9sSGxL9n6v8eW0aAxmXWWAXGTZRZHbzBrjEY5fLGNfCVncmsKNU95OIlJnWyJmWgKXyHGz7ZGA8IWO/KpozWzPVVjHVXd2LLqgpjKvAjvW4c8bN7L8Ds
........................................
........................................

As we can see that the image data is being sent as part of the SOAP message body. You may download the working application of downloading image contents from server which is sent as character data:

Using MTOM to send binary data

Now let us make a small change to the Service Implementation Bean class as shown below:

ImageServiceImpl

package com.sample;

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;

@WebService(endpointInterface="com.sample.ImageService")
@MTOM
public class ImageServiceImpl implements ImageService {


	@Override
	public Image getImage(String name) throws IOException {
		BufferedImage bufImage = ImageIO.read(new File("c://images//" + name));
		return bufImage;
	}
}

Thus we simply directed JAX-WS to use MTOM so that the extra work of encoding and decoding binary data to character data on both the sides can be avoided. Now run the web service publisher and client and see the SOAP message by using a message interceptor.

SOAP response:

The SOAP response in this case is reproduced here:

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: multipart/related;start="<rootpart*d1b00b0a-ad74-44a6-8408-ecd55207d30b@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:d1b00b0a-ad74-44a6-8408-ecd55207d30b";start-info="text/xml"

24a
--uuid:d1b00b0a-ad74-44a6-8408-ecd55207d30b
Content-Id: <rootpart*d1b00b0a-ad74-44a6-8408-ecd55207d30b@example.jaxws.sun.com>
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getImageResponse xmlns:ns2="http://sample.com/"><return><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:6a4682ab-ca2a-4943-9469-8de5a9d5b1ee@example.jaxws.sun.com"></xop:Include></return></ns2:getImageResponse></S:Body></S:Envelope>
1000

--uuid:d1b00b0a-ad74-44a6-8408-ecd55207d30b
Content-Id: <6a4682ab-ca2a-4943-9469-8de5a9d5b1ee@example.jaxws.sun.com>
Content-Type: image/png
Content-Transfer-Encoding: binary

‰PNG


The following link can be used to download an application which implements MTOM:



Points to remember

The significant points to remember about attachments with SOAP and MTOM are:

  • Without MTOM,Base64 encoding is used to encode binary data to character data and hence results in extra processing.
  • The content type of Base64 encoding approach is text/xml and content type “multipart/related” is used with MTOM.
  • Since MTOM doesn’t specify the file type hence some DataHandler is required for processing of binary data whereas there is no such requirement in case of base64 encoding.
Copyright © 2013 Java Experience. All rights reserved.