WSDL (Web Service Description Language) is an XML markup language used to describe a web service. WSDL is programming language-, platform-, and protocol-agnostic. The fact that WSDL is protocol-agnostic means it can describe web services that use protocols other than SOAP and HTTP. This ability makes WSDL very flexible, but it has the nasty side effect of making WSDL abstract and difficult to understand. Fortunately, the WS-I Basic Profile 1.0 endorses only SOAP 1.1 over HTTP, so we’ll discuss WSDL as if that’s the only combination of protocols supported.
Imagine that you want to develop a web service component that implements the following interface:
public interface TravelAgent extends java.rmi.Remote { public StringmakeReservation(int cruiseID, int cabinID,
int customerId, double price)
throws java.rmi.RemoteException; }
Any application should be able to invoke this method using SOAP,
regardless of the language in which it was written or the platform on
which it is running. Since other programming languages
don’t understand Java, we have to describe the web
service in a language they do understand: XML. Using XML, and
specifically the WSDL markup language, we can describe the type of
SOAP messages that must be sent to invoke the
makeReservation( )
method. A WSDL document that
describes the makeReservation( )
method might look
like this:
<?xml version="1.0"?> <definitions name="TravelAgent" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:titan="http://www.titan.com/TravelAgent" targetNamespace="http://www.titan.com/TravelAgent"><!-- message elements describe the paramters and return values -->
<message name="RequestMessage"> <part name="cruiseId" type="xsd:int" /> <part name="cabinId" type="xsd:int" /> <part name="customerId" type="xsd:int" /> <part name="price" type="xsd:double" /> </message> <message name="ResponseMessage"> <part name="reservationId" type="xsd:string" /> </message><!-- portType element describes the abstract interface of a web service -->
<portType name="TravelAgent"> <operation name="makeReservation"> <input message="titan:RequestMessage"/> <output message="titan:ResponseMessage"/> </operation> </portType><!-- binding element tells us which protocols and encoding styles are used -->
<binding name="TravelAgentBinding" type="titan:TravelAgent"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="makeReservation"> <soap:operation soapAction="" /> <input> <soap:body use="literal" namespace="http://www.titan.com/TravelAgent"/> </input> <output> <soap:body use="literal" namespace="http://www.titan.com/TravelAgent"/> </output> </operation> </binding><!-- service element tells us the Internet address of a web service -->
<service name="TravelAgentService"> <port name="TravelAgentPort" binding="titan:TravelAgentBinding"> <soap:address location="http://www.titan.com/webservices/TravelAgent" /> </port> </service> </definitions>
If you find the previous WSDL listing indecipherable, don’t despair. Most people can’t understand a WSDL document the first time they see one. Like many things that are complicated, the best approach to understanding WSDL is to study it in pieces. And fortunately, modern web services platforms like Axis generate (and read) WSDL for you. WSDL should be something you only need to look at when things break. At this point, things still break fairly often, so it’s helpful to be familiar with WSDL: it will show you what the server expects when a method is called. But don’t think that you’ll be called on to write a WSDL document by yourself.
The root element of a WSDL document is the
<definitions>
element. Usually, a WSDL document
declares all the XML namespaces used in the root element. In the
previous example, the <definitions>
element
makes four XML Namespace declarations:
<?xml version="1.0"?> <definitions name="TravelAgent" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:titan="http://www.titan.com/TravelAgent" targetNamespace="http://www.titan.com/TravelAgent">
The default namespace
(xmlns="http://schemas.xmlsoap.org/wsdl/
“) is the
WSDL namespace. The xsd
prefix is assigned to the
XML Schema namespace. It is used primarily to identify simple data
types such as xsd:string
,
xsd:int
, and xsd:dateTime
in
<message>
elements:
<message name="RequestMessage"> <part name="cruiseId" type="xsd:int
" /> <part name="cabinId" type="xsd:int
" /> <part name="customerId" type="xsd:int
" /> <part name="price" type="xsd:double
" /> </message> <message name="ResponseMessage"> <part name="reservationId" type="xsd:string
" /> </message>
The titan
prefix is assigned to a Titan Cruise
URL, which indicates that it’s an XML Namespace that
belongs to Titan Cruises. This namespace is also the value of the
targetNamespace
attribute. This attribute is
similar to the one used in XML Schemas. For example, the
<portType>
references
<message>
elements, and the
<binding>
element references a
<portType>
using the target namespace:
<!-- message elements describe the paramters and return values --> <messagename
="RequestMessage
"> <part name="cruiseId" type="xsd:int" /> <part name="cabinId" type="xsd:int" /> <part name="customerId" type="xsd:int" /> <part name="price" type="xsd:double" /> </message> <messagename
="ResponseMessage
"> <part name="reservationId" type="xsd:string" /> </message> <!-- portType element describes the abstract interface of a web service --> <portTypename
="TravelAgent
"> <operation name="makeReservation"> <inputmessage
="titan:RequestMessage
"/> <outputmessage
="titan:ResponseMessage
"/> </operation> </portType> <!-- binding element tells us which protocols and encoding styles are used --> <binding name="TravelAgentBinding"type
="titan:TravelAgent
"> ... </binding>
As you can see, the different WSDL types reference each other by
name, and a named WSDL type automatically takes on the namespace
declared by the targetNamespace
attribute.
The <message>
and <portType>
elements are the immediate children of the
<definitions>
element.
Here’s what they look like:
<!-- message elements describe the paramters and return values -->
<message name="RequestMessage"> <part name="cruiseId" type="xsd:int" /> <part name="cabinId" type="xsd:int" /> <part name="customerId" type="xsd:int" /> <part name="price" type="xsd:double" /> </message> <message name="ResponseMessage"> <part name="reservationId" type="xsd:string" /> </message><!-- portType element describes the abstract interface of a web service -->
<portType name="TravelAgent"> <operation name="makeReservation"> <input message="titan:RequestMessage"/> <output message="titan:ResponseMessage"/> </operation> </portType>
The <portType>
element describes the web
service operations (Java methods) that are available. An operation
can have input, output, and
fault messages. An input
message describes the type of SOAP message a client should send to
the web service. An output message describes the
type of SOAP message a client should expect to get back. A
fault message (not shown in the example)
describes any SOAP error messages that the web service might send
back to the client. A fault message is similar to a Java exception.
JAX-RPC, and therefore EJB 2.1, supports two styles of web service
messaging: request-response and
one-way. You know you are
dealing with request-response if the
<operation>
element contains a single
<input>
element, followed by a single
<output>
element, and, optionally, zero or
more <fault>
elements. The TravelAgent
<portType>
is an example of the
request-response messaging style:
<!-- portType element describes the abstract interface of a web service -->
<portType name="TravelAgent"> <operation name="makeReservation"> <input
message="titan:RequestMessage"/> <output
message="titan:ResponseMessage"/> </operation> </portType>
The one-way message style, on the other hand, is implied by the
presence of a single <input>
element but no
<output>
or <fault>
messages. Here is a web service that supports one-way messaging:
<!-- portType element describes the abstract interface of a web service -->
<portType name="ReservationProcessor"> <operation name="submitReservation"> <input
message="titan:ReservationMessage"/> </operation> </portType>
The request-response style of messaging is the kind you expect in RPC programming: you send a message and get a response. The one-way style tends to be used for asynchronous messaging; you send a message but do not expect a response. In addition, one-way messaging is frequently used to deliver XML documents, like Reservation, rather than parameters and return values. However, both request-response and one-way messaging styles can be used with either RPC or document-style messaging.
WSDL also supports two other messaging styles:
notification (a single
<output>
and no
<input>
) and
solicitation (a single
<output>
followed by a single
<input>
). While WSDL makes these messaging
styles available, they are not supported by the WS-I Basic Profile
1.0 or JAX-RPC.
If your service needs any custom types, they are defined in the
<types>
element, which is the first child of the
<definitions>
element. The complete WSDL
document shown earlier did not include a
<types>
element because it
didn’t define any new types (it used XML Schema
built-in types). The <types>
element allows
us to declare more complex XML types. For example, instead of
declaring each of the parameters of the
makeReservation
operation as individual parts,
they can be combined into a single structure that serves as the
parameter of the operation:
<?xml version="1.0"?> <definitions name="TravelAgent" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:titan="http://www.titan.com/TravelAgent" targetNamespace="http://www.titan.com/TravelAgent"> <!-- types element describes complex XML data types --> <types> <xsd:schema targetNamespace="http://www.titan.com/TravelAgent"> <xsd:complexType name="ReservationType"> <xsd:sequence> <xsd:element name="cruiseId" type="xsd:int"/> <xsd:element name="cabinId" type="xsd:int"/> <xsd:element name="customerId" type="xsd:int"/> <xsd:element name="price-paid" type="xsd:double"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </types> <!-- message elements describe the paramters and return values --> <message name="RequestMessage"> <part name="reservation" type="titan:ReservationType" /> </message> <message name="ResponseMessage"> <part name="reservationId" type="xsd:string" /> </message>
The <types>
element is frequently used with
document-oriented messaging. For example, the following WSDL binding
defines an XML Schema for the Reservation markup so that Reservation
documents can be submitted to Titan as one-way messages. The schema
is embedded within the WSDL document, as the content of the
<types>
element.
<?xml version="1.0"?> <definitions name="Reservation" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:titan="http://www.titan.com/Reservation" targetNamespace="http://www.titan.com/Reservation"> <!-- types element describes complex XML data types --><types>
<xsd:schema targetNamespace="http://www.titan.com/Reservation"> <xsd:element name="reservation" type="titan:ReservationType"/> <xsd:complexType name="ReservationType"> <xsd:sequence> <xsd:element name="customer" type="titan:CustomerType"/> <xsd:element name="cruise-id" type="xsd:int"/> <xsd:element name="cabin-id" type="xsd:int"/> <xsd:element name="price-paid" type="xsd:double"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CustomerType"> <xsd:sequence> <xsd:element name="last-name" type="xsd:string"/> <xsd:element name="first-name" type="xsd:string"/> <xsd:element name="address" type="titan:AddressType"/> <xsd:element name="credit-card" type="titan:CreditCardType"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CreditCardType"> <xsd:sequence> <xsd:element name="exp-date" type="xsd:dateTime"/> <xsd:element name="number" type="xsd:string"/> <xsd:element name="name" type="xsd:string"/> <xsd:element name="organization" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="AddressType"> <xsd:sequence> <xsd:element name="street" type="xsd:string"/> <xsd:element name="city" type="xsd:string"/> <xsd:element name="state" type="xsd:string"/> <xsd:element name="zip" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema></types>
<!-- message elements describe the paramters and return values --> <message name="ReservationMessage"><part name="inmessage" element="titan:reservation" />
</message> <!-- portType element describes the abstract interface of a web service --> <portType name="ReservationProcessor"> <operation name="submitReservation"> <input message="titan:ReservationMessage"/> </operation> </portType> <!-- binding tells us which protocols and encoding styles are used --> <binding name="ReservationProcessorBinding" type="titan:ReservationProcessor"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="submitReservation"> <soap:operation soapAction="" /> <input> <soap:body use="literal"/> </input> </operation> </binding> <!-- service tells us the Internet address of a web service --> <service name="ReservationProcessorService"> <port name="ReservationProcessorPort" binding="titan:ReservationProcessorBinding"> <soap:address location="http://www.titan.com/webservices/Reservation" /> </port> </service> </definitions>
In addition to the <portType>
and
<message>
elements, a WSDL document also
defines <binding>
and <service>
elements. These elements are used by JAX-RPC to generate marshalling
and network communication code used to send and receive messages.
The <binding>
element describes the type of
encoding used to send and receive messages as well as the protocol on
which the SOAP messages are carried. The
<binding>
definition for the
TravelAgent
port type looks like this:
<!-- binding element tells us which protocols and encoding styles are used -->
<binding name="TravelAgentBinding" type="titan:TravelAgent">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="makeReservation">
<soap:operation soapAction="" />
<input>
<soap:body use="literal"
namespace="http://www.titan.com/TravelAgent"/>
</input>
<output>
<soap:body use="literal"
namespace="http://www.titan.com/TravelAgent"/>
</output>
</operation>
</binding>
A binding element is always interlaced with protocol-specific elements—usually, the elements describe the SOAP protocol binding. (In fact, this is the only binding that is allowed by the WS-I Basic Profile 1.0.) Because J2EE web services must support SOAP with attachments, the MIME binding is also supported when attachments (images, documents, and so on) are sent with SOAP messages. However, that subject is a bit involved and is outside the scope of this book.
The <binding>
element contains
<operation>
,
<input>
, <output>
,
and <fault>
elements, similar to the
<portType>
element. In fact, a binding is
specific to a particular <portType>
: its
<operation>
,
<input>
, and
<output>
elements describe the
implementation details of the corresponding
<portType>
. The previous example used the
HTTP protocol with RPC/Literal-style messaging. The WSDL binding for
Document/Literal style messaging would be different:
<!-- binding element tells us which protocols and encoding styles are used --> <binding name="TravelAgentBinding" type="titan:TravelAgent"><soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="submitReservation"><soap:operation soapAction="" />
<input><soap:body use="literal/"/>
</input> </operation> </binding>
The <binding>
element describes a one-way
web service that accepts an XML document fragment. The
<portType>
associated with this
<binding>
also defines a single input
message (consistent with one-way messaging) within an operation
called submitReservation
:
<!-- portType element describes the abstract interface of a web service -->
<portType name="ReservationProcessor"> <operation name="submitReservation"> <input
message="titan:ReservationMessage"/> </operation> </portType>