Last Updated on 21 December 2019   |   Print Email
In this Java web services tutorial, we are going to discuss how MTOM (Message Transmission Optimization Mechanism) can be used to optimize binary data transfer through web services with JAX-WS (Java API for XML-based Web Services). We will go from background of MTOM and its usages to development of a simple web services application that can transfer large binary data (upload and download files) in the optimized way.
1. Why MTOM?
By default, binary data is converted to base64Binary or hexBinary XML data type within a SOAP envelope, meaning that the raw bytes are encoded as a String using base64 technique. For example, the following XML snippet is content of such a SOAP message:
Look at the text inside the element <arg1> - it is the encoded form of the binary data in base64 format. Basically, the base64 encoding technique bloats the original data by a factor of 1.33x (with UTF-8 encoding) or 2.66x (with UTF-16), so it becomes very inefficient when dealing with a large amount of data. To overcome this drawback, MTOM is defined as a specification for optimizing the transmission of this kind of data type in SOAP messages, and XOP (XML-binary Optimized Packaging) is the concrete implementation. The following example is content of a HTTP POST request which is generated by MTOM/XOP:
Here, the request’s content type becomes multipart/related in which the SOAP message and the binary data are separated as individual parts of a MIME message. The SOAP message itself doesn’t contain the binary data. Instead, it has a reference to the part that contains the actual binary data:
And the binary data is attached to the request as a MIME attachment which is outside the SOAP message.
2. Enabling MTOM in JAX-WS
In JAX-WS, it’s easy to enable MTOM for a web service endpoint by using either the @MTOM or @BindingType annotations. At the client side, MTOM can be enabled either by passing a new instance of MTOMFeature class when getting a reference to the web service endpoint (port), or by calling the SOAPBinding.setMTOMEnabled(true) method on the binding provider object. Here are the usages and examples in details.
Enabling MTOM for the web service endpoint
The following example illustrates a web service endpoint is annotated with the @MTOM annotation:
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.soap.MTOM;
@WebService
@MTOM
public class MyWebService {
@WebMethod
public void upload(byte[] data) {
// implementation details...
}
}
That enables MTOM support for the MyWebService endpoint. The @MTOM annotation has two optional parameters:
enabled: specifies whether MTOM feature is enabled (true) or disabled (false).
threshold: specifies the size (in bytes) above which the binary data will be sent as attachment. This would be useful to enable MTOM only for data which is larger than a specified amount.
This example shows MTOM is used but disabled:
@WebService
@MTOM(enabled = false)
public class MyWebService {
}
This example shows MTOM is enabled only for binary data which is larger than 10KB (10240 bytes):
@WebService
@MTOM(threshold = 10240)
public class MyWebService {
}
An alternative way is using the @BindingType annotation with an appropriate value for the SOAP version used. For example:
Enabling MTOM with SOAP version 1.1:
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
@WebService
@BindingType(value = SOAPBinding.SOAP11HTTP_MTOM_BINDING)
public class MyWebService {
}
Enabling MTOM with SOAP version 1.2:
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
@WebService
@BindingType(value = SOAPBinding.SOAP12HTTP_MTOM_BINDING)
public class MyWebService {
}
From the above examples, we can see that using the @MTOM annotation is preferred as its succinct and flexibility (enabled/disabled and threshold).
Enabling MTOM for the client
The following example shows how to enable MTOM at the client by passing a new instance of the MTOMFeature class when getting a proxy reference the web service endpoint:
import javax.xml.ws.soap.MTOMFeature;
MyWebServiceService service = new MyWebServiceService();
MyWebService port = service.getMyWebServicePort(new MTOMFeature());
Suppose that the MyWebServiceService and MyWebService classes are generated by the wsimport tool. And similar to the @MTOM annotation, we can also specify the enabled and threshold parameters in the MTOMFeature class’ constructor like this:
boolean enabled = true;
int threshold = 10240;
MyWebService port = service.getMyWebServicePort(new MTOMFeature(enabled, threshold));
And here’s an alternative way, calling the SOAPBinding.setMTOMEnabled(true) method:
MyWebServiceService service = new MyWebServiceService();
MyWebService port = service.getMyWebServicePort();
BindingProvider provider = (BindingProvider) port;
SOAPBinding soapBinding = (SOAPBinding) provider.getBinding();
soapBinding.setMTOMEnabled(true);
So far we have understood the advantages of MTOM and how to apply it for a web service end point and client. Now, let’s go through a complete sample application.
3. Code Java Web Service Endpoint
The following class is for a web service endpoint implementation that offers two operations for binary data transfer - files upload and download:
package net.codejava.ws.mtom.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.soap.MTOM;
/**
* A web service endpoint implementation that demonstrates the usage of
* MTOM (Message Transmission Optimization Mechanism).
* @author www.codejava.net
*
*/
@WebService
@MTOM(enabled = true, threshold = 10240)
public class FileTransferer {
@WebMethod
public void upload(String fileName, byte[] imageBytes) {
String filePath = "e:/Test/Server/Upload/" + fileName;
try {
FileOutputStream fos = new FileOutputStream(filePath);
BufferedOutputStream outputStream = new BufferedOutputStream(fos);
outputStream.write(imageBytes);
outputStream.close();
System.out.println("Received file: " + filePath);
} catch (IOException ex) {
System.err.println(ex);
throw new WebServiceException(ex);
}
}
@WebMethod
public byte[] download(String fileName) {
String filePath = "e:/Test/Server/Download/" + fileName;
System.out.println("Sending file: " + filePath);
try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream inputStream = new BufferedInputStream(fis);
byte[] fileBytes = new byte[(int) file.length()];
inputStream.read(fileBytes);
inputStream.close();
return fileBytes;
} catch (IOException ex) {
System.err.println(ex);
throw new WebServiceException(ex);
}
}
}
As we can see, the @MTOM annotation is used to enable binary transfer optimization with the threshold of 10KB.NOTE: You should prepare a file to be sent to the client and correct the file path according to your environment in the download() method.
4. Coding Java Server Program for Web Services
Write a simple server program (console application) that publishes the web services with the following code:
package net.codejava.ws.mtom.server;
import javax.xml.ws.Endpoint;
/**
* A simple web service server.
* @author www.codejava.net
*
*/
public class WebServiceServer {
public static void main(String[] args) {
String bindingURI = "http://localhost:9898/codejava/fileService";
FileTransferer service = new FileTransferer();
Endpoint.publish(bindingURI, service);
System.out.println("Server started at: " + bindingURI);
}
}
Run this program to start the server. We should see the following output in the console:
Server started at: http://localhost:9898/codejava/fileService
5. Code Java Client Program for Web Services
Use the wsimport tool to generate client code for the above web service endpoint (see instructions included in the attached project), then write code for the application client program as follows:
package net.codejava.ws.mtom.client;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.ws.soap.MTOMFeature;
/**
* A client program that demonstrates how to use MTOM to optimize binary data
* transfer with JAX-WS web services.
* @author www.codejava.net
*
*/
public class WebServiceAppClient {
public static void main(String[] args) {
// connects to the web service
FileTransfererService service = new FileTransfererService();
FileTransferer port = service.getFileTransfererPort(new MTOMFeature(10240));
String fileName = "binary.png";
String filePath = "e:/Test/Client/Upload/" + fileName;
File file = new File(filePath);
// uploads a file
try {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream inputStream = new BufferedInputStream(fis);
byte[] imageBytes = new byte[(int) file.length()];
inputStream.read(imageBytes);
port.upload(file.getName(), imageBytes);
inputStream.close();
System.out.println("File uploaded: " + filePath);
} catch (IOException ex) {
System.err.println(ex);
}
// downloads another file
fileName = "camera.png";
filePath = "E:/Test/Client/Download/" + fileName;
byte[] fileBytes = port.download(fileName);
try {
FileOutputStream fos = new FileOutputStream(filePath);
BufferedOutputStream outputStream = new BufferedOutputStream(fos);
outputStream.write(fileBytes);
outputStream.close();
System.out.println("File downloaded: " + filePath);
} catch (IOException ex) {
System.err.println(ex);
}
}
}
As we can see, MTOM is enabled by passing an instance of the MTOMFeature class with an integer indicates a threshold value. This program uploads a file by sending a chunk of bytes to the server, and downloads a file by receiving an array of bytes from the server.NOTE: You should prepare a file to be uploaded to the server and correct the file path according to your environment.
6. Test binary data transfer via web services and inspect SOAP Messages
Now, execute the application client program to test out the web service. We should see the following output at the client:
Server started at: http://localhost:9898/codejava/fileService
Received file: e:/Test/Server/Upload/binary.png
Sending file: e:/Test/Server/Download/camera.png
We inspect the SOAP messages in details by using a monitoring tool such as TCP/IP Monitor in Eclipse IDE. Here’s the summary (WSDL request/response is omitted):
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.
Comments