 | Level: Introductory Doug Tidwell (dtidwell@us.ibm.com), Senior Programmer, IBM
01 Jan 2003 You have no doubt seen plenty of articles on Web services technologies, covering everything from the basics of the Simple Object Access Protocol (SOAP) to more advanced topics like the Web Services Invocation Framework (WSIF) and Web services registries. At developerWorks, we have received several requests for an article that puts everything in perspective; that is what we will do here. In this article, Doug Tidwell takes a simple piece of code, deploys it as a Web service, and writes a few clients for it. Next, he discusses how to create a description of the Web service and how to store that description in a registry and on a Web server. Finally, he looks at two different ways of discovering and invoking a Web service. When you are finished with this article, you should have a better understanding of how all of these technologies work together.
This article was published in the November 2002 issue of the IBM developerWorks journal.
Introduction
Most of the work I will be doing in this article is based on open source tools from the
Apache XML project, including Axis beta 3; the WSIF; the Web Services Inspection Language
(WS-Inspection); the Web Services Description Language for Java Toolkit (WSDL4J) API; and
the Universal Description, Discovery and Integration for Java (UDDI4J) API. (See the Resources section for more details on these tools and how to get them.) To emphasize the open,
cross-platform nature of SOAP applications, I will look at clients written in Perl, Python, and PHP.
The tools
To begin, I will take a simple piece of Java code and make it a Web service.
The sample application emulates an American toy called the Magic Eight Ball. The toy is a giant
billiard ball filled with blue liquid and a clear window that looks in on a shape, which floats
in the liquid, with 20 sides. On each of the 20 sides is an answer to a yes-or-no question. To
receive guidance from the Eight Ball, you shake it as you think of a question, then look down
at the Eight Ball. The 20-sided shape (an icosahedron) floats to the window and one of the 20
answers is visible, telling you the answer to your question.
The Java version of the Eight Ball is a random number generator that returns one of 20 strings at random, as shown in Listing 1.
Listing 1. Look to (but don't shake) EightBall.java for answers
import java.util.Random;
import java.lang.Double;
import java.util.Date;
public class EightBall {
static String answers[] = {"Yes.",
"Outlook not so good.",
// The other 17 answers were
// removed for brevity.
"Don't count on it."};
public static String getAnswer() {
return askQuestion("");
}
public static String askQuestion
String question) {
java.util.Random r = new Random
(new Date().getTime());
java.lang.Double d = new Double
((r.nextDouble()*20)-1);
return new String(answers[d.intValue()]);
}
public static void main(String args[]) {
System.out.println(getAnswer());
}
}
|
The most interesting aspect of this code is that it is not aware of the Web, networking, SOAP,
or XML. Despite that, you can still take this code and make it a Web service without any changes.
That is good news for the example, and it is even better news for anyone trying to add Web
services interfaces to existing applications. In many cases, you can do that without any changes
as well.
Before you actually deploy the code, you should familiarize yourself with three methods.
The main method simply enables you to invoke the Eight Ball from a command line; you will not use it
from your Web services clients. The getAnswer and askQuestion methods are the ones that you will
expose as Web services. The askQuestion method, when given a String, returns 1 of the 20 answers
selected at random. The getAnswer takes no parameters and merely calls askQuestion with a blank
String.
To deploy the code as a Web service hosted by Axis, you need to create a deployment descriptor, as shown in Listing 2.
Listing 2. Deployment descriptor
<deployment xmlns=
"http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/
wsdd/providers/java">
<service name="urn:EightBall"
provider="java:RPC">
<parameter name="className"
value="EightBall"/>
<parameter name="allowedMethods"
value="getAnswer askQuestion"/>
</service>
</deployment>
|
The deployment descriptor defines several things:
- The name of the service (urn:EightBall).
- What type of service this is (java:RPC means this is an RPC-style service written in Java code).
- The name of the Java class that provides the service (EightBall).
- The name of the methods (getAnswer and askQuestion) supported by this service.
 |
Acronym roll call
Here is a list of the technologies that this article discusses:
-
SOAP: The XML-based protocol for invoking Web services. Originally an acronym for
the Simple Object Access Protocol, now it doesn't stand for anything.
-
WSDL: A Web Services Description Language is an XML document that tells you (or a client
application) everything you need to invoke a Web service.
-
UDDI: The Universal Description, Discovery, and Integration protocol. This defines what a
registry of Web services should look like. UDDI registry interactions happen through SOAP messages.
-
WS-Inspection: The Web Services Inspection Language (also known as WSIL). This is an XML vocabulary that lists all of the Web services provided at a given site. You can perform Web services discovery with WS-Inspection instead of UDDI.
-
WSIF: The Web Services Invocation Framework. A tool from IBM that simplifies invoking
a Web service.
Your Web services toolbox
Here are the Web services tools that are used in this article:
-
Axis: The latest version of the Apache SOAP toolkit. Includes a tracing tool that
helps debug SOAP applications.
-
The "4J" libraries (UDDI4J, WSDL4J, WSIL4J, and WSIF4J): Java libraries that simplify
working with Web services registries, descriptions, and inspection documents. You can
find these libraries in the IBM Web Services Toolkit.
|
|
I used the AdminClient class to get Axis to process this data, as follows:
java org.apache.axis.client.AdminClient DeployEightBall.wsdd
Once Axis has processed the deployment descriptor, you need to move the EightBall.class file
to a directory where Axis can find it. In this case, that is the axis\WEB-INF\classes directory;
where that particular directory exists on your system depends on the servlet engine you are
using to host Axis. For Jakarta Tomcat 4.0.3, the directory is jakarta-tomcat-4.0.3\webapps.
Write a client application
Now that you have deployed your Java code as a Web service, you can write a client application.
You will do this in a number of different ways and different languages. Regardless of how you write your client application, the application has to know five things:
- The name of the machine that is hosting the service.
- The name of the service.
- The name of the method that you want to invoke.
- The parameters for the method that you want to invoke (this means you have to
know how many parameters there are and what their data types are).
- What the SOAPAction field should contain (I will cover this when I describe Web services discovery; do not worry about it for now).
The first application will be a Java client written using the Axis client API. The
four steps in using the Axis API are:
- Create a Service object.
- Use the Service object to create a Call object.
- Set the properties of the Call object (method name, parameters, and so on).
- Use the invoke method of the Call object.
There are several things worth noting in Listing 3, which shows the bulk of the
client code. First, notice that your client application does have to know about SOAP, XML, and
so forth, even though your service did not. Next, you create the Service and Call objects and
start setting the properties of the Call object. This includes setting the address of the
machine that hosts the Web service (http://localhost:8070/axis/services/), defining the name
of the service (urn:EightBall), and defining the name of the method (getAnswer). Once you have
set all the properties, you can use the invoke method as shown in Listing 4.
Listing 3. EightBallClient1 segment using the Axis API
import javax.xml.rpc.namespace.QName;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.utils.Options;
public class EightBallClient1 {
public static void main(String [] args)
throws Exception {
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(
new java.net.URL
("http://localhost:8070/axis/
services/"));
call.setOperationName(
new QName("urn:EightBall",
"getAnswer"));
|
Listing 4. Use invoke method
try {
System.out.println(call.invoke(
new Object[] { }));
} catch (java.rmi.RemoteException re) {
System.out.println("Error - " + re);
}
|
Notice that invoke passes an array of Java Objects as its sole parameter. Because everything
in Java code ultimately inherits from java.lang.Object, you can put absolutely anything inside
this array. In the first client application, you are using the getAnswer method, which does not
have any parameters. That means you create the empty array of Java Objects and leave it at that.
In more advanced clients, you can put more interesting and complex items inside the array.
The invoke method builds a SOAP envelope that contains your request and sends it off to the machine
that you set as the endpoint address. The machine that hosts the Web service delivers the
data from the SOAP request to the service, which then processes that request and generates a
response. The response comes back to your client as another SOAP envelope; utilities in the Axis
toolkit enable you to write the contents of the SOAP envelope with a System.out.println statement.
Finally, you use the invoke method inside a Java code try block. Many things can go wrong with a
distributed application, so it is best to anticipate the problems ahead of time. For example,
the remote machine might not be found, it might not respond in a certain amount of time, a
message sent to or from the service could be lost or delayed, and so forth.
Here is how your client application looks from the command line:
D:\webservices\eightball>java EightBallClient1
It is decidedly so.
|
Although this may not be the most visually appealing application you have ever seen, consider
what you have done with little effort:
- You took an ordinary piece of code and exposed its methods across a network.
- You wrote a client application that anyone else can use on that network to invoke methods
of a Java object.
- Because SOAP is language neutral, you can access the methods of that Java object from
any programming language or operating system you are likely to use.
Those are three enormous accomplishments. If you wanted to do this with other remote
technologies, it would take considerably more effort. With CORBA, you would have to generate
language bindings for the various languages you wanted to support. With RMI, you could
only write clients in Java code. SOAP enables you to create a flexible system in a short period of time.
Trace your client application
Before I go on to more advanced client applications, note that Axis ships with an
extremely useful tracing tool for SOAP messages. Here is the command that starts the tracing tool:
java org.apache.axis.utils.tcpmon 8070 localhost 8080
The arguments to the tcpmon class tell it to monitor port 8070 for SOAP envelopes. The tcpmon class writes any SOAP envelope that comes to port 8070 to the tracing window and
sends it to localhost port 8080. When the SOAP response comes back from port 8080, tcpmon writes
the response to the tracing window and sends it back to the client. Figure 1 shows how the tracing window looked when you ran the client application. In Figure 1, you can see the actual
request and response messages as they go back and forth between the client and the service.
Figure 1. AXIS SOAP Tracing window

A more complicated client
For the first client application, you used the getAnswer method, which does not take any parameters.
Your next client application will use the askQuestion method, which requires a single String
(the question you are asking) as a parameter. That means you have to do a little more work before
you use Call.invoke. Fortunately, the amount of extra work is not significant. Listing 5
shows the important part of the code.
Listing 5. Call the EightBall service with a parameter
<question xsi:type="xsd:string">
Will Deutschland win the World Cup?
</question>
call.setTargetEndpointAddress(new
java.net.URL
("http://localhost:8070/axis/services/"));
call.setOperationName(new
QName("urn:EightBall", "askQuestion"));
call.addParameter("question",
XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(
org.apache.axis.encoding.XMLType.XSD_STRING);
try {
String question =
"Will Deutschland win the World Cup?";
String ret = (String) call.invoke
(new Object[] { question });
System.out.print(question + "\n ");
System.out.println(ret);
}
|
Note that Listing 5 does a couple of additional things.
First, it uses the addParameter method to add a new parameter to the Call object. You are defining
that the name of the parameter is question, it is of type string (as defined by the XML Schema standard),
and it is an input parameter. The next item that it uses is the setReturn Type method to tell the Call
object that the data returned by this Web service is a string as well. That sets up the
Call object with all the properties you need. Inside the try block, you create a Java String that contains
your question, and you pass that string in the array of Objects. You also could put the String itself
into the array when you use the invoke method.
When your SOAP request goes to the server, it contains your parameter as well.
The parameter looks like Listing 6.
Listing 6. Parameter
String ret = (String) call.invoke
(new Object[] { "Will Deutschland..." });
|
(I wrote this while presenting at a conference in Berlin, so the question is a shameless
attempt to pander to the audience.) If you need to pass multiple parameters to a Web service,
you can use the addParameter method as many times as you need and put all of the objects you
need in the array used by the invoke method. If there is a mismatch between the number or types
of arguments (you use the addParameter method twice, but only pass one object in the invoke
method, for example), you will get an exception.
Write clients in other languages
Everything you have done to this point has been in Java code. You have been able to do some
impressive things, but one of the goals of SOAP is interoperability. To illustrate just how
interoperable SOAP is, I will describe clients written in three other languages, all of
which can access methods of your Java class without any problems.
A Perl client
To write your Perl client, you will use Pavel Kulchenko's excellent SOAP::Lite library.
Listing 7 has the entire client code.
Listing 7. Perl client code
use SOAP::Lite;
print ("Perl SOAP client:\n");
print SOAP::Lite
-> uri('urn:EightBall')
-> proxy
('http://localhost:8070/axis/services/')
-> askQuestion('Will I win the lottery?')
-> result;
|
As you may expect from a scripting language, the Perl client is brief. Despite the obvious
differences in syntax, this client still defines the same basic information:
- The address of the machine that is hosting the service (http://local-host:8070/axis/services/).
- The name of the service (urn:EightBall).
- The name of the method you want to invoke (askQuestion).
- The parameter for the method that you want to invoke (the string "Will I win the lottery?").
When you run this client at the command line, you get the expected results:
D:\webservices\eightball>eightballclient.pl
Perl SOAP client:
Signs point to yes.
|
A Python client
Next, I will describe a Python client. The Python client uses the SOAP.py library. Listing 8 has the entire source code.
Listing 8. Python client code
#!/usr/bin/env python
import SOAP
print "Python SOAP client: "
server = SOAP.SOAPProxy(
"http://localhost:8070/axis/services/",
namespace = 'urn:EightBall',
encoding = None)
print " ",
server.askQuestion(SOAP.stringType(
'Will I win the lottery?'));
|
Again, you define the same items: the hostname, service name, and so forth. The syntax is
different, but the results are the same:
D:\webservices\eightball>eightballclient.py
Python SOAP client:
Concentrate and ask again.
|
A PHP client
Continuing the tour of popular scripting languages that begin with the letter "P," I will
examine a PHP client. The PHP client is somewhat different in that you are embedding the SOAP
call inside an HTML page. When the user requests a given URL (http://localhost/eightballclient.php, in
this case), the PHP libraries invoke your Web service and put the results from the service inside the
HTML page. Listing 9 shows the PHP source code for the page.
Listing 9. PHP client source code
<html>
<head>
<title>PHPSOAPclienttest</title>
</head>
<body>
<center>
<h1>WillDeutschland
wintheWorldCup?</h1>
<p>Theanswerfromthe
MagicEightBall:</p>
<p>
<fontsize="+3"color="blue">
<?php
require_once('nusoap.php');
$parameters=array('question'=>'Will
DeutschlandwintheWorldCup?');
$soapclient=
newsoapclient(
'http://localhost:8070/axis/services/');
echo$soapclient->call('askQuestion',
$parameters,'urn:EightBall');
?>
</font>
</p>
</center>
</body>
</html>
|
Again, you are using the same
information, but you are embedding the results from the Web service in an HTML page. Figure 2
shows how the page looks. This page was built with the NuSOAP PHP library.
Figure 2. The EightBall predicts through PHP

Generate a Web service description
At this point, you have taken your simple piece of code and written a couple of client
applications for it. If you had a Web Services Description Language (WSDL) file that described
your Web service, you could use tools to generate client applications. Fortunately for us, Axis
automatically will generate a WSDL file from your deployed service. The URL of your Web service
is http://localhost:8080/axis/services/urn:EightBall; to get the WSDL description of the service,
simply append ?WSDL to the URL. Listing 10 shows part of the generated WSDL file. Obviously, this
file is not for human consumption; it is for development tools to use as input.
Listing 10. EightBall sample WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions...>
...
<wsdl:operation name="getAnswer">
<wsdl:input message=
"intf:getAnswerRequest"/>
<wsdl:output message=
"intf:getAnswerResponse"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding
name="urn:EightBallSoapBinding"
type="intf:EightBall">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/
soap/http"/>
...
<wsdl:operation name="askQuestion">
...
</wsdl:binding>
<wsdl:service name="EightBallService">
<wsdl:port binding=
"intf:urn:EightBallSoapBinding"
name="urn:EightBall">
<wsdlsoap:address
location=
"http://localhost:8080/axis/
services/urn:EightBall"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
|
Use the WSDL description in a client
One of the many wonderful features of SOAP::Lite is that it can use a WSDL file directly.
Here is a Perl client (Listing 11) that gets all of the necessary details about the Web service from the WSDL
file and invokes the getAnswer method based on the information in the description.
Listing 11. Perl client WSDL
use SOAP::Lite;
print SOAP::Lite
-> service('http://localhost:8080/axis/
services/urn:EightBall?WSDL')
-> getAnswer(), "\n";
|
Although this code is not much shorter than the original version of your Perl client,
it has one very important difference: it discovers the details of how the Web service
is implemented, and it uses those details to invoke the service. In all of your earlier
clients, you hardcoded the details, such as the hostname, the service name, and so forth. For
the rest of this article, I will describe a couple of approaches to Web services discovery.
WSIF
IBM recently donated WSIF to the Apache XML Project. WSIF is designed to isolate
developers from the details of invoking a Web service; with WSIF, you simply point
the library at the WSDL description of the service that you want to invoke, and the
framework takes it from there. Listing 12 shows the crux of the code that invokes the Web service.
Listing 12. Invoke a Web service with WSIF
WSIFService svc =
ServiceFactory.newInstance().
getService(wsdlLocation);
WSIFPort defPort = svc.getPort();
WSIFOperation myOp =
defPort.createOperation("askQuestion");
WSIFMessage inMsg =
myOp.createInputMessage();
WSIFMessage outMsg =
myOp.createOutputMessage();
WSIFMessage faultMsg =
myOp.createFaultMessage();
myOp.executeRequestResponse
(inMsg, outMsg, faultMsg);
System.out.println("Result:"+
outMessage.getStringPart("return"));
|
Just from looking at the code in Listing 12, you cannot tell much about the kind of service
it is invoking. That is by design; WSIF shields you from having to know those details. The
information about how to invoke the service comes from the WSDL file. The WSIF library discovers
those details at run time. Speaking of discovery ...
Web services discovery
There are two significant approaches to Web services discovery: one is to use WS-Inspection.
With WS-Inspection, you know the URL of your service provider, so you ask the service provider for
a WS-Inspection document that lists all of its Web services. The other approach is to use Universal
Description, Discovery and Integration (UDDI). The UDDI specification defines what a registry of Web
services should look like. With UDDI, your client application will discover the URL of the service
provider. If you want to publicize your Web service, you will store its description in the registry
and create a client that discovers the WSDL description in the UDDI registry and invokes the Web service.
Depending on the type of service you are providing and the needs of your customers, you might use both
approaches. If you want to provide services for the general public, putting them in a UDDI registry
is the simplest way to do that. If you want to provide services for a few partners or customers only,
using WS-Inspection is the simplest approach.
 |
WSIL discovery scenario
The following figure shows the flow of a client discovering a Web service with WSIL (WS-Inspection):

- The client contacts the service provider, requesting its inspection.wsil file. This is
simply the client opening a URL; the name of the file and the URL of the service provider
are known before hand.
- The service provider sends the WSIL file back to the client.
- The client inspects the WSIL file and finds the service it wants to invoke. Part of the
service's definition in the WSIL file is the URL of the WSDL file; the client contacts
the service provider, requesting the WSDL file.
- The service provider sends the WSDL file back to the client.
- The client inspects the WSDL file and builds a SOAP request to invoke the Web service.
- The Web service processes the client's request and sends the response back to the client.
|
|
In both cases, you are using a mechanism to discover some of the information you needed when you
built your client applications earlier. Here are your five elements that the client application needs
to know and how they are handled with your two approaches to Web services discovery:
-
The name of the machine that's hosting the service. In WS-Inspection, you know
the name of the machine; you go directly to it and ask for a list of its services.
In UDDI, you go to the registry and discover the name of the machine.
-
The name of the service. You discover this whether you are using WS-Inspection or UDDI.
-
The name of the method you want to invoke. While it is technically possible to discover
this, it is unlikely that you would ever want to. Yes, you can discover a method you have never
heard of before and send it some data and hope for the best, but that is not a good idea.
-
The parameters for the method. Even if you decided to discover the name of the method, your
client application needs some prior knowledge of the kind of data you are going to pass to the
Web service. Tools can generate the code that passes two strings to a given service (the WSDL
file tells the tool method x takes two strings as its arguments), but it is up to you to write
the business logic to figure out what those two strings are.
-
What the SOAPAction field should contain. You can discover this from the WSDL file. Different
vendors process the SOAPAction field differently, so discovering this information is a good idea.
For example, if Axis hosts the Web service, the SOAPAction field is ignored completely. If it is
hosted by Microsoft .NET, the SOAPAction field must be formatted in a particular way. When you are
invoking a Web service hosted by a SOAP toolkit that requires the SOAPAction field to be in a
certain format, your client application has to know what that format is.
Of these five items, it makes sense to discover items 1, 2, and 5. You usually do not find out
the method name (item 3), and discovering item 4 does not make any sense. You can discover from
a WSDL file that a given Web service takes two strings as its parameters, but you still have to write
the business logic that figures out what those two strings should be. Picking any two strings at
random (your name and credit card number, for example) and sending them to a Web service you just
discovered is not a good idea.
WS-Inspection and discovery
WS-Inspection is a proposed standard for Web services discovery. As I discussed earlier,
WS-Inspection assumes you know the name of the machine that is hosting the service. You go to that
machine and ask for a list of services; you assume here that the list is in the file inspection.wsil.
If the machine hosting the service is http://localhost/, you get the file http://localhost/inspection.wsil
to find the list of Web services hosted on that machine. Listing 13 shows a simple WSIL file that
references the EightBall service.
Listing 13. A simple WS-Inspection file
<?xml version="1.0"?>
<inspection
xmlns="http://schemas.xmlsoap.org/ws
/2001/10/inspection/"
xmlns:wsilwsdl=
"http://schemas.xmlsoap.org/ws
/2001/10/inspection/wsdl/">
<service>
<abstract xml:lang="en-US">
WSDL description for the
Eight Ball service
</abstract>
<name xml:lang=
"en-US">urn:EightBall</name>
<descriptionreferencedNamespace=
"http://schemas.xmlsoap.org/wsdl/"
location=
"http://localhost/EightBall.wsdl"/>
</service>
</inspection>
|
The two most significant items in this file are the name element inside the service element (the
value urn:EightBall) and the location attribute of the description element (http://localhost/EightBall.wsdl).
In the WS-Inspection discovery scenario, the client application searches the WS-Inspection file for
a particular service (one named urn:EightBall) and gets the URL of the WSDL document that describes the
service. Given the WSDL document, it finds the remaining details of the Web service and invokes it.
Setup for WS-Inspection discovery
To set up your Web service so that WS-Inspection can discover it, you follow three relatively simple
steps:
- Generate the WSDL file. The Axis toolkit did this for you.
- Store it as EightBall.wsdl in the document root of your Web server.
- Create the WS-Inspection file. Currently, you have to do this by hand, although future
versions of Axis may generate the WS-Inspection file as well. You created the inspection.wsil
file and stored it in the document root of your Web server.
That's it! Once you complete these steps, you can write a client that asks for a list of all Web
services supported by this server, select one of those services, and invoke it.
UDDI and discovery
The last topic (and, not coincidentally, the most complicated) is UDDI. With UDDI,
you store the description of your service in a UDDI registry. Your client searches the
registry for the appropriate service, finds its details (its WSDL file), and invokes the
service. If for some reason the service fails, the client could go back to the registry,
find another provider of the same service, and attempt to invoke that provider's version of
the service. The UDDI approach is more flexible, but it is a lot more work as well.
 |
UDDI discovery scenario
The following figure shows the flow of a client discovering a Web service with UDDI:

- The client sends a search request to the UDDI registry. The search request is inside a
SOAP envelope.
- The registry sends the search results back to the client. The search results are inside a
SOAP envelope as well. (You must assume at this point that the client has enough information to
select a service provider; in reality, the client and the registry will likely send several
messages back and forth.)
- Having selected a service provider, the client contacts the provider and requests the WSDL
file that describes the Web service. This request is most likely the client opening a URL.
- The WSDL file is sent back to the client.
- The client uses the information in the WSDL file to invoke the service.
- The Web service processes the client's request and sends the response back to the client.
|
|
Setup for UDDI discovery
UDDI discovery is more complex:
-
Split the WSDL file into two files. One file describes the interface to your
service, while the other file describes your implementation of it. In other
words, the interface WSDL file will say, "There's something called an EightBall service,
and it has methods named getAnswer and askQuestion, and here are the inputs to those methods
and the outputs from them, and so forth." The implementation WSDL file will say, "I implement
the EightBall interface, and here are the details that you need to access my implementation
of this service."
-
Register the interface WSDL file as a TModel. A TModel is a UDDI construct that refers
to some kind of standard. (It is an intentionally vague concept that can be confusing.) Note that
the UDDI specification defines them as tModels, lowercase t, while the UDDI4J library
defines a Java class named TModel, capital T. I refer to them both as TModels in this article.
-
Create a BusinessEntity for your company. This represents the organization providing
the Web service.
-
Create a BusinessService for this particular Web service. Your BusinessService will reference
both the BusinessEntity and the TModel; that tells anyone searching the registry that your company
provides the BusinessService, and that the service supports the EightBall Interface as
defined in your TModel.
I will go through each of these steps in the following sections.
Split the WSDL file into two parts
The interface WSDL file contains the type, message, and portType elements. This
defines the methods of the Web service. The implementation WSDL file contains the binding,
service, and port elements, and uses an import statement to include the implementation WSDL
file. Figure 3 shows how to split the WSDL file.
Figure 3. WSDL split file structure

Register the WSDL file as a TModel
The UDDI specifications define a TModel as a reference to a standard. The definition
is completely open-ended, as those standards can be anything from a government regulation to
a vague design that you and I agreed upon over dinner last night. In this case, you are defining
the interface to the EightBall service as a standard. You will create a TModel object
in the UDDI registry and give that TModel a unique ID. When you define your implementation
of the EightBall service, you will reference the TModel to indicate that your service supports
that standard. Listing 14 shows the XML element that defines your new TModel.
Listing 14. EightBall XML TModel
<tModel tModelKey="">
<name>EightBall Interface</name>
<description xml:lang="en">
The interface-only definition
of the EightBall service.
</description>
<overviewDoc>
<description xml:lang="en">
The mystical powers of the EightBall,
channeled into Java.
</description>
<overviewURL>
http://localhost/eightball.org/
eightballinterface.wsdl
</overviewURL>
</overviewDoc>
<categoryBag>
<keyedReference
tModelKey="UUID:C1ACF26D-9..."
keyName="uddi-org:types"
keyValue="wsdlSpec"/>
</categoryBag>
</tModel>
|
The UDDI4J library puts this XML element inside a SOAP envelope and sends it to the
registry; if the TModel is created successfully, you receive a TModelDetail element that
describes the properties of your new TModel. The most important of these properties is the
unique ID of the TModel.
Create a BusinessEntity
Next, you create a BusinessEntity to represent your service provider. Several items can
contain a BusinessEntity; Listing 15 shows the XML that your sample program uses.
Listing 15. EightBall BusinessEntity markup
<businessEntity businessKey="">
<discoveryURLs>
<discoveryURL useType="wsil">
http://localhost/inspection.wsil
</discoveryURL>
</discoveryURLs>
<name>DougCo Software</name>
<description xml:lang="en">
Sample business created for
the UDDI discovery demo.
</description>
<contacts>
<contact useType="Technical contact">
<personName>Doug Tidwell</personName>
<phone useType=
"voice">1-919-555-5583</phone>
<phone useType=
"fax">1-919-555-2389</phone>
<phone useType=
"mobile">1-919-555-9385</phone>
<email>dtidwell@us.ibm.com</email>
<address>
<addressLine>1234 Main Street
</addressLine>
<addressLine>Anytown, TX 73958
</addressLine>
</address>
</contact>
</contacts>
<categoryBag>
<keyedReference keyName=
"uddi-org:iso-ch:3166-1999"
keyValue="US-NC" tModelKey=
"UUID: 4E49A8D6-D5A2-4FC2-93A0-
0411D8D19E88"/>
<keyedReferencekeyName= "ntis-gov:naics:1997"
keyValue="541511" tModelKey=
"UUID: C0B9FE13-179F-413D-8A5B-5
004DB8E5BB2"/>
<keyedReference keyName="unspsc-org:unspsc"
keyValue="43.16.26.05.00" tModelKey=
"UUID: CD153257-086A-4237-B336-6BDCBD
CC6634"/>
</categoryBag>
</businessEntity>
|
There are several things inside your BusinessEntity. You gave your business a name and a
description and defined a contact person at the company. You also defined a discovery URL that
references the WSIL file for your services. The keyed references at the bottom of the markup
refer to three different TModels:
-
uddi-org:iso-ch:3166-1999. Represents ISO names for geographic locations
(US-NC stands for North Carolina in the United States).
-
ntis-gov:naics:1997. Represents the North American Industry Classification
System (541511 means you are in the Custom Computer Programming Services business).
-
unspsc-org:unspsc. Represents the United Nations Standard Products and
Services Code, a categorization scheme for goods and services (43.16.26.05.00 means you
produce Networking Developers Software).
With your BusinessEntity, you defined your business and labeled it with several categories.
Create a BusinessService
When you create your BusinessService, you will provide the appropriate details to reference
the WSDL file for your implementation. Of course, you also will reference the ID of the BusinessEntity
that you created for your company and the ID of the TModel that you created for the EightBall interface.
Listing 16 shows the markup.
Listing 16. EightBall BusinessService markup
<businessService serviceKey=""
businessKey="00EB06FC-3C45-42B8-B394-1
F7F35602B2E">
<name>EightBallservice</name>
<descriptionxml:lang="en">
ThepoweroftheMagicEightBall,
channelledthroughcode.
</description>
<bindingTemplates>
<bindingTemplatebindingKey=""
serviceKey="">
<descriptionxml:lang="en">
Tiesthisimplementationtothe
EightBallInterface.
</description>
<accessPointURLType="http">
http://localhost:8080/axis/services/
urn:EightBall
</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfotModelKey=
"UUID:0B6E1227-329A-4657-89B5-
35DA36CA2554">
<descriptionxml:lang="en">
Implementationofthe
EightBallInterface.
</description>
<instanceDetails>
<overviewDoc>
<overviewURL>
http://localhost/
EightBallImplementation.wsdl
</overviewURL>
</overviewDoc>
</instanceDetails>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
</businessService>
|
The three crucial parts of your BusinessService definition are the reference to the business key,
the TModel key, and the URL of the WSDL document that describes your implementation of the EightBall service.
Write a UDDI client
To write a client application that performs discovery through UDDI, you need to search for
BusinessServices that reference the appropriate TModel. When you find one, you will get the
details about that service through a series of follow-up queries to the registry. Your ultimate
goal is to retrieve the URL of the WSDL file; once you do that, you can use WSIF to invoke the Web
service from the WSDL file. The first step in your UDDI discovery code is to retrieve the TModel
key from a properties file. When you created the TModel, you saved its key to a properties file.
When you need to use the key, you simply retrieve its value from the file, as shown in Listing 17.
Listing 17. Retrieve key value from file
TModelBag tmb = new TModelBag();
TModelKey tmk = new TModelKey();
File testFile = new File
("eightball.properties");
if (testFile.exists()){
FileInputStream propStream =
new FileInputStream(testFile);
props.load(propStream);
propStream.close();
}
tmk.setText(props.getProperty("TModelKey");
Vector tModelKeys = newVector();
tModelKeys.add(tmk);
tmb.setTModelKeyVector(tModelKeys);
|
This creates a TModelBag structure, which is an unordered collection of TModels. You will
use this structure as part of your search criteria. You will ask the UDDI registry to give you a
list of all the BusinessService objects that reference all of the TModels in the TModelBag.
Assuming the UDDI registry finds a match, you will take the first one and find the binding
templates associated with that service, as shown in Listing 18. You will look at the
other properties of the service to find the URL of the WSDL document that describes this
implementation of the Web service.
Listing 18. Java code to find the EightBall WSDL URL
ServiceList sl = proxy.find_service
("", null, null, tmb, null, 0);
Vector serviceInfoVector =
sl.getServiceInfos().getServiceInfoVector();
String serviceKey =
((ServiceInfo)(serviceInfoVector.
elementAt(0)).getServiceKey();
BindingDetail bd = proxy.find_binding(null,
serviceKey, tmb, 0);
Vector bindingTemplates=
bd.getBindingTemplateVector();
BindingTemplate bt = (BindingTemplate)
bindingTemplates.elementAt(0);
AccessPoint ap = bt.getAccessPoint();
Vector tModels =
bt.getTModelInstanceDetails().
getTModelInstanceInfoVector();
TModelInstanceInfo tmii=
(TModelInstanceInfo)tModels.elementAt(0);
InstanceDetails id =
tmii.getInstanceDetails();
OverviewDoc od = id.getOverviewDoc();
OverviewURL ou = od.getOverviewURL();
|
The OverviewURL is the URL of the WSDL document that describes this implementation of the
EightBall service. Once you have the URL, you invoke the service with WSIF as you did before.
Conclusion
In this article, you created a Web service from a simple piece of code. You deployed the service,
wrote clients for it in a number of different programming languages, and looked at two approaches
to Web service discovery. Along the way, you looked at a variety of technologies, including SOAP,
WSDL, UDDI, WSIL, and WSIF. Best of all, everything this article discusses is standards-compliant
code, written in Java code, and built using open-source software. Good luck using this as a
springboard to your own Web services applications!
Resources
About the author  | |  |
Doug Tidwell is a Senior Programmer and a developer Works evangelist for new technologies. He spends most
of his time writing sample code, articles, and presentations, most of which he gives away. You can
find non-free samples of his work in the O'Reilly books XSLT (ISBN 0-596-00053-7) and Programming Web
Services with SOAP (co-written with James Snell and Pavel Kulchenko, ISBN 0-596-00095-2). When not
on an airplane or a stage, he lives in Raleigh with his wife, cooking teacher Sheri Castle, and their
daughter Lily.
|
Rate this page
|  |