SOAP and the WebRub-a-Dub-Dub-Dubya
ABSTRACT
Simple Object Access Protocol (SOAP) is an Extensible Markup Language (XML)-based standard for invoking methods across the Web. Based on XML, it is one of the underpinnings of Web services. SOAP consists of three parts: An XML envelope that defines a framework for describing messages, a set of rules for application-defined datatypes, and a convention for remote procedure calls and responses. This paper discusses the basics of SOAP, then illustrates those concepts by deploying a SOAP service and a client application that accesses it.
Table of Contents
1. Introduction
SOAP is an XML-based protocol for exchanging information in a distributed environment. It consists of three parts: an XML <Envelope> used to transmit information, a set of encoding rules for representing application-defined datatypes, and a convention for representing remote procedure calls and responses. In this paper, we will focus on the third portion, demonstrating how SOAP enables an application to interact with remote objects, moving structured XML data across a network. Before we discuss that, we'll take a brief look at the other two parts of SOAP.
1.1. The <Envelope> Please
The first part of SOAP defines the Envelope, the top-level element of all SOAP messages. Here's an example from the SOAP 1.1 specification:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetLastTradePrice xmlns:m="Some-URI"> <symbol>DIS</symbol> </m:GetLastTradePrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
In this sample, the Envelope contains a <m:GetLastTradePrice> element, an element that contains some application-specific markup. The application-specific markup is namespace-qualified, allowing any XML markup to be contained inside the Envelope. When we discuss this in terms of remote objects, we will use the Envelope to pass method names and parameters to the remote object, and we will use the Envelope to return the results of the method invocation (or any fault codes or exceptions) as well.
1.2. Encoding Objects in XML
In order to work with remote objects, SOAP needed a way to encode complex objects in XML. If a remote object has a method that requires a particular object type as an argument, that object must be included in the Envelope along with the more traditional data types. SOAP defines a number of data types, as well as a way to derive new types. The SOAP type system is based on the XML Schema Datatypes specification. Here is another example from the SOAP 1.1 specification, demonstrating an array of values:
<xyz:Person> <name>John Hancock</name> <phoneNumbers SOAP-ENC:arrayType="xyz:phoneNumber[2]"> <phoneNumber>206-555-1212</phoneNumber> <phoneNumber>1-888-123-4567</phoneNumber> </phoneNumbers> </xyz:Person>
In this example, the element <phoneNumbers> contains an array of two <phoneNumber> elements. Although the encoding mechanisms contain much more detail than we will cover here, it suffices to say that complex data structures and objects can be encoded in the <Envelope>, meeting our needs for working with remote objects.
2. Working with Remote Objects
Having described (albeit briefly) the SOAP protocol, we now turn our attention to working with remote objects. To simplify our discussion, we will discuss invoking remote objects with the Apache SOAP Toolkit, an open source, Java-based implementation of the SOAP protocol. The best feature of the Apache SOAP Toolkit is that it makes it easy to deploy applications as SOAP services, and it makes it easy to write client applications that work with those services.
2.1. Deploying a SOAP Service
Before we begin to work with a remote object, we need to create that remote object. We will use the following piece of code for our demonstrations:
public class HelloWorld
{
String message = "Hello, World!";
public String getMessage()
{
return message;
}
public void setMessage(String m)
{
message = m;
}
}
This code is generously donated to the public domain, with the understanding that it not be used to develop weapons of mass destruction. No animals were harmed during the development, debugging, deploying, or deploring of this application.
Our underwhelming object is a Java class with two public methods: getMessage, which takes no arguments and returns a String; and setMessage, which takes a String as an argument and returns nothing. Once this object is deployed on our server, we can write a SOAP application that invokes these methods. (As we shall see, the Apache SOAP Toolkit shields us from all of the XML details mentioned in the previous section.)
To deploy this application, we will use the SOAP administration console, stunningly depicted in the following figure:
The SOAP administration console
The console provides an HTML form for deploying our application. There are three pieces of information that are required to deploy the application:
-
An ID for the application (any string)
-
The name of each public method we want to make available to remote clients
-
The name and type of all arguments to all of the available methods.
Once this application has been deployed, we can move on to writing the client code that will access our SOAP service. The most significant aspect of our deployment is that we did not have to change any of our original code. The HelloWorld.java file has no knowledge of XML, SOAP, or networking, yet we can deploy this code on a SOAP server so that any machine on the same network can access this code and invoke its methods.
2.2. Accessing a SOAP Service
Now that we have deployed our SOAP service, we can access its methods. Our client application needs four pieces of information to access the SOAP service:
-
The URL of the SOAP router
-
The ID of the application (defined when we deployed it)
-
The name of the public method we want to invoke
-
The arguments (if any) for the method we want to invoke.
We will create a SOAP client application that calls getMessage to retrieve the default greeting, then calls setMessage to change the greeting, wrapping up with another call to getMessage to demonstrate that the default greeting has in fact been changed. Here are the results of a sample run of our client:
C:\SOAP>java HelloWorldClient Invoking service: URL = http://localhost:8080/soap/servlet/rpcrouter URN = urn:Services:HelloWorld Result from getMessage = Howdy, World! Now we're going to call setMessage(), then getMessage() again. Result from getMessage = Howdy, World!
We will review one of the three remote method invocations to illustrate how the Apache SOAP Toolkit works. The setMessage method makes the best example because it requires a parameter. Here is the actual code from HelloWorldClient.java that makes the method call:
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;
import org.apache.soap.Constants;
import org.apache.soap.Fault;
import org.apache.soap.SOAPException;
import org.apache.soap.rpc.Call;
import org.apache.soap.rpc.Parameter;
import org.apache.soap.rpc.Response;
public class HelloWorldClient
{ public static void main(String[] args)
{ try
{ URL url = new URL("http://localhost:8080/soap/servlet/rpcrouter");
String urn = "urn:Services:HelloWorld";
Call call = new Call();
call.setTargetObjectURI(urn);
... System.out.println("\nNow we're going to call setMessage(),
then getMessage() again.");
call.setMethodName("setMessage");
params = new Vector();
params.add(new Parameter("message", String.class, "Howdy, World!", null));
call.setParams(params);
response = call.invoke(url, "");
if (response.generatedFault())
{ Fault f = response.getFault();
System.err.println("Fault = " + f.getFaultCode() +
"," + f.getFaultString()); }
There are several things worth mentioning in this somewhat lengthly listing. First of all, notice that our client application imported several classes from the Apache SOAP Toolkit, the java.net package, and elsewhere. Although our deployed application is not required to be SOAP-aware, any SOAP client must understand how to connect to a SOAP server and invoke remote methods.
To invoke the remote method, we create a Call object, then set its various properties accordingly. We have to set the ID of the service and create the appropriate parameters, then we can use the Call.invoke method. This method returns a Response object; we can look at the state of the Response object to determine if the remote method call was successful. Finally, notice that the Apache SOAP Toolkit provides a Fault class that encapsulates information about a SOAP error. This allows us to handle error conditions cleanly in our client applications.
The administration console provided by the Apache SOAP Toolkit makes it easy to deploy a piece of code as a SOAP service. In addition, classes like Call, Response, Fault, and Parameter greatly simplify the task of writing a SOAP client application. In our sample client application, we were not required to parse the <Envelope> or <Body> elements; that work is handled for us by the toolkit.
2.3. SOAP and Universal Discovery, Description, and Integration (UDDI)
In the world of Web services, the ability to invoke remote methods is crucial. In our client application, notice that we hardcoded all of the details about the remote application and its methods. To enable more dynamic applications, the UDDI is designed to help client applications discover all of these details at runtime. Although UDDI is beyond the scope of this paper, our exploration of SOAP puts the goals of UDDI in perspective.
3. Summary
In this paper, we have briefly reviewed SOAP and its facilities for remote method invocation. As Web services become more important, SOAP will become a vital part of tomorrow's Web infrastructure.


