Previous Section Next Section

Using WSDL with UDDI

UDDI was designed to accommodate the registration of businessService entries regardless of the kind of service description mechanism used. A Web service, registered in UDDI as a businessService, can be described using WSDL, a plain ASCII text document, a RosettaNet pip, RDF, or any number of other description mechanisms. This is one of the aspects of UDDI that makes it generally applicable.

This section is for those developers who use WSDL to describe your Web services and wish to register them in UDDI. UDDI.org has published a best practices document that outlines the convention you should use for WSDL-described Web services. UDDI.org publishes best practices documents at http://www.uddi.org/bestpractices.html. Al Rosen uses this convention to format the UDDI entries for SkatesTown. Let's examine the steps that Al needs to do in order to properly register SkatesTown's PriceCheck service.

Saving a UDDI businessService Based on WSDL

In Chapter 6, we reviewed the major elements in WSDL and outlined the Web services convention of separating service interface definition from service implementation definition. Figure 7.32 outlines how the major elements of WSDL map into UDDI elements.

Figure 7.32. Mapping from WSDL to UDDI.

graphics/07fig32.gif

The best practices document for using WSDL in UDDI discusses how to represent the service interface definition as a tModel. Al Rosen followed an extended convention that defined how to reference the service implementation definition file from the bindingTemplate element.

Al starts with the WSDL file for SkatesTown's priceCheck service. We saw this file in Chapter 6. Al further updates the file from Chapter 6, preparing to save it in UDDI by decomposing the priceCheck service description into two files. The service interface definition is available at www.skatestown.com/services//interfaces/priceCheckInterface.wsdl. The service implementation definition is available at http://www.skatestown.com/services/priceCheck.wsdl.

The first thing Al must do is create a tModel to reference the service interface definition. Al chooses to create this tModel in the UDDI Business Registry itself for maximum exposure. Al could also have chosen to create this tModel in any private UDDI registry, but SkatesTown hoped to make this approach to priceCheck a standard among its supply chain partners, and therefore wanted maximum exposure. The save_service message looks like this:

<save_tModel generic="1.0" xmlns="urn:uddi-org:api">
   <authInfo>...</authInfo>
   <tModel>
      <name>SkatesTown PriceCheck Service Interface Definition</name>
      <description>This tModel defines the service interface definition
         for priceCheck services.
      </description>
      <overviewDoc>
         <overviewURL>
   http://www.skatesTown.com/services/interfaces/priceCheckInterface.wsdl
         </overviewURL>
      </overviewDoc>
      <categoryBag>
         <keyedReference
            keyName="uddi-org:types"
            keyValue="wsdlSpec"
            tModelKey="UUID:C1ACF26D-9672-4404-9D70-39B756E62AB4"/>
            <!-- UDDI Types tModelKey -->
      </categoryBag>
   </tModel>
</save_tModel>

The key points are:

  • The overviewURL element gives the URL to where the service interface definition WSDL file can be found. This allows humans and UDDI/WSDL-aware tooling to locate the service interface definition. As we mentioned in Chapter 6, the goal of acquiring the service interface definition is to generate a client proxy for the requestor application.

  • The purpose of the keyedReference element in the categoryBag is to make sure that this tModel is categorized as a WSDL specification document. UDDI/WSDL-aware tooling relies on consistent categorization as a guarantee of the contents of the resource referenced by the overviewURL.

  • Remember those tModelKeys! The tModelKey assigned to SkatesTown's priceCheck tModel must be used in any subsequent businessService element. In this case, the tModelKey returned assigned by the UDDI operator was UUID:75F83600-4D6E-11D5-83B9-AFF41F112FA2.

No tModelKey is passed in the message; this signals to UDDI that the tModel is a new tModel.

Now that a tModel for SkatesTown's priceCheck service interface is generally available, it is possible to create a businessService element that models a Web service based on this interface. WeMakeIt Inc. can build a Web service based on this price Check standard. Therefore, WeMakeIt Inc.'s Joanna Pravard can define a businessService entry for WeMakeIt Inc.'s priceCheck Web service. The save_service message looks like:

<save_service generic="1.0" xmlns="urn:uddi-org:api">
   <authInfo>...</authInfo>
   <businessService businessKey="...">
      <name>WeMakeIt Inc.&apos;s Price Check Service</name>
      <description>This service is based on the Price Check service
         interface definition...
      </description>
      <bindingTemplates>
         <bindingTemplate>
            <description>See the PriceCheck service interface standard
               Use the address in the svc impl. definition if the
               accessPoint URL doesn&apos;t work.
         </description>
            <accessPointURLType="http">
                www.wemakeit.com/axis/services/priceCheck
            </accessPoint>
            <tModelInstanceDetails>
               <tModelInstanceInfo
                  tModelKey="UUID:75F83600-4D6E-11D5-83B9-AFF41F112FA2">
                  <instanceDetails>
                     <overviewDoc>
                        <description>Points to WeMakeIt Inc.&apos;s service
                           implementation WSDL ...
                        </description>
                        <overviewURL>
                     www.wemakeit.com/webservices/descriptions/priceCheck.wsdl
                        </overviewURL>
                     </overviewDoc>
                  </instanceDetails>
               </tModelInstanceInfo>
            </tModelInstanceDetails>
         </bindingTemplate>
      </bindingTemplates>
   </businessService>
</save_service>

The key points are:

  • The accessPoint element is the URL at which the Web service can be invoked, although the ultimate source of truth for the Web service's location is in the service implementation file.

  • The tModelKey element refers to the tModel representing the priceCheck service interface definition.

  • The tModelInstance element follows an extended convention for locating the service implementation definition file. Joanna uses this additional convention because it allows WeMakeIt Inc. the flexibility of moving the location of this service without having to immediately update the UDDI entry. All WeMakeIt Inc. would have to do is update the service implementation definition (which it controls) and eventually update the accessPoint element of the UDDI entry. The advantage to this approach is that the change of location is made immediately in the local WSDL file and WeMakeIt Inc. does not have to wait until the UDDI entry change is replicated to all the UDDI Business Registry operator nodes.

More Complex WSDL and Corresponding UDDI Entries

For more sophisticated WSDL descriptions, the UDDI entries are slightly more tricky. Let's take a look at some of the entries for the e-Torus marketplace.

The e-Torus marketplace has established a standard, industry-wide service interface definition suite for supply reordering of small wheels and bearings. This suite has built upon the priceCheck service interface definition developed by SkatesTown and adding request for quote and purchase order placement. This resulted in a minor inconvenience to existing service implementations that referenced SkatesTown's tModel. The businessService entries for these services needed to be updated to reference the new tModel defined by e-Torus. Because e-Torus has incorporated SkatesTown's priceCheck and POSubmission service interface definitions into the order suite WSDL, this was a minor inconvenience in UDDI registration only; the programs continued to work.

The details of the e-Torus orderSuite WSDL are not relevant here, but we do include important portions of the WSDL as follows:

<?xml version="1.0"?>
<definitions name="e-Torus Order Suite"
   targetNamespace=
      "http://www.etorus.com/serviceInterfaces/orderSuiteInterface"
   xmlns:tns=
      "http://www.etorus.com/serviceInterfaces/orderSuiteInterface"
   xmlns:orderSchema="http://www.etorus.com/schemas/order.xsd"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns="http://schemas.xmlsoap.org/wsdl/">

   <types>
      <schema targetNamespace="http://www.e-Torus.com/schemas/order.xsd"
      <!-– incorporates priceCheck schema elements from SkatesTown -->
      ...
   </types>

<!-- Message definitions -->

   <message name="PriceCheckRequest">
      <part name="item" type="xsd:string"/>
   </message>
   <message name="PriceCheckResponse">
      <part name="result" type="orderSchema:availability"/>
   </message>

   <message name="RequestForQuotes">
      <part name="body" element="orderSchema:RFQ"/>
   </message>
   <message name="RFQResponse">
      <part name="body" element="orderSchema:RFQResponse"/>
   </message>

   <message name="poSubmissionRequest">
      <part name="purchaseOrder" element="orderSchema:po"/>
   </message>

   <message name="poSubmissionResponse">
      <part name="invoice" element="orderSchema:invoice"/>
   </message>
...

   <!-- Port type definitions -->

   <portType name="PriceCheckPortType">
      <operation name="checkPrice">
         <input message="tns:PriceCheckRequest"/>
         <output message="tns:PriceCheckResponse"/>
      </operation>
   </portType>

   <portType name="RFQPortType">
      <operation name="PlaceRFQ">
         <input message="tns:RequestForQuotes"/>
         <output message="tns:RFQResponse"/>
      </operation>
   </portType>

   <portType name="poSubmissionPortType">
      <operation name="doSubmission">
         <input message="tns:poSubmissionRequest"/>
         <output message="tns:poSubmissionResponse"/>
      </operation>
   </portType>
   ...

   <!-- Binding definitions -->
   <binding name="PriceCheckSOAPBinding" type="tns:PriceCheckPortType">
      <soap:binding style="rpc"
         transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="checkPrice">
      ...
      </operation>
   </binding>

   <binding name="RFQSOAPBinding" type="tns:RFQPortType">
      <soap:binding style="document"
         transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="PlaceRFQ">
      ...
      </operation>
   </binding>

   <binding name="poSubmissionSOAPBinding" type="tns:poSubmissionPortType">
      <soap:binding style="document"
         transport="http://schemas.xmlsoap.org/soap/http"/>
      <operation name="doSubmission">
      ...
      </operation>
   </binding>
</definitions>

This WSDL file is made available at the e-Torus Web site: http://www.etorus.com/webservices/interfaces/orderInterfaces.wsdl.

Note that each business process has a separate portType (PriceCheckPortType, RFQPortType, and POSubmissionPortType are shown). This allows each business process to have separate binding definitions, providing for significant implementation flexibility for different security, reliability, transport mechanism, and so on.

Because this service interface definition has different bindings, the UDDI entries, particularly the businessService elements referencing this service interface definition, look slightly different.

So, e-Torus registers a tModel in its portal private UDDI for each of the bindings. This creates a separate tModel for each binding in the service interface definition file. The technique for registering these tModels is slightly different from what Joanna Pravard used. Because the overviewURL references to the entire document, the developer at e-Torus followed the recommendation in the best practices document and used a URL fragment identifier (http://www.ietf.org/rfc/rfc2396.txt) to indicate exactly which binding in the service interface file each tModel references. The tModel record for the priceCheck binding looks like this:

<tModel
      tModelKey="UUID:72E5F9F0-A4C3-11D5-AF98-BD95162D3AC9" ...>
   <name>e-Torus order Service PriceCheck Interface Definition</name>
   <description xml:lang="en">
      This tModel defines the service interface definition for
      priceCheck within the e-Torus order suite of services.
   </description>
   <overviewDoc>
      <overviewURL>
         http://www.etorus.com/services/interfaces/
            orderInterfaces.wsdl#PriceCheckSOAPBinding
      </overviewURL>
   </overviewDoc>
   <categoryBag>
      <keyedReference
         keyName="uddi-org:types"
         keyValue="wsdlSpec"
         tModelKey="UUID:C1ACF26D-9672-4404-9D70-39B756E62AB4"/>
   </categoryBag>
</tModel>

Now, consider a businessService element for a Web service provided by one of the sellers in the e-Torus marketplace that implements the priceCheck binding tModel. A wheel manufacturer, MakeCircles Inc., is a member of the e-Torus e-marketplace. MakeCircles Inc. defines a service implementation definition file at http://www.makecircles.com/services/priceCheck.wsdl. This file contains ports for the entire set of order suite bindings as follows:

<?xml version="1.0"?>
<definitions name="orderSuite"
   targetNamespace="http://www.makecircles.com/wsdl/orderSuite"
   xmlns:tns="http://www.makecircles.com/wsdl/orderSuite"
   xmlns:order=
      "http://http://www.etorus.com/serviceInterfaces/orderSuiteInterface"
   xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns="http://schemas.xmlsoap.org/wsdl/">
   <import
      namespace=
      "http://www.etorus.com/serviceInterfaces/orderSuiteInterface"
      location=
     "http://www.etorus.com/services/interfaces/orderInterfaces.wsdl"
   />

   <service name="OrderServices">
      <documentation>
         PriceCheck service according to the e-Torus order standard
      </documentation>
      <port name="PriceCheckPort" binding="order:PriceCheckSOAPBinding">
         <soap:address
            location=http://www.makecircles.com/services/priceCheck/>
      </port>

      <port name="RFQPort" binding="order:RFQSOAPBinding">
         <soap:address
            location=http://www.makecircles.com/services/placeRFQ/>
      </port>

      <port name="POSubmissionPort" binding="order: poSubmissionSOAPBinding">
         <soap:address
            location=http://www.makecircles.com/services/submitPO/>
      </port>
   </service>
</definitions>

Let's take a look at a businessService entry for this service. Like Joanna Pravard, the developer at MakeCircles Inc. preferred to have control over where the network address of the services are actually kept, and chose to have the tModelInstanceDetails of the bindingTemplate reference the service implementation file as the ultimate source of truth for the Web service's network address. Note that the service has two ports. The bindingTemplate uses the same fragment identifier mechanism on the overviewURL to reference the particular priceCheck port:

<businessService
      businessKey="..."
      serviceKey="...">
   <name>MakeCircle&apos;s priceCheck Web service</name>
   <description>This service is based on the e-Torus PriceCheck orderSuite
service
      interface definition...
   </description>
   <bindingTemplates>
      <bindingTemplate
         bindingKey="BEF9B260-A4C7-11D5-AF98-BD95162D3AC9"
         serviceKey="BEF9B260-A4C7-11D5-AF98-BD95162D3AC9">
         <description>
            See the e-Torus order suite priceCheck service interface
            standard. Use the address in the svc impl. definition if the
            accessPoint URL does not work.
         </description>
            <accessPoint URLType="http">
               http://www.makecircles.com/services/priceCheck
            </accessPoint>
            <tModelInstanceDetails>
               <tModelInstanceInfo
                  tModelKey="UUID:B04E3710-4D86-11D5-83B9-AFF41F112FA2">
                  <description>
                     Points to MakeCircle&apos;s service
                     implementation WSDL ...
                  </description>
                  <instanceDetails>
                     <overviewDoc>
                        <overviewURL>
                    http://www.makecircles.com/webservices/descriptions/
                       rfq.wsdl#PriceCheckPort
                        </overviewURL>
                     </overviewDoc>
                  </instanceDetails>
               </tModelInstanceInfo>
            </tModelInstanceDetails>
         </bindingTemplate>
      </bindingTemplates>
   </businessService>

Note the tModelKey refers to the RFQ binding as defined by e-Torus order standard service interface definition for order-based Web services.

Putting It All Together: WSDL-Based UDDI and Dynamic Find

By this point, SkatesTown is selling a lot of skateboards. Some of the company's partner retailers are now selling direct to customers via the Web, and those customers get real-time availability and pricing information from SkatesTown via Web services. Retailers use SkatesTown's Web services to order boards, and SkatesTown has committed to giving them real-time availability information for their big orders. In order for SkatesTown to meet this commitment in a cost-effective fashion, SkatesTown needs to verify components supply by orchestrating back-end queries to the e-Torus e-marketplace. For example, if a retailer orders 100 of SkatesTown's MAXX skateboards, to be delivered in two weeks, the system can check the inventory of finished boards and parts, and then query the e-marketplace to make sure enough wheels, bearings, and so on will be available to SkatesTown in order to meet the commitment.

SkatesTown has all the pieces to do dynamic runtime bind of Web services. SkatesTown wants to use the power of the e-Torus marketplace to get the best supplier for any single reorder of wheels or bearings at any given point in time. For wheels and bearings, SkatesTown trusts the vendors active in the e-Torus marketplace. The reorder application that Al Rosen has put together uses dynamic bind to do priceChecks within the e-Marketplace to all vendors that follow the e-Torus order standard suite of service interfaces.

These are the steps Al Rosen used to develop SkatesTown's e-marketplace priceCheck application.

First, Al uses the Java generated from the priceCheck WSDL. You saw this done back in Chapter 6. Others, like Joanna Pravard would generate their company's proxy by retrieving the tModel associated with the e-Torus priceCheck service interface definition standard.

Al uses dynamic binding to fill in the URL to the proxy. Al codes the client application, using the UDDI4J graphics/book.gif API. UDDI4J is an open source project sponsored by IBM; source is available under the IBM Public License. Originally part of the WebServices Toolkit, UDDI4J source is now also available at http://oss.software.ibm.com/developerworks/projects/uddi4j. UDDI4J defines a very straightforward and convenient mapping between the UDDI operations and data structures and Java methods and classes. UDDI4J makes it simple to incorporate UDDI operations as part of any Java program—exactly what Al needs to do.

Al's code does a find operation that retrieves all the vendors from the e-Torus e-marketplace private UDDI that implement the priceCheck binding tModel and also the POSubmission tModel. The find message appears as follows:

<find_business generic="1.0" xmlns="urn:uddi-org:api">
   <tModelBag>
      <tModelKey>UUID:5FE30870-A4C3-11D5-AF98-BD95162D3AC9</tModelKey>
      <tModelKey>UUID:72E5F9F0-A4C3-11D5-AF98-BD95162D3AC9</tModelKey>
   </tModelBag>
</find_business>

The first tModel key corresponds to the POSubmission tModel, and the second one refers to a priceCheck tModel (not shown in any listings).

The UDDI4J code fragment would look like this:

UDDIProxy proxy=new UDDIProxy();

String userid="...";
String password="...";

//set up the TModelBag to refer to both the priceCheck and PoSubmission
//suppliers must support both standards in order to be invoked by the
//application
TModelBag bag=new TModelBag();
Vector v=new Vector();

//UUID of POSubmission tModel
v.addElement("UUID:5FE30870-A4C3-11D5-AF98-BD95162D3AC");
//UUID of PriceCheck tModel
v.addElement("UUID:72E5F9F0-A4C3-11D5-AF98-BD95162D3AC");
bag.setTModelKeyStrings(v);

//finds all businesses that have a service implementing the priceCheck  and
POSubmission tModelsBusinessList bl=proxy.find_business(bag, null, 0);

A sample set of return values from execution of the find operation would look like this:

<businessList generic="1.0" ...
   <businessInfos>
      <businessInfo businessKey="DCD2B450-A4C0-11D5-AF98-BD95162D3AC9">
         <name>WeMakeIt Inc.</name>
         <serviceInfos>
            <serviceInfo
               businessKey="DCD2B450-A4C0-11D5-AF98-BD95162D3AC9"
               serviceKey="9732C900-A4C8-11D5-AF98-BD95162D3AC9">
               <name>WeMakeIt Inc.&apos;s POSubmission Service</name>
            </serviceInfo>
            <serviceInfo
               businessKey="DCD2B450-A4C0-11D5-AF98-BD95162D3AC9"
               serviceKey="ACE9DE00-A4C8-11D5-AF98-BD95162D3AC9">
               <name>WeMakeIt Inc.&apos;s POSubmission Service</name>
            </serviceInfo>
            <serviceInfo
               businessKey="DCD2B450-A4C0-11D5-AF98-BD95162D3AC9"
               serviceKey="D66199C0-A4C9-11D5-AF98-BD95162D3AC9">
               <name>WeMakeIt Inc.&apos;s RFQ Service</name>
            </serviceInfo>
            <serviceInfo
               businessKey="DCD2B450-A4C0-11D5-AF98-BD95162D3AC9"
               serviceKey="CEC8E160-A4CD-11D5-AF98-BD95162D3AC9">
               <name>WeMakeIt Inc.&apos;s Price Check Service</name>
            </serviceInfo>
         </serviceInfos>
      </businessInfo>
      <businessInfo businessKey="05064CC0-A4C1-11D5-AF98-BD95162D3AC9">
         <name>Wheels Made Here</name>
         <serviceInfos>
            <serviceInfo
               businessKey="05064CC0-A4C1-11D5-AF98-BD95162D3AC9"
               serviceKey="2065CFF0-A4CA-11D5-AF98-BD95162D3AC9">
            <name>Wheels Made Here&apos;s PO Submission Web service</name>
            </serviceInfo>
            <serviceInfo
               businessKey="05064CC0-A4C1-11D5-AF98-BD95162D3AC9"
               serviceKey="80DFFE50-A4CA-11D5-AF98-BD95162D3AC9">
               <name>Wheels Made Here&apos;s priceCheck Placement Web
                  service</name>
            </serviceInfo>
            <serviceInfo
               businessKey="05064CC0-A4C1-11D5-AF98-BD95162D3AC9"
               serviceKey="BA661920-A4CA-11D5-AF98-BD95162D3AC9">
               <name>Wheels Made Here&apos;s RFQ Web service</name>
            </serviceInfo>
         </serviceInfos>
      </businessInfo>
   </businessInfos>
</businessList>

For each serviceInfo found in the businessList object returned from the find operation, the code needs to locate the priceCheck service (remember we asked for all businesses that supported both priceCheck and POSubmission, so we need to isolate the priceCheck service). The location of the priceCheck service is found in a bindingTemplate. The priceCheck bindingTemplate is identified by the tModel within one of the bindingTemplate's tModelInstanceInfo elements. The algorithm proceeds as follows. Issue a find_binding for the service, given the tModel bag with the priceCheck tModel. The bindingDetail element returned from this call will contain the bindingTemplate referring to the priceCheck. Other bindingTemplates for other technologies might also be in the bindingDetail structure. Examine each bindingTemplate, looking for a tModelInstanceInfo element that refers to the priceCheck model. When that tModelInstanceInfo element is found, the algorithm has found the right bindingTemplate. The search is complete. This is demonstrated in the following listing, continuing from the previous code example:

//Find the binding that matches the TModel for priceCheck
TModelBag bag2=new TModelBag();
Vector v2=new Vector();
//UUID of priceCheck tModel
v2.addElement("UUID:72E5F9F0-A4C3-11D5-AF98-BD95162D3AC9");
bag2.setTModelKeyStrings(v2);
Vector biv=bl.getBusinessInfos().getBusinessInfoVector();
Enumeration e=biv.elements();
while(e.hasMoreElements()){
   BusinessInfo bi=(BusinessInfo)e.nextElement();
   ServiceInfos sis=bi.getServiceInfos();
   Vector siv=sis.getServiceInfoVector();
   Enumeration e2=siv.elements();

   //loop through the binding templates until a bt is found
   BindingTemplate bt=null;
   while(e2.hasMoreElements() && bt == null){
      ServiceInfo si=(ServiceInfo)e2.nextElement();

      //find the service's bindingDetail that corresponds to the
      //priceCheck tModel
      BindingDetail bd=proxy.find_binding(null, si.getServiceKey(), bag2,0);
      Vector btv=bd.getBindingTemplateVector();
      Enumeration e3=btv.elements();

      //the tModel is hidden in the TModelInstanceDetails
      while(e3.hasMoreElements() && bt == null){
         bt=(BindingTemplate)e3.nextElement();
         Vector tmidv=
            bt.getTModelInstanceDetails().getTModelInstanceInfoVector();
         Enumeration e4=tmidv.elements();

         TModelInstanceInfo tmii=null;
         while(e4.hasMoreElements() && tmii==null){
            tmii=(TModelInstanceInfo)e4.nextElement();
            if(! tmii.getTModelKey().equals
               ("UUID:B04E3710-4D86-11D5-83B9-AFF41F112FA2")){
               tmii=null;//continue
            }
         }
         if(tmii == null){
            bt=null; //continue
         }
      }
   }

The code then extracts the accessPoint element and invokes the priceCheck Web service. Sample code follows, continuing from the previous code sample:

         //invoke the priceCheck WSDL proxy, passing access point, item
         PriceCheckService pcs = new PriceCheckService();
         PriceCheckPortType pcpt =
            pcs.getPriceCheck(new java.net.URL(bt.getAccessPoint().getText()));
         AvailabilityType at = pcpt.checkPrice(sku); //some SKU
         double price = at.getPrice();
         //cache the price in a data structure that associates the businessKey
with the price
 . . .

If the Web service invocation fails, the code should check to see if the InstanceDetails element includes a URL to a service implementation definition. If it does, the code should retrieve the service implementation definition and generate a proxy for that service. The Web service is invoked again, this time using the network address generated in the proxy.

All the responses from the invocations of all the Web services are aggregated, and the list of businessEntities is sorted by the response price of the priceCheck. The company with the best bid price is the winning supplier. Other policies, such as fastest delivery, can also be used to determine the winning supplier.

The final stage of the reorder process is to send a PO to the winning supplier. The actual order placement portion of the application has been built with a proxy generated from the POSubmission service interface standard defined by the e-Torus orderSuite standard WSDL. Like the priceCheck proxy, all the POSubmission proxy needs is a network address to send the purchase order. This information is supplied by the UDDI entries of the supplier that won the priceCheck bid. This is done by issuing a find_service message, passing the businessKey of the winner of the priceCheck bid and a tModelBag containing the UUID of the POPlacement TModel.

UDDI4J code to find the POSubmission service of the best price from priceCheck is as follows:

String winnerBusKey=...

//set up a TModel bag referencing the POSubmission TModel
TModelBag bag=new TModelBag();
Vector v=new Vector();
//UUID of POPlacement tModel
v.addElement("UUID:5FE30870-A4C3-11D5-AF98-BD95162D3AC9");
bag.setTModelKeyStrings(v);

//find the po submission service for the winning business
ServiceList sl=proxy.find_service(winnerBusKey, bag2, null, 0);

Once the POSubmission service of the winning bidder is found, the remainder of the code identifies the bindingTemplate in a fashion similar to the priceCheck portion of the code. Finally, the accessPoint information is extracted from the bindingTemplate element and given to the Web service proxy to invoke the POSubmission Web service of the supplier that won the priceCheck bid. Of course, if the invocation of the Web service fails, with an error that indicates a network failure, the application tries to extract a service implementation definition from the bindingTemplate, and if successful, uses the information in the service implementation definition to invoke the Web service.

UDDI4J code to find the POSubmission bindingTemplate of the best price from priceCheck and then invoke the Web service is as follows:

//traverse the bindingTemplates structure looking for the binding template for
//the POSubmission TModel
BindingTemplate bt=null;
Vector btv= bs.getBindingTemplates().getBindingTemplateVector();
Enumeration e2=btv.elements();

//the tModel is hidden in the TModelInstanceDetails
while(e2.hasMoreElements() && bt == null){
   bt=(BindingTemplate)e2.nextElement();
   Vector tmidv=bt.getTModelInstanceDetails().getTModelInstanceInfoVector();
   Enumeration e3=tmidv.elements();

   TModelInstanceInfo tmii=null;
   while(e3.hasMoreElements() && tmii==null){
      tmii=(TModelInstanceInfo)e3.nextElement();
      if(! tmii.getTModelKey().equals
         ("UUID:5FE30870-A4C3-11D5-AF98-BD95162D3AC9")){
         tmii=null;//continue
      }
   }
   if(tmii == null){
      bt=null; //continue
   }
}

//invoke the POSubmission WSDL proxy, passing access point, purchase Order
. . .

With that algorithm, SkatesTown can find the best supplier for a given part at a given moment in time and place a purchase order with that supplier by invoking a Web service.

The complete program listing for the dynamic find appears in Listing 7.1. Note that some of the program uses utilities to find the tModelKey and other features. Further, the code does not actually invoke the Web services, but rather prints out the access points of the Web services it would have invoked.

Listing 7.1 The Dynamic Find Program
package ch7.ex2;

import java.util.Vector;
import java.util.Enumeration;
import java.util.Hashtable;

import com.ibm.uddi.UDDIException;
import com.ibm.uddi.client.UDDIProxy;
import com.ibm.uddi.response.*;
import com.ibm.uddi.datatype.binding.*;
import com.ibm.uddi.datatype.service.BusinessService;
import com.ibm.uddi.datatype.binding.TModelInstanceDetails;
import com.ibm.uddi.util.TModelBag;

import ch7.UDDIExamples;
import ch7.Util;

import ch6.ex1.*;

/**
 * Chapter 7 - UDDI examples
 *
 * The final example of dynamic find.
 * SkatesTown does a find for all businesses that
 * implement PriceCheck and POSubmission.
 * Based on best priceCheck, a PO is placed with the
 * supplier with the best price.
 *
 */
public class DynamicFindSkatesTown extends UDDIExamples{

/**
 * Place a PO with the supplier that has best priceCheck price.
 * Use the supplier's POSubmission service to place the PO.
 */
public static void main (String args[]) {
   try {

      if(args.length != 1){
          System.err.println("Usage: DynamicFindSkatesTown SKU");
          System.exit(1);
      }

        String sku = args[0];
      //set up the UDDIProxy
      setSecurity();

      UDDIProxy proxy = new UDDIProxy();
      proxy.setInquiryURL(inquiryAPI);
      proxy.setPublishURL(publishAPI);

      String priceCheckTModelKey =
         Util.getTModelKey("E-Torus order suite PriceCheck Service Interface Definition");
      String POSubmissionTModelKey =
         Util.getTModelKey("E-Torus order PO Submission Service Interface Definition");

      //set up the TModelBag to refer to both the priceCheck and POSubmission
      //suppliers must support both standards in order to be invoked by the
      //application
      TModelBag bag = new TModelBag();
      Vector v = new Vector();

      //UUID of priceCheck tModel
      v.addElement(priceCheckTModelKey);
      //UUID of POSubmission tModel
      v.addElement(POSubmissionTModelKey);
      bag.setTModelKeyStrings(v);

      //finds all businesses that have a service implementing the priceCheck tModel
      BusinessList bl = proxy.find_business(bag, null, 0);

      //print it
      System.out.println("List the businesses that support priceCheck and POSubmission");
      Util.printElement(bl);

      //loop through the BusinessList, invoking the priceCheck web service
      //Find the binding that matches the TModel for priceCheck
      TModelBag bag2 = new TModelBag();
      Vector v2 = new Vector();
      //UUID of priceCheck tModel
      v2.addElement(priceCheckTModelKey);
      bag2.setTModelKeyStrings(v2);
      Vector biv = bl.getBusinessInfos().getBusinessInfoVector();
      Enumeration e = biv.elements();
      while(e.hasMoreElements()){
         BusinessInfo bi = (BusinessInfo)e.nextElement();
         ServiceInfos sis = bi.getServiceInfos();
         Vector siv = sis.getServiceInfoVector();
         Enumeration e2 = siv.elements();

         //loop through the binding templates until a bt is found
         BindingTemplate bt = null;
         while(e2.hasMoreElements() && bt == null){
            ServiceInfo si = (ServiceInfo)e2.nextElement();

            //find the service's bindingDetail that corresponds to the priceCheck tModel
            BindingDetail bd = proxy.find_binding(null, si.getServiceKey(), bag2,0);
            Vector btv = bd.getBindingTemplateVector();
            Enumeration e3 = btv.elements();

            //the tModel is hidden in the TModelInstanceDetails
            while(e3.hasMoreElements() && bt == null){
               bt = (BindingTemplate)e3.nextElement();
               Vector tmidv = bt.getTModelInstanceDetails().getTModelInstanceInfoVector();
               Enumeration e4 = tmidv.elements();

               TModelInstanceInfo tmii = null;
               while(e4.hasMoreElements() && tmii==null){
                  tmii = (TModelInstanceInfo)e4.nextElement();
                  if(! tmii.getTModelKey().equals(priceCheckTModelKey)){
                     tmii = null;//continue
                  }
               }
               if(tmii == null){
                  bt = null; //continue
               }
            }
         }

         //invoke the priceCheck WSDL proxy, passing access point, item
         PriceCheckService pcs = new PriceCheckService();
         PriceCheckPortType pcpt = pcs.getPriceCheck(new 
graphics/ccc.gifjava.net.URL(bt.getAccessPoint().getText()));
         //for now, avoid the invocation as the various company's services are not set up
         //AvailabilityType at = pcpt.checkPrice(sku); //some SKU
         //double price = at.getPrice();

         //cache the price in a data structure that associates the businessKey with the 
graphics/ccc.gifprice

         //instead of invoking, print
         System.out.println("Business: " + bi.getNameString() + " priceCheck service 
graphics/ccc.gifaccessPoint: " + bt.getAccessPoint().getText());
      }

      //use the cache to determine the winning supplier's business Key based on best price
      //force the issue by choosing We Make It Inc.
      String winnerBusKey = Util.getBusinessKey("WeMakeIt Inc.");

      TModelBag bag3 = new TModelBag();
      v = new Vector();
      v.addElement(POSubmissionTModelKey);
      bag3.setTModelKeyStrings(v);
      ServiceList sl = proxy.find_service(winnerBusKey, bag3, null, 0);
      ServiceInfos sis = sl.getServiceInfos();

      //take first matching service, normally one would check for multiples and choose 
graphics/ccc.gifbest
      ServiceInfo si = (ServiceInfo)sis.getServiceInfoVector().firstElement();
      ServiceDetail sd = proxy.get_serviceDetail(si.getServiceKey());
      BusinessService bs = (BusinessService)sd.getBusinessServiceVector().firstElement();

      //traverse the bindingTemplates structure looking for the binding template for
      //the POSubmission TModel
      BindingTemplate bt = null;
      Vector btv =  bs.getBindingTemplates().getBindingTemplateVector();
      Enumeration e2 = btv.elements();

      //the tModel is hidden in the TModelInstanceDetails
      while(e2.hasMoreElements() && bt == null){
         bt = (BindingTemplate)e2.nextElement();
         Vector tmidv = bt.getTModelInstanceDetails().getTModelInstanceInfoVector();
         Enumeration e3 = tmidv.elements();

         TModelInstanceInfo tmii = null;
         while(e3.hasMoreElements() && tmii==null){
            tmii = (TModelInstanceInfo)e3.nextElement();
            if(! tmii.getTModelKey().equals(POSubmissionTModelKey)){
               tmii = null;//continue
            }
         }
         if(tmii == null){
            bt = null; //continue
         }
      }

      //invoke the POSubmission WSDL proxy, passing access point, purchase Order
      System.out.println(" PO service accessPoint: " + bt.getAccessPoint().getText());

        // Handle possible errors
   } catch (UDDIException e) {
      DispositionReport dr = e.getDispositionReport();
      if (dr!=null) {
         System.out.println("UDDIException faultCode:" + e.getFaultCode() +
            "\n operator:" + dr.getOperator() +
            "\n generic:"  + dr.getGeneric() +
            "\n errno:"    + dr.getErrno() +
            "\n errCode:"  + dr.getErrCode() +
            "\n errInfoText:" + dr.getErrInfoText());
      }
      e.printStackTrace();

      // Catch any other exception that may occur
      } catch (Exception e) {
         e.printStackTrace();
      }

     System.exit(0);
   }
}
    Previous Section Next Section