Consuming MTOM/XOP web services from Axis 1

Axis 1 does not support MTOM specification for the client side (and it only supports this specification partially for the server side [1]). However, sometimes this combination is required due to technologic restrictions.

In this tutorial is described a way to access MTOM/XOP web services for file transfers using Axis 1 as client by implementing two Java projects:

  1. Creating a MTOM/XOP web service with Apache CXF 2
  2. Consuming the web service with Apache Axis 1

1. Creating a MTOM/XOP web service with Apache CXF

Let’s create a simple web service exposing a XOP node to download a file. Several samples to build a CXF web services client are available [2], so only main resources are detailed.

1.a. Web service interface

package cxf.mtom.server.service;

import javax.jws.WebService;

import cxf.mtom.server.bean.ResponseDownloadFile;

public interface DownloadFile {

	ResponseDownloadFile getFile() throws Exception;


1.b. Web service implementation

package cxf.mtom.server.service;


import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.jws.WebService;

import cxf.mtom.server.bean.ResponseDownloadFile;

@WebService(endpointInterface = "cxf.mtom.server.service.DownloadFile", serviceName = "DownloadFileWS")
public class DownloadFileImpl implements DownloadFile {

	public ResponseDownloadFile getFile() throws Exception {
		ResponseDownloadFile rdf = new ResponseDownloadFile();
		rdf.setFile(new DataHandler(new FileDataSource(new File("C:/tmp/readme.txt"))));
		return rdf;


1.c. Web service response bean

package cxf.mtom.server.bean;

import javax.activation.DataHandler;

 * Web service response bean.
public class ResponseDownloadFile {

	private String fileName;
	private String fileType;
	private DataHandler file;

	public String getFileName() {
		return fileName;

	public void setFileName(String fileName) {
		this.fileName = fileName;

	public String getFileType() {
		return fileType;

	public void setFileType(String fileType) {
		this.fileType = fileType;

	public DataHandler getFile() {
		return file;

	public void setFile(DataHandler file) {
		this.file = file;

1.d. Spring configuration for CXF

<beans xmlns=""

  <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" />
  <jaxws:endpoint id="downloadfile"
           <entry key="mtom-enabled" value="true"/>

1.e. Web descriptor

<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"


1.f. Generated WSDL (p. e. http://localhost:8080/cxfMTOMServer/services/DownloadFileWS?wsdl)

<?xml version='1.0' encoding='utf-8'?>
<wsdl:definitions name="DownloadFileWS"
    <xs:schema elementFormDefault="unqualified"
    targetNamespace="http://service.server.mtom.cxf/" version="1.0"
      <xs:element name="getFile" type="tns:getFile" />
      <xs:element name="getFileResponse"
      type="tns:getFileResponse" />
      <xs:complexType name="getFile">
        <xs:sequence />
      <xs:complexType name="getFileResponse">
          <xs:element minOccurs="0" name="return"
          type="tns:responseDownloadFile" />
      <xs:complexType name="responseDownloadFile">
<!-- XOP Node -->          
          <xs:element minOccurs="0" name="file"
          type="xs:base64Binary" />
          <xs:element minOccurs="0" name="fileName"
          type="xs:string" />
          <xs:element minOccurs="0" name="fileType"
          type="xs:string" />
  <wsdl:message name="getFileResponse">
    <wsdl:part element="tns:getFileResponse" name="parameters">
  <wsdl:message name="getFile">
    <wsdl:part element="tns:getFile" name="parameters"></wsdl:part>
  <wsdl:portType name="DownloadFile">
    <wsdl:operation name="getFile">
      <wsdl:input message="tns:getFile" name="getFile">
      <wsdl:output message="tns:getFileResponse"
  <wsdl:binding name="DownloadFileWSSoapBinding"
    <soap:binding style="document"
    transport="" />
    <wsdl:operation name="getFile">
      <soap:operation soapAction="" style="document" />
      <wsdl:input name="getFile">
        <soap:body use="literal" />
      <wsdl:output name="getFileResponse">
        <soap:body use="literal" />
  <wsdl:service name="DownloadFileWS">
    <wsdl:port binding="tns:DownloadFileWSSoapBinding"
      <soap:address location="http://localhost:8080/cxfMTOMServer/services/DownloadFileWS" />

2. Consuming the web service with Apache Axis 1

And now the Axis 1 client to consume CXF web service.

2.a. Create standard axis client through WSDL file

Use wsdl2java tool [3].

2.b. Axis client configuration (client-config.wsdd)

<deployment xmlns="" xmlns:java="">

    <handler name="log" type="java:org.apache.axis.handlers.LogHandler"/>
    <!-- MTOM Axis 1 Handler -->
    <handler name="xop" type="java:axis.mtom.client.handler.XOPHandler">
        <parameter name="serviceName" value="{http://service.server.mtom.cxf/}DownloadFileWS"/>
        <parameter name="operationName" value="getFile"/>
        <parameter name="mtomNodePath" value="getFileResponse.return.file"/>
           <handler type="log"/>
            <handler type="log"/>
            <handler type="xop"/>
    <transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>

2.c. Axis Response Handler for XOP

package axis.mtom.client.handler;

import java.util.Iterator;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.apache.axis.AxisFault;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.attachments.AttachmentPart;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.handlers.BasicHandler;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

 * Retrieve MTOM/XOP file referenced by "mtomNodePath" parameter 
 * from "client-config.wsdd" file.
 * Exposes a Stream including file content to clients through 
 * ThreadLocal mechanism. 
public class XOPHandler extends BasicHandler {

	// "client-config.wsdd" parameters
	private static final String HANDLER_OPTION_MTOM_NODE_PATH = "mtomNodePath";
	private static final String HANDLER_OPTION_OPERATION_NAME = "operationName";
	private static final String HANDLER_OPTION_SERVICE_NAME = "serviceName";
	// Stream including file content 
	private static ThreadLocal documentStream = new ThreadLocal();
    public static InputStream getDocumentStream() {
        return (InputStream)documentStream.get();
	 * Copy Stream reference to file content by searching specified SOAP node on client-config.wsdd file.
    public void invoke(MessageContext msgContext) throws AxisFault {
    	// Only process targeted service and operation
    	if (isTargetedServiceAndOperation(msgContext)) {
			// Recover SOAP node from client-config.wsdd parameter
			String mtomNodePath = (String) getOption(HANDLER_OPTION_MTOM_NODE_PATH);
			if (mtomNodePath == null) {
				System.out.println("No mtomNodePath parameter specified on client-config.wsdd file");
			} else {
				String[] pathToNode = mtomNodePath.split("\\.");
				int nodesLevel = pathToNode.length;
				try {
					// Recover SOAP Body
					Message msg = msgContext.getResponseMessage();
					SOAPMessage soapMessage = msgContext.getResponseMessage();
		            SOAPBody soapBody = soapMessage.getSOAPBody();
		        	// Search mtomNodePath in SOAP Body
		            Node currentNode = null;
		            int currentNodeLevel = 0;
		            NodeList nodeList = soapBody.getChildNodes();
		            while (currentNodeLevel < nodesLevel && nodeList != null) {
		            	currentNode = null;
		                for (int i = 0; i < nodeList.getLength(); i++) {
		                	if (nodeList.item(i).getLocalName().equals(pathToNode[currentNodeLevel])) {
		                		currentNode = nodeList.item(i);
		                if (currentNode != null) {
		                    nodeList = currentNode.getChildNodes();
		                } else {
		                	nodeList = null;
		            // mtomNodePath found
		            if (currentNode != null) {
			            // Recover reference to SOAP Attachment from node attribute "Include" 
		            	String attachmentRef = null;
		            	if (currentNode.getChildNodes() != null && 
						    currentNode.getChildNodes().getLength() > 0) {
				    		NamedNodeMap nnm = currentNode.getChildNodes().item(0).getAttributes();
				    		for (int j = 0; j < nnm.getLength(); j++) {
				    			attachmentRef = nnm.item(j).getNodeValue();
				    		// (!) Delete XOP node to prevent Axis service unmarshalling errors
		            	} else {
		            		System.out.println("No reference founded at node " + mtomNodePath);
						// Recover SOAP Attachment from attachments using the reference
		            	if (attachmentRef != null) {
				            Iterator attachments = msg.getAttachments();
							while (attachments.hasNext()) {
								AttachmentPart attachmentPart = (AttachmentPart);
								if (attachmentPart.getContentIdRef().equals(attachmentRef)) {
				            // Perform SOAP Body operations to persist changes
							TransformerFactory tff = TransformerFactory.newInstance();
				            Transformer tf = tff.newTransformer();
				            Source sc = soapMessage.getSOAPPart().getContent();
				            StringWriter modifiedBody = new StringWriter();
				            StreamResult result = new StreamResult(modifiedBody);
				            tf.transform(sc, result);            
				            Message modifiedMsg = new Message(modifiedBody.toString(), false);
		            	} else {
		            		System.out.println("No reference to XOP file founded at node " + mtomNodePath);
		            } else {
		            	System.out.println("Node " + mtomNodePath + " not found at Response SOAP Body");
				} catch (Exception e) {
					throw new AxisFault("Handler exception", e);

     * Check targeted service and operation from "client-config.wsdd" parameters
     * with runtime service and operation from the web service response.
    private boolean isTargetedServiceAndOperation(MessageContext msgContext) {
    	boolean parametersFound = false;
    	String serviceName = (String) getOption(HANDLER_OPTION_SERVICE_NAME);
        if (serviceName == null) {
        	System.out.println("No serviceName property specified on client-config.wsdd file");
		Service locator = (Service) msgContext.getProperty(Call.WSDL_SERVICE);
		if (locator != null && locator.getServiceName().toString().equals(serviceName)) {
	    	String operationName = (String) getOption(HANDLER_OPTION_OPERATION_NAME);
	        if (operationName == null) {
	        	System.out.println("No operationName property specified on client-config.wsdd file");
	        } else if (msgContext.getOperation().getName().equals(operationName)) {
			    parametersFound = true;
		return parametersFound;

2. d. Sample web service client

package axis.mtom.client;


import axis.mtom.client.handler.XOPHandler;

import cxf.mtom.server.service.DownloadFileWSLocator;
import cxf.mtom.server.service.DownloadFileWSSoapBindingStub;
import cxf.mtom.server.service.ResponseDownloadFile;

 * Access MTOM / XOP service from Axis 1
public class TestClient {

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

       	// Axis client invocation
		DownloadFileWSSoapBindingStub binding =
			(DownloadFileWSSoapBindingStub) new DownloadFileWSLocator().getDownloadFileImplPort();
        ResponseDownloadFile rdf = binding.getFile();

        // Recovered file name

        // Recovered file type

        // UNUSED METHOD -> System.out.println(rdf.getFile());
        // Recover file content
        convertStreamToFile(XOPHandler.getDocumentStream(), rdf.getFileName());


	 * Sample method: write Stream to File
	 * @param is
	 * @param fileName
	 * @throws IOException
	public static void convertStreamToFile(InputStream is, String fileName) throws IOException {

		if (is != null) {

			FileOutputStream fos = new FileOutputStream(fileName);

			byte[] buffer = new byte[1024];
			try {
				int n;
				while ((n = != -1) {
					fos.write(buffer, 0, n);
			} finally {

3. Final considerations

3.a. Sample SOAP Request

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv=""
    <getFile xmlns="http://service.server.mtom.cxf/" />

3.b. Sample SOAP Response

<soap:Envelope xmlns:soap="">
    <ns2:getFileResponse xmlns:ns2="http://service.server.mtom.cxf/">
		  <!-- XOP node -->
          <xop:Include xmlns:xop=""
          href="" />

content-type: application/octet-stream
content-transfer-encoding: binary
content-id: <>

Binary Data.....

3.c. Resources