Axis2 - POJO Web Service

Axis2 offers easy way of deploying web service based on POJOs.

Let’s create a web service which will offer a few simple SOAP methods:

  • echo input string
  • add two integers
  • get bill for items in shopping list

Create new Dynamic Web Project in Eclipse named HelloPojo. Copy jars from $AXIS2_HOME/lib to your project’s WEB-INF/lib directory. Jar files will be automatically added to project’s classpath and you should see them under Web App Libraries library folder.
In next step create new directory ‘services’ inside WEB-INF directory. This is default location where axis2 will search for services and their deployment descriptors.



Inside 'services' directory create 'PojoService' directory.
Furthermore, inside 'PojoService' directory create new directory META-INF. In META-INF directory axis2 expects to find service deployment descriptor file called services.xml. Deployment descriptor will tell axis2 where to look for web service implementation (ServiceClass).

Contents of services.xml

<service name="HelloPojo" scope="application">
<description>
POJO 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>
<parameter name="ServiceClass">
si.matjaz.example.PojoService
</parameter>
</service>

Now it’s time to implement PojoService class. The class contains two public methods.

package si.matjaz.example;

public class PojoService {

public String echo(String string) {
return string;
}

public Integer add(Integer a, Integer b) {
return a+b;
}

}

Add the following servlet definition to web.xml:

<servlet>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

Now we are ready to deploy our web service on Tomcat server. In Eclipse right click on HelloPojo project, select Run as --> Run on Server.

Check if web service is up and running. Go to address

http://localhost:8080/HelloPojo/services/HelloPojo?wsdl

and you should see the contents of wsdl file (view source code of the page if you don’t see anything in browser).

To test web service we will use soapUI which is great SOAP client application. In soapUI import wsdl file from above url address. Check that add(..) method works correctly:

Request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:exam="http://example.matjaz.si">
<soapenv:Header/>
<soapenv:Body>
<exam:add>
<exam:a>1</exam:a>
<exam:b>3</exam:b>
</exam:add>
</soapenv:Body>
</soapenv:Envelope>

Response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:addResponse xmlns:ns="http://example.matjaz.si">
<ns:return>4</ns:return>
</ns:addResponse>
</soapenv:Body>
</soapenv:Envelope>

We are still missing one method: buy(..). Imagine a local restaurant which accepts SOAP requests for food from hungry SOAP developers. Restaurant defines <shoppingList> element in SOAP message body, which can contain many <item> elements.

Create new class called Item. Item class is just a bean that holds food name, quantity and price getters and setters.

package si.matjaz.example;

public class Item {

private String name;

private Integer quantity;

private Double price;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getQuantity() {
return quantity;
}

public void setQuantity(Integer quantity) {
this.quantity = quantity;
}

public Double getPrice() {
return price;
}

public void setPrice(Double price) {
this.price = price;
}
}

Next we need to define new class SoppingList, which is just a container for an array of Item objects and its getters and setters:

package si.matjaz.example;

public class ShoppingList {

private Item[] item;

public Item[] getItem() {
return item;
}

public void setItem(Item[] item) {
this.item = item;
}

}

Now we need an object that we will return back to the user. It will be called ‘Bill’ and it will contain an array of Item objects (the same as in ShoppingList). Additionally we will implement a method calculate() to calculate the total price of all items being bought.

package si.matjaz.example;

import java.util.Hashtable;

public class Bill {

private Item[] item;

private Double total;

public Item[] getItem() {
return item;
}

public void setItem(Item[] item) {
this.item = item;
}

public Double getTotal() {
return total;
}

public void setTotal(Double total) {
this.total = total;
}

public void calculate(ShoppingList list) {
Item[] items = list.getItem();
this.item = new Item[items.length];
for (int i = 0; i < items.length; i++) {
this.item[i] = items[i];
int q = items[i].getQuantity().intValue();
double p = getPrice(items[i].getName());
double sum = q*p;
this.item[i].setPrice(new Double(sum));
}

total = new Double(0.0);
for (int i = 0; i < item.length; i++) {
Item it = item[i];
total += it.getPrice();
}
}


private Hashtable<String, Double> priceList = null;

private double getPrice(String name) {

if (priceList == null) {
priceList = new Hashtable<String, Double>();
priceList.put("pizza", new Double(5.99));
priceList.put("cola", new Double(0.99));
priceList.put("hamburger", new Double(10.99));
}

if (priceList.containsKey(name)) {
return priceList.get(name).doubleValue();
} else {
return 0.0;
}
}

}

Last piece of code to add to PojoService class is buy(..) method which accepts ShoppingList object as input and returns Bill object as response:

public Bill buy(ShoppingList shoppingList) {
Bill bill = new Bill();
bill.calculate(shoppingList);
return bill;
}

Deploy web service on Tomcat and update wsdl file in soapUI to see new method buy(..) and try the service. As a client you don’t need to fill <price> element, it will be filled in response.

Request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:exam="http://example.matjaz.si" xmlns:xsd="http://example.matjaz.si/xsd">
<soapenv:Header/>
<soapenv:Body>
<exam:buy>
<exam:shoppingList>
<xsd:item>
<xsd:name>cola</xsd:name>
<xsd:price></xsd:price>
<xsd:quantity>2</xsd:quantity>
</xsd:item>
<xsd:item>
<xsd:name>pizza</xsd:name>
<xsd:price></xsd:price>
<xsd:quantity>2</xsd:quantity>
</xsd:item>
</exam:shoppingList>
</exam:buy>
</soapenv:Body>
</soapenv:Envelope>

Response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:buyResponse xmlns:ns="http://example.matjaz.si">
<ns:return xsi:type="ax21:Bill" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ax21="http://example.matjaz.si/xsd">
<ax21:item xsi:type="ax21:Item">
<ax21:name>cola</ax21:name>
<ax21:price>1.98</ax21:price>
<ax21:quantity>2</ax21:quantity>
</ax21:item>
<ax21:item xsi:type="ax21:Item">
<ax21:name>pizza</ax21:name>
<ax21:price>11.98</ax21:price>
<ax21:quantity>2</ax21:quantity>
</ax21:item>
<ax21:total>13.96</ax21:total>
</ns:return>
</ns:buyResponse>
</soapenv:Body>
</soapenv:Envelope>

Hint 1: Instead of simple type definitions (int, double...) rather use their class instances (Integer, Double...).
Hint 2: Instead of ArrayList<> rather use array[] of objects
Hint 3: Don’t use constructors in classes that are used as web service (ShoppingList, Item, Bill) or you might end with bunch of exceptions.