Month: May 2011

Mtom Using Apache CXF and Maven


MTOM is Message Transmission Optimization Mechanism, is a method to send binary data over web service calls.  Usual web service calls does not let you pass large amounts of data as a part of Web Service method invocations. To solve this, one either employ SOAP with Attachments or Mtom. SOAP with attachments require you to modify the ‘binding’ part of the wsdl exposed by your webservice. With Mtom, you get to skip all that and more. Here i discuss Mtom

You need to do the following things to  transfer binary data using Mtom

  1. Annotate the data that you are sending as attachment
  2. Enable the runtime’s MTOM support.
  3. Use a DataHandler to handle the data that is being sent.

1. Annotate the data that you are sending as an attachment.

Here i annotate the element definition in my xsd file which in turn is used by the wsdl which exposes my webservice. Find below, both the xsd and the wsdl. Highlighted in red is the annotated part of the xsd (mtomElements.xsd)

<?xml version=”1.0″ encoding=”UTF-8″?>
<xsd:schema targetNamespace=”http://mtom.arun.test.com/&#8221;
xmlns:tns=”http://mtom.arun.test.com/&#8221;
xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;
xmlns:xmime=”http://www.w3.org/2005/05/xmlmime”&gt;

<xsd:element name=”mtomRequest”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”documentName” type=”xsd:string” />
<xsd:element name=”documentData” type=”xsd:base64Binary”
                               xmime:expectedContentTypes=”application/octet-stream”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name=”mtomResponse”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”mtomOutput” type=”xsd:string” />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name=”mtomFault”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”errorCode” nillable=”true” type=”xsd:int”    />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

</xsd:schema>

Also, find below the wsdl(MtomApp.wsdl) which uses the mtomElements.xsd

<?xml version=”1.0″ encoding=”UTF-8″?>
<wsdl:definitions
targetNamespace=”http://mtom.arun.test.com/&#8221;
xmlns=”http://mtom.arun.test.com/&#8221;
xmlns:mtom=”http://mtom.arun.test.com/&#8221;
xmlns:soapenc=”http://schemas.xmlsoap.org/soap/encoding/&#8221; xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/&#8221;
xmlns:wsdlsoap=”http://schemas.xmlsoap.org/wsdl/soap/&#8221; xmlns:xsd=”http://www.w3.org/2001/XMLSchema”&gt;

<wsdl:types>
<xsd:schema>
<xsd:import
namespace=”http://mtom.arun.test.com/&#8221;
schemaLocation=”mtomElements.xsd” />
</xsd:schema>
</wsdl:types>

<wsdl:message name=”mtomRequest”>
<wsdl:part element=”mtom:mtomRequest” name=”parameters” />
</wsdl:message>
<wsdl:message name=”mtomResponse”>
<wsdl:part element=”mtom:mtomResponse” name=”parameters” />
</wsdl:message>
<wsdl:message name=”mtomException”>
<wsdl:part element=”mtom:mtomFault” name=”mtomException”>
</wsdl:part>
</wsdl:message>

<wsdl:portType name=”MtomInterface”>

<wsdl:operation name=”mtomOperation”>
<wsdl:input message=”mtomRequest” />
<wsdl:output message=”mtomResponse” />
<wsdl:fault message=”mtomException” name=”mtomException”>
</wsdl:fault>
</wsdl:operation>

</wsdl:portType>

<wsdl:binding name=”MtomServiceSOAPBinding” type=”MtomInterface”>
<wsdlsoap:binding style=”document”
transport=”http://schemas.xmlsoap.org/soap/http&#8221; />
<wsdl:operation name=”mtomOperation”>
<wsdlsoap:operation
soapAction=”” />
<wsdl:input>
<wsdlsoap:body use=”literal” />
</wsdl:input>
<wsdl:output>
<wsdlsoap:body use=”literal” />
</wsdl:output>
<wsdl:fault name=”mtomException”>
<wsdlsoap:fault name=”mtomException” use=”literal” />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

<wsdl:service name=”MtomService”>
<wsdl:port binding=”MtomServiceSOAPBinding” name=”MtomPort”>
<wsdlsoap:address location=”http://localhost:8899/MtomService/myMtomService&#8221; />
</wsdl:port>
</wsdl:service>

</wsdl:definitions>

2. Enable the run time’s MTOM support

This can be done either programatically, or by using configuration. Since im using spring, i specify this in configuration. Find below the appContext.xml that i use. Highlighted in red is the configuration that enables MTOM.

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:context=”http://www.springframework.org/schema/context&#8221;
xmlns:jee=”http://www.springframework.org/schema/jee&#8221; xmlns:jaxws=”http://cxf.apache.org/jaxws&#8221;
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd&#8221;
default-dependency-check=”none” default-lazy-init=”false”>

<!– Load the needed resources that are present in the cxf* jars –>
<import resource=”classpath:META-INF/cxf/cxf.xml” />
<import resource=”classpath:META-INF/cxf/cxf-extension-soap.xml” />
<import resource=”classpath:META-INF/cxf/cxf-servlet.xml” />

<!– Hook up the web service –>
<jaxws:endpoint id=”MtomService” implementor=”com.arun.test.mtom.impl.MtomImplementation”
address=”/arunMtomService”>
        <jaxws:properties>
          <entry key=”mtom-enabled” value=”true”/>
        </jaxws:properties>  
</jaxws:endpoint>
</beans>

3.  Use a Data Handler to handle the data that is being passed from the client to the server

Find below the classes which act as server and client. The DataHandler part is highlighted in red.

Server Code

package com.arun.test.mtom.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import javax.activation.DataHandler;

import com.test.arun.mtom.MtomException;
import com.test.arun.mtom.MtomInterface;
import com.test.arun.mtom.MtomRequest;
import com.test.arun.mtom.MtomResponse;

public class MtomImplementation implements MtomInterface{

@SuppressWarnings(“restriction”)
public MtomResponse mtomOperation(MtomRequest parameters)
throws MtomException {

/* Creating a Response object */
MtomResponse mtomResponse = new MtomResponse();
mtomResponse.setMtomOutput(“Success”);

/* DataHandler – The object which contains the File Data */
        DataHandler handler = parameters.getDocumentData();
try {

/* Creating an InputStream from the DataHandler */
InputStream is = handler.getInputStream();
String fileName = “/home/mindtree/Desktop/”+parameters.getDocumentName();

/* Creating an Output stream and writing to the target file */
OutputStream os = new FileOutputStream(new File(fileName));
byte[] b = new byte[100000];
int bytesRead = 0;
while ((bytesRead = is.read(b)) != -1) {
os.write(b, 0, bytesRead);
}
os.flush();
os.close();
is.close();

} catch (Exception e) {

System.out.println(“Exception in webservice : “+e.getMessage());
mtomResponse.setMtomOutput(“Failure : Exception :”+e.getMessage());
}

return mtomResponse;
}

}

Client Code

Run the client code to call the webservice method ‘mtomOperation’.  Here the file that is passed is mtom.service.war at /home/mindtree/Desktop/. When the web service method gets executed, it gets saved as arun_mtom.service2.war on the server side at the location /home/mindtree/Desktop.

package com.arun.test.mtom.client.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.test.arun.mtom.MtomInterface;
import com.test.arun.mtom.MtomRequest;
import com.test.arun.mtom.MtomResponse;

public class MtomClient {

public static void main(String[] args) {

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(MtomInterface.class);
factory.setAddress
(“http://172.25.200.107:8899/mtom.service/arunMtomService&#8221;);
MtomInterface client = (MtomInterface) factory.create();

MtomResponse output = new MtomResponse();

/* Setting the input values */
MtomRequest input=new MtomRequest();
input.setDocumentName(“arun_mtom.service2.war”);
        DataSource source = new FileDataSource(new File(“/home/mindtree/Desktop/mtom.service.war”));
        input.setDocumentData((new DataHandler(source)));

try {
output=client.mtomOperation(input);
System.out.println(output.getMtomOutput());
}catch(Exception e) {

System.out.println(“Exception : “+e.getMessage());
}

System.out.println(“Done”);

}

}

Also, find below the pom.xml that i use for compiling and creating my webservice

<project xmlns=”http://maven.apache.org/POM/4.0.0&#8243; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”&gt;
<modelVersion>4.0.0</modelVersion>
<groupId>com.arun.test.mtom</groupId>
<artifactId>MtomApp</artifactId>
<name>MtomApp</name>
<packaging>war</packaging>
<version>1.0</version>
<description>Mtom Application</description>
<url>http://maven.apache.org</url&gt;

<properties>
<cxf.version>2.1</cxf.version>
<spring.version>3.0.5.RELEASE</spring.version>
</properties>

<build>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.0.6</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/MtomApp.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
</plugin>

</plugins>
<finalName>mtom.service</finalName>
</build>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-common-utilities</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>

<dependency>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
<type>jar</type>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opensymphony.quartz</groupId>
<artifactId>quartz-all</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>

<dependency>
<groupId>jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</dependency>

</dependencies>

</project>

For more on MTOM using  Apache CXF, go to http://cxf.apache.org/docs/mtom.html

Regards,

The NonsenseLogger

Advertisements