Thursday, April 14, 2011

Axis2 Maven Web service client Example

Aim: To learn how to generate java client stubs from WSDL using wsdl2java script of axis2. Use the client stubs to consume a web service using SOAP over HTTP.

Requirements:
1. you need WSDL of the service you wish to consume using your generated client.
2. If you are going to test both service generation and consumption in local system, download axis2 binary distribution.
3. SoapUI if you need to test the remote Server and its operations with sample requests.


Steps:

I followed this source to set up the axis2's http server and also download SimpleService.aar file to deploy. Here is the simple steps to follow:

1. Download and extract axis2 binary distribution to /usr/local, at the time of writing[Apr 14,2011] we have axis2-1.5.4. Set /usr/local/axis2-1.5.4 as AXIS_HOME. You can find the scripts in AXIS_HOME/bin folder. You need to copy .aar file of your service into repository/services folder.

2. Start the axis2 server by executing AXIS_HOME/bin/axis2server.sh. In a browser if you access, http://localhost:8080 it would list all services deployed on the axis2server. You can get the WSDL of the service from its links.

SimpleService.wsdl:
==============

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ns="http://ws.apache.org/axis2" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://ws.apache.org/axis2">
<wsdl:types>
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ws.apache.org/axis2">
<xs:element name="echo">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="args0" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="echoResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="echoRequest">
<wsdl:part name="parameters" element="ns:echo"/>
</wsdl:message>
<wsdl:message name="echoResponse">
<wsdl:part name="parameters" element="ns:echoResponse"/>
</wsdl:message>
<wsdl:portType name="SimpleServicePortType">
<wsdl:operation name="echo">
<wsdl:input message="ns:echoRequest" wsaw:Action="urn:echo"/>
<wsdl:output message="ns:echoResponse" wsaw:Action="urn:echoResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SimpleServiceSoap11Binding" type="ns:SimpleServicePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="echo">
<soap:operation soapAction="urn:echo" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="SimpleServiceSoap12Binding" type="ns:SimpleServicePortType">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="echo">
<soap12:operation soapAction="urn:echo" style="document"/>
<wsdl:input>
<soap12:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap12:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="SimpleServiceHttpBinding" type="ns:SimpleServicePortType">
<http:binding verb="POST"/>
<wsdl:operation name="echo">
<http:operation location="SimpleService/echo"/>
<wsdl:input>
<mime:content type="text/xml" part="echo"/>
</wsdl:input>
<wsdl:output>
<mime:content type="text/xml" part="echo"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SimpleService">
<wsdl:port name="SimpleServiceHttpSoap11Endpoint" binding="ns:SimpleServiceSoap11Binding">
<soap:address location="http://localhost:8080/axis2/services/SimpleService.SimpleServiceHttpSoap11Endpoint/"/>
</wsdl:port>
<wsdl:port name="SimpleServiceHttpSoap12Endpoint" binding="ns:SimpleServiceSoap12Binding">
<soap12:address location="http://localhost:8080/axis2/services/SimpleService.SimpleServiceHttpSoap12Endpoint/"/>
</wsdl:port>
<wsdl:port name="SimpleServiceHttpEndpoint" binding="ns:SimpleServiceHttpBinding">
<http:address location="http://localhost:8080/axis2/services/SimpleService.SimpleServiceHttpEndpoint/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>


Things you need to know about any WSDL is
a. What are the possible 'operation' from the service. Their input and output element type and their arguments.
b. What is the address Location of the service.

3. I use Maven2Eclipse plugin to generate and execute my project. Create a maven project. Update its pom.xml with the following:

<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-wsdl2code-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<goals>
<goal>wsdl2code</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>axis.test</packageName>
<wsdlFile>src/main/wsdl/SimpleService.wsdl</wsdlFile>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-local</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.schema</groupId>
<artifactId>XmlSchema</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.neethi</groupId>
<artifactId>neethi</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.axiom</groupId>
<artifactId>axiom-api</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.axiom</groupId>
<artifactId>axiom-impl</artifactId>
<version>1.2.11</version>
</dependency>
...
</dependencies>
...
</project>


These are the dependencies you will need to execute your Client stub generated by wsdl2java. The plugin is used to generate the stubs. When you run Maven Install on the project it should generate SimpleServiceCallbackHandler.java and SimpleServiceStub.java in target/generated-sources/../axis/test folder. Move it to your project's src folder under needed package name.

4. Here is a sample Client.java that you need to write to consume the SimpleService using the stubs we just generated.

Client.java:
========
package axis.test;

import java.rmi.RemoteException;

public class Client {

/**
* @param args
* @throws RemoteException
*/
public static void main(String[] args) {

try {
SimpleServiceStub stub = new SimpleServiceStub();

SimpleServiceStub.Echo request = new SimpleServiceStub.Echo();

request.setArgs0("This is my message");

SimpleServiceStub.EchoResponse response = stub.echo(request);

System.out.println("Response from Simple service: "+response.get_return());

}
catch(RemoteException ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
}

This is a very simple client code to start with. You need to create an instance of stub class which would be ServiceName+Stub.java. You need to create a request object. It will be a inner class of stub. You can check wsdl for operation name(that would request name). Set the arguments for the operation request and verify you are complying the format specified in WSDL. In this case its a string to echo back. Similarly create instance of response to hold the response of the operation. You actually consume the service when you call the operation via stub object. get_return() method always returns the value of response object.


5. Run Client as Java application and make sure service is up by checking via browser. You will get response in console. Viola.


Possible errors/exceptions:

1. When the service is down, the SOAP Fault would say Connection refused.
2. There are 3 data binding frameworks possible. Default is adb(Axis data binding framework). You can specify it in in maven plugin for wsdl2code.

References:
[1]. Hello world with Apache Axis2

No comments: