Saturday, January 3, 2009

Using MTOM with Axis2

MTOM provides a way to send binary data as it is without encoding it to a text format. Axis2 ADB has built in support for MTOM. Therefore it is almost a trivial task to send and receive binary data using axis2.

Here is an sample wsdl

<definitions xmlns:tns="http//tempuri.org/sample"
xmlns:ns1="http//tempuri.org/sample/types"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http//tempuri.org/sample">
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http//tempuri.org/sample/types"
targetNamespace="http//tempuri.org/sample/types"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="echoBinaryData">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="param" type="xsd:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="echoBinaryDataResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="param" type="xsd:base64Binary"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>

<message name="EchoBinaryDataRequest">
<part name="part1" element="ns1:echoBinaryData"/>
</message>
<message name="EchoBinaryDataResponse">
<part name="part1" element="ns1:echoBinaryDataResponse"/>
</message>

<portType name="SamplePortType">
<operation name="echoBinaryData">
<input message="tns:EchoBinaryDataRequest"/>
<output message="tns:EchoBinaryDataResponse"/>
</operation>
</portType>

<binding name="SampleSoap11Binding" type="tns:SamplePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="echoBinaryData">
<soap:operation style="document" soapAction="urn:echoBinaryData"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<binding name="SampleSoap12Binding" type="tns:SamplePortType">
<soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="echoBinaryData">
<soap12:operation style="document" soapAction="urn:echoBinaryData"/>
<input>
<soap12:body use="literal"/>
</input>
<output>
<soap12:body use="literal"/>
</output>
</operation>
</binding>

<service name="SampleService">
<port name="Soap11Port" binding="tns:SampleSoap11Binding">
<soap:address location="http://localhost:8080/axis2/services/SampleService"/>
</port>
<port name="Soap12Port" binding="tns:SampleSoap12Binding">
<soap:address location="http://localhost:8080/axis2/services/SampleService"/>
</port>
</service>
</definitions>

then both client and server side code can be generated with the wsdl2java tool.

it sends and receives a binary file. Following client and server side code can be used to send and receive binary data.
try {
SampleServiceStub stub = new SampleServiceStub("http://localhost:8080/axis2/services/SampleService");
stub._getServiceClient().getOptions().setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);
String clientFolder = "/home/amila/work/articles/binary/samples/mtom/client/";
DataSource dataSource = new FileDataSource(clientFolder + "client.jar");
DataHandler request = new DataHandler(dataSource);
DataHandler response = stub.echoBinaryData(request);
FileOutputStream fileOutputStream = new FileOutputStream(clientFolder + "server.jar");
response.writeTo(fileOutputStream);
fileOutputStream.flush();
System.out.println("Saved the file to client folder");
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (java.rmi.RemoteException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

Skelton code.
public javax.activation.DataHandler echoBinaryData
(
javax.activation.DataHandler param
) {

String serverFolder = "/home/amila/work/articles/binary/samples/mtom/server/";
try {
FileOutputStream fileOutputStream = new FileOutputStream(serverFolder + "client.jar");
param.writeTo(fileOutputStream);
fileOutputStream.flush();
System.out.println("Saved the file to client.jar");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

FileDataSource fileDataSource = new FileDataSource(serverFolder + "server.jar");
DataHandler dataHandler = new DataHandler(fileDataSource);
return dataHandler;
}

6 comments:

Savvy said...

I am using axis2 and ADB.The task i am working on is: copying database records from clients local DB and giving results to WebService to copy those records to main applications DB.Data consists of string as well as binary data.

1)while reading data from client DB,i am creating array of File objects.This File object is the one defined by Stub. code snippet is:
File file = new File();
byte [] fileContent = resultSet.getBytes("FileContent");
javax.mail.util.ByteArrayDataSource dataSource = new javax.mail.util.ByteArrayDataSource(fileContent,"application/msword");
DataHandler dh = new DataHandler(dataSource);
file.setFileContent(dh);

2) Then calling the stub method as:
NYCRADDSDownloadServiceStub.UploadDocuments uploadDocuments = new NYCRADDSDownloadServiceStub.UploadDocuments();
uploadDocuments.setDocumentsList(filesArray);//array of stub File Objects
stub.UploadDocuments(uploadDocuments);

3)Web service code is:
public void UploadDocuments(File [] documentsList)
{
UploadBO uploadBO = new UploadBO();
uploadBO.uploadDocuments(documentsList);
}

4) i dont get any binary data when i do (File)document.getFileContent() in web service call.Here the File object is what i defined ,a java bean kind od object.


Can u pls help me by pointing where i am missing something.I can provide more info if needed

Amila Suriarachchi said...

First please generate the code using -u option which gives you unpacked classes.

Did you try to save the content of the DataHander to some location?

DataHandler response = stub.echoBinaryData(request);
FileOutputStream fileOutputStream = new FileOutputStream(clientFolder + "server.jar");
response.writeTo(fileOutputStream);
fileOutputStream.flush();

you may not seen the binary string since it is created when the time you try to read it.

Could you please send the request message through the tcpmon[1] and see whether correct message being send to server.

[1] http://ws.apache.org/commons/tcpmon/

Anonymous said...

Hi,

I try to do something like you but I use a byte array in my server method. The problems is that I always have an empty byte array on the server side.

My client code is like your code.

Thank you for your help

St├ęphane

rohans said...

can you please post the client generation code? what databinding method are you using? xmlbeans or adb?

Amila Suriarachchi said...

I have used adb as the databinding. you can generate the code with the wsdl2java tool with the given wsdl.

Satya said...

I have jax-rpc webservice provider which sends attachments. I want to use axis2,could you pl. point me to some samples which I can refer to. I tried, but could not get a concrete one.

Thanks in advance
Satya