O'Reilly logo

Java Web Services: Up and Running by Martin Kalin

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Java’s SOAP API

A major appeal of SOAP-based web services is that the SOAP usually remains hidden. Nonetheless, it may be useful to glance at Java’s underlying support for generating and processing SOAP messages. Chapter 3, which introduces SOAP handlers, puts the SOAP API to practical use. This section provides a first look at the SOAP API through a simulation example. The application consists of one class, DemoSoap, but simulates sending a SOAP message as a request and receiving another as a response. Example 1-10 shows the full application.

Example 1-10. A demonstration of Java’s SOAP API

package ch01.soap;

import java.util.Date;
import java.util.Iterator;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.Node;
import javax.xml.soap.Name;

public class DemoSoap {
    private static final String LocalName = "TimeRequest";
    private static final String Namespace = "http://ch01/mysoap/";
    private static final String NamespacePrefix = "ms";

    private ByteArrayOutputStream out;
    private ByteArrayInputStream in;

    public static void main(String[ ] args) {
       new DemoSoap().request();
    }

    private void request() {
       try {
         // Build a SOAP message to send to an output stream.
         SOAPMessage msg = create_soap_message();
   
         // Inject the appropriate information into the message. 
         // In this case, only the (optional) message header is used
         // and the body is empty.
         SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
         SOAPHeader hdr = env.getHeader();
  
         // Add an element to the SOAP header. 
         Name lookup_name = create_qname(msg);
         hdr.addHeaderElement(lookup_name).addTextNode("time_request");

         // Simulate sending the SOAP message to a remote system by
         // writing it to a ByteArrayOutputStream.
         out = new ByteArrayOutputStream();
         msg.writeTo(out);

         trace("The sent SOAP message:", msg);

         SOAPMessage response = process_request();
         extract_contents_and_print(response);
       }
       catch(SOAPException e) { System.err.println(e); }
       catch(IOException e) { System.err.println(e); }
    }

    private SOAPMessage process_request() {
       process_incoming_soap();
       coordinate_streams();
       return create_soap_message(in);
    }
       
    private void process_incoming_soap() {
       try {
         // Copy output stream to input stream to simulate
         // coordinated streams over a network connection.
         coordinate_streams();

         // Create the "received" SOAP message from the
         // input stream.
         SOAPMessage msg = create_soap_message(in);

         // Inspect the SOAP header for the keyword 'time_request' 
         // and process the request if the keyword occurs.
         Name lookup_name = create_qname(msg);

         SOAPHeader header = msg.getSOAPHeader();
         Iterator it = header.getChildElements(lookup_name);
         Node next = (Node) it.next();
         String value = (next == null) ? "Error!" : next.getValue();

         // If SOAP message contains request for the time, create a
         // new SOAP message with the current time in the body.
         if (value.toLowerCase().contains("time_request")) {

           // Extract the body and add the current time as an element.
           String now = new Date().toString();
           SOAPBody body = msg.getSOAPBody();
           body.addBodyElement(lookup_name).addTextNode(now);
           msg.saveChanges();

           // Write to the output stream.
           msg.writeTo(out);
           trace("The received/processed SOAP message:", msg);
         }
       }
       catch(SOAPException e) { System.err.println(e); }
       catch(IOException e) { System.err.println(e); }
    }
    
    private void extract_contents_and_print(SOAPMessage msg) {
       try {
         SOAPBody body = msg.getSOAPBody();

         Name lookup_name = create_qname(msg);
         Iterator it = body.getChildElements(lookup_name);
         Node next = (Node) it.next();
    
         String value = (next == null) ? "Error!" : next.getValue();
         System.out.println("\n\nReturned from server: " + value);
       }
       catch(SOAPException e) { System.err.println(e); }
    }

    private SOAPMessage create_soap_message() {
       SOAPMessage msg = null;
       try {
         MessageFactory mf = MessageFactory.newInstance();
         msg = mf.createMessage();
       }
       catch(SOAPException e) { System.err.println(e); }
       return msg;
    }

    private SOAPMessage create_soap_message(InputStream in) {
       SOAPMessage msg = null;
       try {
         MessageFactory mf = MessageFactory.newInstance();
         msg = mf.createMessage(null, // ignore MIME headers
                                in);  // stream source
       }
       catch(SOAPException e) { System.err.println(e); }
       catch(IOException e) { System.err.println(e); }
       return msg;
    }

    private Name create_qname(SOAPMessage msg) {
       Name name = null;
       try {
         SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
         name = env.createName(LocalName, NamespacePrefix, Namespace);
       }
       catch(SOAPException e) { System.err.println(e); }
       return name;
    }

    private void trace(String s, SOAPMessage m) {
       System.out.println("\n");
       System.out.println(s);
       try {
         m.writeTo(System.out);
       }
       catch(SOAPException e) { System.err.println(e); }
       catch(IOException e) { System.err.println(e); }
    }

    private void coordinate_streams() {
       in = new ByteArrayInputStream(out.toByteArray());
       out.reset();
    }
}   

Here is a summary of how the application runs, with emphasis on the code involving SOAP messages. The DemoSoap application’s request method generates a SOAP message and adds the string time_request to the SOAP envelope’s header. The code segment, with comments removed, is:

SOAPMessage msg = create_soap_message();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
Name lookup_name = create_qname(msg);
hdr.addHeaderElement(lookup_name).addTextNode("time_request");

There are two basic ways to create a SOAP message. The simple way is illustrated in this code segment:

MessageFactory mf = MessageFactory.newInstance();
SOAPMessage msg = mf.createMessage();

In the more complicated way, the MessageFactory code is the same, but the creation call becomes:

SOAPMessage msg = mf.createMessage(mime_headers, input_stream);

The first argument to createMessage is a collection of the transport-layer headers (for instance, the key/value pairs that make up an HTTP header), and the second argument is an input stream that provides the bytes to create the message (for instance, the input stream encapsulated in a Java Socket instance).

Once the SOAP message is created, the header is extracted from the SOAP envelope and an XML text node is inserted with the value time_request. The resulting SOAP message is:

<SOAP-ENV:Envelope
     xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
      <ms:TimeRequest xmlns:ms="http://ch01/mysoap/">
        time_request
      </ms:TimeRequest>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body/>
</SOAP-ENV:Envelope>

There is no need right now to examine every detail of this SOAP message. Here is a summary of some key points. The SOAP body is always required but, as in this case, the body may be empty. The SOAP header is optional but, in this case, the header contains the text time_request. Message contents such as time_request normally would be placed in the SOAP body and special processing information (for instance, user authentication data) would be placed in the header. The point here is to illustrate how the SOAP header and the SOAP body can be manipulated.

The request method writes the SOAP message to a ByteArrayOutputStream, which simulates sending the message over a network connection to a receiver on a different host. The request method invokes the process_request method, which in turn delegates the remaining tasks to other methods. The processing goes as follows. The received SOAP message is created from a ByteArrayInputStream, which simulates an input stream on the receiver’s side; this stream contains the sent SOAP message. The SOAP message now is created from the input stream:

SOAPMessage msg = null;
try {
   MessageFactory mf = MessageFactory.newInstance();
   msg = mf.createMessage(null, // ignore MIME headers
                          in);  // stream source (ByteArrayInputStream)
}  

and then the SOAP message is processed to extract the time_request string. The extraction goes as follows. First, the SOAP header is extracted from the SOAP message and an iterator over the elements with the tag name:

<ms:TimeRequest xmlns:ms="http://ch01/mysoap/>

is created. In this example, there is one element with this tag name and the element should contain the string time_request. The lookup code is:

SOAPHeader header = msg.getSOAPHeader();
Iterator it = header.getChildElements(lookup_name);
Node next = (Node) it.next();
String value = (next == null) ? "Error!" : next.getValue();

If the SOAP header contains the proper request string, the SOAP body is extracted from the incoming SOAP message and an element containing the current time as a string is added to the SOAP body. The revised SOAP message then is sent as a response. Here is the code segment with the comments removed:

if (value.toLowerCase().contains("time_request")) {
  String now = new Date().toString();
  SOAPBody body = msg.getSOAPBody();
  body.addBodyElement(lookup_name).addTextNode(now);
  msg.saveChanges();

  msg.writeTo(out);
  trace("The received/processed SOAP message:", msg);
}

The outgoing SOAP message on a sample run was:

<SOAP-ENV:Envelope 
      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
       <ms:TimeRequest xmlns:ms="http://ch01/mysoap/">
          time_request
       </ms:TimeRequest>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
       <ms:TimeRequest xmlns:ms="http://ch01/mysoap/">
          Mon Oct 27 14:45:53 CDT 2008
       </ms:TimeRequest>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

This example provides a first look at Java’s API. Later examples illustrate production-level use of the SOAP API.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required