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.
In this chapter
- What is Apache Axis?
- Server-side Development with Apache Axis
- Step 1: Define the server object interface
- Step 2: Java2WSDL – Generate a WSDL document from the given stock-forecasting Java interface
- Step 3: WSDL2Java – Generate server-side wrapper code
- Step 4: Tune-up – Modify
FcastSoapBindingImpl.java
to call server implementation code - Step 5: Compile and deploy
- Client-side Development with 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:
- Define Java interface of the Web service (and a class that implements this interface)
- Generate the WDSL document from the service’s Java interface (Java -> WSDL)
- Generate the skeleton Java class (server-side proxy) from the WSDL document (WSDL -> Java)
- 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.
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 methodgetPriceForecast()
.
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
, orSession
) - 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 undersrc/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:
- Generate the stub Java class (server-side SOAP proxy) from the WSDL document
- 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