Monday, September 29, 2008

Axis2 web service muddle through

Step1 Install Axis2
go to http://ws.apache.org/axis2 to download a binary version (I'm using 1.4.1 Standard Binary Distribution). After successfully installment, you can get the following screen after Axis2 started.

Step2: Define web service
Create a new Java project inside eclipse. Its structure should look like the picture below. I named my project VINWebService which return some dumb information of vehicles.

In my example I defined three web services:
1. findMakes: return car makes for a given year
2. findModels: return models for a given car make
3. findBodyTypes: return body types for a given model

the source code is:
package tao.test.web.vin;


import java.util.HashMap;
import java.util.Map;

public class VINService {
private static Map makeData = new HashMap();
private static Map modelData = new HashMap();
private static Map bodyTypeData = new HashMap();

static {
String[] makes_08 = {"CLK-CLASS", "CLS-CLASS", "E-CLASS", "GL-CLASS"};
makeData.put(2008L, makes_08);
}

public String[] findBodyTypes(String modelCode) {
return bodyTypeData.get(modelCode);
}

public String[] findMakes(long year) {
return makeData.get(year);
}

public String[] findModels(String makeCode) {
return modelData.get(makeCode);
}

}
Though there are rumors that the newest Axis2 version supports Java Collection as the return type now, I still got ADBException due to "any type element type has not been given". It seems Array is the safest choice.

Step3: Prepare service.xml
The easiest way of preparing service.xml is to modify a current one. My file is original from that Stock Quote sample, which comes with the Axis2 binary. Only those orange marked fields need to be changed based on different service.
<service name="VINService" scope="application" targetNamespace="http://tao.vinservice/">


<description>

VIN Query Service

</description>

<messageReceivers>

<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"

class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>

<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"

class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>

</messageReceivers>

<schema schemaNamespace="
http://tao.vinservice/xsd"/>

<parameter name="ServiceClass">
tao.test.web.vin.VINService</parameter>

</service>
Step 4: Deploy Web Service
I tweaked the ant.build file of the stock quote example and extracted project-specified field out into the properties file. After changing those property values, you can build the web service directly if the project's structure remains same as the first picture.

Ant build.property
axis2.home=C:/Tao/software/axis2-1.4.1 #Where you installed your Axis2

aar.file.name=VINService.aar #The aar file name
service.class.name=tao.test.web.vin.VINService #Service Java class name, keep it same with the service.xml
service.target.namespace=http://tao.vinservice/ #Name space, keep it same with the service.xml
service.schema.target.namespace=http://tao.vinservice/xsd #Schema name space, keep it same with the service.xml
Ant.xml

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



<project name="VINWebService" basedir="." default="generate.service">

<property environment="env"/>

<property file="build.properties"/>

<property name="build.dir" value="build"/>

<path id="axis2.classpath">

<fileset dir="${axis2.home}/lib">

<include name="*.jar"/>

</fileset>

</path>

<target name="clean" description="Remove all build files">

<delete dir="${build.dir}" includeEmptyDirs="true"/>

</target>

<target name="compile.service">

<mkdir dir="${build.dir}"/>

<mkdir dir="${build.dir}/classes"/>

<!--First let's compile the classes-->

<javac debug="on" fork="true" destdir="${build.dir}/classes" srcdir="${basedir}/src" classpathref="axis2.classpath" target="1.5"/>

</target>

<target name="generate.wsdl" depends="compile.service">

<taskdef name="java2wsdl" classname="org.apache.ws.java2wsdl.Java2WSDLTask" classpathref="axis2.classpath"/>

<java2wsdl className="${service.class.name}" outputLocation="${build.dir}" targetNamespace="${service.target.namespace}" schemaTargetNamespace="${service.schema.target.namespace}">

<classpath>

<pathelement path="${axis2.classpath}"/>

<pathelement location="${build.dir}/classes"/>

</classpath>

</java2wsdl>

</target>


<target name="generate.service" depends="compile.service">

<!--aar them up -->

<copy toDir="${build.dir}/classes" failonerror="false">

<fileset dir="${basedir}/resources">

<include name="**/*.xml"/>

</fileset>

</copy>

<jar destfile="${build.dir}/${aar.file.name}">

<fileset excludes="**/Test.class" dir="${build.dir}/classes"/>

</jar>

</target>

</project>
Run ant build, VINService.aar will be created. Droping this file into the services fold of your Axis2 home, you can see the new service VINService is ready for use.

Step 5: Test
Using WSDL2Java script come with Axis2 binary, you can create a test client at a drop of a hat. In my case, just run
WSDL2Java.bat -uri http://localhost:8080/axis2/services/VINService?wsdl -o .
two java file VINServiceCallbackHandler.java and VINServiceStub.java will be generated. Those two files will be grouped under package vinservice.tao which we defined as our service target namespace.
Create a new java class named client and add the following data:
package vinservice.tao;


import vinservice.tao.VINServiceStub.FindMakes;
import vinservice.tao.VINServiceStub.FindMakesResponse;

public class Client {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
VINServiceStub stub = new VINServiceStub();

FindMakes request = new VINServiceStub.FindMakes();
request.setYear(2008L);

FindMakesResponse response = stub.findMakes(request);

String[] rs = (String[])response.get_return();

for (String s : rs) {
System.out.println(s);
}
}
}
Run this client, the console will print out our the makes we have in the server side.


Example source code:

1 comment:

Unknown said...

BTW, here's the universal VIN decoder API. It shows extended tech info and list of factory options. Hope the tool will be helpful for developers.