Using SOAP with Tomcat

02/27/2002

The Apache SOAP Project is an open source Java implementation of the Simple Object Access Protocol (SOAP) v1.1. SOAP is a wire protocol that leverages HTTP or SMTP as its transport layer and XML as its data layer, to execute remote methods, known as SOAP services.

The Apache implementation of SOAP provides two methods for invoking SOAP services: a Remote Procedure Call (RPC) model and a message-based model. The RPC method, which is the focus of this article, is a synchronous technique using a client-server model to execute remote SOAP services. The message-based model uses SMTP to transport SOAP documents to and from the appropriate SOAP server. While this method is interesting, it is out of the scope of this article.

The RPC model can be defined using the following steps:

A client application builds an XML document containing the URI of the server that will service the request, the name of the remote method to execute, and the parameters associated with that method.

The targeted server receives and unwinds the XML document. It then executes the named method.

After the named method has returned its results, the results are packed into a response XML document, which is sent back to the calling client.

The client application receives the response and unwinds the results, which contains the response of the invocated method.

Integrating Apache SOAP into Tomcat

Before we begin using the Apache SOAP project, we must acquire the necessary components to execute SOAP services. Listing 1 provides a list of these items and where they can be found.

Listing 1. Components required to execute SOAP clients and services

SOAP v2.2 (soap.jar)

http://xml.apache.org/soap/index.html

mail.jar v1.2

This .jar file is packaged with Tomcat in the <TOMCAT_HOME>/common/lib/ directory.

activation.jar v1.0.1

This .jar file is packaged with Tomcat in the <TOMCAT_HOME>/common/lib/ directory.

xerces.jar v1.4.2

This .jar file is packaged with Tomcat in the <TOMCAT_HOME>/common/lib/ directory.

Once we have all of these items, we need to extract the SOAP archive to a local directory. We then need to add each of the previously mentioned .jar files to your classpath, including soap.jar, which comes packaged with the SOAP archive. This step is very important and must not be ignored.

Deploying Apache-SOAP using Tomcat

There are several ways to deploy a SOAP project to Tomcat. Of these methods, we are going to perform the easiest, which is simply to copy the soap.war file to the <TOMCAT_HOME>/webapps/ directory. You can find this file in the SOAP 2.2 archive.

Once you have moved the soap.war file into <TOMCAT_HOME>/webapps/directory, you need to make sure that each of the previously listed .jar files are in the <TOMCAT_HOME>/common/lib/ directory, excluding the soap.jar file.

After you have copied the above files to the named locations, restart Tomcat. You should now be able to access the SOAP Web application by opening your Web browser to http://localhost:8080/soap/

At this point, you should also be able to use the SOAP admin tool, which can be accessed by selecting the Run link. Figure 2 shows the home page for the SOAP admin tool. From this page, you can list the current services, deploy new services, and remove previously-deployed services.

Creating a Sample SOAP Application

Now let's develop a simple SOAP application that acts as a simple integer calculator, with only addition and subtraction functions. To do this, we need to first develop a SOAP service for handling our calculator functions, and then create a client to access the service.

SOAP Services

Writing an RPC-based SOAP service is a very simple process that can be broken down into three steps.

Create the Java class that contains the SOAP service to publish.

Create a deployment descriptor that describes the service.

Publish the service.

Creating a SOAP Service

Creating a SOAP service is the simplest step of the entire "SOAPifying" process. A SOAP service can be just about any Java class that exposes public methods for invocation. The class does not need to know anything about SOAP, or even that it is being executed as a SOAP service.

The only restriction is that the method parameters of a SOAP service must be serializable. The available types that can, by default, be used as SOAP service parameters are shown in Listing 2.

Listing 2. Types that can be used as SOAP service parameters.

All Java primitive types and their corresponding wrapper classes

Java arrays

java.lang.String

java.util.Date

java.util.GregorianCalendar

java.util.Vector

java.util.Hashtable

java.util.Map

java.math.BigDecimal

javax.mail.internet.MimeBodyPart

java.io.InputStream

javax.activation.DataSource

javax.activation.DataHandler

org.apache.soap.util.xml.QName

org.apache.soap.rpc.Parameter

java.lang.Object (must be a JavaBean)

The source listing for our service, a simple adding and subtracting calculator, is shown in its entirety in Example 1.

As you can see, there is really nothing special about this class. It simply defines two public methods, add() and subtract(), each with a parameter list containing two native ints. To make this class available, build and copy it into the <TOMCAT_HOME>/webapps/soap/WEB-INF/classes/onjava/ directory.

Creating the Deployment Descriptor

The next step in creating a new SOAP service is to create a deployment descriptor. The deployment descriptor describes the SOAP service. This description is required for the service to be published as an Apache SOAP service. The deployment descriptor for our service is contained in Example 2.

The deployment descriptor for our calculator service contains only three elements that we need to look at. The first element is the service element, which defines two attributes, the XML namespace and the unique ID of the service to be deployed. The ID defined in the service element must be unique, since this attribute is used to uniquely identify a published SOAP service.

The next element we need to examine is the provider element. It defines the actual implementation of the SOAP service. It does this with three attributes, each of which are defined as follows:

Listing 3. Attributes of the Provider Element

type

The type attribute defines the implementation type of the SOAP service. We defined our service as a Java service.

scope

The scope attribute defines the lifetime of the SOAP service. The possible values are page, scope, session, and application. These scope values map one-to-one with the scope values defined by the JSP specification.

methods

The methods attribute defines the names of the methods that can be invoked on this service object. This list should be a space-separated list of method names.

The final element of the deployment descriptor that we'll look at here is the java element. This element contains a single attribute, class, which names the fully qualified class of the named service.

Running the Server-Side Admin Tool to Manage Services

Now that we have defined our SOAP service and its deployment descriptor, we can publish it so that it can start servicing requests. To do this, you need to first compile the service and make sure it is in your classpath.

After you have compiled the service, you're ready to deploy it. The Apache SOAP Project is packaged with two administration tools -- a graphical tool and a command-line tool. They both allow you to easily deploy and undeploy services to the SOAP server. The three functions provided by these tools are listed below:

The deploy function allows you to deploy a new service to a SOAP server.

The undeploy function removes an existing SOAP service from a SOAP server.

The list function lists all deployed SOAP services.

For our examples, we are going to use the Apache SOAP command-line tools to manage our service. SOAP command-line management functions are implemented by the org.apache.soap.server.ServiceManagerClient class. Using the ServiceManagerClient is very easy. We'll go through each of its functions in this section.

As we cover the following commands, you should note that each command references a servlet named rpcrouter. This servlet is at the core of all SOAP actions. It performs all service management and execution.

List

The list command lists all currently deployed services. To execute the list command, type the following line:

If you have not published any other SOAP services, you should get a response that shows no deployed services. If you examine this command, you see that it executes the Java application ServiceManagerClient with two parameters: the location of the SOAP server, and the command to perform (list, in this case).

Deploy

The deploy command deploys our service to the SOAP server. This command also uses the ServiceManagerClientwith the deployment descriptor describing the SOAP service. To deploy our service, execute the following command:

This command takes three parameters: the URL to the SOAP server, the command deploy, and the file containing our deployment descriptor. After you have executed this command, execute the list command. You should now see output listing urn:onjavaserver, which is the unique ID of our service. You can also view this service from the Web admin tool. Go to http://localhost:8080/soap/admin/index.html and select the "List" button. Typical results are shown in Figure 3.

If you select the service name, you will see the details of the service, as shown in Figure 4.

Undeploy

The undeploy command removes a previously deployed service. To execute the undeploy command, type the following line:

Note: Do not execute this command until you have completed the remaining exercises in this article.

The undeploy command takes three parameters: the location of the SOAP server, the actual command to perform (in this case, the undeploy command), and the name of the service to remove.

SOAP Clients

Now that we have a service defined and deployed, let's write a client that will execute one of the service's methods. The Apache SOAP Project provides a client-side API that makes it extremely simple to create SOAP clients. An example client, which we will use to execute the subtract method of our service, can be found in Example 3.

This client follows a simple process that is common to most SOAP RPC clients. It first creates a URL referencing the rpcrouter (which we noted earlier) on the HTTP server localhost. This is done in the following code snippet:

URL url = new URL
("http://localhost:8080/soap/servlet/rpcrouter");

The next step performed by the client application is to parse the arguments from the command line. These values will be passed to the SOAP service in a subsequent method. The values created will be integers.

After the client has parsed to command-line arguments, it creates an instance of an org.apache.soap.rpc.RPCMessage.Call. The Call object is the main interface used when executing a SOAP RPC invocation.

To use the Call object, we first tell it which service we want to use. We do this by calling the setTargetObjectURI, passing it the name of the service that we want to execute. We then set the name of the service method we want to execute using the setMethodName() method, with the name of the method we want to execute. The next step is to set the encoding style used in the RPC call. The final step is to add the parameters that are expected when executing the named method. This is done by creating a Vector of Parameter objects and adding them to the Call object using the setParams() method. All of these steps are completed using the following code snippet:

The next step performed by the client application is to call the service method that we are interested in. This is done using invoke() with the URL we created earlier. Here is the snippet of code calling the invoke() method:

Response resp = call.invoke(url, "" );

You will notice the return value of the invoke() method is a Response object. The Response object returns two very important items -- an error code and the value returned from the executed service method. You check for an error by calling the generatedFault() method. This method will return true if there was an error returned; then you can check the getFault() method. If generatedFault() returns false, you can then get the value returned in the Response object, using the Response.getReturnValue() method. The following code snippet shows how you should process the response of an invoke():

That is all there is to it. To test your client and service, compile the client and execute it using the following command line:

java onjava.CalcClient 98 90

Note:At this point, you should have the CalcService deployed and Tomcat should be running.

Summary

In this article we discussed the Apache SOAP Project. We described each of the steps involved when integrating SOAP into the Tomcat container. We also created a sample SOAP application demonstrating how each of the SOAP components works together.

As for the next topic we examine, I am leaving it up to you. From this point, we can go in many different directions. Some of the topics that we can discuss include:

Further Apache SOAP topics

The Java Web Services Developers Pack (WSDP)

The Apache Axis Project (the next Apache SOAP implementation)

Please let me know where you think we should go next, or if you have other related topics that you would like to see covered. You can reach me at jgoodwill@virtuas.com
Please include "onjava" in the subject line.