JMU
Simple Object Access Protocol (SOAP) v1.2
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Simple Object Access Protocol Basics
SOAP Basics (cont.)
The SOAP Envelope
The SOAP Envelope (cont.)

An Example

  <env:Envelope
    xmlns:env="http://www.w3.org/2003/05/soap-envelope"
    xmlns:xml="http://www.w3.org/XML/1998/namespace">




  </env:Envelope>
  
The SOAP Header
The SOAP Body
The SOAP Body (cont.)

An Example

     <env:Body>
         <TextAlert>
             <Message>Port Rd. has been closed</Message>
             <Alert>Road CLosed - Find Alternate</Alert>
             <Priority>6</Priority>
         </TextAlert>
     </env:Body>
  
The Fault Element
Data Types
Data Types (cont.)

An Example

  <element name="age" type="int"/>
  <element name="height" type="float"/>
  <element name="eyecolor">
    <simpleType base="xsd:string">
      <enumeration value="Green"/>
      <enumeration value="Blue"/>
    </simpleType>
  </element>
  
Data Types (cont.)

An Example Using References

  <complexType name="Book">
     <!-- Either the following group must occur or else the
          href attribute must appear, but not both. -->
     <sequence minOccurs="0" maxOccurs="1">
         <element name="title" type="xsd:string"/>
         <element name="firstauthor" type="Person"/>
         <element name="secondauthor" type="Person"/>
     </sequence>
     <attribute name="href" type="uriReference"/>
     <attribute name="id" type="ID"/>
  </complexType>
  
  <Book>
     <title>Paradise Lost</title>
     <firstauthor href="http://www.dartmouth.edu/~milton/"/>
  </Book>
  
Method/Procedure Calls
Method/Procedure Calls (cont.)

An Example: Convert from U.S. dollars to British Pounds

<env:Envelope
  xmlns:env="http://www.w3.org/2003/05/soap-envelope">
   <env:Body>
       <CurrencyConverter>
         <convert>
           <fromCurrency>USD</fromCurrency>
           <toCurrency>GBP</toCurrency>
           <amount>100.00</amount>
         </convert>
       </CurrencyConverter>
   <env:Body>
</env:Envelope>
  
Method/Procedure Calls (cont.)

An Example Response

<env:Envelope
  xmlns:env="http://www.w3.org/2003/05/soap-envelope">
   <env:Body>
       <CurrencyConverterResponse>
         <convert>
           <amount>72.45</amount>
         </convert>
       </CurrencyConverterResponse>
   </env:Body>
</env:Envelope>
  
Method/Procedure Calls (cont.)

An Example Fault

<env:Envelope
  xmlns:env="http://www.w3.org/2003/05/soap-envelope">
   <env:Body>
     <env:Fault>
       <env:Code>env:Server</env:Code>
       <env:Reason>Server Error</env:Reason>
       <env:Detail>
         <FaultDetails>
           <code>8</code>
           <message>Unknown fromCurrency</message>
         </FaultDetails>
       </env:Detail>
     </env:Fault>
   </env:Body>
</env:Envelope>
  
A Currency Converter

The Interface

javaexamples/http/v5/CurrencyConverter.java
/**
 * The requirements of a currency converter
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public interface CurrencyConverter
{

    /**
     * Convert between currencies
     *
     * @param amount  The amount of "from" currency to convert
     * @param from    The "from" currency
     * @param to      The "to" currency
     * @return        The equivalent amount of "to" currency (or -1)
     */
    public double convert(double amount, String from, String to);

}
        
A Currency Converter (cont.)

The Server Side - The Implementation

javaexamples/http/v5/CurrencyConverterImpl.java
/**
 * An implementation of a currency converter
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CurrencyConverterImpl implements CurrencyConverter
{

    /**
     * Convert between currencies (required by CurrencyConverter)
     *
     * @param amount  The amount of "from" currency to convert
     * @param from    The "from" currency
     * @param to      The "to" currency
     * @return        The equivalent amount of "to" currency (or -1)
     */
    public double convert(double amount, String from, String to)
    {
       double        value;

       value = -1.0;
       if (from.equals("USD") && to.equals("GBP")) 
       {
          value = amount / 1.9;
       }


       return value;
    }

}
        
A Currency Converter (cont.)

The Server Side - The Handler

javaexamples/http/v5/CurrencyConverterSOAPHandler.java
import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * Handles elements in CurrencyConverter SOAP requests and responses
 *
 * @author   Prof. David Bernstein, James Madison University
 * @version  1.0
 */
public class CurrencyConverterSOAPHandler extends DefaultHandler
{
    private boolean        foundConvert;
    private String         amount, from, root, to, waitingFor;



    /**
     * Explicit Value Constructor
     *
     * @param root    Either ConvertCurrency or ConvertCurrencyResponse
     */
    public CurrencyConverterSOAPHandler(String root)
    {
       this.root = root;
    }
    


    /**
     * Receive notification of character data inside an element
     *
     * @param ch     The characters
     * @param start  The start position in the character array
     * @param length The number of characters to use from the character array
     */
    public void characters(char[] ch, int start, int length)
    {
       if      (waitingFor.equals("fromCurrency_characters")) 
       {
          from =  new String(ch, start, length).trim();
       }
       else if (waitingFor.equals("toCurrency_characters")) 
       {
          to = new String(ch, start, length).trim();
       }
       else if (waitingFor.equals("amount_characters")) 
       {
          amount = new String(ch, start, length).trim();
       }
    }


    /**
     * Get the amount of the FromCurrency to be converted
     *
     * @return    The amount
     */
    public double getAmount()
    {
       double       amt;

       amt = 0.0;
       try 
       {
          amt = Double.parseDouble(amount);
       }
       catch (NumberFormatException nfe) 
       {
          amt = -1.0;
       }

       return amt;
    }


    /**
     * Get the FromCurrency
     *
     * @return  The FromCurrency
     */
    public String getFromCurrency()
    {
       return from;
    }


    /**
     * Get the ToCurrency
     *
     * @return  The ToCurrency
     */
    public String getToCurrency()
    {
       return to;
    }



    /**
     * Receive notification of the start of an element
     *
     * @param uri        The namespace URI 
     * @param localName  The local name or the empty string (if no namespace)
     * @param qName      The qualified name (with prefix)
     */
    public void endElement(String uri, String localName, String qName)
    {
       if (qName.equals(root))  foundConvert = false;
       if (foundConvert)        waitingFor = "";
    }





    /**
     * Receive notification of the beginning of the document
     *
     */
    public void startDocument()
    {
       foundConvert = false;
       waitingFor = "";
    }




    /**
     * Receive notification of the start of an element
     *
     * @param uri        The namespace URI 
     * @param localName  The local name or the empty string (if no namespace)
     * @param qName      The qualified name (with prefix)
     * @param attributes The specified or default attributes
     */
    public void startElement(String uri, String localName, String qName,
                             Attributes attributes)
    {
       if (foundConvert) 
       {
          waitingFor = qName + "_characters";
       }
       else if (qName.equals(root)) 
       {
          foundConvert = true;
          waitingFor = "";
       }
    }
}
        
A Currency Converter (cont.)

The Server Side - The Servlet

javaexamples/http/v5/CurrencyConverterSOAPServlet.java
import java.io.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;


/**
 * An SOAP servlet for converting currencies.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CurrencyConverterSOAPServlet extends AbstractHttpServlet
{
    /**
     * Default Constructor
     */
    public CurrencyConverterSOAPServlet()
    {
       super();
    }

    /**
     * Explicit Value Constructor
     *
     * @param in   The HttpInputStream to read from
     * @param out  The HttpOutputStream to write to
     */
    public CurrencyConverterSOAPServlet(HttpInputStream  in, 
                                        HttpOutputStream out)
    {
       super(in, out);
    }
    


    /**
     * Handle a SOAP request for a currency converter
     *
     * Note: This method only handles SOAP requests for
     *       a particular service.  It is for illustrative
     *       purposes only.
     *
     * @param request   Contents of the request
     * @param response  Used to generate the response
     */
    protected void doPost(HttpRequest request, 
                          HttpResponse response)
    {
       byte[]                        content;
       ByteArrayInputStream          bis;        
       CurrencyConverterSOAPHandler  handler;
       CurrencyConverter             cc;
       double                        amount, rate, value;
       HttpInputStream               is;
       HttpOutputStream              os;
       InputSource                   inputSource;
       int                           length;
       SAXParser                     parser;
       SAXParserFactory              factory;
       String                        contentString, from, soapResponse;
       String                        soapRequest, to;



       try 
       {
          // Get the Content-Length of the SOAP request
          length = request.getContentLength();            

          // Read the SOAP request
          request.readContent(in);
          contentString = new String(request.getContent());
          soapRequest = URLDecoder.decode(contentString, "UTF-8");

          // Create a ByteArrayInputStream from the SOAP request
          // (for the SAX Parser)
          bis = new ByteArrayInputStream(soapRequest.getBytes());

          // Parse the request
          inputSource = new InputSource(bis);
          factory     = SAXParserFactory.newInstance();
          parser      = factory.newSAXParser();
          handler     = new CurrencyConverterSOAPHandler("convert");
          parser.parse(inputSource, handler);
          amount      = handler.getAmount();
          from        = handler.getFromCurrency();
          to          = handler.getToCurrency();

          // Perform the conversion
          cc = new CurrencyConverterImpl();
          value  = cc.convert(amount, from, to);

          // Create the SOAP response
          // (Note: This version does not use the fault
          //         feature of SOAP but could)
          soapResponse = "<?xml version=\"1.0\"?>"+
             "<env:Envelope>"+
             "<env:Body>"+
             "<CurrencyConverterResponse>"+
             "<convert>"+
             "<amount>"+value+"</amount>"+
             "</convert>"+
             "</CurrencyConverterResponse>"+
             "</env:Body>"+
              "</env:Envelope>";

          // Setup the HTTP response
          response.setContentLength(soapResponse.length());
          response.setStatus(HttpResponse.SC_OK);
          response.setContentType("text/xml");

          // Put the content in the response
          response.setContent(soapResponse.getBytes());
                
          // Transmit the response
          response.write(out);
       } 
       catch (Exception e) 
       {
          response.sendError(HttpResponse.SC_NOT_FOUND, out);
       } 
    }



}
        
A Currency Converter (cont.)

The Client Side

javaexamples/http/v5/CurrencyConverterStub.java
import java.io.*;
import java.net.*;
import java.util.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * A SOAP-based "stub" for a CurrencyCoverter
 *
 * Note: This version does not use the fault feature of SOAP
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CurrencyConverterStub implements CurrencyConverter
{

    /**
     * Convert between currencies (required by CurrencyConverter)
     *
     * @param amount  The amount of "from" currency to convert
     * @param from    The "from" currency (e.g. USD)
     * @param to      The "to" currency (e.g., GBP)
     * @return        The equivalent amount of "to" currency (or -1.0)
     */
    public double convert(double amount, String from, String to)
    {
       ByteArrayInputStream          bis;          
       CurrencyConverterSOAPHandler  handler;
       double                        value;
       HttpInputStream               in;
       HttpOutputStream              out;          
       HttpRequest                   request;
       HttpResponse                  response;
       InputSource                   inputSource;
       SAXParser                     parser;
       SAXParserFactory              factory;
       Socket                        socket;
       String                        requestString, responseString;
       String                        soapResponse;
       URI                           u;
        
       value = 0.0;
        
       requestString = "<?xml version=\"1.0\"?>"+
          "<env:Envelope>"+
          "<env:Body>"+
          "<CurrencyConverter>"+
          "<convert>"+
          "<amount>"+amount+"</amount>"+
          "<fromCurrency>"+from+"</fromCurrency>"+
          "<toCurrency >"+to+"</toCurrency>"+
          "</convert>"+
          "</CurrencyConverter>"+
          "</env:Body>"+
          "</env:Envelope>";

       try 
       {
          // Create the HttpRequest
          u = new URI("http://localhost:8080/CurrencyConverter.soap");
          request = new HttpRequest();
          request.setVersion("1.0");
          request.setMethod("POST");
          request.setURI(u);          
          request.setContent(requestString.getBytes());
          
          // Make the connection
          socket = new Socket("localhost", 8080);
          in  = new HttpInputStream(socket.getInputStream());
          out = new HttpOutputStream(socket.getOutputStream());
          
          // Send the request
          request.write(out);
          

          // Construct and read the response (which is a SOAP response)
          response = new HttpResponse();          
          response.read(in);
          response.readContent(in);

          // Create a ByteArrayInputStream from the SOAP request
          // (for the SAX Parser)
          responseString = new String(response.getContent());
          soapResponse = URLDecoder.decode(responseString, "UTF-8");
          bis = new ByteArrayInputStream(soapResponse.getBytes());
          
          // Parse the response
          inputSource = new InputSource(bis);
          factory     = SAXParserFactory.newInstance();
          parser      = factory.newSAXParser();
          handler     = new CurrencyConverterSOAPHandler("convert");
          parser.parse(inputSource, handler);

          // Get the return value
          value = handler.getAmount();
       } 
       catch (Exception e) 
       {
          value = -1.0;
       }
       return value;
    }

}
        
The javax.xml.soap Package
The javax.xml.soap Package (cont.)
The Currency Converter Revisited

Creating a Request

javaexamples/soap/CurrencyConverterRequestFactory.java
import javax.xml.soap.*;


/**
 * A factory that demonstrates the use of the javax.xml.soap
 * package.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CurrencyConverterRequestFactory
{
    /**
     * Create a SOAPMessage for a CurrencyConverter request.
     */
    public static SOAPMessage createRequest(String from, String to, String amt)
        throws SOAPException
    {
        MessageFactory messageFactory = 
            MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);

        SOAPMessage  soapMessage  = messageFactory.createMessage();
        SOAPPart     soapPart     = soapMessage.getSOAPPart();
        SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
        SOAPBody     soapBody     = soapEnvelope.getBody();
        
        SOAPElement  currencyConverter = 
            soapBody.addChildElement("CurrencyConverter");
        SOAPElement  convert = currencyConverter.addChildElement("convert");

        SOAPElement  param;
        param = convert.addChildElement("fromCurrency");
        param.addTextNode(from);
        param = convert.addChildElement("toCurrency");
        param.addTextNode(to);
        param = convert.addChildElement("amount");
        param.addTextNode(amt);
        
        return soapMessage;
    }
    
    
}
        
SOAP Connections
The Currency Converter Revisited Again

Making a Request

javaexamples/soap/CurrencyConverterClient.java
import javax.xml.soap.*;

/**
 * An example that uses a SOAPConnection to invoke a remote method.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CurrencyConverterClient
{
    /**
     * The entry point of the application.
     *
     * @param args  The command line arguments (from, to, amt)
     */
    public static void main(String[] args) throws SOAPException
    {
        // Create a factory
        SOAPConnectionFactory soapConnectionFactory = 
            SOAPConnectionFactory.newInstance();

        // Create a connection
        SOAPConnection soapConnection = 
            soapConnectionFactory.createConnection();

        // Create a request
        SOAPMessage soapRequest = 
            CurrencyConverterRequestFactory.createRequest(args[0], args[1], args[2]);
        
        // Send the request and get the respons
        String soapEndpoint = "http://w3.cs.jmu.edu/currency.soap";
        
        SOAPMessage soapResponse = soapConnection.call(soapRequest,
                                                       soapEndpoint);


        // Process the response

    }
}