WSDL your POJOs with Apache Axis

This article was originally published in VSJ, which is now part of Developer Fusion.
More than eight years have elapsed since the first promise of a completely software-interoperable world consisting of web services, enabled through the ubiquity of SOAP (Simple Object Access Protocol). During this period, amazing progress has been made by developers all over the world. Today, many enterprises are specifying their relationships and interactions with partners, suppliers, and customers through web services. Most programming languages can be used to quickly create applications that consume web services, and Java has become one of the leading languages used in creating actual web services.

This article covers some of the advanced features of the Apache Axis toolkit, used in creating Java-based web services. The focus will be on how to give existing software systems a new life by exposing their functionality through a web service. For an introduction to Axis, see Will Iverson’s article on Implementing a web service in Java in VSJ July/August 2005.

A Brief Web Service Overview

The technology used to access software services over a network is not new; it has been around for several decades. There are DCE RPC, DCOM, CORBA, and RMI – all designed to connect service clients to their servers. Why, then, is there a need for another mechanism – such as web services? One of the key reasons is obvious when one looks inside a corporate Intranet.

Figure 1 is typical of many corporate Intranets.

Figure 1
Figure 1: A corporate Intranet

Their connection to the outside world (the Internet) is completely blocked off, by sophisticated firewalls, except for HTTP-based traffic generated by web browsers. This allows their staff to access the world wide web, while protecting the systems inside the Intranet from external hackers and possible network-propagated viruses.

While great for security, the restricted access shown in Figure 1 is bad news for existing client/server interconnect mechanisms (RPC, CORBA, etc). Essentially, the potential clients inside the Intranet are trapped, prevented from accessing any outside services. The only possible way to connect to the outside is via HTTP. That is, the server has somehow to mimic the behaviour of a web server – web services do exactly this. While some of the earlier mentioned client/server protocols can be forced into a tunnelling over an HTTP connection, these adaptations are typically complex and difficult to configure and maintain. These access mechanisms were designed long before the network access pattern was restricted to the situation depicted in Figure 1, and their age shows.

The SOAP and JAX-RPC protocols are custom designed from day one to work over an HTTP connection, with the topology shown in Figure 1. See Figure 2 for the HTTP tunnelling capabilities of web services.

Figure 2
Figure 2: An HTTP web service

In Figure 2, you can see that the web services access protocol rides naturally through the HTTP opening that exists in most Intranets, even those with heavy firewall protection. This allows clients (consumer of web services) inside the Intranet to access any web services outside of the firewall (typically using the Internet, although often via a VPN to a business partner’s network).

The protocol messages for web services are all expressed in XML. This makes it rather simple to create clients that process this message, using almost any programming language that has a networking and XML or text-processing library. In fact, you can write web services consumers using PERL, Python, PHP, C, C++, C#, Visual Basic, Java and many other programming languages.

The Apache Axis web services toolkit

The open source Apache Axis project is a versatile toolkit for creating web services using the Java programming language.

One of the most frequently used components of the toolkit is a Tomcat-based web application (including a servlet) that can hosts web services – see Figure 3.

Figure 3
Figure 3: Tomcat as a web services engine

Figure 3 shows how the Axis servlet turns your Tomcat server into a high performance web services engine. Incoming HTTP (SOAP/JAX-RPC) requests are processed by the servlet and dispatched to one of your web services implementation (named A, B, and C in Figure 3). Note that the servlet takes on most of the hard work of implementing web services (such as handling the HTTP protocol, parsing the incoming messages, serialising and deserialising data objects). As an Axis web service developer, you can focus your effort on design and programming of the service logic.

Exposing your POJO or existing services

A POJO is a Plain Old Java Object. It is simply existing classes that you may have in a software library that are already performing some business function. A POJO need not contain any networking code to be exposed as a web service. You don’t even have to have the source code to the POJO to expose it as a web service. You may also have internal Intranet services that you want to expose (all or partially) to your partners or clients as web services – Axis can help you do this easily.

The key to exposing POJO or existing services is in creating and implementing a suitable Java interface. This may mean that you need to provide a thin wrapper or façade to your existing POJOs and services. The interface should:

  • Have methods that do not, as much as possible, depend on server-side state
  • Have arguments with data types that are compatible with the consuming web services client
If you know ahead of time that all your web services consuming clients are exclusively written in Java, you’ll have more latitude to use object type in your method arguments. But if you need to cater to a wide variety of clients, you should stick to basic types and arrays of basic types (such as int, String, byte, Boolean, double, float, long and short). The ability to work with arguments and return the value of complex object type varies widely between client-side programming languages. The safest approach is to adopt the lowest common denominator approach.

A simple implementation

The example code shows how to expose an existing server-side POJO as a web service. To expose existing service(s), simply code the POJO to call these services. The interface that is defined for the example POJO is called Shop, you can find it in the file code\src\Shop.java in the code distribution. It is shown below:
public interface Shop {
	public String [] getSKUs();
	public int getPrice(String sku);
	public int order(String custID,
		String sku, int quan);
}
The getSKU() method obtains a list of SKUs, note the use of String arrays instead of complex data types – catering a variety of web services consumers. Once the client finds the SKU that needs to be ordered, it can call getPrice() to obtain a price for the SKU. Finally, the client can call the order() method to place the order.

Again, note the use of String, int, and array types throughout the definition of this interface. This is a typical Java interface that you need to write, in order to expose a POJO as a web service. The actual POJO implementation is in shop.server.ShopImpl. You can find it in src\shop\server\ShopImpl.java . The code is shown below:

package shop.server;
import shop.*;
public class ShopImpl implements Shop {
	private static ShopImpl inst = new ShopImpl();
	private ShopImpl() {
	}
	public static ShopImpl getInst() {
		return inst;
	}
	public String [] getSKUs() {
		String [] skus = {“12345”,”00929”,”88888”};
		return skus;
	}
	public int getPrice(String sku) {
		return 100;
	}
	public int order(String custID, String sku, int quan) {
	// process the order here
		return 0;
	}
}
Most of the above logic is stubbed out or uses trivial implementation code for simplicity. You can, of course, write logic that accesses your RDBMS or other existing services to implement the methods.

Using Axis for the web service

Code focusing on the business logic is all that you need to write. The tools in the Axis toolkit will generate the rest of the required code in exposing a web service. Figure 4 shows the files that Axis tools will generate.

Figure 4
Figure 4: The generated files

Note that the Java interface file at the top in Figure 4 is the source to generate a large number of artefacts (required files to implement a web service). The first step is the use the java2wsdl tool from Axis to generate the all-important WSDL file. This descriptor file is key to linking the client and the server sides. From this WSDL file, the wsdl2java tool is then used to generate the client access code and (optionally) the server-side binding code. The example requires the generation of both sides – since you will be implementing both the web service and a client. If you were to consume an existing web service, you would only need its WSDL, and could generate the client access code using wsdl2java.

Table 1 summarises the server-side generated code, the tool that generates it and its purpose. You can find all of the generated files in the generated directory of the code distribution.

Table 1: Server-side code generation
File Name Tool used Description
shop.wsdl java2wsdl This is the Web Service Description Language file. WSDL is in a standard format (a standard written by IBM and Microsoft) used by almost all web services. This file include all the information necessary for a client to generate the access code, including the methods, data types, messages, etc.
shop\Shop.java wsdl2java This is almost a clone of your defined Shop interface, but embellished with RPC Remote Exceptions for network transport.
shop\ShopServiceLocator.java wsdl2java Client side service locator class that finds an instance of the required Shop web service (with the help of the Axis engine).
shop\ShopService.java wsdl2java Client side service class that provides an object (a stub) that implements the Shop interface on the client side.
shop\ShopSoapBindingStub.java wsdl2java Client side stub object implementing the Shop interface. Your client code calls this stub. It will marshal all the input parameters into SOAP messages to send to the server side and process response messages accordingly.
shop\ShopSoapBindingSkeleton.java wsdl2java Server side skeleton object receiving the messages from the corresponding client side stub object methods. Deals with extracting the parameters and invoking the actual server-side implementation class.
shop\ShopSoapBindingImpl.java wsdl2java Server side implementation class of the Shop interface. This class should implement the actual service logic. In the example, you need to add code to this generated file that calls the corresponding methods of your shop.server.ShopImpl implementation.
shop\deploy.wsdd, shop\undeploy.wsdd wsdl2java Two Web Service Deployment Descriptor files. These deployment descriptors can be used to deploy and undeploy the web services using the Axis web engine’s Admin client tool.

Managing generation and build with Ant

The example code is created using an Ant build.xml file. You can look into this file to see how generation and compilation is done. You will need to have Ant 1.5.4 or later installed and running to generate and compile the example. The Ant targets that are available, and their functions, are tabulated in Table 2.

Table 2: Ant targets and functions
Ant Target Description
clean Removes the generated and classes directories
compileinterface Compiles the Shop interface that you define (the java2wsdl tool in Axis requires a compiled interface)
genwsdl Generates the WSDL file from the Shop interface using the java2wsdl tool from Axis
genjava Generates all the client and server side artefacts from the WSDL file, using the wsdl2java from Axis; all generated artefacts are placed in the generated directory
compile Compiles both the server-side and client-side code, including the code you write and the generated code – all of the binaries are placed into the class directory
deploy Deploys the web service to Tomcat using Axis’s Adminclient tool, also copies all the required classes from the project’s classes directory to the Axis web application’s WEB-INF\classes directory

Before you can use this build file, you need to edit it to supply your own Axis and Tomcat installation directory. Remember to do this first, or your compilation and generation will fail for sure.

To try out the example, you do not have to run any of the targets – as the code has already been generated, modified, and compiled for you. Simply run the deploy target. If you ever modify the Shop interface, you will need to run the compileinterface target:

ant compileinterface
To generate the WSDL file again, run the genwsdl target:
ant genwsdl
This will place the shop.wsdl file at the top level source directory. You can examine it there.

To generate all the artifacts, run the genjava target:

ant genjava
The generated directory will then be populated with all the generated files. Remember, you must modify the generated\shop\ShopSoapBindingImpl.java file each and every time after generation. The code you need to add is emboldened below. It delegates the actual implementation logic to your shop.server.ShopImpl class.
package shop;
import shop.server.ShopImpl;
public class ShopSoapBindingImpl implements shop.Shop{
	public int order(java.lang.String in0,
			java.lang.String in1, int in2)
				 throws java.rmi.RemoteException {
		return ShopImpl.getInst().order(in0, in1, in2);
	}

	public java.lang.String[] getSKUs()
			throws java.rmi.RemoteException {
		return ShopImpl.getInst().getSKUs();
	}

	public int getPrice(java.lang.String in0)
			throws java.rmi.RemoteException {
		return ShopImpl.getInst().getPrice(in0);
	}
}
After you modify the code above, use the compile target to compile both the client and the server side code:
ant compile
You can then deploy the web service code to your Tomcat server using the deploy target:
ant deploy
Before you try out the web service, let’s take a look at how all of this plumbing works, and also the client-side web service consuming code that you have to write.

Interactions between custom code and Axis generated code

By now, you should realise that Axis generates most of the tedious code that otherwise you may need to write. Figure 5 puts things into perspective.

Figure 5
Figure 5: Web service structure

On the client side, you write the client code and Axis takes care of finding the web service for you (via the generated locator), implementing that service (via the generated service), and sending that call over to the service (using the generated stub). On the server side, you only write the code that implements the service logic. Axis handles the incoming request using its own engine (servlet), then passes the incoming request to the generated skeleton, which in turn delegates it to the call to the generated implementation class (which you will have modified to call your own implementation).

Zooming in, Figure 6 shows the client-side picture of how your client code interacts with the Axis generated code.

Figure 6
Figure 6: Client action

In Figure 6, your client.Shopper code is the application that consumes the Shop web service. It creates a new ShopServiceLocator (a generated class), and uses it to locate a ShopService. Calling getshop() on the service returns a stub instance that implements the Shop interface on the client side. Once the stub is obtained, it can proceed to make calls to the web service.

The actual client code can be found in the src\shop\client\Shopper.java file. It is displayed below:

package shop.client;
import shop.*;
public class Shopper {
	public static void main(String [] args) throws Exception {
		ShopService service = new ShopServiceLocator();
		Shop port = service.getshop();
		String [] skus = port.getSKUs();
		System.out.println(“SKUs”);
		System.out.println(“” + skus.length + “ skus”);
		if (skus.length > 0) {
			for (int i=0; i< skus.length; i++)
				System.out.println(“ -> “ + skus[i]);
			int price = port.getPrice(skus[0]);
			System.out.println(“SKU “ + skus[0] +
				“ is priced at $” + price);
			System.out.println(“ordering 10…”);
			port.order(“cust101”, skus[0], 10);
		}
	}
}
The client code simply calls getSKUs(), and then prints out all the SKU. It then gets the price on the first SKU (calls getPrice()) and then makes an order for it (calls order()).

The server-side interactions

On the server-side, Figure 7 illustrates the interaction between the Axis generated code and your implementation of the Shop interface.

Figure 7
Figure 7: Server action

In Figure 7, the Axis engine running inside Tomcat processes the incoming client request and then sends it to the skeleton.

The skeleton extracts arguments from the requests and delegates the work by calling the BindingImpl class (ShopSoapBindingImpl) class that implements the Shop interface. The ShopSoapBindingImpl class is the generated class that you have modified to send calls to your own POJO.

Testing the Shop web service

To try out the web service, make sure you have followed along, and ran the deploy target.

Now, start your Tomcat server. Try:

http://localhost:8080/axis/index.jsp
…to make sure the Axis engine is running file. Click the list link on this page, and verify that the Shop web service is ready to go.

Now, execute the run target, this will run the client code:

ant run
If everything is working fine, you should see the output of the client consuming the Shop web service – similar to Figure 8.

Figure 8
Figure 8: The web service working

Conclusions

Ordinary Java objects implementing business logic, as well as legacy services within your Intranet, can be converted readily to modern web services. The Apache Axis toolkit provides a web service hosting engine, and a set of tools, that ease the otherwise daunting task of creating and hosting web services.


Sing Li is a consultant, trainer and freelance writer specialising in Java, Windows NT and distributed object technologies. Li’s most recent publication is Early Adopter JXTA: Peer-to-Peer Computing with Java from Wrox Press.

Installing the Axis web application

To get the Axis web application set up and running in Tomcat, first copy the webapps directory from the Axis distribution to the webapps directory of Tomcat. You should use the latest version of Tomcat if possible. The code in this article is tested with Tomcat release 5.5.9. The Axis release tested is 1.2.1. Next, there are some additional libraries that you need to download separately. These are JAR files that you need to place into the webapps\Axis\WEB-INF\lib directory of both the Tomcat and Axis webapps directory. The JARs that you should download separately, extracting where necessary, are: To test that your Axis servlet is running fine, start Tomcat and use the URL:
http://localhost:8080/Axis/index.jsp
Click the validation link, and it will show the famous Axis Happiness page, indicating if there are additional libraries that you need to download and install.

You might also like...

Comments

About the author

Sing Li United States

Sing Li has been writing software, and writing about software for twenty plus years. His specialities include scalable distributed computing systems and peer-to-peer technologies. He now spends ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Debuggers don't remove bugs. They only show them in slow motion.”