ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Using Tomcat

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:

  1. 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.
  2. The targeted server receives and unwinds the XML document. It then executes the named method.
  3. 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.
  4. 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.

Related Reading

Programming Web Services with SOAP
By James Snell, Doug Tidwell, Pavel Kulchenko

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/

You should see a page similar to Figure 1.

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.

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.

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

Example 1. Simple calculator service

package onjava;
public class CalcService {
  public int add(int p1, int p2) {
  
    return p1 + p2;
  }

  public int subtract(int p1, int p2) {

    return p1 - p2;
  }
}

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.

Example 2. Deployment descriptor for a simple calculator

<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
    id="urn:onjavaserver">
        <isd:provider type="java"
            scope="Application"
            methods="add subtract">
            <isd:java class="onjava.CalcService"/>
        </isd:provider>
    <isd:faultListener>org.apache.soap.server.DOMFaultListener</isd:faultListener>
</isd:service>

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:

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.

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.

Example 3. A SOAP Client

package onjava;

import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.soap.*;
import org.apache.soap.rpc.*;

public class CalcClient {

  public static void main(String[] args) throws Exception {

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

    Integer p1 = new Integer(args[0]);
    Integer p2 = new Integer(args[1]);

    // Build the call.
    Call call = new Call();
    call.setTargetObjectURI("urn:onjavaserver");
    call.setMethodName("subtract");
    call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
    Vector params = new Vector();
    params.addElement(new Parameter("p1", Integer.class, p1, null));
    params.addElement(new Parameter("p2", Integer.class, p2, null));
    call.setParams (params);

    // make the call: note that the action URI is empty because the
    // XML-SOAP rpc router does not need this. This may change in the
    // future.
    Response resp = call.invoke(url, "" );

    // Check the response.
    if ( resp.generatedFault() ) {

      Fault fault = resp.getFault ();
      System.out.println("The call failed: ");
      System.out.println("Fault Code   = " + fault.getFaultCode());
      System.out.println("Fault String = " + fault.getFaultString());
    }
    else {

      Parameter result = resp.getReturnValue();
      System.out.println(result.getValue());
    }
  }
}

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.


O'Reilly Emerging Technologies Conference

The 2002 O'Reilly Emerging Technologies Conference explored how P2P and Web services are coming together in a new Internet operating system.


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:

Call call = new Call();

call.setTargetObjectURI("urn:onjavaserver");

call.setMethodName("subtract");

call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

Vector params = new Vector();

params.addElement(new Parameter("p1", Integer.class, p1, null));

params.addElement(new Parameter("p2", Integer.class, p2, null));

call.setParams (params);

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():

if ( resp.generatedFault() ) {

  Fault fault = resp.getFault();

  System.out.println("The call failed: ");

  System.out.println("Fault Code   = " + fault.getFaultCode());

  System.out.println("Fault String = " + fault.getFaultString());

}

else {

  Parameter result = resp.getReturnValue();

  System.out.println(result.getValue());

}

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:

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.

James Goodwill is the co-Founder of Virtuas Solutions, LLC, a Colorado-based software consultancy.


Read more Using Tomcat columns.

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.