|
Simple Object Access Protocol (SOAP) v1.2
An Introduction with Examples in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Envelope is the top element of the XML
document representing the messagehttp://www.w3.org/2003/05/soap-envelope
encodingStyle Attribute:
http://www.w3.org/2003/05/soap-encoding
<env:Envelope
xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:xml="http://www.w3.org/XML/1998/namespace">
</env:Envelope>
Header is a generic mechanism for
adding features to a SOAP messageHeader could be used to indicate who
should deal with a feature and whether it is
optional or mandatoryHeader element MUST be the first
immediate child of the Envelope elementBody is a container elementEnvelope elementHeader element,
if one is present, otherwise it must be the first
immediate child of Envelope
Fault items
<env:Body>
<TextAlert>
<Message>Port Rd. has been closed</Message>
<Alert>Road CLosed - Find Alternate</Alert>
<Priority>6</Priority>
</TextAlert>
</env:Body>
Code
|
The machine-usable cause of the fault |
Reason
|
The human-readable cause of the fault |
Node
|
The Node that caused the fault
|
Role
|
The role the Node that caused the
fault was playing
|
Detail
|
Application-specific information |
<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>
<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>
<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>
<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>
<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>
/**
* 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);
}
/**
* 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;
}
}
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 = "";
}
}
}
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);
}
}
}
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;
}
}
javax.xml.soap Packagejavax.xml.soap Package (cont.)
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;
}
}
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
}
}