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.
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 thebsf.jar(Bean Scripting Framework) andxalan.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.
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 oftargetNamespace. This attribute is discussed later in more detail.xmlns:soapandxmlns: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 tohttp://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
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.
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.
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.
-
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
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 (Undergoing maintenance)





