Books / SOAP Web Services / Chapter 10

Developing SOAP Web Services with Java and Apache Axis

As the brief review above illustrates, the technology behind Web services is quite complex. Luckily, most Web services developers will not have to deal with this infrastructure directly. There are a number of Web services development toolkits to assist with developing and using Web services. There are currently many tools that automate the process of generating WSDL and mapping it to programming languages (Figure 9-1). One of the most popular such tools is Apache Axis.

What is Apache Axis?

Apache Axis (Apache EXtensible Interaction System) is essentially a SOAP engine - a framework for constructing SOAP processors such as clients, servers, gateways, etc. The current version of Axis is written in Java. Axis includes a server that plugs into servlet engines such as Apache Tomcat, extensive support for WSDL, and tools that generate Java classes from WSDL.

Apache Axis provides automatic serialization/deserialization of Java Beans, including customizable mapping of fields to XML elements/attributes, as well as automatic two-way conversions between Java Collections and SOAP Arrays.

Axis also provides automatic WSDL generation from deployed services using Java2WSDL tool for building WSDL from Java classes. The generated WSDL document is used by client developers who can use WSDL2Java tool for building Java proxies and skeletons from WSDL documents.

Axis also supports session-oriented services, via HTTP cookies or transport-independent SOAP headers.

Server-side Development with Apache Axis

At the server side (or the Web service side), the steps are as follows:

  1. Define Java interface of the Web service (and a class that implements this interface)
  2. Generate the WDSL document from the service’s Java interface (Java -> WSDL)
  3. Generate the skeleton Java class (server-side proxy) from the WSDL document (WSDL -> Java)
  4. Modify the skeleton proxy to interact with the Java class that implements the Java interface (both created in Step 1 above).

Let’s look at an example of a client that could remotely connect to the Web service and request a price forecast for stocks of interest. The details for each of the above steps for this particular example are as follows.

Step 1: Define the server object interface

There are three key Java classes (from the point of view of Web services) responsible for providing a stock price forecast and trading recommendation: ForecastServer.java, its implementation (ForecastServerImpl.java) and ParamsBean.java, a simple container object used to transfer information to and from the Web service. The structure of other package is not important, since all we care about is the Web service interface definition, which will be seen by entities that want to access this Web service.

(a) UML package diagram for the example application. (b) Web-service related classes

Figure 10-1: (a) UML package diagram for the example application. (b) Web-service related classes

The Java interface ForecastServer.java is given as:

 package stock_analyst.interact;

 import java.rmi.RemoteException;

 public interface ForecastServer {

     public void getPriceForecast(ParamsBean args)
     throws RemoteException;

     public void getRecommendation(ParamsBean args)
     throws RemoteException;
 }

The code description is as follows:

  • Line 1: Java package where the interface class is located.
  • Line 3: Exception RemoteException may be thrown by the Web service methods.
  • Lines 7–8: Method getPriceForecast() takes one input argument, which is a Java Bean used to transport information to and from the Web service. The method return type is void, which implies that any result values will be returned in the args parameter.
  • Lines 10–11: Method getRecommendation() signature, defined similarly as for the method getPriceForecast().

Step 2: Java2WSDL – Generate a WSDL document from the given stock-forecasting Java interface

Now that we defined the Java interface for the stock-forecasting service, it is time to generate a WSDL (Web Service Definition Language) file, which will describe our web service in a standard XML format. For this, we will use an Apache Axis command line tool Java2WSDL. A detailed documentation on Java2WSDL, its usage and parameters can be found at the Axis website.

java org.apache.axis.wsdl.Java2WSDL
 -o wsdl/interact.wsdl
 -l "http://localhost:8080/axis/services/interact"
 -n "urn:interact"
 -p "stock_analyst.interact" "urn:interact"
 stock_analyst.interact.ForecastServer 

Java2WSDL tool will generate a standard WSDL file, which is an XML representation of a given interface (ForecastServer.java in our case). We tell the program the information that it needs to know as it builds the file, such as:

  • Name and location of output WSDL file ( -o wsdl/interact.wsdl )
  • Location URL of the Web service ( -l http://localhost:8080/axis/services/interact )
  • Target namespace for the WSDL ( -n urn:interact )
  • Map Java package to namespace ( stock_analyst.interact -> urn:interact )
  • The fully qualified Java interface of the Web service itself ( stock_analyst.interact.ForecastServer )

Step 3: WSDL2Java – Generate server-side wrapper code

(This step generates code for both server and client side, as seen below.) Our next step is to take the WSDL, synthesized in step 2, and generate all of the glue code for deploying the service. The WSDL2Java Axis tool comes to our aid here. Complete documentation on this tool can be found at the Axis website.

java org.apache.axis.wsdl.WSDL2Java
 -o src/
 -d Session
 -s
 -p stock_analyst.interact.ws
 wsdl/interact.wsdl 

Once again, we need to tell our tool some information for it to proceed:

  • Base output directory ( -o src/ )
  • Scope of deployment ( Application, Request, or Session )
  • Turn on server-side generation ( -s ) — we would not do this if we were accessing an external Web service, as we would then just need the client stub
  • Package to place code ( -p stock_analyst.interact.ws )
  • Name of WSDL file used to generate all this code ( wsdl/interact.wsdl ) For separating the automatically generated code from the original code, we store it a new Web service package “stock_analyst.interact.ws”, shown in Figure 10-1(b). After running the WSDL2Java code generator, we get the following files under src/stock_analyst/interact/ws:

  • FcastSoapBindingImpl.java This is the implementation code for our web service. We will need to edit it, to connect it to our existing ForecastServerImpl (see Step 4 below).
  • ForecastServer.java This is a remote interface to the stock forecasting system (extends Remote, and methods from the original ForecastServer.java throw RemoteExceptions).
  • ForecastServerService.java Service interface of the Web services.
  • ForecastServerServiceLocator.java A helper factory for retrieving a handle to the service.
  • FcastSoapBindingStub.java Client-side stub code that encapsulates client access.
  • ParamsBean.java A copy of our bean used to transfer data.
  • deploy.wsdd Deployment descriptor that we pass to Axis system to deploy these Web services.
  • undeploy.wsdd Deployment descriptor that will un-deploy the Web services from the Axis system

Step 4: Tune-up – Modify FcastSoapBindingImpl.java to call server implementation code

We need to tweak one of the output source files to tie the web service to our implementation code (ForecastServerImpl.java). Since we passed a mere interface to the Java2WSDL tool, the generated code has left out the implementation. We need to fill out the methods to delegate the work to our implementation object ForecastServerImpl.

FcastSoapBindingImpl.java is waiting for us to add the stuff into the methods that it created. The lines that should be added are highlighted in boldface in Listing 10-1 below.

 package stock_analyst.interact.ws;

 import stock_analyst.interact.ForecastServerImpl; // Axis generated

 public class FcastSoapBindingImpl implements stock_analyst.interact.ForecastServer {

     ForecastServerImpl analyst; // Axis generated

     // Axis generated
     public FcastSoapBindingImpl() throws java.rmi.RemoteException {
         analyst = new ForecastServerImpl();
     }

     public void getPriceForecast(
         stock_analyst.interact.ParamsBean inout0
     ) throws java.rmi.RemoteException {
         return analyst.getPriceForecast(inout0); // Axis generated
     }

     public void getRecommendation(
         stock_analyst.interact.ParamsBean inout0
     ) throws java.rmi.RemoteException {
         return analyst.getRecommendation(inout0); // Axis generated
     }
 }

Listing 10-1: FcastSoapBindingImpl.java – Java code automatically generated by Axis, with the manually added modifications as commented.

Step 5: Compile and deploy

We first need to compile and compress our newly generated Web service, including both the original code and the automatically generated Web service code:

javac -d bin src/stock_analyst.interact.ws/*.java
cd bin
jar -cvf ../stock_analyst.jar *
cd ..

Finally, we copy the JAR file into Tomcat library path visible by Axis and deploy it:

cp stock_analyst.jar $TOMCAT_HOME/webapps/axis/WEB-INF/lib/
--reply=yes
java org.apache.axis.client.AdminClient
-l "http://localhost:8080/axis/services/AdminService"
src/stock_analyst/interact/ws/deploy.wsdd

Admin client is yet another command line tool provided by Apache Axis, which we can use to do tasks such as deployment, un-deployment, and listing the current deployments. We pass the deployment descriptor to this program so it can do its work.

Now our Stock Forecasting Web Service is up and running on the server.

Client-side Development with Axis

At the client side (or the service consumer side), the steps are as follows:

  1. Generate the stub Java class (server-side SOAP proxy) from the WSDL document
  2. Modify the client code to invoke the stub (created in Step 1 above)

Step 1: WSDL2Java – Generate client-side stub

The Step 1 is the same as Step 3 for the server side, except that this time we omit the option -s on the command line. We have seen above that WSDL2Java generated the client-side stub code FcastSoapBindingStub.java that encapsulates client access.

Step 2: Modify the client code to invoke the stub

Normally, a client program would not instantiate a stub directly. It would instead instantiate a service locator and call a get method which returns a stub. Recall that ForecastServerServiceLocator.java was generated in Step 3 of the server side. This locator is derived from the service element in the WSDL document. WSDL2Java generates two objects from each service element. The service interface defines a get method for each endpoint listed in the service element of the WSDL document. The locator is the implementation of this service interface. It implements these get methods. It serves as a locator for obtaining Stub instances. The Service class will generate, by default, a Stub that points to the endpoint URL described in the WSDL document, but you may also specify a different URL when you ask for the endpoint.

A typical usage of the stub classes would be as follows Listing 10-2 below:

 package facilitator.client;

 import stock_analyst.interact.ws.ForecastServerService;
 import stock_analyst.interact.ws.ForecastServerServiceLocator;

 public class Facilitator {
     public static void main(String[] args) throws Exception {
         // Make a service
         ForecastServerService service1 =
                        new ForecastServerServiceLocator();

         // Now use the service to get a stub which implements the SDI.
         ForecastServer endpoint1 = service1.getForecastServer();

         // Prepare the calling parameters
         ParamsBean args = new ParamsBean();
         args.addParam("...", "..."); // 1st parameter
         //...etc.... // 2nd parameter

             // Make the actual call
             try {
                 endpoint1.getRecommendation(args);
                 args.getParam("result", ...); // retrieve the recommendation
                 // ... do something with it ...
             } catch (RemoteException ex) {
                 // handle the exception here
             }
             //...call endpoint2(i.e.another forecaster web service)
     }
 }

Listing 10-2: Example of the Delphi method facilitator client for the project Web-based Stock Forecasters


Licenses and Attributions


Speak Your Mind

-->