By Robert Englander
Book Price: $39.95 USD
£28.50 GBP
PDF Price: $31.99
Cover | Table of Contents | Colophon
http://xml.apache.org/soap/index.html. Four
very important factors led me to choose this implementation: it
supports a good deal of the specification, it has a reasonably large
user base, the source code is available, and it's
free.
http://jakarta.apache.org/tomcat/index.html.
The reasons are not particularly tied to SOAP, but it does work well
in Tomcat. The use of Tomcat has no real impact on the examples in
the book, so you can feel free to select some other server technology
if you like.
POST /LocalWeather HTTP/1.0
Host: www.mindstrm.com
Content-Type: text/xml; charset="utf-8"
Content-Length: 328
SOAPAction: "WeatherStation"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetCurrentTemperature xmlns:m="WeatherStation">
<m:scale>Celsius</m:scale>
</m:GetCurrentTemperature>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
/LocalWeather at the host specified later in the
HTTP header. This tells the server how to route the request within
its own processing space. Finally, our example indicates that
we're using HTTP Version 1.0, although SOAP
doesn't require a particular version of HTTP.
Host: header field
specifies the address of the server to which
we're sending this request,
www.mindstrm.com.
The next header field,
Content-Type:, tells the server that
we're sending data using the
text/xml media type. All SOAP messages must be
sent using text/xml. The content type in the
example also specifies that the data is encoded using the UTF-8
character set. The SOAP standard doesn't require any
particular encoding. Content-Length: tells the
server the character count of the POSTed SOAP XML payload data to
follow.
HTTP/1.0 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: 359
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetCurrentTemperatureResponse xmlns:m="WeatherStation">
<m:temperature>26.6</m:temperature>
</m:GetCurrentTemperatureResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Content-Type: and
Content-Length: fields have the same meanings as
they did in the request message. No other HTTP header fields are
needed; the correlation between the request and response is implied
by the fact that the HTTP POST is inherently a request/response
mechanism. You send the request and get the response as part of a
single transaction.
<m:scale>Calcium</m:scale>
HTTP/1.0 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: 525
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Client Error</faultstring>
<detail>
<m:weatherfaultdetails xmlns:m="WeatherStation">
<message>No such temperature scale: Calcium</message>
<errorcode>1234</errorcode>
</m:weatherfaultdetails>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>Envelope is the highest-level XML element in the
message, and it must be present for the message to be considered
valid. So in essence, the Envelope represents the
XML document that contains the SOAP message. The
Envelope can contain an optional
Header element that, if present, has to be the
first subelement of the Envelope.
The Envelope must
contain a Body element.
If the Envelope contains a
Header element, then the Body
element has to come right after the Header;
otherwise the Body has to be the first subelement
of the Envelope.
Envelope is the topmost element of the
XML
document that represents the SOAP message. The
Envelope is the only XML element at the top level;
the rest of the SOAP message resides within the
Envelope, encoded as subelements. A SOAP message
must have an Envelope element.
The
Envelope can have namespace declarations, as shown
in the earlier examples, and needs to be qualified as shown earlier,
using the http://schemas.xmlsoap.org/soap/envelope
namespace. That's why the element name is shown as
SOAP-ENV:Envelope.
It is also common for the
Envelope element to declare the
encodingStyle attribute, with the attribute
namespace-qualified using the declared namespace identifier
SOAP-ENV as well.
Envelope must themselves be namespace-qualified.
These elements and attributes are also qualified by
SOAP-ENV, just as the Envelope
is qualified. For the remainder of this chapter and the rest of the
book, we'll use the SOAP-ENV
namespace identifier to mean the
http://schemas.xmlsoap.org/soap/envelope
namespace. This should make for easier reading. Keep in mind that
it's the namespace itself that matters, not the name
used for the qualifier.
Header and be the first
subelement of the Envelope element. The
Header element is also
namespace-qualified using the
SOAP-ENV identifier.
Header entries are used to
encode elements used for transaction processing, authentication, or
other information related to the processing or routing of the
message. This is useful because, as we'll see, the
Body element is used for encoding the information
that represents an RPC (or other) payload. The
Header is an extension mechanism that allows any
kind of information that lies outside the semantics of the message in
the Body, but is nevertheless useful or even
necessary for processing the message properly.
Header
elements should limit the use of
attributes to those elements that are immediate children of the
Header element itself. The spec says that this
should be done, meaning that although one can
use them on elements deeper in the element hierarchy underneath the
Header element, the recipient is required to
ignore the attributes on such elements.
username. We
don't apply any attributes to the
username element, but we do namespace-qualify it.
The username element identifies the user who is
making the request.
<SOAP-ENV:Header>
<ns1:username xmlns:ns1="JavaSoapBook">
Jessica
</ns1:username>
</SOAP-ENV:Header>
actor attribute
identifies (either implicitly or explicitly) the intended recipient
of a Header element.
Header elements intended for use by an
intermediary are not passed on to the next SOAP processor in the
path. Header elements represent contracts between
the sender and receiver. However, if the information contained in a
Header element intended for an intermediary is
also needed by a downstream server, the intermediary can insert the
appropriate Header in the message to be sent
downstream. In fact, the intermediary is free to add any
Header elements it deems necessary.
actor attribute doesn't
appear on a Header element, it's
assumed that the element is intended for the ultimate recipient. In
essence, this is equivalent to including the actor
attribute with its value being the URI of the ultimate destination.
actor attribute. Say that the message is being
sent to an intermediate application server located at
http://www.mindstrm.com/AppServer. We want that
application server to log the name of the user that made the request,
and then pass the request on to the final destination server. To do
so, we set the actor for the
username element to
http://www.mindstrm.com/AppServer:
<SOAP-ENV:Header>
<ns1:username
xmlns:ns1="JavaSoapBook"
SOAP-ENV:actor="http://www.mindstrm.com/AppServer">
Jessica
</ns1:username>
</SOAP-ENV:Header>Header element. This
requirement allows us to accommodate situations in which a recipient
of a SOAP message can't perform its job unless it
knows what to do with the data provided by a specific
Header element. In this case the element can
include the mustUnderstand attribute with an
assigned value of 1.
username header element must be understood by the
recipient; if it is not, the message should be rejected. We can
include this requirement in the SOAP message by assigning the
mustUnderstand attribute the value of 1. (The
value 0 is essentially equivalent to not supplying the attribute.)
Let's modify our previous example to indicate that
the recipient must understand the username
element:
<SOAP-ENV:Header>
<ns1:username
xmlns:ns1="JavaSoapBook"
SOAP-ENV:actor="http://www.mindstrm.com/AppServer"
SOAP-ENV:mustUnderstand="1">
Jessica
</ns1:username>
</SOAP-ENV:Header>
username element, it is required to respond with a
SOAP fault. The response might look something like this:
HTTP/1.0 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: 373
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:MustUnderstand</faultcode>
<faultstring>SOAP Must Understand Error</faultstring>
<faultactor>http://www.mindstrm.com/AppServer</faultactor>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>encodingStyle
attribute specifies the data
encoding rules used to serialize and deserialize data elements. It is
important to understand that SOAP does not specify any default rules
for data serialization. SOAP does, however, specify a simple data
typing scheme commonly supported by SOAP implementations. This is the
subject of the next chapter, so we won't get into
the details of the encoding rules here. However,
it's important to understand how to specify the
encoding style to be used for serializing and deserializing the
element data in the SOAP message.
encodingStyle
attribute is namespace-qualified using the
SOAP-ENV namespace identifier. In the following
example we specify the encodingStyle attribute as
part of the Envelope element;
we'll see examples in later chapters that make this
declaration in the Body element instead. Either
way works, as long as you recognize that the
encodingStyle attribute applies to the element in
which it was declared as well as all of its subelements (i.e.,
it's in-scope).
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
. . .
. . .
</SOAP-ENV:Envelope>
SOAP-ENV:encodingStyle="http://www.mindstrm.com/tightEncoding http://www.mindstrm.com/looseEncoding"
""). This declaration applies to the current
element and all of its subelements.
http://schemas.xmlsoap.org/soap/envelope
namespace, which we've used in all of the previous
examples. That's it.
No other versioning information
is used for SOAP envelopes at this time. If a SOAP message is
associated with any other namespace, or if no namespace is declared,
then the recipient has to respond with a SOAP version mismatch. Here
is an example of a SOAP fault response for this situation:
HTTP/1.0 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: 311
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:VersionMismatch</faultcode>
<faultstring>SOAP Envelope Version Mismatch</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Body element is mandatory in SOAP 1.1. If there is
no SOAP header, the Body must be the first
subelement of the Envelope; otherwise it must
directly follow the SOAP Header element. The
Body element is also namespace-qualified using the
SOAP-ENV identifier.
Body element contains the SOAP request or
response. This is where you might find an RPC-style message that
contains the method name and its parameters, or a one-way message and
its relevant parts, or a fault and its details. SOAP
Body elements are not completely defined by the
SOAP specification; we'll cover that subject in
great detail later. In fact, SOAP defines only one kind of
Body: the SOAP Fault.
Body element. In this case the request is an
RPC. We've namespace-qualified the
Body element using the same
SOAP-ENV namespace identifier that we used for the
other SOAP-defined elements and attributes.
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetCurrentTemperature xmlns:m="WeatherStation">
<m:scale>Celsius</m:scale>
</m:GetCurrentTemperature>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Fault
is
the only Body element entry defined by SOAP.
It's used to carry error information back to the
originator of a SOAP message. The Fault element
must appear as an immediate subelement of the Body
element, and it can't appear more than once.
Fault
element. Not all of these are required, and some are appropriate only
under certain conditions. These elements are described in the
following sections. You'll probably recognize that
we've seen all of these in previous examples, so you
may want to flip back and look at them again after
you've read these descriptions.
faultcode
element
provides an indication of the fault that is recognizable by a
software process, providing an opportunity for the system receiving
the fault to act appropriately. The code is not necessarily useful to
humans — that is the purpose of the
faultstring element described in the next section.
The faultcode element is mandatory, and must
appear as a subelement of the Fault element.
SOAP defines a number of fault codes for
use in the faultcode element. These codes are
associated with the
http://schemas.xmlsoap.org/soap/envelope
namespace. Here are brief descriptions of the SOAP-defined fault
codes:
VersionMismatch
Envelope.
MustUnderstand
Header element that
contained the
mustUnderstand
attribute with a value of 1,
and either the attribute was not understood or the semantics
associated with the attribute couldn't be followed.
http://schemas.xmlsoap.org/encoding namespace, is
often referred to as "SOAP Section
5." In SOAP messages, this namespace is by
convention referenced using a namespace qualifier such as
SOAP-ENC or soapenc. In our
examples we will use the
SOAP-ENC
namespace qualifier to refer to this namespace.
http://schemas.xmlsoap.org/encoding namespace, is
often referred to as "SOAP Section
5." In SOAP messages, this namespace is by
convention referenced using a namespace qualifier such as
SOAP-ENC or soapenc. In our
examples we will use the
SOAP-ENC
namespace qualifier to refer to this namespace.
xsd
and associate it with the namespace
http://www.w3.org/2001/XMLSchema. As we saw in the
previous chapter, this declaration is usually done as an
attribute of the SOAP
Envelope or SOAP Body.
xsi, which is associated
with the namespace
http://www.w3.org/2001/XMLSchema/instance. The
easiest way to explain this identifier is with an example. Imagine
that we want to declare that the data type of a particular XML
element is a id
of type ID. The value of the id
attribute is the name that other elements use to reference the value.
Here is such an element:
<lastName id="name-1">Englander</lastName>
lastName element is a perfectly valid accessor
in its own right. In addition, it has an identifier that allows other
elements to reference the data value.
href
attribute that references the
value. The href attribute is of type
uri-reference defined in the XML Schema
specification; the value of this attribute references the
xsi:type attribute as part of the element. This
means that the attribute is named type, as defined
by the namespace indicated by xsi. The value
assigned to xsi:type must be a valid type
identifier such as xsd:float,
xsd:string, etc. In the second mechanism, the
value can be an element of an array that already constrains the type
of its constituent parts to a particular data type. In this case, no
explicit type declaration for the individual values is necessary;
we'll see this later when we talk about arrays.
Finally, the element name itself can be related to some type that can
be determined by looking at the associated XML schema. The following
extract from an XML schema defines a compound data type:
<element name="Automobile" type="Automobile"/>
<complexType name="Automobile">
<element name="make" type="xsd:string"/>
<element name="model" type="xsd:string"/>
<element name="year" type="xsd:int"/>
</complexType>
Automobile contains elements named
make and model of type
string, as well as a year of
type int. Now let's look at an
instance of type Automobile based on this schema:
<niceCar xsi:type="Automobile" >
<model>Corvette</model>
<make>Chevrolet</make>
<year>1999</year>
</niceCar>
Automobile: a
1999 Chevrolet Corvette. Because the schema for the
Automobile type already specifies the data types
for the constituent parts, we don't need to declare
the types in the example.