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 } }