The details of the XML elements in the SOAP message are best explained with an example. We will use Flute Bank's bill payment service as an example and examine how one of its operations may be invoked using SOAP. The online bill payment service is offered to Flute's customers as a value-added service. In keeping with this chapter's goal of focusing on SOAP, the bill payment service illustrated is deliberately kept simple. The service assumes that payees or merchants have been registered with the bank and that Flute Bank's customers may only schedule new payments or view scheduled payments.
To illustrate the structure and content of a SOAP message, Listing 4.1a shows the SOAP message sent from a service consumer to the Web service in an HTTP request for the operation "getLastPayment." The service processes this message and returns a response with the last payment amount information. Listing 4.1b shows the corresponding response message sent by the service. Figure 4.5 maps Listing 4.1a to elements of the SOAP message structure.
HTTP request header POST /flute/billPay HTTP/1.1 Content-Type: text/xml; charset="utf-8" Content-Length: 513 SOAPAction: User-Agent: Java1.3.1_04 Host: localhost:8080 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive <?xml version="1.0" encoding="UTF-8"?> <env:Envelope env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://www.flutebank.com/xml"> <env:Body> <ns0:getLastPayment> <String_1 xsi:type="xsd:string">my cable tv provider</String_1> </ns0:getLastPayment> </env:Body> </env:Envelope>
HTTP/1.1 200 OK Content-Type: text/xml; charset="utf-8" SOAPAction: "" Transfer-Encoding: chunked Date: Thu, 03 Oct 2002 17:52:05 GMT Server: Apache Coyote HTTP/1.1 Connector [1.0] <?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://www.flutebank.com/xml" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <env:Body> <ns0:getLastPaymentResponse> <result xsi:type="xsd:double">829.0</result> </ns0:getLastPaymentResponse> </env:Body> </env:Envelope>
The SOAP Envelope element identifies to the processing node that the message is a SOAP message. The namespace is used in place of versioning numbers as a means for the processing node to handle versioning. This is quite different from the approach taken by protocols such as HTTP, in which it is possible to derive a meaning from the version number-that is, HTTP 1.1 is a newer version than HTTP 1.0. In the case of SOAP versioning, no such numeric meaning can be inferred.
SOAP messages rely heavily on XML namespaces. Because the message can contain any XML elements, the SOAP elements must be scoped in some manner, to avoid conflicts with the elements of the message. For example, the message may contain a user-defined Envelope tag, which will break the well-formed structure and validity of the message itself. Namespace usage is analogous to the way Java uses package names for classes.
A SOAP node may support one or more SOAP versions. If the node receives a message with a version it does not understand, the SOAP specification requires that it discard the message or, in a request-response scenario, return a Version-Mismatch "fault." We will talk about faults soon.
The SOAP Header provides a container to add metadata to the content of the SOAP body and a facility to influence the processing of the SOAP message. Listings 4.1a and 4.1b contain no header element, because it is optional.
Headers are a key mechanism of vertical extensibility in SOAP. By adding appropriate entries in the header, context information relating to areas such as authentication, authorization, transitions, and routing may be included with the message.
As an example of a SOAP header in use, consider how the Business Transaction Protocol (BTP) specification covered in Chapter 14 extends SOAP by defining the XML elements that can be contained in the header block. The header in Listing 4.2 shows how a transaction coordinator passes the context of the transaction from one service to another by adding header entries.
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" env:encodingStyle=""> <env:Header> <btp:messages xmlns:btp="urn:oasis:names:tc:BTP:1.0:core" env:mustUnderstand="1"> <btp:context> <btp:superior-address> <btp:binding>soap-http-1</btp:binding> <btp:binding-address> http://www.flute.com/btpengine </btp:binding-address> </btp:superior-address> <btp:superior-identifier> http://www.flute.com/btp01 </btp:superior-identifier> <btp:qualifiers> <btpq:transaction-timelimit> xmlns:btpq="urn:oasis:names:tc:BTP:1.0:qualifiers"> <btpq:timelimit>500</btpq:timelimit> </btpq:transaction-timelimit> </btp:qualifiers> </btp:context> </btp:messages> </env:Header> <env:Body> <!--some XML content here--> </env:Body> </env:Envelope>
Sometimes the meta-information included in the headers may be critical to the message exchange. For example, in Listing 4.2, if the message recipient does not process the headers, the entire transaction processing model comes unhinged.
This is where the mustUnderstand attribute comes in. A sender can indicate the header entries the recipient must process by setting the mustUnderstand attribute to true (i.e., mustUnderstand="1"). If the recipient does not know what to do with this mandatory header, it will generate a well-defined fault. This ensures a robust processing model.
The Body element contains the message sent from consumer to provider, or vice versa. This message can be RPC style, in which it describes details about the procedure and the parameters, using an encoding style. In Listing 4.3a, the getLast-Payment element indicates the procedure to invoke on the receiver. It consists of one parameter that describes the name of the account for which the last payment is to be returned.
<env:Body> <ans1:getLastPayment xmlns:ans1="http://com.flute.webservice/billPay/wsdl/billPay"> <String_1 xsi:type="xsd:string">Buzz</String_1> </ans1:getLastPayment> </env:Body>
Alternatively the Body element can include a complete XML document, such as a purchase order, as in Listing 4.3b.
<env:Body> <purchaseorder xmlns="http://www.flutebank.com/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:po="http://www.flutebank.com/schema" xsi:schemaLocation="http://www.flutebank.com/schema purchaseorder.xsd"> <identifier>87 6784365876JHITRYUE</identifier> <date>29 October 2002</date> <billingaddress> <name>John Malkovich</name> <street>256 Eight Bit Lane</street> <city>Burlington</city> <state>MA</state> <zip>01803-6326</zip> </billingaddress> <items> <item> <quantity>3</quantity> <productnumber>229AXH</productnumber> <description>High speed photocopier machine with automatic sensors </description> <unitcost>1939.99</unitcost> </item> <item> <quantity>1</quantity> <productnumber>1632</productnumber> <description>One box of color toner cartridges</description> <unitcost>43.95</unitcost> </item> </items> </purchaseorder> </env:Body>
In both cases, the SOAP message is still well-formed and valid XML data from the sender to the receiver. What is different is the way the recipient uses the encoding scheme. We will see this later in the chapter.
Earlier in this chapter, we used the term fault, which requires some elaboration. By embedding a well-defined XML Fault element in the body, a SOAP node indicates it had a problem processing the message. Such a message is generically termed a SOAP fault. The processing error could arise from any number of causes, from application-specific (e.g., account not found) to system issues (e.g., problem resolving a host name or finding a class in Java).
Listing 4.4 shows a SOAP fault message sent by a message receiver in the HTTP response to the client. The message was generated as a result of an unchecked RuntimeException in the Java code.
HTTP/1.1 500 Internal Server Error Content-Type: text/xml; charset="utf-8" SOAPAction: "" Transfer-Encoding: chunked Date: Wed, 18 Sep 2002 18:10:34 GMT Server: Apache Coyote HTTP/1.1 Connector [1.0] <?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi="http://www.w3.org/2001/ XMLSchema-instance" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://com.flute.webservice/billPay/types/billPay" env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <env:Body> <env:Fault> <faultcode>env:Server</faultcode> <faultstring> Internal Server Error (caught exception while handling request: java.lang.RuntimeException: Demo of SOAP runtime Fault) </faultstring> </env:Fault> </env:Body> </env:Envelope>
The SOAP body contains the single Fault element, which has the following subelements:
A mandatory faultcode element, which indicates the general class of errors.
A mandatory faultstring element, which provides a human-readable explanation of the error.
An optional faultactor element, which indicates the URI of the fault source. This element is mandatory if a SOAP intermediary reports the error.
An optional detail element. If the fault is generated because of the request in the SOAP request body, the detail element must provide details for the processing error. If the fault is generated because of a processing error in the SOAP request header, this element must not be present-that is, the presence of this element indicates that the fault occurred in processing the SOAP request body. The detail element can have subelements, and the content of the detail element can be encoded.
The faultcode format provides an extensible mechanism to report the type of error that occurred. Fault codes are XML-qualified names. The dot (".") is used as a separator to indicate that the code to the left of it is a more generic faultcode (e.g., client.Authentication). The faultcode element can have the following four possible classes of values:
versionMismatch. The processing node does not support SOAP message with the version reflected in the namespace. As discussed earlier, SOAP does not handle versioning through the use of version numbers. The Envelope namespace is used instead, and a SOAP processing node should throw this fault if it cannot handle the Envelope namespace.
mustUnderstand. This fault is returned if a processing node cannot understand the semantics of a mandatory SOAP header element targeted at that node.
client. This value signifies that the fault occurred because of some error within the client itself. It could be that the client did not provide sufficient/and or correct information (such as authentication credentials) or that the request itself was not formed correctly. The fault is assumed to have originated at the client that composed the message and is an indication that retrying the message without making the appropriate correction will result in the same error.
server. An error occurred at the server. Based on the error, the client may decide to retry. All Java exceptions that occur on the service provider's side (both application-thrown and runtime exceptions) are reported under this fault code.