Binary Data with Axis2

Archived Content
This article is provided for historical perspective only, and may not reflect current conditions. Please refer to relevant product page for more up-to-date product information and resources.
  • By Deepal Jayasingha
  • 21 Jul, 2008

Introduction

With Web services, there are many instances in which, we need to send and receive binary data. As a result, binary data handling is becoming a key feature for most Web services frameworks. Being one of the most commonly used Web services engines, Axis2 also adds support for binary data handling. In addition to this, Axis2 has first class support for storing binary data at the XML inofoset level, where you could simply store and work on binary data with AXIOM.

AXIOM is the XML infoset representation in Axis2. AXIOM has inbuilt support for MTOM at the infoset level. This is how you get MTOM support in Axis2.

In this tutorial we will not discuss how MTOM works or how Axis2 supports MTOM. Rather, we will discuss how to write a service to handle binary data, as well as creating clients to access such a service.

Table of Contents

Writing the Service

There are three main ways in which we can write our service to handle binary data. Amongst them, the first two methods can be considered as externally visible means of handling the binary data. What we mean by externally visible is that, in the WSDL file we are able to see the service as containing binary data handling operations. Where as in the third option, you will not be able to see that in the WSDL.

  1. Writing method signature with DataHandler

  2. Writing method signature with byte[]

  3. Writing method signature with Axiom

Method signature of the above three options will look like the following:

1 :-

public void doBinaryWithDataHandler(DataHandler data){

}

2 :-

public void doBinaryWithByteArray(byte[] data){

}

3 :-

public void doBinaryWithOM(OMElement data) {

}

For simplicity, all of the above methods are written such they send binary data to the server, not read data from the server. Accepting data from the server is a matter of changing the return type form “void” to whatever the data type returned.

Now, let's look at sample service for all the above methods. Our service implementation class is such that it gets an image as the binary data and saves the file in the file system.

 

 
import org.apache.axiom.attachments.ByteArrayDataSource;
import org.apache.axiom.attachments.utils.DataHandlerUtils;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import javax.activation.DataHandler;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryService {

public static final String fileName = "path to the file /outputfile.jpg";
public void doBinaryWithDataHandler(DataHandler data) {
try {
File outFile = new File(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
data.writeTo(fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public void doBinaryWithByteArray(byte[] data) {
try {
File outFile = new File(fileName);
ByteArrayDataSource dataSource = new ByteArrayDataSource(data);
DataHandler dh = new DataHandler(dataSource);
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
dh.writeTo(fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public void doBinaryWithOM(OMElement data) {
OMNode node = data.getFirstOMChild();
File outFile = new File(fileName);
try {
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
if (node instanceof OMText) {
OMText txt = (OMText) node;
if (txt.isOptimized()) {
DataHandler dh = (DataHandler) txt.getDataHandler();
dh.writeTo(fileOutputStream);
} else {
DataHandler dh = (DataHandler) DataHandlerUtils .getDataHandlerFromText(txt.getText(), null);
dh.writeTo(fileOutputStream);
}
}
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

 

Once you have the source code with you, you can now start Axis2 and deploy this particular service using the following code:

new AxisServer().deployService(BinaryService.class.getName());

Note : Before deploying the service set the output location, i.e. set the fileName variable at the top of the service source code to a real location on your system. Else, you would get a runtime exception.

Once you run the above code, it will start Axis2 on port 6060 and you are able to see the corresponding WSDL by browsing the following location:

https://localhost:6060/axis2/services/BinaryService?wsdl

If you closely look at the auto-generated WSDL, you will see that for two of the methods it has the schema type as “base64Binary”, and for the other, as “anyType”.

 

Writing the Client

Now, let's look at how we are going to write our client to invoke the service..



public static void main(String[] args) throws Exception {

RPCServiceClient client = new RPCServiceClient();

Options opts = new Options();

opts.setAction("ns:doBinaryWithByteArray");

EndpointReference to = new EndpointReference();

to.setAddress("https://localhost:6060/axis2/services/BinaryService");

opts.setTo(to);

client.setOptions(opts);

DataHandler dh = new DataHandler(new FileDataSource("file path to image location"));

client.invokeRobust(new QName("https://ws.apache.org/axis2", "doBinaryWithByteArray"),

new Object[] { dh });

}

Here we have used a very convenient method to invoke a service, which is RPC ServiceClient.

  • First, create the serviceClient

  • Next, create an option object and set the SOAP action and the end point reference address.

  • Next, we set options to the client

  • Then, we create the data handler with the image path. First copy the image attached with this article to your file system. Then, get the full path for that file and create the data handler by replacing "file path to image location" with that on your system.

  • Finally, invoke the service as shown.

Once you invoke the service you will be able to see the exact copy of the image in the output location that was given in the service to save the file returned.

Now, change the method name to “doBinaryWithDataHandler” and follow ip the same steps. Thereafter change the method name to “doBinaryWithOM” and then follow the exact same steps. This way, you can try out all three different ways of dealing with binary data using the same client and the service given earlier.

Conclusion

In this tutorial, we discussed different ways in which we can write a POJO (Plain Old Java Object) class to handle binary data. As we have discussed in this tutorial, there are three main ways of doing this. In addition to that, we also discussed writing a simple client to invoke the service and sending binary data to the server. We can easily extend this sample to receive binary data from the server, simply by inverting the logic in the service and client.

About Author

  • Deepal Jayasingha
  • WSO2 Inc.