|
Related Reading
Java Web Services |
This excerpt from O'Reilly's Java Web Services focuses on UDDI programming with the Java API for XML Registries (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);
}
|
In this Series
UDDI: Universal Description, Discovery, and Integration, Part 4
UDDI: Universal Description, Discovery, and Integration, Part 2
UDDI: Universal Description, Discovery, and Integration, Part 1 |
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.
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.
|
Message name |
Response document |
Brief description |
|---|---|---|
|
|
|
Given one or more UUIDs of different |
|
|
|
Given one or more UUIDs of different |
|
|
|
Given one or more UUIDs of different |
|
|
|
Given one or more UUIDs of different |
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.
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.
|
Taxonomy name |
tModel name |
Description |
|---|---|---|
|
NAICS |
|
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 |
|
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 |
|
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 |
|
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.
|
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.
|
Identifier name |
tModel name |
Description |
|---|---|---|
|
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. |
|
Thomas Register |
|
This scheme provides identifiers for over 150,000 manufacturing and
|
<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 involves any operation that would create, update, or destroy data in a UDDI registry. Here are some key technical differences between publishing and inquiring:
<businessEntity> structure and prevent them from inserting additional data without special permissions.The Publisher API messages that require authentication are listed in Table 6-6.
|
Message name |
>
Response document |
Brief description |
|---|---|---|
|
|
|
Given a valid authentication token and a |
|
|
|
Given a valid authentication token and the UUID of one or more |
|
|
|
Given a valid authentication token and the UUID of one or more |
|
|
|
Given a valid authentication token and the UUID of one or more |
|
|
|
Given a valid authentication token and the UUID of one or more |
|
|
|
Given a valid authentication token and the UUID of one or more |
|
|
|
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 |
|
|
|
Given a valid authentication token, this message returns a report that details all |
|
|
|
Given a username and password, this message retrieves an authentication token from an operator node to be used on other Publisher API messages. |
|
|
|
Given a valid authentication token, this message returns a complete list of |
|
|
|
Given a valid authentication token, this message returns a complete list of |
|
|
|
Given an authenticated token and one or more |
|
|
|
Given an authenticated token and one or more |
|
|
|
Given an authenticated token and one or more |
|
|
|
Given an authenticated token and one or more |
|
|
|
Given an authenticated token and one or more |
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
keytoolutility.The real value of using a custom Java API such as Systinet's is apparent when you look at the difficulty of using the
UDDISoapClientto 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 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>.
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:
Your program signals the difference between a creation and an update by the value of a document's UUID fields on a save_ message. If a save_ message is used for updating an existing document in a UDDI registry, the value of the existing document's UUID is placed in the input document's UUID field. If a save_ message is used to create a new document in a UDDI registry, the UUID should be left blank. For example, if you wanted to update a <businessEntity> document with a fictional UUID of 43, then you would create a <businessEntity> document, fill it with the contents you want stored in the registry, and then set this document's businessKey attribute to 43. However, if you wanted to insert a new registration into the registry, the businessKey value would be "".
Be careful when using the delete_ and save_ messages. If the structure you are updating has a number of subelements, such as a <businessEntity>, you can inadvertently destroy them by removing their containment. If you delete a <businessEntity>, it will delete all <businessService> and <bindingTemplate> elements contained within the <businessEntity>. It will not delete a <businessService> referenced by the <businessEntity>, which would occur only if the <businessService> is contained with a different <businessEntity>. For example, if you want to update a <businessEntity> document using a save_ message, you might accidentally delete <businessService> and <bindingTemplate> structures in the process. If the existing <businessEntity> element stored in a UDDI registry has <businessService> or <bindingTemplate> structures, but the <businessEntity> document used as input to the save_ message does not have those same subelements, the <businessService> and <bindingTemplate> subelements will be destroyed automatically as part of the update process.
<tModel> documents are never fully destroyed. When you use the <delete_tModel> message, a <tModel> element saved in the registry is merely hidden. Hidden documents can be located through <get_tModelDetail> and <get_registeredInfo> messages, but will not be displayed by any find_ queries. This behavior ensures that the details associated with any <tModel> are still available to anyone who may currently implement the specifications referred by the <tModel>. <tModel> documents can be unhidden by using the <save_tModel> message.
The next and final installment covers WSDL Definitions with UDDI.
Tyler Jewell, David A. Chappell , Director, Technical Evangelism, BEA Systems Tyler oversees BEA's technology evangelism efforts that are focused on driving early adoption of strategic BEA technologies into the ISV and developer community.
View catalog information for Java Web Services
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.