The WSDL Service Contract in Detail

The WSDL document, which is XML, is structured as follows:

  • The document or root element is named definitions. This is appropriate because the WSDL defines the web service thoroughly enough that utilities such as wsimport can use the WSDL to generate code, typically but not exclusively client-side support code.
  • The first child element of definitions, named types, is technically optional but almost always present in a modern WSDL. This element contains (or links to) an XML Schema or the equivalent—a grammar that specifies the data types for the messages involved in the service. In a modern SOAP-based web service, the arguments passed to web service operations are typed—but the SOAP messages themselves are also typed. For this reason, the receiver of a SOAP message can check, typically at the library level, whether the received message satisfies the constraints that the message’s type impose.
  • Next come one or more message elements, which list the messages whose data types are given in the types section immediately above. Every message has a corresponding complexType entry in the schema from the types section, assuming that the types section is nonempty.
  • The portType section comes next. There is always exactly one portType element. The portType is essentially the service interface: a specification of the service’s operations and the message patterns that the operations exemplify. For example, in the request/response pattern, the client begins the conversation with a request message and the service counters with a response message. In the solicit/response pattern, by contrast, the service starts the conversation with a solicitation message and the client counters with a response. There is also the one-way pattern (client to server only) and the notification pattern (server to client only). Richer conversational patterns can be built out of these simpler ones. The message items in the preceding section are the components of an operation, and the portType section defines an operation by placing message items in a specific order.
  • Next come one or more binding sections, which provide implementation detail such as the transport used in the service (for instance, HTTP rather than SMTP), the service style, and the SOAP version (that is, 1.1 or 1.2). By default, Java generates a single binding section but DotNet generates two: one for SOAP 1.1 and another for SOAP 1.2.
  • The last section, named service, brings all of the previous details together to define key attributes such as the service endpoint—that is, the URL at which the service can be accessed. Nested in the service element are one or more port subelements, where a port is a portType plus a binding:

    port = portType + binding

    Since there is only one portType in a WSDL, the number of port subelements equals the number of binding elements.

The biggest section in a WSDL is typically the types section because an XML Schema tends to be wordy. An example from Amazon, introduced shortly, illustrates. For now, the WSDL (see Example 4-11) for the RandService is only about a page or so in size.

Example 4-11. The dynamically generated WSDL for the RandService

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:tns="http://rand/"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             targetNamespace="http://rand/" name="RandServiceService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://rand/"
                  schemaLocation="http://localhost:8888/rs?xsd=1"></xsd:import>
    </xsd:schema>
  </types>
  <message name="next1">
    <part name="parameters" element="tns:next1"></part>
  </message>
  <message name="next1Response">
    <part name="parameters" element="tns:next1Response"></part>
  </message>
  <message name="nextN">
    <part name="parameters" element="tns:nextN"></part>
  </message>
  <message name="nextNResponse">
    <part name="parameters" element="tns:nextNResponse"></part>
  </message>
  <portType name="RandService">
    <operation name="next1">
      <input message="tns:next1"></input>
      <output message="tns:next1Response"></output>
    </operation>
    <operation name="nextN">
      <input message="tns:nextN"></input>
      <output message="tns:nextNResponse"></output>
    </operation>
  </portType>
  <binding name="RandServicePortBinding" type="tns:RandService">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
                  style="document"></soap:binding>
    <operation name="next1">
      <soap:operation soapAction=""></soap:operation>
      <input>
        <soap:body use="literal"></soap:body>
      </input>
      <output>
        <soap:body use="literal"></soap:body>
      </output>
    </operation>
    <operation name="nextN">
      <soap:operation soapAction=""></soap:operation>
      <input>
        <soap:body use="literal"></soap:body>
      </input>
      <output>
        <soap:body use="literal"></soap:body>
      </output>
    </operation>
  </binding>
  <service name="RandServiceService">
    <port name="RandServicePort" binding="tns:RandServicePortBinding">
      <soap:address location="http://localhost:8888/rs"></soap:address>
    </port>
  </service>
</definitions>

The first three WSDL sections (types, message, and portType) present the service abstractly in that no implementation details are present. The binding and service sections provide the concrete detail by specifying, for example, the type of transport used in the service as well as the service endpoint.

The portType is of particular interest because it characterizes the service in terms of operations, not simply messages; operations consist of one or more messages exchanged in a specified pattern. The two areas of immediate interest in the WSDL for a programmer writing a client against a service would be the portType and the service; the portType section informs the programmer about what calls can be made against the service, and the service section gives the service endpoint, the URL through which the service can be reached.

XML is not fun to read, but the basic profile WSDL for the RandService is not unduly forbidding. Perhaps the best way to read the document is from top to bottom.

The types Section

This section contains or links to an XML Schema or equivalent. (In the case of Java, the schema is a separate document shown in Example 4-3; in the case of DotNet, the schema is included in the WSDL.) To understand how the schema relates to its WSDL, consider this segment of the XML Schema from Example 4-3:

<xs:element name="nextNResponse" type="tns:nextNResponse">             1
</xs:element>
...
<xs:complexType name="nextNResponse">                                  2
  <xs:sequence>
    <xs:element name="return"                                          3
                type="xs:int" minOccurs="0" maxOccurs="unbounded">
    </xs:element>
  </xs:sequence>
</xs:complexType>

The xs:element in line 1 has a specified type, in this case tns:nextNResponse. The type is the complexType in line 2. XML Schema has built-in simple types such as xsd:int and xsd:string, but XML Schema is also extensible in that new complex types can be added as needed. The complexType in this case is for the nextNResponse message that the service returns to the client. Here is that message from the WSDL in Example 4-11:

<message name="nextNResponse">
  <part name="parameters" element="tns:nextNResponse"></part>  1
</message>

The message has an element attribute (line 1) with tns:nextNResponse as the value; tns:nextNResponse is the name of the element in line 1 of the XML Schema. The WSDL, in defining a message, points back to the XML Schema section that provides the data type for the message.

The complexType section of the WSDL indicates that a nextNResponse message returns zero or more integers (XML type xs:int). The zero leaves open the possibility that the service, in this case written in Java, might return null instead of an actual array or equivalent (e.g., List<Integer>). At this point a human editor might intervene by changing the minOccurs in line 3 from 0 to 1. (If the minOccurs attribute were dropped altogether, the value would default to 1.) The dynamically generated WSDL may not capture the intended design of a service; hence, the WSDL may need to be edited by hand.

The message Section

Each message element in the WSDL points to an element and, more important, to a complexType in the WSDL’s XML Schema. The result is that all of the messages are typed. The RandService exposes two operations and each follows the request/response pattern; hence, the WSDL has four message elements: two for the next1 and nextN requests and two for the corresponding responses named next1Response and nextNResponse, respectively.

The portType Section

This section contains one or more operation elements, each of which defines an operation in terms of messages defined in the immediately preceding section. For example, here is the definition for the nextN operation:

<operation name="nextN">
  <input message="tns:nextN"></input>
  <output message="tns:nextNResponse"></output>
</operation>

The input message precedes the output message, which signals that the pattern is request/response. Were the order reversed, the pattern would be solicit/response. The term input is to be understood from the service’s perspective: an input message goes into the service and an output message comes out from the service. Each input and output element names the message defined in a message section, which in turn refers to an XML Schema complexType. Accordingly, each operation can be linked to the typed messages that make up the operation.

The binding Section

This section and the next, service, provide implementation details about the service. In theory, but rarely in practice, there are several options or degrees of freedom with respect to the service that the WSDL defines, and a binding section selects among these options. One option for a SOAP-based service such as the RandService is the SOAP version: 1.1 or 1.2. SOAP 1.1 is the default in Java; hence, the one and only binding section is for SOAP 1.1. In DotNet, a dynamically generated WSDL usually has two binding sections: one for SOAP 1.1 and the other for SOAP 1.2. However, the very same DotNet WSDL typically has only one service endpoint or URL; this means the same deployed service is for SOAP 1.1 and SOAP 1.2, thereby signaling that no difference between the two SOAP versions comes into play for the service.

There are three other options to be considered: transport (line 1) and style (line 2) are two of the three. Here is the first subelement in the binding section, a subelement that makes choices on these two options:

<soap:binding transport="http://schemas.xmlsoap.org/soap/http"  1
              style="document"></soap:binding>                  2

The transport value is a URI that ends with soap/http, which can be summed up as SOAP over HTTP. Another option would be SMTP (Simple Mail Transport Protocol) or even TCP (Transmission Control Protocol, which underlies HTTP), but in practice, HTTP is the dominant transport. HTTP in this context includes HTTPS. The other option (line 2) concerns the service style, in this case set to document. A web service in document style always has an XML Schema or equivalent that types the service’s constituent messages. The other choice for style is misleadingly named rpc, which is short for remote procedure call. The name is misleading because a document-style service such as the RandService can and typically does follow the request/response pattern, which is the RPC pattern. In the context of a WSDL, rpc style really means that messages themselves are not typed, only their arguments and return values are typed. The WSDL for an rpc style service may have no types section at all or only an abbreviated one. In modern SOAP-based services, document style dominates and represents best practice. Indeed, both Java and DotNet toyed for a time with the idea of dropping support altogether for rpc style. The issue of rpc style will come up again later but only briefly.

The document style deserves to be the default. This style can support services with rich, explicitly defined Java data types such as Employee or ChessTournament because the service’s WSDL can define, for the XML side, the required types in an XML Schema. Any service pattern, including request/response, is possible under the document style.

The last option concerns use, more accurately called encoding, because the choice determines how the service’s data types are to be encoded and decoded. The WSDL has to specify how the data types used in an implementation language such as Java are to be serialized into and deserialized out of WSDL-compliant types—the types laid out in the WSDL’s XML Schema or equivalent (see Example 4-12). For example, Java and Ruby have similar but subtly different data types. In a conversation based on SOAP messages, a conversation in which the SOAP remains transparent, the two languages would need the ability to serialize from instances of native types to XML and to deserialize from XML to instances of native types.

Example 4-12. Encoding and decoding XML

           encode                   decode
Java types-------->XML Schema types-------->Ruby types

Java types<--------XML Schema types<--------Ruby types
           decode                   encode

The attribute

use = 'literal'

means the service’s type definitions in the WSDL literally follow the WSDL’s schema. The alternative to literal is named encoded, which means that the service’s type definitions come from implicit encoding rules, typically the rules in the SOAP 1.1 specification. However, the use of encoded does not comply with WS-I (Web Services Interoperability) standards.

The service Section

This section brings the pieces together. Recall that a WSDL has but one portType section but may have multiple binding sections. The service element has port subelements, where a port is a portType linked to a binding; hence, the number of port subelements equals the number of binding sections in the WSDL. In this example, there is one binding and, therefore, one port subelement:

<port name="RandServicePort" binding="tns:RandServicePortBinding">
   <soap:address location="http://localhost:8888/rs"></soap:address> 1
</port>

The address subelement specifies a location (line 1), whose value is commonly called the service endpoint. A web service with two significantly different bindings (for instance, one for HTTP and another for SMTP) would have different location values to reflect the different bindings.

Java and XML Schema Data Type Bindings

The foregoing examination of the WSDL, and in particular its XML Schema, prompts an obvious question: Which Java data types bind to which XML Schema data types? Table 4-1 summarizes the bindings.

Table 4-1. Java and XML Schema data type bindings

Java data typeXML schema data type

boolean

xsd:boolean

byte

xsd:byte

short

xsd:short

short

xsd:unsignedByte

int

xsd:int

int

xsd:unsignedShort

long

xsd:long

long

xsd:unsignedInt

float

xsd:float

double

xsd:double

byte[ ]

xsd:hexBinary

byte[ ]

xsd:base64Binary

java.math.BigInteger

xsd:integer

java.math.BigDecimal

xsd:decimal

java.lang.String

xsd:string

java.lang.String

xsd:anySimpleType

javax.xml.datatype.XMLGregorianCalendar

xsd:dateTime

javax.xml.datatype.XMLGregorianCalendar

xsd:time

javax.xml.datatype.XMLGregorianCalendar

xsd:date

javax.xml.datatype.XMLGregorianCalendar

xsd:g

javax.xml.datatype.Duration

xsd:duration

javax.xml.namespace.QName

xsd:QName

javax.xml.namespace.QName

xsd:NOTATION

java.lang.Object

xsd:anySimpleType

The bindings in Table 4-1 are automatic in the sense that, in a JAX-WS service, the SOAP infrastructure does the conversions without application intervention. Conversions also are automatic for arrays of any type in Table 4-1. For example, an array of BigInteger instances converts automatically to an array of xsd:integer instances, and vice versa. Programmer-defined classes whose properties reduce to any type in Table 4-1 or to arrays of these likewise convert automatically. For example, an Employee class that has properties such as firstName (String), lastName (String), id (int), salary (float), age (short), hobbies (String[ ]), and the like would convert automatically to XML Schema types. The upshot is that the vast majority of the data types used in everyday Java programming convert automatically to and from XML Schema types. The glaring exception is the Map—a collection of key/value pairs. However, a Map is readily implemented as a pair of coordinated arrays: one for the keys, the other for the values.

Wrapped and Unwrapped Document Style

The source for the RandService class begins as follows:

@WebService
public class RandService {
...

The default style, document, could be overridden with an additional annotation:

@WebService
@SOAPBinding(style = Style.RPC) // versus Style.DOCUMENT, the default
public class RandService {
...

The RandService is simple enough that the difference would be transparent to clients against the service. Of interest here is how the different styles impact the underlying SOAP messages.

Consider a very simple SOAP-based service with operations named add, subtract, multiply, and divide. Each operation expects two arguments, the numbers on which to operate. Under the original SOAP 1.1 specification, a request message for document style—what is now called unwrapped or bare document style—would look like Example 4-13:

Example 4-13. Unwrapped document style

<?xml version="1.0" ?>
<!-- Unwrapped document style -->
<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soapenv:Body>
     <num1 xmlns:ans="http://arith/">27</num1>
     <num2 xmlns:ans="http://arith/">94</num2>
  </soapenv:Body>
</soapenv:Envelope>

The Body of the SOAP message contains two elements at the same level, the elements tagged num1 and num2; each element is a child of the soapenv:Body element. The glaring omission is the name of the operation, for instance, add. This name might occur instead, for example, in the request URL:

http://some.server.org/add

It is peculiar that the SOAP envelope should contain the named arguments but not the named operation. Under rpc style, however, the operation would be the one and only child of the Body element; the operation then would have, as its own child elements, the arguments. Here is the contrasting SOAP message in rpc style or, what now comes to the same thing, wrapped document style (Example 4-14).

Example 4-14. Wrapped document style, the same as rpc style

<?xml version="1.0" ?>
<!-- Wrapped document or rpc style -->
<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soapenv:Body>
     <add xmlns:ans="http://arith/">  1
       <num1>27</num1>
       <num2>94</num2>
     </addNums>
  </soapenv:Body>
</soapenv:Envelope>

The add element (line 1) now acts as a wrapper for the argument elements, in this case num1 and num2. The wrapped convention, unofficial but dominant in SOAP frameworks, gives a document-style service the look and feel of an rpc-style service—at the message level. The document style still has the advantage of a full XML Schema that types the messages. In Java as in DotNet, the default style for any SOAP-based service is wrapped document; hence, a service such as RandService, with only the @WebService annotation, is wrapped document in style. This style is often shortened to wrapped doc/lit: wrapped document style with literal encoding.

wsimport Artifacts for the Service Side

The wsimport utility produces, from a WSDL document, code that directly supports client calls against a web service. This same code can be used, with a few adjustments, to program a service. This section illustrates with a simple example.

Here are two operations for a temperature conversion service written in C#:

[WebMethod]
public double c2f(double t) { return 32.0 + (t * 9.0 / 5.0); }
[WebMethod]
public double f2c(double t) { return (5.0 / 9.0) * (t - 32.0); }

The c2f operation converts from centigrade to fahrenheit and the f2c method converts from fahrenheit to centigrade.

DotNet, by default, generates a WSDL with SOAP 1.1 and SOAP 1.2 bindings. This temperature conversion service is simple enough that the two bindings have the same implementation. In general, however, the wsimport utility can handle multiple bindings with the -extension flag. Assuming that the WSDL for the service is in the file tc.wsdl, the command:

% wsimport -p tempConvert -keep -extension tc.wsdl

generates the usual artifacts: Java .class files that represent the c2f and f2c request messages and their corresponding responses, together with various support files. Of interest here is the interface—the Java file that represents the portType section of the WSDL. Here is the file, cleaned up for readability:

package tempConvert;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

@WebService(name = "ServiceSoap",
            targetNamespace = "http://tempConvertURI.org/")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface ServiceSoap {
    @WebMethod(operationName = "c2f",
               action = "http://tempConvertURI.org/c2f")
    @WebResult(name = "c2fResult",
               targetNamespace = "http://tempConvertURI.org/")
    @RequestWrapper(localName = "c2f",
                    targetNamespace = "http://tempConvertURI.org/",
                    className = "tempConvert.C2F")
    @ResponseWrapper(localName = "c2fResponse",
                     targetNamespace = "http://tempConvertURI.org/",
                     className = "tempConvert.C2FResponse")
    public double c2F(
        @WebParam(name = "t",
                  targetNamespace = "http://tempConvertURI.org/")
        double t);
    @WebMethod(operationName = "f2c",
               action = "http://tempConvertURI.org/f2c")
    @WebResult(name = "f2cResult",
               targetNamespace = "http://tempConvertURI.org/")
    @RequestWrapper(localName = "f2c",
                    targetNamespace = "http://tempConvertURI.org/",
                    className = "tempConvert.F2C")
    @ResponseWrapper(localName = "f2cResponse",
                     targetNamespace = "http://tempConvertURI.org/",
                     className = "tempConvert.F2CResponse")
    public double f2C(
        @WebParam(name = "t",
                  targetNamespace = "http://tempConvertURI.org/")
        double t);
}

The ServiceSoap interface, like any interface, declares but does not define methods, which in this case represent service operations. If the semantics of these two operations c2f and f2c are understood, then converting this wsimport artifact to a web service is straightforward:

  • Change the interface to a POJO class.

    ...
    public class ServiceSoap {
    ...
  • Implement the c2f and f2c operations by defining the methods. Java and C# are sufficiently close that the two implementations would be indistinguishable. For example, here is the body of c2f in either language.

    public double c2f(double t) { return 32.0 + (t * 9.0 / 5.0); }

    Not every language is as close to Java as C#, of course. Whatever the original implementation of a service, the challenge is the same: to understand what a service operation is supposed to do so that the operation can be re-implemented in Java.

  • Publish the service with, for example, Endpoint or a web server such as Tomcat or Jetty.

    Although the wsimport utility could be used to help write a SOAP-based service in Java, the main use of this utility is still in support of clients against a SOAP-based service. The point to underscore is that the WSDL is sufficiently rich in detail to support useful code on either the service or the client side. The next section returns to the Amazon E-Commerce service to illustrate this very point.

Get Java Web Services: Up and Running, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.