Skip to main content

The Web services (r)evolution: Part 4

Web Services Description Language (WSDL)

Graham Glass (graham-glass@mindspring.com), CEO/Chief Architect, The Mind Electric
Graham Glass is founder, CEO, and Chief Architect of The Mind Electric, which designs, builds and licenses forward-thinking distributed computing infrastructure. He believes that the evolution of the Internet will mirror that of a biological mind, and that architectures for helping people and businesses to network effectively will provide insight into those that wire together the human brain. He can be reached at graham-glass@mindspring.com.

Summary:  This article describes the Web Services Description Language (WSDL), an XML grammar for specifying properties of a Web service such as what it does, where it's located, and how to invoke it. It also introduces the IBM WSDL toolkit, which can generate stubs from WSDL and simplify the creation of Web services applications.

Date:  01 Feb 2001
Level:  Introductory
Activity:  2264 views
Comments:  

Welcome to the fourth installment of my column that focuses on the evolutionary and revolutionary aspects of Web services technology. In the third installment (see Resources), I showed you how Simple Object Access Protocol (SOAP) works under the hood. In this installment, I'll explain WSDL, the standard way to describe the core properties of a Web service, and introduce a couple of tools that leverage WSDL to accelerate your development process.

Tools and installation

There are two new tools that we'll use in this installment:

  • IBM WSTK 2.1 : The IBM Web Services Toolkit 2.1 (see Resources) includes Apache SOAP, a WSDL generator, and a Universal Description, Discovery and Integration (UDDI) client. Because we've been using Apache SOAP 2.0 so far in this series, we'll continue to use it as our SOAP server, but we'll use the WSDL generator from WSTK in this installment.
  • IBM WSDL 1.1 Toolkit - The IBM Web Services Description Language toolkit (see Resources) generates client and server stubs from WSDL. Its code is packaged as wsdl.jar, which utilizes the bsf.jar (Bean Scripting Framework) and xalan.jar (XML stylesheet processor) files from WSTK.

Once you've downloaded and installed these tools, make sure that wsdl.jar, bsf.jar, and xalan.jar are in your CLASSPATH and you'll be ready to build your first WSDL-powered program.


Introducing WSDL

One of the main ideas behind Web services is that applications of the future will be assembled from a collection of networked-enabled services. As long as two equivalent services are able to advertise themselves to the network in a standard and neutral way, an application could theoretically choose between alternative competing services based on criteria such as price or performance. In addition, some services could allow themselves to be copied between machines, thereby allowing an application running on a particular computer (or cluster) to improve its performance by copying useful services into its local storage.

If you think about it, this is similar to how the human labor market works. Job sites and recruiting companies provide a matchmaker service between workers and employers, utilizing r_m_and job descriptions to facilitate the matching process. If a good match is found, the interested parties attempt to negotiate acceptable terms. If an agreement is reached, the worker either moves to the employer's location or takes advantage of the Internet and telecommutes instead.

The Web Services Description Language is the XML equivalent of a rsum -- it describes what a Web service can do, where it resides, and how to invoke it. To see what it looks like, let's take a look at the WSDL for the Current Exchange service that's hosted at the Xmethods site (see Resources). If you visit http://www.xmethods.net/sd_ibm/CurrencyExchangeService.wsdl, you'll see the top-level description of the service. Click on the WSDL URL field and you should see the WSDL code in Listing 1.

Note that if you go to the XMethods site, you'll see two versions for each WSDL, one of which is specific to IBM WSDL. This is because the current IBM WSDL toolkit has a bug in it that does not let it process WSDL from other toolkits. It will be fixed shortly; in the meantime, I worked with XMethods to create a version that works for this article.

Let's examine each part of the WSDL document, starting with the <definitions> section.

<definitions>
The <definitions> element contains the definition of one or more services. In most cases, a WSDL file defines a single service. The <definitions> tag is usually followed by the following attribute declarations:

  • name: This attribute is optional and is meant to convey the overall purpose of the service.
  • targetNamespace: This attribute defines the logical namespace for information about the service, and is usually chosen to be unique to the individual service. This attribute is discussed later in more detail.
  • xmlns:tns: This namespace is not present in many WSDL files (including our example) but is quickly coming into vogue. If present, it is set to the value of targetNamespace. This attribute is discussed later in more detail.
  • xmlns:soap and xmlns:xsd: These are standard namespace definitions that are used later in the WSDL document for specifying SOAP-specific information as well as data types.
  • xmlns: The default namespace of a WSDL document is set to http://schemas.xmlsoap.org/wsdl/. All the WSDL tags such as <definitions>, <message>, and <service> reside in this namespace.

Within <definitions>, are three conceptual sections:

  • <message> and <portType>: What operations the service provides.
  • <binding>: How the operations are invoked.
  • <service>: Where the service is located.

In addition, any complex data type that the service uses must be defined in an optional <types> section immediately before the <message> section. Because our example is simple and uses only primitive argument types, there is no <types> section.

Let's take a look at each section.

<message> and <portType>
A <message> corresponds to a single piece of information moving between the invoker and the service. A regular round trip remote method call is modeled as two messages, one for the request and one for the response. Each <message> can have zero or more parts, and each part can have a name and an optional type. When WSDL describes an object, each part maps to an argument of a method call. If a method returns void, the response is an empty message.

A <portType> corresponds to a set of one or more operations, where an <operation> defines a specific input/output message sequence. The message attribute of each input/output must correspond to the name of a <message> that was defined earlier. If an operation specifies just an input, it is a one-way operation. An output followed by an input is a solicit-response operation, and a single input is a notification. When WSDL describes an object, each <operation> maps to a method and each <portType> maps to a Java interface or class.

In this example, the getRate operation accepts a getRateRequest message as its input and returns a getRateResponse message as its output.

<binding>
A <binding> corresponds to a <portType> implemented using a particular protocol such as SOAP or CORBA. The type attribute of the binding must correspond to the name of a <portType> that was defined earlier. Because WSDL is protocol neutral, you can specify bindings for SOAP, CORBA, DCOM and other standard protocols. If a service supports more than one protocol, the WSDL should include a <binding> for each protocol that it supports.

In the example, the <binding> section indicates RPC-over-HTTP communications using standard SOAP encoding. Note also that the soapAction (described in the last installment) setting in this example is set to the empty string, and the URI of the service is set to "urn:xmethods-CurrencyExchange".

<service>
A <service> is modeled as a collection of ports, where a <port> represents the availability of a particular binding at a specific end-point. The binding attribute of a port must correspond to the name of a <binding> that was defined earlier.

In the example, the <service> is accessible via the CurrentExchangeBinding binding at the Xmethods Web site.

<documentation>
Any WSDL element can declare an optional <documentation> element that contains human-readable information about the element. In the example, the only documented element is <service>. It is quite common for other elements, such as individual operations, to be documented as well.


Using WSDL to generate Client Stubs

Because WSDL contains a thorough description of the interface to a service, it is possible to use it to create stubs that simplify access to the service.

The IBM WSDL toolkit allows you to create stubs for Apache SOAP. To illustrate this, let's create a client stub that allows us to invoke the Currency Exchange service hosted at Xmethods. First, create a \demo3 directory to hold all of the software for this installment. Then save the example CurrentExchange WSDL file into this directory by using the File, Save As option from your browser.

Then create the client stub by typing the following command:

\demo3> java com.ibm.wsdl.Main -in CurrencyExchangeService.wsdl

This generates a client stub class called CurrencyExchangePortTypeProxy.java (as shown in Listing 2). Ignore the message "unable to load JDK compiler" if you get it, since we'll compile the stub manually.

As you can see, the client stub looks just like the code we used in the previous installment. Client programs can now use the Proxy class to access the Web service just like a regular Java object (see Listing 3).


Listing 3: A proxy client class

public class Client1
  {
  public static void main( String[] args ) throws Exception
    {
    CurrencyExchangePortTypeProxy exchange = new CurrencyExchangePortTypeProxy();
    float rate = exchange.getRate( "USA", "japan" );
    System.out.println( "rate = " + rate );
    }
  }

If you compile and run these files, you should see the output in Figure 1.


Figure 1: Output from CurrencyExchangePortTypeProxy.java


Generating WSDL

Most vendor toolkits include some kind of automated way of generating WSDL from a component, including IBM WSTK and the Microsoft .NET studio. To illustrate how WSTK allows to generate WSDL from a service, I'll use the weather service in Listing 4.


Listing 4: Generating WSDL from a component

public class Weather
  {
  public float getTemp( String zipcode )
    {
    System.out.println( "getTemp( " + zipcode + " )" );
    return 56;
    }
  public void setTemp( String zipcode, float temp )
    {
    System.out.println( "setTemp( " + zipcode + ", " + temp + " )" );
    }
  }

To create WSDL for this class, first compile it and then start the WSTK serviceWizard from within the \demo3 directory. Make sure that \wstk-2.1\bin is in your PATH setting before attempting to invoke the command:

\demo3> serviceWizard

You should see the output window in Figure 2.


Figure 2: Web service creation tool

Click on Next and you'll be prompted for the name of the class and its CLASSPATH. The rest of the fields are set to defaults which are fine for this example. Figure 3 shows you how to fill in the fields.


Figure 3: Web service creation tool WSDL information

When you click Next, you are asked to select which methods you wish to expose via WSDL. Shift-select all of the methods shown in Figure 4.


Figure 4: Exposing selected methods through WSDL.

Finally, you're given a summary (in Figure 5) and asked to press Finish to complete the process.


Figure 5: Summary of the Web services creation tool

Congratulations, you've just created your first WSDL file! In fact, you have actually created two files:

  • Weather_Service-interface.wsdl: This file contains the <message>, <portType>, and <binding> parts of a WSDL description, that describe the interface to the Web service (see Listing 5).
  • Weather_Service-impl.wsdl: This file defines the <service> part of a WSDL description and then imports Weather_Service-interface.wsdl (see Listing 6).

This is a nice separation, because it decouples the interface specification from the implementation specification. You could theoretically have many *impl.wsdl files for a single *interface.wsdl file, and search a registry such as UDDI (to be discussed in the next installment) for one or more implementations of a particular interface description.

One interesting question is: does the <binding> section really belong in the WSDL interface file or in the implementation file? You could argue that it belongs in the implementation file, because it is specific to a particular binding such as SOAP or CORBA. We'll have to wait and see if a future standard sets a convention for this.


Listing 5: Weather_Service-interface.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="Weather_Service-interface"
  targetNamespace="http://www.weatherservice.com/Weather-interface"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://www.weatherservice.com/Weather"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<message
      name="IngetTempRequest">
  <part name="meth1_inType1"
    type="xsd:string"/>
</message>
<message
      name="OutgetTempResponse">
  <part name="meth1_outType"
    type="xsd:float"/>
</message>
<message
      name="InsetTempRequest">
  <part name="meth2_inType1"
      type="xsd:string"/>
  <part name="meth2_inType2"
    type="xsd:float"/>
</message>
<portType
      name="Weather_Service">
  <operation name="getTemp">
    <input
        message="IngetTempRequest"/>
    <output
      message="OutgetTempResponse"/>
  </operation>
  <operation
        name="setTemp">
    <input
    message="InsetTempRequest"/>
  </operation>
</portType>
<binding
    name="Weather_ServiceBinding"
      type="Weather_Service">
  <soap:binding style="rpc"
      transport="http://schemas.xmlsoap.org/soap/http"/>
  <operation
        name="getTemp">
    <soap:operation
          soapAction="urn:weather-service"/>
    <input>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:weather-service"
          use="encoded"/>
    </input>
    <output>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:weather-service"
      use="encoded"/>
    </output>
  </operation>
  <operation
        name="setTemp">
    <soap:operation
          soapAction="urn:weather-service"/>
    <input>
      <soap:body
          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
          namespace="urn:weather-service" use="encoded"/>
    </input>
  </operation>
</binding>
</definitions>


Listing 6: Weather_Service-impl.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="Weather_Service"
  targetNamespace="http://www.weatherservice.com/Weather"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://www.weatherservice.com/Weather"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<service
      name="Weather_Service">
  <documentation>IBM WSTK 2.0 generated service definition file</documentation>
  <port
      binding="Weather_ServiceBinding"
        name="Weather_ServicePort">
    <soap:address
    location="http://localhost:8080/soap/servlet/rpcrouter/"/>
  </port>
</service><import
    location="http://localhost:8080/wsdl/Weather_Service-interface.wsdl" 
    namespace="http://www.weatherservice.com/Weather-interface">
</import>
</definitions>


Generating stubs from WSTK WSDL files

Creating stubs from the WSTK WSDL files is a little tricky because the import statement in Weather_Service.impl causes the WSDL stub generator to perform an HTTP Get to the location of the interface file, which in this case is http://localhost:8080/wsdl/Weather_Service-interface.wsdl. To make sure that Tomcat can serve up this file, create a directory \wsdl in the Tomcat root folder $TOMCAT_HOME\webapps\ROOT, and copy the .wsdl files into this directory. Then, assuming tomcat is running in the \demo3 directory, type the following command while in the \demo3 directory:

\demo3> java com.ibm.wsdl.Main -in Weather_Service-impl.wsdl

Tomcat will serve up the Weather_Service-interface.wsdl file from the \wsdl directory, and you should end up with a stub class called Weather_ServiceProxy.java in \demo3. Listing 7 shows a test client program that accesses a weather service hosted in your local Tomcat server:


Listing 7: Test code for Weather Web service

public class Client2
  {
  public static void main( String[] args ) throws Exception
    {
    Weather_ServiceProxy weather = new Weather_ServiceProxy();
    float temp = weather.getTemp( "75248" );
    System.out.println( "temp = " + temp );
    weather.setTemp( "75248", 84 );
    }
  }

To run the program, compile all the Java files in \demo3, deploy the Weather service with URN urn:weather-service using the Apache deployment screen, and then execute the Client program. Figure 6 shows what the deployment screen should look like after you fill in all the fields:


Figure 6: Running the Web service

When you run the program, the client should display the return of the getTemp() invocation, and the tomcat window should display the incoming setTemp() invocation.


Target Namespaces

Because WSDL files can import other WSDL files, there is always the possibility of a name clash. Because of this, the latest crop of WSDL files define the targetNamespace and xml:tns attributes in their <definitions> section, where targetNamespace is set to a unique URL for the particular WSDL (usually the name of the original WSDL file). WSDL generators that do this then scope references between sections with tns: to prevent clashes. For example, in Listing 8, the operation declaration explicitly scopes the messages that it uses to a particular WSDL file using the tns: prefix.


Figure 8: Using the tns: prefix

    <portType name = "CurrencyExchangePortType">
        <operation name = "getRate">
            <input message = "tns:getRateRequest" name = "getRate"/>
                <output message = "tns:getRateResponse" name = "getRateResponse"/>
          </operation>
    </portType>

It is likely that all WSDL toolkits will soon adopt this approach.


Next Installment

In the next installment, we'll take a look at how a Web service can advertise itself using UDDI (Universal Description, Discovery and Integration) for use by other Web services. We'll use the newly-released IBM UDDI4J toolkit to publish and bind to Web services in a UDDI repository.


Resources

  • In his first installment, Graham examines the benefits and challenges of building Web service applications to enable peer-to-peer distributed networks.

  • In the second installment, Graham provided a step by step explanation of how to develop a Web service, including the tools you need, how to install them, how to write the code, and how to deploy the service.

  • In his third installment of this column, Graham examines the behavior of SOAP's exchange of messages on-the-wire and explains how it works.

  • Read the WSDL 1.1 specification on the World Wide Web Consortium.

  • The WSDL Toolkit is no longer distributed separately -- it is now part of the IBM Web Services Toolkit on alphaWorks.

  • Download the IBM Web Services Toolkit from alphaWorks.

  • Xmethods.net has a directory of publicly available Web services, one of which is used in this article

About the author

Graham Glass is founder, CEO, and Chief Architect of The Mind Electric, which designs, builds and licenses forward-thinking distributed computing infrastructure. He believes that the evolution of the Internet will mirror that of a biological mind, and that architectures for helping people and businesses to network effectively will provide insight into those that wire together the human brain. He can be reached at graham-glass@mindspring.com.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=11481
ArticleTitle=The Web services (r)evolution: Part 4
publish-date=02012001
author1-email=graham-glass@mindspring.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers