Search the Catalog
Java Web Services

Java Web Services

By Tyler Jewell, David Chappell
March 2002
0-596-00269-6, Order Number: 2696
276 pages, $39.95 US $61.95 CA £28.50 UK

Chapter 6
UDDI: Universal Description, Discovery, and Integration

The Universal Description, Discovery, and Integration (UDDI) Project provides a standardized method for publishing and discovering information about web services. The UDDI Project is an industry initiative that attempts to create a platform-independent, open framework for describing services, discovering businesses, and integrating business services. UDDI focuses on the process of discovery in the service-oriented architecture.

The UDDI Project is an initiative that communicates with the public through www.uddi.org. The UDDI Community runs the UDDI Project. The Community consists of a group of Working Group members who develop the specifications and Advisory Group members who provide requirements and review the specifications. The Working Group is an invitation-based group and the Advisory Group is open to everyone.

Web services are becoming the basis for electronic commerce of all forms. Companies invoke the services of other companies to accomplish a business transaction. In an environment in which only a few companies participate, managing the discovery of business partners manually would be simple. After all, how difficult would it be to figure out if one of your few business partners has an access point that adheres to your requirements? This model breaks down, however, as the number of companies that you need to interact with grows, along with the number and types of interfaces they export. How do you discover all the business partners that you can do business with? If you attempted to account for them manually, you could never be sure that you discovered every partner. UDDI is a single conceptual registry distributed among many nodes that replicate the participating businesses' data with one another. The UDDI registry of services (hosted by different businesses on the Internet) attempts to solve this problem.

This chapter presents an overview of UDDI and how to put it to work. It includes a discussion about the information stored in a UDDI registry, the different potential uses of UDDI, and its technical architecture; the specifications that comprise the UDDI effort, with a focus on their relevance to developers and a list of different Java approaches for programming with UDDI; and an introduction to interacting with a UDDI registry programmatically. The following sections cover the UDDI data structures and XML APIs available for accessing a registry.

UDDI Overview

Prior to the UDDI project, no industry-wide approach was available for businesses to reach their customers and partners with information about their products and web services. Nor was there a uniform method that detailed how to integrate the systems and processes that are already in place at and between business partners. Nothing attempted to cover both the business and development aspects of publishing and locating information associated with a piece of software on a global scale.

Conceptually, a business can register three types of information into a UDDI registry. The specification does not call out these types specifically, but they provide a good summary of what UDDI can store for a business:

White pages
Basic contact information and identifiers about a company, including business name, address, contact information, and unique identifiers such as D-U-N-S numbers or tax IDs. This information allows others to discover your web service based upon your business identification.

Yellow pages
Information that describes a web service using different categorizations (taxonomies). This information allows others to discover your web service based upon its categorization (such as being in the manufacturing or car sales business).

Green pages
Technical information that describes the behaviors and supported functions of a web service hosted by your business. This information includes pointers to the grouping information of web services and where the web services are located.

How UDDI Is Used

UDDI has several different uses, based on the perspective of who is using it. From a business analyst's perspective, UDDI is similar to an Internet search engine for business processes. Typical search engines, such as AskJeeves, organize and index URLs for web sites. However, a business exporting a web service needs to expose much more than a simple URL. A business analyst can browse one or more UDDI registries to view the different businesses that expose web services and the specifications of those services. However, business users probably won't browse a UDDI registry directly, since the information stored within it is not necessarily reader friendly. A series of marketplaces and business search portals could crop up to provide business analysts with a more user-oriented approach to browsing the services and businesses hosted in a UDDI registry.

Software developers use the UDDI Programmer's API to publish services (i.e., put information about them in the registry) and query the registry to discover services matching various criteria. It is conceivable that software will eventually discover a service dynamically and use it without requiring human interaction.

TIP:   Even though the API provided by UDDI allows random searching for businesses, it's not feasible for a program to select new business partners dynamically. Realistically, it's more likely that business analysts with specific knowledge of the problem at hand will use UDDI portals to discover potentially interesting services and partners, and technologists will write programs to use the services from companies that have already been discovered. We'll probably see programs that update the data in a UDDI registry, but most publicly available registries already have a user-friendly interface that allows human users to update information in a registry.

Even though the registries have human-friendly interfaces for direct access, humans should never have to interface with a repository directly. The web service tool you use should automate interaction with a UDDI registry. For example, if you use a tool that creates a web service, that tool should be able to not only deploy the web service into production, but add it to the UDDI registry for you on your behalf.

Both business analysts and software developers can publish new business entities and services. Business analysts can use portals attached directly to a particular UDDI server or to a more general search portal that supports UDDI. Figure 6-1 depicts the relationship between business analysts and technologists.

Figure 6-1. Relationship between business analysts and technologists

 

Technical Architecture

Figure 6-2 depicts the makeup of the UDDI project. The UDDI Business Registry (UBR), also known as the Public Cloud, is a conceptually single system built from multiple nodes that has their data synchronized through replication. A series of operator nodes each hosts a copy of the content. The global grouping of operator nodes is jointly known as the UBR. Operator nodes replicate content among one another. Accessing any individual operator node provides the same information and quality of service as any other operator node. Content inserted into the UBR is done at a single node, and that operator node becomes the master owner of that content. Any subsequent updates or deletes of the data must occur at the operator node where the data was inserted.

Figure 6-2. The UDDI initiative

 

Note that the scope of the UDDI project is much more than the UBR; a company can provide a private operator node that is not part of the UBR. Private nodes do not have data synchronized with the UBR, so the information contained within is distinct. A grouping of companies can also create a "private cloud" of nodes that have information replicated between their private nodes, but that replication sequence will not have any interaction with the UBR nodes.

The UBR has widely accessible inquiry services, but services may be published only by authenticated entities. Any business can create an operator node and make it available over the Internet and part of the UBR. Private operator nodes can define the access rules for their nodes on a case-by-case basis. They can follow the same model as the UBR or make the restrictions looser or tighter.

Companies will likely set up private UDDI nodes. Even though use of these nodes will probably be limited in the near future, quite a few companies are showing interest in setting up private registries for internal or B2B operations. Industry groups are also discussing options for meeting the demands of their individual sector.

Many products have either been created or are being expanded to allow companies to create their own public and private UDDI registries. For example, BEA WebLogic Server and IBM WebSphere both intend to ship a fully compliant UDDI Server embedded within the application server sometime in 2002. Other companies, such as Systinet, HP, Oracle, SAP, Cape Clear, The Mind Electric, and Silverstream, have created J2EE-compliant UDDI implementations that work with existing application servers, including Tomcat, BEA, and IBM. Microsoft has an implementation based upon .NET. Additionally, two open source J2EE UDDI projects are in development: Bowstreet's jUDDI (http://www.juddi.org) and JP Moresmau's pudding (http://www.opensorcerer.org).

UDDI Specifications and Java-Based APIs

This section discusses the different specifications that make up the UDDI initiative and the options available to developers writing Java programs that interact with a UDDI registry.

UDDI Specifications

The UDDI project also defines a set of XML Schema definitions that describe the data formats used by the various specification APIs. These documents are all available for download at http://www.uddi.org. The UDDI project releases their specifications in unison. The current version of all specification groups is Version 2.0. The specifications include:

UDDI replication
This document describes the data replication processes and interfaces to which a registry operator must conform to achieve data replication between sites. This specification is not a programmer's API; it defines the replication mechanism used among UBR nodes.

UDDI operators
This document outlines the behavior and operational parameters required by UDDI node operators. This specification defines data management requirements to which operators must adhere. For example, node operators are responsible for durable recording and backup of all data, ensuring that each business registration has a valid email address associated with it, and the integrity of the data during deletions (e.g., deleting a business means that all of its service entries must also be deleted). This document is not a programmer's API and private registries are not required to support it.

UDDI Programmer's API
This specification defines a set of functions that all UDDI registries support for inquiring about services hosted in a registry and for publishing information about a business or a service to a registry. This specification defines a series of SOAP messages containing XML documents that a UDDI registry accepts, parses, and responds to. This specification, along with the UDDI XML API schema and the UDDI Data Structure specification, makes up a complete programming interface to a UDDI registry.

UDDI data structures
This specification covers the specifics of the XML structures contained within the SOAP messages defined by the UDDI Programmer's API. This specification defines five core data structures and their relationships to one another.

The UDDI XML API schema is not contained in a specification; rather, it is stored as an XML Schema document that defines the structure and datatypes of the UDDI data structures.

Java-Based APIs

The UDDI specifications do not directly define a Java-based API for accessing a UDDI registry. The Programmer's API specification only defines a series of SOAP messages that a UDDI registry can accept. Thus, a Java developer who wishes to access a UDDI registry can do so in a number of ways:

Using a Java-based SOAP API
A Java programmer can use an API that creates SOAP messages containing a UDDI XML document. The Java programmer would be have to create each XML document by hand and insert this document into the body of each SOAP message. This approach would require that a developer understand the ordering of the SOAP messages that a UDDI registry accepts and format each SOAP message properly.

Using a custom Java-based UDDI client API
Some companies, such as Systinet, have created client APIs for accessing a UDDI registry. These APIs have classes and constructs that represent the data structures and messages supported by UDDI. These APIs also allow you to interact with a UDDI registry without knowing the specifics of SOAP or the XML messages and data structures that UDDI interacts with. These custom libraries work with any UDDI registry, so you can use Systinet's library to access Microsoft's UBR node.

Using JAXR
The JAXR specification defines a standardized way for Java programs to access a registry. JAXR allows developers to write code that can access several different registries, including UDDI and the ebXML Registry/Repository. JAXR's programming constructs don't mimic those used by UDDI, but this API gives you a common way to access a variety of different registry types, whereas a custom Java-based UDDI client API can access only a UDDI registry. The trade-off for portability is dealing with the additional layer of abstraction required by JAXR. JAXR is currently in an early preview release

To get you up to speed with UDDI, this chapter presents a simple UDDI example implemented three times--one time for each technique. Apache SOAP is used to develop a client that uses a Java-based SOAP API, Systinet WASP UDDI Client Package demonstrates a custom Java-based UDDI client API, and a JAXR client shows how JAXR's abstract approach looks to the developer. However, as more details of UDDI are explained, the examples use the Apache SOAP implementation because it allows us to focus on the details of XML and UDDI.

Programming UDDI

Two APIs are described by the UDDI specification: the inquiry API and the Publishing API. They are accessed using the same techniques but use different XML documents, data structures, and access points. The inquiry API locates information about a business, the services a business offers, the specifications of those services, and information about what to do in a failure situation. Any read operation from a UDDI registry uses one of the inquiry API's messages. The inquiry API does not require authenticated access and is subsequently accessed using HTTP.

The Publishing API is used to create, store, or update information located in a UDDI registry. All functions in this API require authenticated access to a UDDI registry; the UDDI registry must have a logon identity, and the security credentials for this identity must be passed as a parameter of the XML document for each UDDI invocation. Because publishing requires authenticated access, it is accessed over HTTPS, with a different URL than the one used with the inquiry access point. Table 6-1 lists the inquiry and publishing access point URLs for some major operator nodes.

Table 6-1: Access point URLs for some operator nodes

Operator node

Inquiry URL

Publishing URL

HP

http://uddi.hp.com/inquire

https://uddi.hp.com/publish

IBM Production

http://www-3.ibm.com/services/uddi/inquiryapi

https://www-3.ibm.com/services/uddi/protect/publishapi

IBM Test

http://www-3.ibm.com/services/uddi/testregistry/inquiryapi

https://www-3.ibm.com/services/uddi/testregistry/protect/publishapi

Microsoft
Production

http://uddi.microsoft.com/inquire

https://uddi.microsoft.com/publish

Microsoft
Test

http://test.uddi.microsoft.com/inquire

https://test.uddi.microsoft.com/publish

SAP Test

http://udditest.sap.com/UDDI/api/inquiry/

https://udditest.sap.com/UDDI/api/publish/

Systinet

http://www.systinet.com/wasp/uddi/inquiry/

https://www.systinet.com/wasp/uddi/publishing/

Several primary information types construct the XML documents used as input and output to UDDI invocations. This section shows these data structures along with the major APIs as defined by the UDDI specifications.

UDDI APIs are designed to be simple. All operations that a UDDI registry performs are synchronous, meaning that the requesting client blocks and waits until it receives a response message. Additionally, all operations have a simple request/response mechanism that gives them a stateless behavior. Therefore, using the UDDI APIs doesn't require a lot of complex ordering.

UDDI Data Structures

To understand the structure of the messages that are part of the API, you need a basic appreciation for the different data structures and XML formats that are used. This section discusses the major data structures that are passed as input and output parameters for major API messages. Figure 6-3 shows the relationships between the primary UDDI data structures.

Figure 6-3. Relationship of primary UDDI data structures

 

A <businessEntity> structure represents a business's basic information. This information includes contact information, categorization, identifiers, descriptions, and relationships to other businesses. UDDI allows companies to establish relationships with one another. Many different types of relationships are possible. For example, a conglomerate can reference a subsidiary, or two companies can declare a partnership. In either case, each company must establish a unique <businessEntity> and separately establish its relationships to other companies that have their own <businessEntity> structures.

The <publisherAssertion> structure is used to establish public relationships between two <businessEntity> structures. A relationship between two <businessEntity> structures is visible only to the "public" when both companies have created the same assertion with two separate <publisherAssertion> documents independently. Thus, a company can claim a business relationship only if its partner asserts the same relationship. One company's assertion about a business relationship isn't visible to the public until its partner creates a similar, but separate, <publisherAssertion> document for its own <businessEntity> structure. Thus, if Company A asserts a relationship with Company B (fromKey=A, toKey=B), then the relationship will become public when Company B asserts a relationship with Company A (fromKey=B, toKey=A).

A <businessEntity> contains one or more <businessService> structures. A <businessService> represents a single, logical service classification. A <businessService> element is used to describe a set of services provided by the business. These services can be web services or manual services such as a nonelectronic service. A <businessService> document is reusable (i.e., a <businessService> element can be used by several <businessEntity> elements). For example, GE might create an HR web service and publish that service as part of an "HR web service" <businessService> structure. Additionally, GE might choose to list each of its subsidiaries as a separate <businessEntity>, since each subsidiary has its own IT infrastructure. Doing so would allow the <businessEntity> structure for the Plastics division to reference the same "HR web service" <businessService> as the Chemicals division.

A <businessService> contains one or more <bindingTemplate> structures. A <bindingTemplate> contains pointers to technical descriptions and the access point URL, but does not contain the details of the service's specifications. A <bindingTemplate> contains an optional text description of the web service, the URL of its access point, and a reference to one or more <tModel> structures. A <tModel> is an abstract description of a particular specification or behavior to which the web service adheres. A <tModel> is a type of digital "fingerprint" for determining the specifics of how to interact with a particular web service. The <tModel> structure does not provide the web service's specification directly. Instead, it contains pointers to the locations of the actual specifications. Companies can use the information pointed to by a <tModel> to determine whether a web service is compatible with their business requirements.

UUID

Instances of these data structures are identified and referenced by a universally unique identifier, known as a UUID. UUIDs are assigned when the data structure is first inserted into the UUID registry. They are hexadecimal strings whose structure and generation algorithm is defined by the ISO/IEC 11578:1996 standard. This standard virtually guarantees the generation of a unique identifier by concatenating the current time, hardware address, IP address, and random number in a specific fashion. The Inquiry API uses the UUID to request a particular structure on demand.

<publisherAssertion> documents do not have UUIDs, however.

Browsing Basic Information

A series of messages allow a program to retrieve basic information about a business, a web service, or metadata about a specification that a web service supports. These messages all have SOAP messages whose XML body element begins with find. Table 6-2 lists the messages that can be used to retrieve basic information for searching purposes. The "Message name" column lists the name of the XML root element used as the body of the SOAP envelope on the call's request portion. The "Response document" column shows the name of the XML root element that is the body of the SOAP envelope for the response.

Table 6-2: XML documents used in browsing inquiry messages

Message name

Response document

Brief description

<find_binding>

<bindingDetail>

Given a UUID to a <businessService> structure, this message retrieves zero or more <bindingTemplate> structures within a single <bindingDetail> structure matching the criteria specified in the input arguments.

<find_business>

<businessList>

Given a regular expression, business category, business identifier, or <tModel>, this message retrieves zero or more <businessInfo> structures contained within a single <businessList> structure that meet the criteria specified in the input arguments.

<find_relatedBusinesses>

<relatedBusinessesList>

Given the UUID of a <businessEntity>, this message returns a list of UUIDs contained within a <relatedBusinessList> structure for the other businesses that have a relationship with this business.

<find_service>

<serviceList>

Given the UUID of a <businessEntity> and either the name of the service, the <tModel> of an implemented specification, or the service category, this message returns a list of all matching <businessService> documents contained within a <serviceList> structure.

<find_tModel>

<tModelList>

Given the a name, a category, or identifier, this message returns all matching <tModel> structures contained within a <tModelList> structure.

UDDI Response Structure

Many response messages return an XML document that contains zero or more of the primary UDDI data structures, rather than the data structures themselves. For example, the <find_business> message returns zero or more <businessInfo> structures, but does so in a <businessList> structure. The <businessList> structure is merely another data structure designed to hold zero or more other elements, similar to a Java Collection object. Don't confuse collection structures such as <businessList> with the primary UDDI data structures; they exist only for grouping.

The UDDI Programmer's API and UDDI Schema documents identify dozens of different structures used to make up the request and response messages. The Programmer's API identifies the structure of the request and response messages, paying particular attention to the input parameters for every request message. The UDDI Schema represents the same data structures, but provides datatyping and constraint information that can't be conveyed in the Programmer's API. When doing any development with UDDI, you should keep a copy of these two documents.

Traversing UDDI data structures can be complicated. To demonstrate this complexity, let's delve into the inner workings of the <find_business> message. The <find_business> message returns a <businessList> structure. Here's the definition of <businessList> from the UDDI Schema:

<element name="businessList" type="uddi:businessList" /> 
<complexType name="businessList">
  <sequence>
    <element ref="uddi:businessInfos" /> 
  </sequence>
  <attribute name="generic" use="required" type="string" /> 
  <attribute name="operator" use="required" type="string" /> 
  <attribute name="truncated" use="optional" type="uddi:truncated" /> 
</complexType>

This definition says that a <businessList> contains a single <businessInfos> subelement (defined in the same schema, as indicated by the preceding uddi:) and three attributes named generic, operator, and truncated. Doesn't tell us much, does it? So, let's delve further. The schema for the <businessInfos> structure is:

<element name="businessInfos" type="uddi:businessInfos" /> 
<complexType name="businessInfos">
  <sequence>
    <element ref="uddi:businessInfo" minOccurs="0" maxOccurs="unbounded" /> 
  </sequence>
</complexType>

This definition tells us that a <businessInfos> structure contains zero or more <businessInfo> subelements, which are also defined in the same schema document. minOccurs="0" and maxOccurs="unbounded" tell us that the included <businessInfo> elements can be repeated zero or more times. We now need to seek out the schema definition of the <businessInfo> structure, which is:

<element name="businessInfo" type="uddi:businessInfo" /> 
<complexType name="businessInfo">
  <sequence>
    <element ref="uddi:name" maxOccurs="unbounded" /> 
    <element ref="uddi:description" minOccurs="0" maxOccurs="unbounded" /> 
    <element ref="uddi:serviceInfos" /> 
  </sequence>
  <attribute name="businessKey" use="required" type="uddi:businessKey" /> 
</complexType>

This structure contains three subelements and an attribute. The attribute, businessKey, is the UUID for this business. The first subelement, <name>, gives the name of the business. The second subelement, <description>, is zero or more text elements that describe what the business does. The third subelement, <serviceInfos>, is a grouping of <businessService> documents. To figure out what a <businessService> document is, we must search the schema for the <serviceInfos> element.

Searching for this schema is left as the proverbial "exercise for the reader." At this stage, you should have an idea of the complexity of UDDI data structures and their navigation. An entire book could be dedicated to exploring every facet of the UDDI Programmers API. The rest of this chapter focuses on how to interact with UDDI and presents Java clients that demystify some of the complexity in the UDDI API and its data structures.

Finding a Business

Now it's finally time to pull everything that we have talked about together into a program. The examples in this chapter use Systinet WASP UDDI Standard. We selected this software because it is robust and free for development purposes. It includes:

We use Systinet WASP UDDI Standard primarily for its local registry, which allows you to run a registry locally on your computer for testing and development. We won't focus on the client API. Since a UDDI server accepts standard SOAP messages, we can use any Java-based SOAP client API to create the appropriate messages and direct them to a valid UDDI registry.

Our first UDDI client retrieves basic business information for a fictitious company called Demi Credit. The Systinet WASP UDDI registry comes with a preconfigured entry for Demi Credit. This example uses the Apache SOAP client library to create an appropriate SOAP message that has a <find_business> document as its body. We won't create this document programmatically, which would be an exercise in the use of the DOM or JDOM APIs; instead, we'll take the body for our SOAP request message from the file Ch6_FindBusiness.xml:

<uddi:find_business generic="2.0" maxRows="10">
  <uddi:name>
    Demi Credit
  </uddi:name>
</uddi:find_business>

The <uddi:find_business> tag indicates that this element is named find_business and defined in the uddi namespace. The contents of the tag must adhere to the schema for find_business, which defines a couple of different attributes. The generic attribute indicates the UDDI API version that is used (Version 2.0, in this case). maxRows indicates how many matching <businessInfo> structures should be returned if the query matches more than one company.

Optional Attributes and Elements

All UDDI API messages have several optional attributes and elements. For example, the maxRows attribute of the <find_business> element is optional. If this attribute is not included, the response message will contain an unbounded list of every match that could be found (up to the point where the UDDI server truncates a response).

In fact, the <name> subelement of <find_business> is optional as well. You can search for companies in other ways (besides using their name). You can search by category (through the <categoryBag> element), identifier (through the <identifierBag> element), or a particular specification that one of their web services implements (through the <tModelBag> element). Categories and identifiers are discussed in more detail later in this chapter.

This <find_business> element has a single subelement, <name>, which is the meat of our request. The value of the <name> element is a simple regular expression used to search the names of different businesses. The percentage sign (%) can be used for wildcard matching. In this example, we know the name of the company we are searching for: Demi Credit.

Before looking at the code for the client, let's run it and observe its behavior. The client reads an XML file, wraps it in a SOAP envelope, and sends it to a URL destination, adding various UDDI and Systinet namespace declarations that are required to make the SOAP message comply to the UDDI specification. The destination is the URL of an endpoint configured to accept UDDI inquiry messages. Run the command:

java UDDISoapClient -df ./Ch6_FindBusiness.xml

You should see the following output:

_________________________________________________
Starting UDDISoapClient:
    host url      = http://localhost:8080/wasp/uddi/inquiry/
    data file     = Ch6_FindBusiness.xml
_________________________________________________
Sent SOAP Message with Apache HTTP SOAP Client.
Waiting for response....
 
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <businessList xmlns="urn:uddi-org:api_v2" generic="2.0" operator="SYSTINET">
      <businessInfos>
        <businessInfo businessKey="892ac280-c16b-11d5-85ad-801eef208714">
          <name xml:lang="en">
            Demi Credit
          </name>
          <description xml:lang="en">
            A smaller demo credit agency used for illustrating UDDI inquiry.
          </description>
          <serviceInfos>
            <serviceInfo serviceKey="860eca90-c16d-11d5-85ad-801eef208714" 
              businessKey="9a26b6e0-c15f-11d5-85a3-801eef208714">
              <name xml:lang="en">
                DCAmail
              </name>
            </serviceInfo>
          </serviceInfos>
        </businessInfo>
      </businessInfos>
    </businessList>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

This output is saved as Ch6_FindBusiness_OUTPUT.xml and is included with the examples provided for this chapter. Other examples that use this program have their response documents saved in the same format.

Let's pick apart the response to see what it contains. The UDDI Server returned a single <businessList> structure which, in turn, has a single <businessInfos> structure. The <businessInfos> element can have zero or more <businessInfo> elements, based upon the number of businesses that were matched as part of the query. In this case, the server found only one business matching the name Demi Credit in the UDDI registry.

The <businessInfo> element contains several other important pieces of information. First, the businessKey attribute contains the UUID of Demi Credit. The UUID value is needed to do a more detailed information search or an update using the Publisher's API. Second, the <businessInfo> structure has a <description> that contains a textual description of what the company does. Next, the <businessInfo> structure contains a <serviceInfos> structure that contains a collection of all web services registered by this business. Each web service is described by a single <serviceInfo> structure, which contains the web service's UUID as an attribute.

Now that we've seen what the client does and examined the documents it sends and receives, it is time to look at UDDISoapClient.java in its entirety:

import java.io.*;
import java.util.*;
 
public class UDDISoapClient
{
    // Default values used if no command line parameters are set
    private static final String DEFAULT_HOST_URL = 
                               "http://localhost:8080/wasp/uddi/inquiry/";
    private static final String DEFAULT_DATA_FILENAME   = "./Default.xml";
    
    // In the SOAP chapter, we used "urn:oreilly:jaws:samples", 
    // but Systinet UDDI requires this to be blank.
    private static final String URI                     = "";
    private String m_hostURL;
    private String m_dataFileName;
 
    public UDDISoapClient(String hostURL, String dataFileName) throws Exception
    {
        m_hostURL = hostURL;
        m_dataFileName    = dataFileName;
        
        System.out.println(  );
        System.out.println("______________________________________");
        System.out.println("Starting UDDISoapClient:");
        System.out.println("    host url        = " + m_hostURL);
        System.out.println("    data file       = " + m_dataFileName);
        System.out.println("______________________________________");
        System.out.println(  );
    }
    
    public void sendSOAPMessage(  ) {
        try {
 
            // Get soap body to include in the SOAP envelope from FILE
            FileReader fr = new FileReader (m_dataFileName);
            javax.xml.parsers.DocumentBuilder xdb = 
                org.apache.soap.util.xml.XMLParserUtils.getXMLDocBuilder(  );
            org.w3c.dom.Document doc = 
                xdb.parse (new org.xml.sax.InputSource (fr));
            if (doc == null) {
                throw new org.apache.soap.SOAPException 
                    (org.apache.soap.Constants.FAULT_CODE_CLIENT, "parsing error");
            }
            
            // Create a vector for collecting the body elements
            Vector bodyElements = new Vector(  );
            
            // Parse XML element as soap body element
            bodyElements.add(doc.getDocumentElement (  ));
            
            // Create the SOAP envelope
            org.apache.soap.Envelope envelope = new org.apache.soap.Envelope(  );
            envelope.declareNamespace("idoox", "http://idoox.com/uddiface");
            envelope.declareNamespace("ua", "http://idoox.com/uddiface/account");
            envelope.declareNamespace("config", 
              "http://idoox.com/uddiface/config");
            envelope.declareNamespace("attr", "http://idoox.com/uddiface/attr");
            envelope.declareNamespace("fxml", "http://idoox.com/uddiface/formxml");
            envelope.declareNamespace("inner", "http://idoox.com/uddiface/inner");
            envelope.declareNamespace("", "http://idoox.com/uddiface/inner");
            envelope.declareNamespace("uddi", "urn:uddi-org:api_v2");
            
            //
            // NO SOAP HEADER ELEMENT AS SYSTINET WASP DOES NOT REQUIRE IT
            //
            
            // Create the SOAP body element
            org.apache.soap.Body body = new org.apache.soap.Body(  );
            body.setBodyEntries(bodyElements);
            envelope.setBody(body);
            
            // Build and send the Message.
            org.apache.soap.messaging.Message msg = 
                new org.apache.soap.messaging.Message(  );
            msg.send (new java.net.URL(m_hostURL), URI, envelope);
            System.out.println("Sent SOAP Message with Apache HTTP SOAP Client.");
            
            
            // Receive response from the transport and dump it to the screen
            System.out.println("Waiting for response....");
            org.apache.soap.transport.SOAPTransport st = msg.getSOAPTransport (  );
            BufferedReader br = st.receive (  );
            
            if(line == null) {
                System.out.println("HTTP POST was unsuccessful. \n");
            } else {
                while (line != null) {
                    System.out.println (line);
                    line = br.readLine(  );
                }
            }
 
        /////
        // Version in examples has XML pretty printing logic here.
        ////
 
        } catch(Exception e) {
            e.printStackTrace(  );
        }
    }
    
    //
    // NOTE: the remainder of this deals with reading arguments
    //
    /** Main program entry point. */
    public static void main(String args[]) {
    
      // Not Relevant
 
    }
}

This code is similar to the code presented in the SOAP chapters, with a couple of exceptions. First, Systinet WASP UDDI uses different servlets to implement the inquiry and publisher ports. When Systinet WASP UDDI is first installed, the URL of the inquiry port is http://localhost:8080/wasp/uddi/inquiry. In the program, this URL is assigned to the constant DEFAULT_HOST_URL:

private static final String DEFAULT_HOST_URL = 
        "http://localhost:8080/wasp/uddi/inquiry/";

Second, UDDI SOAP messages don't require the use of a SOAP header. Thus, all of the code used to create a SOAP header and fill it with values, such as mustUnderstand, is not needed. Next, UDDI and Systinet WASP UDDI SOAP envelopes require the addition of several different namespaces that they have defined. These namespaces are required at the envelope level of the message, not the SOAP header or body. In the Apache SOAP API, the Envelope interface has a method called declareNamespace( ) that adds these additional namespaces:

// Create the SOAP envelope
org.apache.soap.Envelope envelope = new org.apache.soap.Envelope(  );
 
// Add the Systinet namespaces.  
envelope.declareNamespace("idoox", "http://idoox.com/uddiface");
envelope.declareNamespace("ua", "http://idoox.com/uddiface/account");
envelope.declareNamespace("config", "http://idoox.com/uddiface/config");
envelope.declareNamespace("attr", "http://idoox.com/uddiface/attr");
envelope.declareNamespace("fxml", "http://idoox.com/uddiface/formxml");
envelope.declareNamespace("inner", "http://idoox.com/uddiface/inner");
 
// Add the default namespace
envelope.declareNamespace("", "http://idoox.com/uddiface/inner");
 
// Include the standard UDDI namespace.
// This URN contains all of the UDDI XML data structures and messages.
envelope.declareNamespace("uddi", "urn:uddi-org:api_v2");

WARNING:   Systinet was formally named Idoox. In their documentation, namespaces, and other declarations, you'll often see references to Idoox. When you come across these references, treat them synonymously with Systinet.

Using Systinet's UDDI Java API

The simple SOAP client we've just examined is sufficient to demonstrate a variety of UDDI APIs and data structures. It has some obvious limitations, however:

To get a feeling for what these limitations mean, we'll implement the same example using Systinet's UDDI Java API. To run this program, compile the file SystinetFindBusiness.java and execute the following command:

java -Dwasp.restrictor.packages=- SystinetFindBusiness

Because of a limitation in the way the Systinet UDDI client library operates, you get a series of array typing error messages if you omit the -Dwasp.restrictor.packages=- environment variable definition. Don't forget to include the hyphen (-) after the equal sign!

Here's a listing of the Systenet-based client in its entirety:

import org.idoox.uddi.client.api.v2.request.inquiry.*;
import org.idoox.uddi.client.structure.v2.tmodel.*;
import org.idoox.uddi.client.api.v2.response.*;
import org.idoox.uddi.client.structure.v2.base.*;
import org.idoox.uddi.client.structure.v2.business.*;
import org.idoox.uddi.client.api.v2.*;
import org.idoox.uddi.client.*;
 
/**
 * This is simple example of Systinet's UDDI Java API for accessing 
 * a UDDI registry.
 * This program does a find_business call by name.
 */
 
public class SystinetFindBusiness {
 
    // Program Entry Point
    public static void main(String args[]) throws Exception
    {
        String company = "Demi Credit";
        findBusinessByName(company);
    }
 
    public static void findBusinessByName(String name) throws Exception
    {
        System.out.println("Searching for businesses named '" + 
                            name + "'...");
 
        // Create a FindBusiness instance.
        // This creates a SOAP message.
        FindBusiness findBusiness = new FindBusiness(  );
 
        // Set the name to use in the query.
        findBusiness.addName(new Name(name));
 
        // This will limit the number of returned matches.  
        // maxRows is an optional attribute.
        findBusiness.setMaxRows(new MaxRows("10"));
 
        // This will retrieve a stub to the UDDI inquiry port.
        UDDIApiInquiry inquiry = 
               UDDILookup.getInquiry("http://localhost:8080/wasp/uddi/inquiry/");
 
        // Send the message and retrieve the response.
        BusinessList businessList=inquiry.find_business(findBusiness);
 
        // Show the results
        if (businessList==null) {
            System.err.println("ERROR: Business list is null!");
        }
        else {
            // Business list is holder for results - business infos.
            BusinessInfos businessInfos = businessList.getBusinessInfos(  );
            System.out.println("\nFound: " + 
                               businessInfos.size(  ) + 
                               " businesses.\n");
 
            // Iterate through each company found in the query.
            BusinessInfo businessInfo = businessInfos.getFirst(  );
            BusinessKey result;
            if (businessInfo != null) {
                result=businessInfo.getBusinessKey(  );
                
                while (businessInfo!=null) {
                    System.out.println("BusinessEntity name = " + 
                               businessInfo.getNames().getFirst().getValue(  ));
                    System.out.println("BusinessEntity UUID = " + 
                               businessInfo.getBusinessKey(  ));
                    System.out.println("***");
                    businessInfo = businessInfos.getNext(  );
                }
            }
        }
    }
}  

The Systinet UDDI client library is spread throughout several different packages. Since the UDDI API and data structures changed from Version 1.0 to Version 2.0 of the specification, Systinet opted to create separate Java packages for each version. This can be problematic for developers, but it is workable. Here are the import statements needed for the current crop of packages:

import org.idoox.uddi.client.api.v2.request.inquiry.*;
import org.idoox.uddi.client.structure.v2.tmodel.*;
import org.idoox.uddi.client.api.v2.response.*;
import org.idoox.uddi.client.structure.v2.base.*;
import org.idoox.uddi.client.structure.v2.business.*;
import org.idoox.uddi.client.api.v2.*;
import org.idoox.uddi.client.*;

The main( ) method is responsible for declaring the search string for the company and calling findBusinessByName( ), where the bulk of the work is performed:

    // Program Entry Point
    public static void main(String args[]) throws Exception
    {
        String company = "Demi Credit";
        findBusinessByName(company);
    }

Within findBusinessByName( ), the program needs to create a <find_business> message and populate it with the search criteria we established. The Systinet UDDI library has a separate class abstraction representing each UDDI XML message. Therefore, to create a <find_business> structure, you merely need to create an instance of their FindBusiness class. The FindBusiness class has several methods that add elements and attributes to the underlying <find_business> structure. In this example, we'll use addName( ), which adds the company name to search for, and setMaxRows( ), which limits the number of matches returned:

        // Create a FindBusiness instance.
        // This creates a SOAP message.
        FindBusiness findBusiness = new FindBusiness(  );
 
        // Set the name to use in the query.
        findBusiness.addName(new Name(name));
 
        // This will limit the number of returned matches.  
        // maxRows is an optional attribute.
        findBusiness.setMaxRows(new MaxRows("10"));

Next, the program creates a connection to a UDDI server's inquiry port. The UDDILookup class has static methods that create a dynamic Java proxy object that communicates using SOAP. From the developer's point of view, it looks and feels like an RMI stub, except it doesn't communicate over RMI. The UDDILookup.getInquiry( ) method creates an inquiry connection. This program uses the same inquiry port as the UDDISoapClient program, http://localhost:8080/wasp/uddi/inquiry/. An UDDIApiInquiry object is returned and encapsulates an active stub that communicates with the UDDI server:

        // This will retrieve a stub to the UDDI inquiry port.
        UDDIApiInquiry inquiry = 
               UDDILookup.getInquiry("http://localhost:8080/wasp/uddi/inquiry/");

Finally, the program needs to send the <find_business> document as part of a SOAP message. The UDDIApiInquiry object has a number of methods that create the SOAP envelope and populate it with an XML structure. A separate method exists for each UDDI XML message in the Programmer's API. For our example, the program calls the find_business( ) method on the UDDIApiInquiry object, passing in the FindBusiness object containing the XML structure.

The Systinet API also has matching classes for the response XML structures. Thus, since a <find_business> request yields a <businessList> response structure, the Systinet API has a BusinessList class. We can traverse this class to get to each subelement and attribute that was returned:

        BusinessList businessList=inquiry.find_business(findBusiness);
 
        // Show the results
        if (businessList==null) {
            System.err.println("ERROR: Business list is null!");
        }
        else {
            // Business list is holder for results - business infos.
            BusinessInfos businessInfos = businessList.getBusinessInfos(  );
            System.out.println("\nFound: " + 
                               businessInfos.size(  ) + 
                               " businesses.\n");
 
            // Iterate through each company found in the query.
            BusinessInfo businessInfo = businessInfos.getFirst(  );
            BusinessKey result;
            if (businessInfo != null) {
                result=businessInfo.getBusinessKey(  );
        
                while (businessInfo!=null) {
                    System.out.println("BusinessEntity name = " + 
                               businessInfo.getNames().getFirst().getValue(  ));
                    System.out.println("BusinessEntity UUID = " + 
                               businessInfo.getBusinessKey(  ));
                    System.out.println("***");
                    businessInfo = businessInfos.getNext(  );
                }
            }
        }

Using JAXR

Now that we've looked at a simple SOAP client to build a request by hand, and a client that uses a UDDI API to build a request with slightly higher-level tools, let's proceed to the next level of abstraction: the Java API for XML Registries (JAXR). JAXR is a uniform approach to accessing a registry that advertises business information and services in XML. JAXR attempts to provide a single API that can access many different kinds of registries, including ISO 11179, OASIS, eCo Framework, ebXML, and UDDI (although the reference implementation can access only a UDDI registry).

The JAXR reference implementation is unique because it requires Tomcat for the client implementation! This requirement is somewhat odd, but fortunately, it is only a characteristic of the reference implementation. The provider implementations created by vendors will probably be simple libraries that don't require an external server such as Tomcat. You can get JAXR and Systinet WASP UDDI Standard to use the same Tomcat installation; details on how to accomplish this installation are in this chapter's README.txt file. When installing and configuring JAXR on your machine, make sure that the .jaxr.properties file included with this chapter's examples is placed in your home directory. On a Unix system, this directory is the ~/ directory; on NT or Windows 2000, the home directory is given by the value of the %USERPROFILE% environment variable. To run the program to search for Demi Credit using JAXR, use this command:

java JAXRFindBusiness "Demi Credit"

The following output should be seen on the console:

Query string is Demi Credit
JAXR Reference Implementation -- logging started
 
Org name: Demi Credit
Org description: A smaller demo credit agency used for illustrating UDDI inquiry
.
Org key id: 892ac280-c16b-11d5-85ad-801eef208714
Contact name: David Tarnov
---

Since you should now have a better understanding of how these UDDI queries work, this example provides a more thorough parsing of the response message. This program provides a formatted output, rather than simply dumping an XML document to the screen. The code for this client is in the file JAXRFindBusiness.java. Here is the source code in its entirety:

import javax.xml.registry.*; 
import javax.xml.registry.infomodel.*; 
import java.net.*;
import java.util.*;
 
/*
 * This is the FindBusiness UDDI example implemented using
 * the JAXR libraries and the reference implementation
 * JAXR provider for accessing a UDDI registry.
 */
public class JAXRFindBusiness {
 
    public JAXRFindBusiness(  ) {}
 
    public static void main(String[] args) {
 
        if (args.length != 1) {
            System.out.println("Usage: java " +
                "JAXRFindBusiness <query-string>");
            System.exit(1);
        }
 
        String queryString = new String(args[0]);
        System.out.println("Query string is " + queryString);
 
        doQuery(queryString);
    }
    
    public static void doQuery(String qString) {
        Connection conn = null;
 
        // Define connection configuration properties 
        // To query, you need only the query URL
        Properties props = new Properties(  );
        props.setProperty("javax.xml.registry.queryManagerURL", 
                          "http://localhost:8080/wasp/uddi/inquiry/");
        props.setProperty("javax.xml.registry.factoryClass", 
                          "com.sun.xml.registry.uddi.ConnectionFactoryImpl");
 
        try {
            // Create the connection, passing it the 
            // configuration properties
            ConnectionFactory factory = 
                ConnectionFactory.newInstance(  );
            factory.setProperties(props);
            conn = factory.createConnection(  );
 
            // Get registry service and query manager
            RegistryService rs = conn.getRegistryService(  );
            BusinessQueryManager bqm = rs.getBusinessQueryManager(  );
 
            // Define find qualifiers and name patterns
            Collection qualifiers = new ArrayList(  );
            qualifiers.add(FindQualifier.SORT_BY_NAME_DESC);
            Collection namePatterns = new ArrayList(  );
            namePatterns.add(qString);
 
            // Find using the name
            BulkResponse response = 
                bqm.findOrganizations(qualifiers, 
                    namePatterns, null, null, null, null);
            Collection orgs = response.getCollection(  );
 
            // Display information about the organizations found
            Iterator orgIter = orgs.iterator(  );
            while (orgIter.hasNext(  )) {
                Organization org = 
                    (Organization) orgIter.next(  );
                System.out.println("Org name: " + getName(org));
                System.out.println("Org description: " + 
                    getDescription(org));
                System.out.println("Org key id: " + getKey(org));
 
                // Display primary contact information
                User pc = org.getPrimaryContact(  );
                if (pc != null) {
                    PersonName pcName = pc.getPersonName(  );
                    System.out.println(" Contact name: " + 
                        pcName.getFullName(  ));
                    Collection phNums = 
                        pc.getTelephoneNumbers(pc.getType(  ));
                    Iterator phIter = phNums.iterator(  );
                    while (phIter.hasNext(  )) {
                        TelephoneNumber num = 
                            (TelephoneNumber) phIter.next(  );
                        System.out.println("  Phone number: " + 
                            num.getNumber(  ));
                    }
                    Collection eAddrs = pc.getEmailAddresses(  );
                    Iterator eaIter = eAddrs.iterator(  );
                    while (phIter.hasNext(  )) {
                        System.out.println("  Email Address: " + 
                            (EmailAddress) eaIter.next(  ));
                    }
                }
 
                // Display service and binding information
                Collection services = org.getServices(  );
                Iterator svcIter = services.iterator(  );
                while (svcIter.hasNext(  )) {
                    Service svc = (Service) svcIter.next(  );
                    System.out.println(" Service name: " + 
                        getName(svc));
                    System.out.println(" Service description: " +
                        getDescription(svc));
                    Collection serviceBindings = 
                        svc.getServiceBindings(  );
                    Iterator sbIter = serviceBindings.iterator(  );
                    while (sbIter.hasNext(  )) {
                        ServiceBinding sb = 
                            (ServiceBinding) sbIter.next(  );
                        System.out.println("  Binding " +
                            "Description: " + 
                            getDescription(sb));
                        System.out.println("  Access URI: " + 
                            sb.getAccessURI(  ));
                    }
                }
                // Print spacer between organizations
                System.out.println(" --- "); 
            }
        } catch (Exception e) {
            e.printStackTrace(  );
        } finally  {
            // At end, close connection to registry
            if (conn != null) {
                try {
                    conn.close(  );
                } catch (JAXRException je) {}
            }
        }
    }
 
    private static String getName(RegistryObject ro) throws JAXRException {
        try {
            return ro.getName().getValue(  );
        } catch (NullPointerException npe) {
            return "";
        }
    }
    
    private static String getDescription(RegistryObject ro) throws JAXRException {
        try {
            return ro.getDescription().getValue(  );
        } catch (NullPointerException npe) {
            return "";
        }
    }
    
    private static String getKey(RegistryObject ro) throws JAXRException {
        try {
            return ro.getKey().getId(  );
        } catch (NullPointerException npe) {
            return "";
        }
    }
}

JAXR uses javax.xml.registry for the base package name for all of its classes. The main( ) method for this program parses a single parameter, which is the query string to use as the business name in the request:

import javax.xml.registry.*; 
import javax.xml.registry.infomodel.*; 
import java.net.*;
import java.util.*;
 
/*
 * This is the FindBusiness UDDI example implemented using
 * the JAXR libraries and the reference implementation
 * JAXR provider for accessing a UDDI registry.
 */
public class JAXRFindBusiness {
 
    public JAXRFindBusiness(  ) {}
 
    public static void main(String[] args) {
 
// Parameter parsing, not entirely relevant
 
        doQuery(queryString);
    }

Most work for this program takes place in the doQuery( ) method. A client program first needs to create a connection to the service provider. In our case, the service provider is our local UDDI registry running at http://localhost:8080/wasp/uddi/inquiry/. To create the connection, we create a Properties object and fill it with relevant information: the javax.xml.registry.queryManagerURL value should be the URL of the UDDI registry that you are accessing, while the javax.xml.registry.factoryClass is the class that implements a ConnectionFactory object. Different JAXR providers provide different values for this property; the JAXR reference implementation uses com.sun.xml.registry.uddi.ConnectionFactoryImpl. Finally, the client code creates an instance of the ConnectionFactory class, associates the properties with this class, and then creates a Connection object using the createConnection( ) method:

    public static void doQuery(String qString) {
        Connection conn = null;
 
        // Define connection configuration properties 
        // To query, you need only the query URL
       Properties props = new Properties(  );
        props.setProperty("javax.xml.registry.queryManagerURL", 
                          "http://localhost:8080/wasp/uddi/inquiry/");
        props.setProperty("javax.xml.registry.factoryClass", 
                          "com.sun.xml.registry.uddi.ConnectionFactoryImpl");
 
        try {
            // Create the connection, passing it the 
            // configuration properties
            ConnectionFactory factory = 
                ConnectionFactory.newInstance(  );
            factory.setProperties(props);
            conn = factory.createConnection(  );

Once we have a connection to a service provider, we need to connect to a RegistryService object. Since different registries support different types of services, a RegistryService object tells your program exactly which services the registry supports. For example, some registries allow declarative SQL queries (UDDI does not). The RegistryService interface has methods for telling a program the registry's capabilities and returning manager objects that support a particular type of capability. For business requests, such as the requests that UDDI supports, the BusinessQueryManager interface must be used. To retrieve a reference to a BusinessQueryManager object, call the getBusinessQueryManager( ) method on a RegistryService object:

            // Get registry service and query manager
            RegistryService rs = conn.getRegistryService(  );
            BusinessQueryManager bqm = rs.getBusinessQueryManager(  );

The BusinessQueryManager interface has a series of findXXX( ) methods that perform different types of queries. Different methods query for different items; for example, the findOrganizations( ) method queries a registry for business information, while the findServices( ) method asks for different services that may or may not be available. Most methods take one or more Collection objects as input; these objects refine the query using qualifiers. The first parameter of the findOrganizations( ) method takes a Collection of find qualifiers that refines how the query should be performed. Find qualifiers can apply a sort or restrict the number of entries that are returned; in this case, we ask that the responses be sorted by name. The second parameter of the findOrganizations( ) takes a Collection of name patterns to apply to the search. To populate this Collection, we add the business name that we read from the command line. The other parameters (all set to null in this example) take qualifiers that search for businesses based upon classifications, specifications supported, external identifiers, and external URLs, respectively. The query returns a BulkResponse object that can be checked for exceptions from the server or converted to a Collection:

            // Define find qualifiers and name patterns
            Collection qualifiers = new ArrayList(  );
            qualifiers.add(FindQualifier.SORT_BY_NAME_DESC);
            Collection namePatterns = new ArrayList(  );
            namePatterns.add(qString);
 
            // Find using the name
            BulkResponse response = 
                bqm.findOrganizations(qualifiers, 
                    namePatterns, null, null, null, null);
            Collection orgs = response.getCollection(  );

The rest of the program is responsible for iterating through the output and formatting it for display on the screen. It's a bit wordy, so it's not included again here. A client application would use the information retrieved from the query to perform other queries or to leverage a particular service.

As you undoubtedly noticed, the JAXR API is more complicated than the Systinet API. JAXR does not have class representations for each UDDI XML structure; instead, we have to work with query managers and lists of various qualifiers. Working with the Systinet API is convenient because every class has an XML counterpart with the same name. You pay a price for abstraction, though: the Systenet client is tied to UDDI, while the JAXR client could conceivably make a similar request from a different kind of registry with little or no modification.

Getting More Detail

find_ messages are designed to return basic information about the structures that a UDDI registry manages. Given the UUID to one of the major data structures, you can drill down into the registry to get a full listing of the details stored in that structure. The UDDI inquiry API provides a series of messages that begin with get_ for retrieving information from the registry. Table 6-3 lists these messages.

Table 6-3: XML documents used to get detailed information

Message name

Response document

Brief description

<get_bindingDetail>

<bindingDetail>

Given one or more UUIDs of different <bindingTemplate> documents, this message returns a <bindingDetail> structure containing the complete <bindingTemplate> document for each matching UUID. The specification recommends that a client application caches <bindingTemplate> documents locally so repeated calls to a web service do not require a query on the UDDI server each time. If a call based on cached <bindingDetail> information fails, a new <bindingDetail> structure can be retrieved using this message.

<get_businessDetail>

<businessDetail>

Given one or more UUIDs of different <businessEntity> documents, this message retrieves a <businessDetail> structure that contains <businessEntity> documents for each matching UUID.

<get_serviceDetail>

<serviceDetail>

Given one or more UUIDs of different <businessService> documents, this message returns a <serviceDetail> structure that contains the complete <businessService> document for each matching UUID.

<get_tModelDetail>

<tModelDetail>

Given one or more UUIDs of different <tModel> documents, this message returns a <tModelDetail> structure containing the complete <tModel> document for each matching UUID.

All of these messages are fairly straightforward. As long as you can get a valid UUID for the data structure you are interested in, you can get its details. In the <find_business> example for Demi Credit, the response document indicated that Demi Credit had published a web service named DCAmail with the UUID 860eca90-c16d-11d5-85ad-801eef208714. Let's send a <get_serviceDetail> message to get all of the information about this web service. To get this information, we'll use the UDDISoapClient program from our previous examples to send a handwritten XML document. This document contains a <get_serviceDetail> message using the UUID for the DCAmail web service. Here's a listing of Ch6_GetServiceDetail.xml:

<uddi:get_serviceDetail generic="2.0">
  <uddi:serviceKey>860eca90-c16d-11d5-85ad-801eef208714</uddi:serviceKey>
</uddi:get_serviceDetail>

The <get_serviceDetail> message doesn't have any optional attributes; it has only one subelement, <serviceKey>, which is the UUID of the web service for which you want more detail. The <get_serviceDetail> message can accept one or more <serviceKey> subelements on which to query. Here is the response document returned by the UDDI server:

<serviceDetail generic="2.0" operator="SYSTINET" xmlns="urn:uddi-org:api_v2">
  <businessService businessKey="9a26b6e0-c15f-11d5-85a3-801eef208714" 
                   serviceKey="860eca90-c16d-11d5-85ad-801eef208714">
    <name xml:lang="en">DCAmail</name>
    <description xml:lang="en">Get credit assessment by email</description>
    <bindingTemplates>
      <bindingTemplate bindingKey="f9274a50-c16f-11d5-85ad-801eef208714" 
                       serviceKey="860eca90-c16d-11d5-85ad-801eef208714">
        <description xml:lang="en">The address to which you should send the name 
            and address of your credit report target</description>
        <accessPoint URLType="mailto">mailto:DCAmail@democredit.bar</accessPoint>
        <tModelInstanceDetails>
          <tModelInstanceInfo 
              tModelKey="uuid:93335d49-3efb-48a0-acea-ea102b60ddc6">
            <description xml:lang="en">The smtp protocol is used when sending 
                information</description>
            <instanceDetails>
              <overviewDoc>
                <description xml:lang="en">Describes how to use this 
                    service</description>
                <overviewURL>http://www.creditdemo.bar/DCAmail/howto</overviewURL>
              </overviewDoc>
            </instanceDetails>
          </tModelInstanceInfo>
          <tModelInstanceInfo 
              tModelKey="uuid:25ddf051-c164-11d5-85a6-801eef208714">
            <description xml:lang="en">The namespace in which our credit numbers 
                are used.</description>
          </tModelInstanceInfo>
        </tModelInstanceDetails>
      </bindingTemplate>
    </bindingTemplates>
    <categoryBag>
      <keyedReference keyName="Personal credit agencies" 
                      keyValue="841416" 
                      tModelKey="uuid:db77450d-9fa8-45d4-a7bc-04411d14e384"/>
      <keyedReference keyName="Credit agencies" 
                      keyValue="8414" 
                      tModelKey="uuid:db77450d-9fa8-45d4-a7bc-04411d14e384"/>
      <keyedReference keyName="Netherlands" 
                      keyValue="NL" 
                      tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>
      <keyedReference keyName="France" 
                      keyValue="FR" 
                      tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>
      <keyedReference keyName="Belgium" 
                      keyValue="BE" 
                      tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>
      <keyedReference keyName="Business credit agencies" 
                      keyValue="841417" 
                      tModelKey="uuid:db77450d-9fa8-45d4-a7bc-04411d14e384"/>
      <keyedReference keyName="Luxembourg" 
                      keyValue="LU" 
                      tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>
      <keyedReference keyName="Germany, Federal Republic of" 
                      keyValue="DE" 
                      tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>
    </categoryBag>
  </businessService>
</serviceDetail>

This document contains a <businessService> structure, which is a logical grouping of web services by a business. In the case of Demi Credit, this grouping lists a number of web services that allow you to do a credit check via email. The returned <businessService> has a single <bindingTemplate> that provides technical details of how to access the web service. The <accessPoint> is the web service endpoint URL. In this case, it is a simple email address: mailto:DCAmail@democredit.bar.

More importantly, the <bindingTemplate> has two <tModelInstanceInfo> documents that show where to find more information about how this web service runs and the specifications it supports. Each <tModelInstanceInfo> document contains a tModelKey attribute, which is the UUID of a <tModel> structure that contains a particular specification's metadata. The <tModelInstanceInfo> document also contains an <instanceDetails> subelement that contains a description of how to use the web service.

Categorization

Our <businessService> document also contains a <categoryBag> structure. <categoryBag> documents can appear with <businessEntity>, <businessService>, and <tModel> documents.

Categorization of data was an important requirement during the development of UDDI. Categorization allows data in a UDDI registry to be associated with an industry, product, or geographic code set. Some obvious problems come with the use of categories; they should be familiar to anyone who's ever searched for something on the Web. Broad categories, such as manufacturing, can return thousands of matching services and businesses--certainly too many to sift through manually. On the other hand, specific categories, such as "manufacturing in Buffalo," might be too specific to return any results.

It's probably not realistic to expect software to dynamically discover and use new businesses on the fly in the near future. Realistically, human analysts need to browse a UDDI portal that allows customized searches and queries to discover the businesses they are interested in working with. It's more likely that software will contain the logic necessary to locate and integrate with web services for companies that have been predetermined. It's also likely that businesses will set up private UDDI registries that they can share with their approved partners to facilitate B2B integration.

Many categorization systems can be used on data within UDDI. These systems are summarized in Table 6-4. Each taxonomy categorization is registered as a <tModel> structure within UDDI. This registration means that each categorization has a tModel name and UUID that can be used to reference it. The tModel name is the same in all UDDI registries, but the UUID for the tModel may change between operator nodes.

Table 6-4: Supported categorization taxonomies

Taxonomy name

tModel name

Description

NAICS

ntis-gov:naics:1997

The North American Industry Classification system. Hundreds of classifications are in this system, including "Pet supply stores," "Hazardous waste collection," and "Diet and weight reducing centers." More information can be found at http://www.census.gov/epcd/www/naics.html.

UNSPSC

unspsc-org:unspsc:3-1

The Universal Standard Products and Services Classification. It is the first system to classify products and services for worldwide use. More information can be found at http://www.unspsc.org.

ISO 3166

iso-ch:3166:1999

International standard geographical regions. This taxonomy includes codes for countries and their administrative support staffs. More information can be found at http://www.din.de/gremien/nas/nabd/iso3166ma.

Other

uddi-org:general_keywords

General-purpose associations that a business might want to make. This taxonomy allows operator nodes to promote invalid entries or entries that would otherwise be rejected by another classification system. There is no specification on how this works; it is operator-node specific.

A <categoryBag> structure contains zero or more <keyedReference> structures. Each <keyedReference> structure contains the name and value of a category to which the data element belongs. In the previous <businessService> example, the <categoryBag> had eight <keyedReference> subelements. Three <keyedReference> subelements were for NAICS categorizations; the other five were for ISO 3166 country categorizations.

Determining which categorization a <keyedReference> belongs to can be difficult, but more details can be discovered by looking up the <tModel> document, using the tModelKey attribute that is also part of a <keyedReference>. If you look at the <categoryBag>, you will notice that three of the <keyedReference> elements have the same tModelKey value and the other five attributes have a different tModelKey value. For example, here is one of the ISO 3166 country categorization <keyedReference> elements returned as part of the <categoryBag>:

<keyedReference keyName="Netherlands" 
                keyValue="NL" 
                tModelKey="uuid:4e49a8d6-d5a2-4fc2-93a0-0411d8d19e88"/>

The keyName value identifies the categorization. It is also a textual name given to the categorization. The keyValue is the categorization code, as identified by the specification. The categorization code is guaranteed to be unique. The tModelKey value is the UUID of a <tModel> document that provides metadata of the specification that this categorization supports.

Identifiers

An identifier is a type of property or keyword used to uniquely identify a business or specification. Identifiers can be applied to <businessEntity> and <tModel> structures. Identifiers, like categorizations, can be used as part of a search when doing a <find_business> or <find_tModel> request message.

Identifiers and categorizations are implemented similarly. Identifiers are attached to <businessEntity> and <tModel> documents through an <identifierBag> structure. The <identifierBag> structure can have one or more <keyedReference> structures that provide the name, value, and <tModel> UUID reference for locating more information.

At this time, only two general-purpose identifier schemes have been incorporated into all operator nodes, but other schemes can be used as well. Table 6-5 lists the identifier types that are a core part of an operator node.

Table 6-5: Supported identifier types

Identifier name

tModel name

Description

D-U-N-S

dnb-com:D-U-N-S

The Dun & Bradstreet D-U-N-S number is a unique nine-digit identification sequence. This sequence provides unique identifiers for single business entities, while linking corporate family structures. More information can be found at http://www.d-u-n-s.com.

ThomasNet

thomasnet-com:supplierID

This scheme provides identifiers for over 150,000 manufacturing and
e-commerce companies worldwide. More information can be found at http://www.thomasnet.com.

tModel

<tModel> documents provide metadata information about a web service specification, categorization specification, or identifier specification. <tModel> documents are a core data structure in the UDDI specification and represent the most detailed information that a UDDI registry can provide about any specification.

Looking at Demi Credit, we can see that the DCAmail <businessService> has a <bindingTemplate> with two <tModelInstanceInfo> documents. Each <tModelInstanceInfo> document contains a tModelKey attribute that is the UUID of a <tModel> document representing information about the supporting specification. There are also tModelKey attributes for each <keyedReference> structure that was part of the <categoryBag>. We can use the UDDISoapClient to retrieve the <tModel> document for any of these UUIDs. Let's get the <tModel> document for uuid:93335d49-3efb-48a0-acea-ea102b60ddc6, which is a specification implemented by the DCAmail web service. Here is the listing of Ch6_GetTModelDetail.xml, which is used as the body of the SOAP request:

<uddi:get_tModelDetail generic="2.0">
  <uddi:tModelKey>uuid:93335d49-3efb-48a0-acea-ea102b60ddc6</uddi:tModelKey>
</uddi:get_tModelDetail>

The resulting response is saved as Ch6_GetTModelDetail_OUTPUT.xml:

<tModelDetail generic="2.0" operator="SYSTINET" xmlns="urn:uddi-org:api_v2">
  <tModel authorizedName="admin" 
          operator="SYSTINET" 
          tModelKey="uuid:93335d49-3efb-48a0-acea-ea102b60ddc6">
    <name>uddi-org:smtp</name>
    <description xml:lang="en">E-mail based web service</description>
    <categoryBag>
      <keyedReference keyName="A transport tModel is a specific type of protocol" 
                      keyValue="transport" 
                      tModelKey="uuid:c1acf26d-9672-4404-9d70-39b756e62ab4"/>
    </categoryBag>
  </tModel>
</tModelDetail>

The authorizedName attribute is the recorded name of the individual who published this <tModel>. The operator attribute is the certified name of the UDDI registry site that owns the master copy of the <tModel> data. The tModelKey is the UUID of this <tModel>; it matches the tModelKey for the request document. The <name> subelement is the recorded name of the <tModel>; it can be used as part of a search when doing a <find_tModel> request. The <description> subelement provides a specification's textual description. A <tModel> can have an optional <categoryBag> or <identifierBag> structure as well. Finally, a <tModel> can contain an optional <overviewDoc> subelement, which contains a URL that points to remote descriptive information.

Publishing to a UDDI Registry

Publishing to a UDDI registry involves any operation that would create, update, or destroy data in a UDDI registry. Here are some key technical differences between publishing and inquiring:

Authenticated access
All publishing messages require authenticated access. The process for authentication is not defined by the UDDI specification and is specific to the operator node. Given authenticated credentials, however, your program can access any publishing message.

Different access point
Publishing message requests use a different access point than do inquiry messages. The HTTP protocol was suitable for inquiry messages, but HTTPS is required for all publishing messages.

Space limits
Operator nodes can impose space and registration restrictions on an individual or company. For example, a site may limit some users to one <businessEntity> structure and prevent them from inserting additional data without special permissions.

Operator node binding
When information is inserted into an operator node, that site becomes the owner of that data's master copy. Any subsequent updates or changes to the data must be performed at the same operator node. UDDI does not have a mechanism for resolving conflicts if duplicate entries are made at another operator node.

The Publisher API messages that require authentication are listed in Table 6-6.

Table 6-6: UDDI Publisher API messages

Message name

Response document

Brief description

<add_publisherAssertions>

<dispositionReport>

Given a valid authentication token and a <publisherAssertion> document, this message adds a <publisherAssertion> to an individual publisher's collection of assertions. A publisher assertion creates an association between two businesses. When the publishers of both businesses have added matching <publisherAssertion> documents to their collection, the relationship becomes publically visible.

<delete_binding>

<dispositionReport>

Given a valid authentication token and the UUID of one or more <bindingTemplate> documents, this message deletes the matching <bindingTemplate> documents from the UDDI registry.

<delete_business>

<dispositionReport>

Given a valid authentication token and the UUID of one or more <businessEntity> documents, this message deletes the matching <binding-Template> documents from the UDDI registry. Deleting these documents causes the deletion of any contained <businessService> or <bindingTemplate> data. Additionally, any <publisherAssertions> created with the UUID of this <businessEntity> will be deleted.

<delete_publisherAssertions>

<dispositionReport>

Given a valid authentication token and the UUID of one or more <publisherAssertion> documents, this message deletes the matching <publisherAssertion> documents from this publisher's collection. If other companies have created similar <publisherAssertion>
documents, their documents remain part of their collection.

<delete_service>

<dispositionReport>

Given a valid authentication token and the UUID of one or more <businessService> documents, this message deletes the matching <businessService> documents from the UDDI registry.

<delete_tModel>

<dispositionReport>

Given a valid authentication token and the UUID of one or more <tModel> documents, this message logically deletes the matching <tModel> documents from the UDDI registry by marking them as hidden. The documents are not actually destroyed. Hidden <tModel> documents are not returned as part of a result of a <find_tModel> message, but are still accessible through <get_tModelDetail> and <get_registeredInfo> messages. <tModel> messages are not permanently destroyed, which allows any organization still using the <tModel> to get basic details about it.

<discard_authToken>

<dispositionReport>

Given a valid authentication token, this message tells an operator node to discard the active authentication session, effectively logging out the client. To perform additional Publishing API operations, a new authentication token must be retrieved from the operator node by using the <get_authToken> message.

<get_assertionStatusReport>

<assertionStatusReport>

Given a valid authentication token, this message returns a report that details all <publisher-Assertion> documents that have been created on any <businessEntity> documents managed by this publisher. This report returns <publisherAssertion> documents that were created by this publisher and other publishers. This query can search for complete or incomplete associations.

<get_authToken>

<authToken>

Given a username and password, this message retrieves an authentication token from an operator node to be used on other Publisher API messages.

<get_publisherAssertions>

<publisherAssertions>

Given a valid authentication token, this
message returns a complete list of <publisherAssertion> documents that have been associated with the authenticated publisher account.

<get_registeredInfo>

<registeredInfo>

Given a valid authentication token, this message returns a complete list of <businessEntity> and <tModel> documents that are managed by the individual associated with the authentication
credentials.

<save_binding>

<bindingDetail>

Given an authenticated token and one or more <bindingTemplate> documents, this
message inserts or updates a UDDI registry with the <bindingTemplate> documents passed as input. This message can also update any associations made between a <businessService> document and a <bindingTemplate>
document. This message returns a <bindingDetail> message that contains the final results of the call that reflect the information in the UDDI registry.

<save_business>

<businessDetail>

Given an authenticated token and one or more <businessEntity> documents, this message inserts or updates a UDDI registry with the <businessEntity> documents passed as input. This message can make sweeping changes to a UDDI registry; the changes may involve inserts, updates, and deletes of subdocuments contained within a <businessEntity>. Changes to an existing <businessEntity> can impact existing references to <publisherAssertion> documents, <businessService> documents, and <bindingTemplate> documents. This message returns a <businessDetail> message that contains the final results of the call that reflect the UDDI registry information.

<save_service>

<serviceDetail>

Given an authenticated token and one or more <businessService> documents, this message inserts or updates a UDDI registry with the <businessService> documents passed as input. This message can modify <businessService> data and any references to <bindingTemplate> structures. This message returns a <serviceDetail> message that contains the final results of the call that reflect the UDDI registry information.

<save_tModel>

<tModelDetail>

Given an authenticated token and one or more <tModel> documents, this message inserts or updates a UDDI registry. If a passed-in <tModel> documet refers to a <tModel> that was previously deleted (hidden), it will be made visible again. This message returns a <tModelDetail> message that contains the final results of the call that reflect the UDDI registry information.

<set_publisherAssertions>

<publisherAssertions>

Given an authenticated token and one or more <publisherAssertion> documents, this message updates a UDDI registry to contain
a complete collection of <publisherAssertion> documents while deleting documents that are not present as part of the input. This message returns a<publisherAssertions> document that contains the current collection of <publisherAssertions> as they are stored in the UDDI registry.

Security and Authentication

Authentication with an operator node is typically straightforward. Most operator nodes implement a name/password scheme that allows you to retrieve an authentication token. Operator nodes that support the name/password scheme for authentication expose their authentication interface through the <get_authToken> message. Operator nodes do not have to support this scheme for authentication and can provide alternative techniques for allowing a client to get an authentication token. Those techniques are not documented by the UDDI specifications and are specific to the operator node. An operator node also has specific ways of registering new publishers and verifying their information. The only requirement that an operator node has to adhere to is that the authentication token returned must be a text value that can be inserted in subsequent XML messages.

The Systinet WASP UDDI Standard has a preconfigured username (admin) and password (changeit). We can obtain an authentication token by running the UDDISoapClient program with the Ch6_GetAuthToken.xml file as input and two command-line modifications:

java -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol  
     UDDISoapClient 
     -url https://localhost:8443/wasp/uddi/publishing/ 
     -df Ch6_GetAuthToken.xml

First, the JDK java.net.URL class does not support HTTPS as a standard protocol. The Message.send( ) method in the Apache SOAP library requires a URL object as input, so enabling HTTPS is key. Enabling HTTP is done by including the -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol option on the command line. Using this option assumes that you have installed the jsse.jar library. This library is installed as part of Systinet WASP UDDI; if you use a different UDDI package, you may have to install JSSE yourself. Second, since we are using the Publishing API, we must access a different URL than the default that is configured for inquiries. The publishing URL for Systinet WASP UDDI is https://localhost:8443/wasp/uddi/publishing/.

TIP:  Using the JSSE library directly is not for the weak of heart. In addition to setting up JSSE and enabling HTTPS as a valid protocol, SSL requires that your program have a valid client certificate to be used against the server. Fortunately, Systinet WASP UDDI Standard installs a client certificate for your use, but otherwise, you would have to create a new certificate using Java's keytool utility.

The real value of using a custom Java API such as Systinet's is apparent when you look at the difficulty of using the UDDISoapClient to generate HTTPS messages. Two complete round-trip SOAP invocations have to be made and you have to go through the rigmarole of configuring SSL appropriately on the client. Systinet's library handles this situation cleanly by providing one method that retrieves your authentication credentials and other methods that use the rest of the Publishing API.

Here is the Ch6_GetAuthToken.xml document that we send to the server to request an authentication token:

<uddi:get_authToken generic="2.0" userID="admin" cred="changeit" />

The <get_authToken> element doesn't have any subelements and passes the name and password as the userID and cred attributes, respectively. Here's the body of the SOAP response:

    <authToken xmlns="urn:uddi-org:api_v2" generic="2.0" operator="SYSTINET">
      <authInfo>
MIHLMDYbBWFkbWluMB4XDTAxMTIzMDAwNDYzNVoXDTAxMTIzMDAxNDYzNVoEDUFkb
WluaXN0cmF0b3IwDQYJKoZIhvcNAQEEBQADgYEA4Cci/CbDji6RiQFneRt7gVXwX/
4TA7qCZNUmTnXFJdVNFIDvp4WV+IW+/
deDCQk0GVAdsub0vkXJX3dqdDGqDsDleXwm7cDN2ENW7K/IeN9ii7/
pfbVryPtKzzbe07ETcWAoRnkcgDteC7I77VpyiqKHUqwmi5+kN10XMRXfkTw=
      </authInfo>
    </authToken>

The response document contains an <authToken> element that has an <authInfo> subelement. The value of the <authInfo> subelement is a key that will be used as the authentication token on all other publishing messages. To write a program that makes a series of updates on a UDDI registry, you must parse the <get_authToken> response message and store the authentication token as a String object. Your program would then have to create a second SOAP message to perform an insert, an update, or a delete operation.

Errors and <dispositionReport> Documents

Errors can occur on any request message, whether they are part of the inquiry API or the Publishing API. UDDI errors are always returned as SOAP Fault messages. (For more information on SOAP Fault messages and their structure, refer to Chapter 4.) The subelement of a SOAP Fault <detail> message is a UDDI <dispositionReport> document; this document is defined in the UDDI schema. Despite being used for all error code situations, <dispositionReport> documents are also used in some non-error situations as a status indicator. Non-error <dispositionReport> documents are returned as part of a standard SOAP response for any UDDI delete_ message.

UDDI SOAP Faults can be returned for dozens of reasons: expiration of an authentication token, a server that is busy and unable to handle requests, the use of invalid categorization and identifiers, unsupported APIs, etc. A full listing of error codes is contained in Appendix A of the UDDI Programmer's API specification. Here is an error that I received one time when I tried to exceed my limit for <businessEntity> documents while using Systinet's WASP UDDI Standard:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <ns0:Fault xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
      <faultcode>
         ns0:Client
      </faultcode>
      <faultstring>
        ClientError
      </faultstring>
      <detail>
        <dispositionReport generic="2.0" 
                           operator="SYSTINET" 
                           xmlns="urn:uddi-org:api_v2">
          <result errno="10160">
            <errInfo errCode="E_accountLimitExceeded">
              An attempt to save more data than allowed.
            </errInfo>
          </result>
        </dispositionReport>
      </detail>
    </ns0:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

A <dispositionReport> has a <result> subelement with an errno attribute. The <result> subelement also has an <errInfo> subelement with an errCode attribute. The value of the errCode attribute must be one of the error codes that are identified in Appendix A of the UDDI Programmer's API specification. In this example, the errCode value is E_accountLimitExceeded. The value of the <errInfo> element is a textual explanation of the error that can be displayed to a user.

When designing a program that interacts with a UDDI registry, your program needs to be prepared to handle SOAP Faults and react appropriately. If you want your program to parse UDDI responses intelligently, use the DOM API to parse a <dispositionReport> structure and then implement specialized actions to handle different errCode situations.

Abstraction APIs, such as the UDDI API provided by Systinet and JAXR, capture SOAP Faults and convert their contents into a specialized exception. This action allows you to write a program that has a familiar try/catch block to handle SOAP Fault scenarios, rather than using the DOM API to parse a <dispositionReport>.

What About the Rest of the Publishing API?

Using the rest of the Publishing API is straightforward. If you have the UUID of one major data structure element, you can use the delete_ messages to destroy data in the registry. If you want to insert or update data in a UDDI registry, construct a valid data structure, such as a <businessEntity>, and then use one of the save_ messages.

Since this chapter has already covered the major talking points of every major UDDI data structure, demonstrating Publishing APIs in full form would be repetitive. At this stage, you have all the necessary tools to work with the UDDI Programmer's and Data Structure specifications.

When working with the Publishing API, keep a couple of points in mind:

Using WSDL Definitions with UDDI

WSDL is used to describe the interface of a web service. <tModel> UDDI documents provide metadata descriptions of a web service and pointers to specifications that describe their implementation. Given this provision, WSDL documents tie into the UDDI data structures in a couple of places:

For example, if you implement one web service that has a single access point and is defined by a single WSDL document, you would create a single <tModel>, a single <bindingTemplate>, and a single <businessService>. Also, if you implement one web service that has two separate access points, each defined by a different WSDL document, you would create two <tModel> documents (one for each interface), two <bindingTemplate> documents (one for each access point), and a single <businessService> document. Each <bindingTemplate> document must point to the <tModel> that references its interface.

The Hertz reservation system web service provides a concrete example of how UDDI and WSDL work together. Here is the <tModel> for this web service:

<tModel authorizedName="..." operator="..." tModelKey="...">
    <name>HertzReserveService</name>
    <description xml:lang="en">WSDL description of the Hertz reservation service
     interface</description>
    <overviewDoc>
        <description xml:lang="en">WSDL source document.</description>
        <overviewURL>http://mach3.ebphost.net/wsdl/hertz_reserve.wsdl</overviewURL>
    </overviewDoc>
    <categoryBag>
        <keyedReference tModelKey="uuid:C1ACF26D-9672-4404-9D70-39B756E62AB4" 
         keyName="uddi-org:types" keyValue="wsdlSpec"/>
    </categoryBag>
</tModel>

The WSDL document URL that this web service implements is contained as the value of the <overviewURL>. Additionally, this <tModel> is categorized as a web service by incorporating a <categoryBag>. <categoryBag> has a <keyedReference> that specifies the keyName attribute as uddi-org:types and the keyValue attribute as wsdlSpec.

A <tModel> can further qualify the portion of the WSDL document it refers to. For example, a <tModel> can refer to a specific <binding> element within a WSDL document that has multiple <binding> elements. A pound sign fragment identifier is used between the URL of the WSDL document and the name of the <binding> element that accomplishes this qualification. For example:

<overviewURL>http://mach3.ebphost.net/wsdl/hertz_reserve.wsdl#HertzReserveBinding
</overviewURL>

An Abstraction API

Writing a Java program that creates a complete web service registration to a UDDI registry requires a lot of effort: an understanding of SOAP, accessing a UDDI registry using the correct SOAP messages, and ensuring that WSDL documents are placed in the correct locations in a UDDI registry. A developer can easily make mistakes when following this model.

It didn't take long for companies to begin developing abstraction APIs that facilitate this process. It is argued that companies and developers will use the UDDI/WSDL/SOAP model more than any other model since it is a worldwide standard and supported by every major technology business. As such, providing an abstraction layer that simplifies publishing documents following this model makes sense.

IBM created an API that does this abstraction very cleanly. This API is called the Service Registry Proxy (SRP) and is contained as part of the UDDI4J project at IBM. This pseudocode demonstrates how to publish a new web service exposed by WSDL into a UDDI registry:

// Create an active connection to a UDDI registry
ServiceRegistryProxy srp = new ServiceRegistryProxy(
                     "http://localhost:8080/wasp/uddi/inquiry/",
                     "https://localhost:8443/wasp/uddi/publishing/",
                     "admin", 
                     "changeit");
 
// Create a category list for an existing tModel (<categoryBag> document)
CategoryList categoryList = new CategoryList(
             TModelKeyTable.getTModelKey(TMODEL_UUID_VALUE_HERE),
             "uddi-org:types", 
             "wsdlSpec");
 
// Create service provider (<businessService> document)
ServiceProvider serviceProvider = new ServiceProvider(
                "Demi Credit",
                "Financing Company",
                categoryList);
 
// Publish the service to UDDI
srp.publish(serviceProvider);

The ServiceRegistryProxy class creates connections to an inquiry and publishing access point. The program instantiating the proxy passes in all the information needed to create these connections, including the username and password needed to get an authentication token. The CategoryList object creates the equivalent of a <categoryBag> document for a specific <tModel>. Since WSDL <tModel> documents are supposed to have a special categorization, creating a CategoryList instance and passing this instance as an input parameter to the ServiceProvider constructor creates this categorization. A ServiceProvider object is an abstraction of a <businessService> document. Finally, the ServiceProvider object has a series of methods that allow a program to perform such actions as publish, unpublish, and find. All of these actions result in SOAP messages that are sent to the UDDI server.

Back to: Java Web Services


oreilly.com Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies | Privacy Policy

© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com