站内搜索: 请输入搜索关键词
当前页面: 图书首页 > XML and Java: Developing Web Applications, Second Edition

XML and Java: Developing Web Applications, Second Edition

[ directory ] Previous Section Next Section

13.4 Application to Dynamic e-Business

So far, we have discussed WSDL and UDDI and the relationship between them. The UDDI registry can store information on businesses and services in an orderly fashion as well as implementation-specific information such as access points. Also, WSDL documents can be retrieved via tModels in the UDDI registry. In principle, you can get all the information needed to invoke services. In this sense, we have already obtained a basis to perform dynamic e-business, in which a requestor finds a particular service provided by a business and invokes it, referring an access point and a WSDL document. In this section, we show a dynamic e-business scenario with the travel service example and implement some portions of the scenario.

13.4.1 Application Scenario

Figure 13.13 illustrates a dynamic e-business scenario. A travel agency publishes in advance the tModel for its WSDL and business details that include business, service, and binding information. The following are the typical steps a requestor can take to retrieve all the necessary information and invoke services:

  1. Find businesses based on a category code of NAICS

  2. Filter services provided by the businesses based on a category code of UNSPSC

  3. Find access points from binding templates in the filtered services

  4. Find tModels by using the tModel key provided in the binding templates

  5. Find the locations of WSDL documents from the tModels

  6. Retrieve WSDL documents from the locations

  7. Invoke services by referring to the access points and the WSDL documents

Figure 13.13. Dynamic e-business scenario

graphics/13fig13.gif

The ultimate dynamic e-business would automate all the steps without human intervention. However, there are at least two obstacles to complete automation. First, it is often risky for the requestor to trust the retrieved businesses. In UDDI 2.0, the validate_values element has been added to ensure accurate values for tax onomies such as NAICS and UNSPSC. With this extension, the requestor can trust the retrieved businesses and services to some extent. Although this is still insufficient for real trading, it is a good first step toward solving the first problem. Second and more important, even if you can get the WSDL documents, your programs cannot always invoke the services properly. Generally, any program cannot understand the semantics defined in the WSDL documents. You can develop a program that finds a mapping from a known WSDL document to the unfamiliar document based on the similarity of words梖or example, "travel" is similar to "trip." However, it is almost impossible to develop a complete inference engine. What we can do for the second problem is provide human users with some tools to help the mapping.

In Section 13.4.2, we show an example of finding a business, service, and access point dynamically, assuming that the requestor knows the WSDL document. In Section 13.4.3, we improve the example, adding dynamic binding. More specifically, we process the WSDL document on the fly to invoke a service. The second example is still far from the ultimate dynamic e-business but can help you consider semiautomating service invocations.

13.4.2 Discovering Businesses on the Fly

Here, we show a typical use of the UDDI registry with a program called DynamicTravelRequestor. Listing 13.23 shows the main method of the class. We assume that the requestor knows a WSDL document and the tModel for a travel service. However, you have your own tModel key if you performed the instructions in this chapter. Therefore, we check the tModel with its WSDL location URL (line 74). In the program, first we find businesses with a NAICS code and then find services with a UNSPSC code. Next we retrieve binding templates, checking whether they include the tModel key. We can get access points from the binding templates. So far, we have all the necessary information for the target services. Next, we create a TravelServiceRPCProxy object (see Listing 13.6), specifying the access point we have found. Finally, we invoke the reserve method of the proxy to reserve a package tour.

Listing 13.23 The main() method in DynamicTravelRequestor.java
public static void main(java.lang.String[] args) {
   // args[0]: UDDI Registry access point url
   // args[1]: User ID for travel reservation
   // args[2]: Tour ID
   // args[3]: year of the departure (e.g. 2002)
   // args[4]: month of the departure (e.g. 5 for May)
   // args[5]: date of the departure (e.g. 15 for 15th)
   try {
       DynamicTravelRequestor req =
           new DynamicTravelRequestor(args[0]);
       // looking for tModel
       System.out.println("Looking for tModel " +
                          "for the travel service");
       TModelInfo tmodelInfo = req.getTravelServiceTModel();

       // get location of the WSDL
       TModel tmodel = req.getTModel(tmodelInfo);
       String wsdlLocationURL =
           tmodel.getOverviewDoc().getOverviewURL().getText();
       String wsdlLocation =
           "http://demohost:8080/xmlbook2/chap13/" +
           "travel-rpc-iface.wsdl";
[74]       if (!wsdlLocationURL.equals(wsdlLocation)) {
                System.out.println("I am not familiar to " +
                          wsdlLocationURL);
                System.exit(1);
           } else {
                System.out.println("I am familiar to " +
                             wsdlLocationURL);
           }

           // find business by NAICS,  "56151"
           System.out.println("Looking for travel agencies");
           BusinessInfos bizInfos = req.getTravelAgencies();

           // find service by "UNSPSC", "901215"
          System.out.println("Looking for "+
                             "travel reservation service");
          BusinessInfo bizInfo =
              (BusinessInfo)
                  bizInfos.getBusinessInfoVector().elementAt(0);
          ServiceInfos svcInfos = req.getTravelSerivces(bizInfo);

          // find binding template
          // which matches against our TModel
          System.out.println("Looking for a binding template");
          ServiceInfo svcInfo =
              (ServiceInfo)
                  svcInfos.getServiceInfoVector().elementAt(0);
          BindingTemplate bTmp =
             req.findBindingTemplate(tmodelInfo, svcInfo);

          // get access point
          AccessPoint accessPoint = bTmp.getAccessPoint();
          String accessPointURL = accessPoint.getText();
          System.out.println("Access point is " +
                             accessPointURL);

          // instantiate proxy object
          TravelServiceRPCProxy proxy=
              new TravelServiceRPCProxy(new URL(accessPointURL));
          Calendar cal=Calendar.getInstance();
          cal.clear();
          cal.set(Integer.parseInt(args[3]),
                  Integer.parseInt(args[4])-1,
                  Integer.parseInt(args[5]));
          Date departure = cal.getTime();
          // invoke the service
          Reservation rsv =
              proxy.reserve(args[1], args[2], departure);
          // print out the given reservationId
          System.out.println("The reservation id is: " +

You can execute the program as follows:

R:\samples>java chap13.demo.DynamicTravelRequestor
           http://demohost/services/uddi/servlet/uddi
           nakamury hawaii55 2002 8 21
Looking for tModel for the travel service
I am familiar to http://demohost:8080/xmlbook2/chap13/travel-rpc-
iface.wsdl
Looking for travel agencies
Looking for travel reservation service
Looking for a binding template
Access point is http://demohost:8080/soap/servlet/rpcrouter
The reservation id is: hawaii551002540004508

DynamicTravelRequestor defines a collection of utility methods for searching the UDDI registry, such as getTravelServiceTModel, getTModel, get TravelAgencies, getTravelServices, and findBindingTemplate. Here we examine only getTravelAgencies to see how we can use category IDs for the search.

Listing 13.24 is a method to find travel agencies by using an NAICS category ID. The idea is to create a KeyedReference object setting an NAICS tModel key and an NAICS category ID (56151). The KeyedReference object is contained in a CategoryBag object to invoke the UDDIProxy.find_business method. The result should be a collection of businesses that have the NAICS category ID.

Listing 13.24 Finding businesses by using an NAICS category ID
public BusinessInfos getTravelAgencies() throws Exception {
    CategoryBag cBag = new CategoryBag();
    Vector keyRefVector = new Vector();
    KeyedReference keyRef =
        new KeyedReference("NAICS", "56151");
    keyRef.setTModelKey(
        "UUID:C0B9FE13-179F-413D-8A5B-5004DB8E5BB2");
    keyRefVector.addElement(keyRef);
    cBag.setKeyedReferenceVector(keyRefVector);
    BusinessList bizList =
        proxy.find_business(cBag, null, 0);
    BusinessInfos bizInfos = bizList.getBusinessInfos();
    return bizInfos;
}

We have shown a program that dynamically finds a business, service, and access point and invokes services with the client stub code shown in Listing 13.6. This is the most typical use of the UDDI registry. Although we have reviewed only a small portion of the program, the complete code for DynamicTravelRequestor is provided on the CD-ROM.

13.4.3 Dynamic Binding

Now we extend the previous program, adding dynamic processing of WSDL. The main method of the new program, called DynamicTravelRequestor1, is shown in Listing 13.25. The key difference from the previous program is that the WSDLServiceProxy class is used to invoke the service.

Listing 13.25 The main() method in DynamicTravelRequestor1.java
public static void main(java.lang.String[] args) {
    // args[0]: UDDI Registry access point url
    // args[1]: User ID for travel resrvation
    // args[2]: Tour ID
    // args[3]: year of the departure (e.g. 2002)
    // args[4]: month of the departure (e.g. 5 for May)
    // args[5]: date of the departure (e.g. 15 for 15th)
    try {
        DynamicTravelRequestor1 req =
            new DynamicTravelRequestor1(args[0]);
        // looking for tModel
        System.out.println("Looking for tModel " +
                           "for the travel service");
        TModelInfo tmodelInfo = req.getTravelServiceTModel();

        // get location of the WSDL
        TModel tmodel = req.getTModel(tmodelInfo);
        String wsdlLocationURL =
            tmodel.getOverviewDoc().getOverviewURL().getText();
        System.out.println("WSDL is located at " +
                           wsdlLocationURL);

        // find business by NAICS,  "56151"
        System.out.println("Looking for travel agencies");
        BusinessInfos bizInfos = req.getTravelAgencies();

        // find service by "UNSPSC", "901215"
        System.out.println("Looking for "+
                           "travel reservation service");
        BusinessInfo bizInfo =
            (BusinessInfo)
                bizInfos.getBusinessInfoVector().elementAt(0);
        ServiceInfos svcInfos = req.getTravelSerivces(bizInfo);

        // find binding template
        // which matches against our TModel
        System.out.println("Looking for a binding template");
        ServiceInfo svcInfo =
            (ServiceInfo)
                svcInfos.getServiceInfoVector().elementAt(0);
        BindingTemplate bTmp =
            req.findBindingTemplate(tmodelInfo, svcInfo);

        // get access point
        AccessPoint accessPoint = bTmp.getAccessPoint();
        String accessPointURL = accessPoint.getText();
        System.out.println("Access point is " +
                           accessPointURL);

        // create WSDLServiceProxy object
        System.out.println("creating WSDLServiceProxy object");
        URL objURL = new URL(wsdlLocationURL);
        HttpURLConnection
            con = (HttpURLConnection)objURL.openConnection();
        con.getInputStream();
        InputSource src =
            new InputSource(
                new InputStreamReader(con.getInputStream()));
        WSDLServiceProxy proxy = new WSDLServiceProxy(src);

        // set up travel-specific information
        proxy.setTravelInfo();

        // prepare parameters
        Object params[] = new Object[3];
        params[0] = args[1];
        params[1] = args[2];
        Calendar cal=Calendar.getInstance();
        cal.clear();
        cal.set(Integer.parseInt(args[3]),
                Integer.parseInt(args[4])-1,
                Integer.parseInt(args[5]));
        Date departure = cal.getTime();
        params[2] = departure;

        // invoke service, feeding the access point
        System.out.println("invoking the service");
        URL url = new URL(accessPointURL);
        ServiceResponse resp = // Reservation object
            proxy.invoke(url, "reserve", params);
        // print out the given reservationId
        System.out.println("The reservation id is: " +
                           resp.getValue("reservationId"));

     } catch(Exception ex) {
        ex.printStackTrace();
     }
}

Before going into the details of the program, let us see how it works. You can execute the program as follows:

R:\samples>java chap13.demo.DynamicTravelRequestor
           http://demohost/services/uddi/servlet/uddi
           nakamury hawaii55 2002 8 21
Looking for tModel for the travel service
WSDL is located at
    http://demohost:8080/xmlbook2/chap13/travel-rpc-iface.wsdl
Looking for travel agencies
Looking for travel reservation service
Looking for a binding template
Access point is http://demohost:8080/soap/servlet/rpcrouter
creating WSDLServiceProxy object
invoking the service
The reservation id is: hawaii551001820780320

The output message is similar to that of the previous program. But you may notice that a WSDLServiceProxy object is created and used.

Let us look at the WSDLServiceProxy class in more detail. This class takes a WSDL document as a parameter of the constructor and uses it to perform SOAP RPC. In Section 13.2, we compiled a WSDL document to generate client stub code, but this program does the same thing on the fly. Listing 13.26 shows its key method, invoke. In the method, we retrieve the information from the WSDL document necessary for constructing a Call object of Apache SOAP. For example, the target object URI is extracted from the soap:body element in the binding section (see Listing 13.4 also). The types and names of parameters are also retrieved so that given parameter values are properly set on the Call object. Because of such careful analysis of the WSDL document, the service invocation can be performed properly.

Listing 13.26 The invoke() method in WSDLServiceProxy.java
public ServiceResponse invoke(
    URL url, String op, Object paramArray[])
    throws Exception
{
    // construct call object
    Call call = new Call ();
    call.setSOAPMappingRegistry(smr);

    BindingOperation bindingOp = getBindingOperation(op);
    SOAPOperation soapOp = getSOAPOperation(bindingOp);

    SOAPBody inputSOAPBody =
        getSOAPBody(bindingOp.getBindingInput());
    call.setTargetObjectURI (inputSOAPBody.getNamespaceURI());
    call.setMethodName (op);
    call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

    Vector params = new Vector ();
    for(int i=0; i<paramArray.length; i++) {
        Part part = getPart(bindingOp, i);
        QName qname =
            new QName(part.getTypeName().getNamespaceURI(),
                      part.getTypeName().getLocalPart());
        String javaType = (String)mappingWsdlJava.get(qname);
        params.addElement(
            new Parameter(
                part.getName(),
                Class.forName(javaType),
                paramArray[i], null));
    }
    call.setParams (params);

    Response resp =
        call.invoke(url, soapOp.getSoapActionURI());
    if (resp.generatedFault ()) {
        org.apache.soap.Fault fault = resp.getFault ();
        throw new Exception(fault.toString());
    } else {
        Parameter result = resp.getReturnValue ();
        return new ServiceResponse(result.getValue());
    }
}

The program shown here seems flexible enough. However, as you can see in Listing 13.25, you have to embed the semantics of the service. In other words, DynamicTravelRequestor1 knows the travel service reservation precisely. In this sense, this program does not provide any value by dynamically analyzing the WSDL document. However, if you want to semiautomate the dynamic binding, the program should be a good starting point.

    [ directory ] Previous Section Next Section