Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

Technical Draft

This document describes how to connect MTOM/XOP web services (WS-i compliance) using an
Axis 1 web service client.

Consuming MTOM/XOP web services from Axis 1 ....................................................................... 2


1. Creating a MTOM/XOP web service with Apache CXF.......................................................... 2
1.a. Web service interface..................................................................................................... 2
1.b. Web service implementation......................................................................................... 2
1.c. Web service response bean............................................................................................ 3
1.d. Spring configuration for CXF .......................................................................................... 3
1.e. Web descriptor............................................................................................................... 4
1.f. Generated WSDL............................................................................................................. 4
2. Consuming the web service with Apache Axis 1 ................................................................... 6
2.a. Create standard axis client through WSDL file............................................................... 6
2.b. Axis client configuration................................................................................................. 6
2.c. Axis Response Handler for XOP ...................................................................................... 6
2. d. Sample web service client ........................................................................................... 10
3. Final considerations ............................................................................................................ 11
3.a. Sample SOAP Request .................................................................................................. 11
3.b. Sample SOAP Response................................................................................................ 11
3.c. Resources...................................................................................................................... 11

1
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;

@WebService
public interface DownloadFile {

ResponseDownloadFile getFile() throws Exception;

1.b. Web service implementation

package cxf.mtom.server.service;

import java.io.File;

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.setFileName("c:/tmp/readme.txt");
rdf.setFileType("plain/text");

2
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="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd

3
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">

<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"
implementor="cxf.mtom.server.service.DownloadFileImpl"
address="/DownloadFileWS">
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>

1.e. Web descriptor

<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
<display-name>DownloadFile</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:cxf.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>

1.f. Generated WSDL

(p. e. http://localhost:8080/cxfMTOMServer/services/DownloadFileWS?wsdl )

<?xml version='1.0' encoding='utf-8'?>


<wsdl:definitions name="DownloadFileWS"
targetNamespace="http://service.server.mtom.cxf/"
xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.server.mtom.cxf/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

4
<wsdl:types>
<xs:schema elementFormDefault="unqualified"
targetNamespace="http://service.server.mtom.cxf/" version="1.0"
xmlns:tns="http://service.server.mtom.cxf/"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="getFile" type="tns:getFile" />
<xs:element name="getFileResponse"
type="tns:getFileResponse" />
<xs:complexType name="getFile">
<xs:sequence />
</xs:complexType>
<xs:complexType name="getFileResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return"
type="tns:responseDownloadFile" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="responseDownloadFile">
<xs:sequence>
<!-- 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" />
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="getFileResponse">
<wsdl:part element="tns:getFileResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getFile">
<wsdl:part element="tns:getFile" name="parameters"></wsdl:part>
</wsdl:message>
<wsdl:portType name="DownloadFile">
<wsdl:operation name="getFile">
<wsdl:input message="tns:getFile" name="getFile">
</wsdl:input>
<wsdl:output message="tns:getFileResponse"
name="getFileResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DownloadFileWSSoapBinding"
type="tns:DownloadFile">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getFile">
<soap:operation soapAction="" style="document" />
<wsdl:input name="getFile">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="getFileResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="DownloadFileWS">
<wsdl:port binding="tns:DownloadFileWSSoapBinding"

5
name="DownloadFileImplPort">
<soap:address
location="http://localhost:8080/cxfMTOMServer/services/DownloadFileWS"
/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

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="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/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>

<globalConfiguration>
<requestFlow>
<handler type="log"/>
</requestFlow>
<responseFlow>
<handler type="log"/>
<handler type="xop"/>
</responseFlow>
</globalConfiguration>

<transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender"/>

</deployment>

2.c. Axis Response Handler for XOP

package axis.mtom.client.handler;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.Iterator;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPMessage;

6
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

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 {

7
// 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);
break;
}
}
if (currentNode != null) {
nodeList = currentNode.getChildNodes();
} else {
nodeList = null;
}
currentNodeLevel++;
}

// 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
currentNode.getParentNode().removeChild(currentNode);
} 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)attachments.next();
if (attachmentPart.getContentIdRef().equals(attachmentRef)) {
documentStream.set(attachmentPart.getDataHandler().getInputStream());
}
}

// Perform SOAP Body operations to persist changes


TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
Source sc = soapMessage.getSOAPPart().getContent();
StringWriter modifiedBody = new StringWriter();

8
StreamResult result = new StreamResult(modifiedBody);
tf.transform(sc, result);
Message modifiedMsg = new Message(modifiedBody.toString(), false);
msgContext.setResponseMessage(modifiedMsg);

} 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;
}

9
2. d. Sample web service client

package axis.mtom.client;

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

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


System.out.println(rdf.getFileName());

// Recovered file type


System.out.println(rdf.getFileType());

// 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 = is.read(buffer)) != -1) {

10
fos.write(buffer, 0, n);
}
} finally {
is.close();
fos.close();
}
}
}
}

3. Final considerations
3.a. Sample SOAP Request

<?xml version="1.0" encoding="utf-8"?>


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getFile xmlns="http://service.server.mtom.cxf/" />
</soapenv:Body>
</soapenv:Envelope>

3.b. Sample SOAP Response

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getFileResponse xmlns:ns2="http://service.server.mtom.cxf/">
<return>
<file>
<!-- XOP node -->
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="cid:89f719ee-ed51-4955-a80d-103f1d851763-4@cxf.apache.org" />
</file>
<fileName>c:/tmp/readme.txt</fileName>
<fileType>plain/text</fileType>
</return>
</ns2:getFileResponse>
</soap:Body>
</soap:Envelope>

--MIMEBoundary4A7AE55984E7438034
content-type: application/octet-stream
content-transfer-encoding: binary
content-id: <89f719ee-ed51-4955-a80d-103f1d851763-4@cxf.apache.org>

Binary Data.....
--MIMEBoundary4A7AE55984E7438034--

3.c. Resources

[1] http://axis.apache.org/axis2/java/core/docs/mtom-guide.html
[2] http://cxf.apache.org/docs/writing-a-service-with-spring.html
[3] http://axis.apache.org/axis/java/user-
guide.html#WSDL2JavaBuildingStubsSkeletonsAndDataTypesFromWSDL

11

You might also like