SOAP

SOAP is an acronym for Simple Object Access Protocol.  It is an application-layer protocol that is usually carried within HTTP messages, although it can be used with other protocols at this level, such as SMTP.  SOAP messages  -- not surprisingly -- are comprised entirely of XML.  SOAP originated in the latter part of the 1990s, with SOAP 1.0 appearing in December, 1999.

SOAP is important because it can be used to build a standards-based infrastructure for distributed systems that is built on XML and enables communication among multiple components written in different languages running on different vendor platforms.

SOAP can currently be used in one of two basic ways.  First, it supports a form of Remote Procedure Call (RPC) in which a client makes a requests and waits for a response.  Second, it supports a document-oriented approach in which a client submits an XML document that may involve a number of different transactions from a number of different remote services.  The client would not necessarily await a response for this second type of request.

SOAP messages can, of course, be handled by any program designed to do so.  Most often, however, they are handled by a so-called SOAP engine.  These servers listen for connections, receive HTTP Requests (and, perhaps, other similar protocols), unpack the SOAP message carried in the data portion of the HTTP (or other) message, and pass the SOAP XML string to a back-end process for parsing and processing.  When the back-end finishes its work, it passes the SOAP XML response message back to the SOAP engine, which returns the result as an HTTP (or similar) Response. 

Because of this close relationship with HTTP, SOAP engines can be implemented using conventional Servlets, thereby taking advantage of the Servlet engines HTTP support.  Such is the case for Axis, the SOAP engine distributed by Apache.  This is evident from the implementation procedure of just adding Axis directories to Tomcat, or another Servlet engine's, webapps directory.

There are a number of SOAP tutorials available.  One that that I have found useful is W3Schools Soap Tutorial, and the XML.org site lists a number of tutorials on the subject.

The discussion that follows will focus on SOAP RPC messages, as implemented in Java and using an AXIS engine for processing.


Protocol

Like most protocols, SOAP messages are carried in a packet, called an envelope.  The envelope must include a body, but it may include an optional header.  SOAP also uses several namespaces.  The following is a basic SOAP template:

<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
  ...
</soap:Header>
<soap:Body>
  ...
  <soap:Fault>
    ...
  </soap:Fault>

</soap:Body>
</soap:Envelope>

Both the soap and the encodingStyle namespaces are required in the envelope.  The body may include fault elements, but they are not mandatory.

SOAP messages are one of  two basic types:  requests or responses.  Rather than discuss requests and responses in the abstract, they are discussed with respect to a simple example.

The example is based on a Hello, World Java classe, called MessageObject.  MessageObject provides a getMessage() method that returns a String message.  In the example, a Java class, called SOAP_Call, creates a org.apache.axis.client.Call object, points it at the Axis engine, the deployed MessageObject, and its getMessage() method.  It then invokes the call.

The Java support packages (e.g., org.apache.axis.client) generate the necessary SOAP request, send it to the Axis engine as an HTTP request, receive the resulting SOAP response, process it, and return the message String to the original SOAP_Call method.  

On the server side, the Axis engine provides all of the support to process the SOAP request, call the indicated method in the deployed MessageObject, receive its String result, package it in a SOAP response, and return it via HTTP to the client.

The discussion of the example includes the following parts:


1. Example: MessageObject


public class MessageObject extends java.lang.Object
{

	protected java.lang.String message;
	
	public MessageObject()
	{
	    message = "Hello, World, from jbs MessageObject";
	}

	public void setMessge(java.lang.String message)
	{
	    this.message = message;
	}

	public java.lang.String getMessage()
	{                        
            return this.message;
	}
	
	public java.lang.String getMessageXML()
	{
	    String xmlString  = "<?xml version='1.0'?>\n";
                   xmlString += "<return_message>"; 
                   xmlString += this.message; 
                   xmlString += "</return_message>\n";
                             
            return xmlString;
	}

    }

This class is straight forward.  It includes a getMessage() method that returns an Hello, World message.  It is this method that is called in an rpc-like way by a SOAP request.

 


SOAP Client

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

import javax.xml.namespace.QName;

public class SOAP_Call
{
    public static String callService()
    {
        String msg = null;

        try {

           String endpoint = 
                    "http://jbs.cs.unc.edu:8888/axis/MessageObject.jws";
     		  //"http://jbs.cs.unc.edu:8888/axis/services/MessageObject";

           Service  service = new Service();
           Call     call    = (Call) service.createCall();

           call.setTargetEndpointAddress( new java.net.URL(endpoint) );
           call.setOperationName(new QName("http://soapinterop.org/", "getMessage") );

           msg = (String) call.invoke( new Object[]{}  );
           
       } catch (Exception e) {
           System.err.println(e.toString());
       }
       return msg;
       
    }

    public SOAP_Call()  {
        super();
    }
}

This client relies on the org.apache.axis.client package for Java-level support.  A Service obgject is created which, in turn, is used to create a Call object.  Several parameters are set on the Call object: the URL for the endpoint (the Axis engine plus deployed MessageObject class) and the name of the method Axis is to call, structured as a namespace qualified name.  The particular namespace used here, soapinterop.org, is one registered by Apache, is often seen in similar examples, is used here simply for convenience, but could be any unique string.


SOAP Request: MessageObject

POST /axis/MessageObject.jws HTTP/1.0
Host: localhost
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Content-Length: 448

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
                  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
 <soapenv:Body>
  <ns1:getMessage xmlns:ns1="http://soapinterop.org/"/>
 </soapenv:Body>
</soapenv:Envelope>

The SOAP request is carried in the body of an HTTP request; thus, note the HTTP header information appearing above the SOAP request, proper.

The only unusual aspect of the SOAP request is all of the namespaces referenced.  Those in the envelope are conventional and most are expected by the SOAP engine (e.g.,  encodingStyle, soapenv, xsd, xsi, and SOAP-ENC).  The soapinterop.org namespace appears in the body and is required because of the QName reference in the client; that is, it qualifies getMessage.


SOAP Response: MessageObject

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Date: Tue, 17 Sep 2002 15:35:36 GMT
Server: Apache Tomcat/4.0.4 (HTTP/1.1 Connector)
Connection: close
Set-Cookie: JSESSIONID=115C2B8879FCC1E2603BE3F9617D7910;Path=/axis

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ns1:getMessageResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
                          xmlns:ns1="http://soapinterop.org/">
   <getMessageReturn xsi:type="xsd:string">Hello, World, from jbs MessageObject</getMessageReturn>
  </ns1:getMessageResponse>
 </soapenv:Body>
</soapenv:Envelope>

Similarly, the SOAP response is carried in the body of an HTTP response; thus, note the HTTP header information appearing above the SOAP response, proper.

Again, the envelope namespaces are conventional.  In the body, note that the tag for the response is constructed from the name of the method with Response appended.  Within it, the actual data value is bounded by another constructed tag;  the name of the method with Return appended, indicating that the value is that returned by the method called.  Note also that its type is indicated as xsd:string