ONJava.com -- The Independent Source for Enterprise Java  
oreilly.comSafari Books Online.Conferences.
 

A Tour Through WebLogic Workshop 8.1: Westside Auto Sales
Pages: 1, 2, 3, 4, 5, 6

Calling a Web Service from a Web Service

We are finally ready to add the code to the original Westside application that calls our CarSource Web service. Before we do, we will need a WSDL that describes the CarSource Web service so our Westside application will know how to access the CarSource methods. To create this file, right-click on the CarSourceWS.jws file and choose "Generate WSDL File". This will create a file called CarSourceWSContract.wsdl.

Now, go back to the Westside application. The first thing we will do is create a java control to talk to CarSourceWS. Under the WestsideWeb/Controls directory, right-click and choose Import. Navigate to the WSDL file we created in our CarSource project and click OK. To create a Web service java control, simply right-click on the WSDL file and choose "Generate Service Control". This creates the control we will use to communicate with the CarSource Web service.

We also need to import the OrderCar and OrderHonda schemas. To do this, right-click on the Schemas project and choose Import. Select Honda.xsd and OrderCar.xsd from the CarSource project and click OK. This will create the XMLBeans we need to build the XML that we'll pass to the CarSource Web service.

Because we are using an XQuery in the CarSource Web service, we will want to edit our service control to accept the HondaCar schema for the orderHonda method and the orderCar schema for the orderOther method. To do this, open CarSourceWSControl.jcx, delete the class OrderCar (since we will use XMLBeans), and change the orderHonda, orderOther, and Callback methods to the following (click OK when it asks if you want to modify the file):

public interface Callback extends com.bea.control.ServiceControl.Callback
{
    /**
     * @jc:conversation phase="finish"
     */
    public void finishOrder (com.beaOrderCar.OrderCarDocument OrderCar);
}

/**
* @jc:protocol form-post="false" form-get="false" 
* @jc:conversation phase="start"
*/
public java.lang.String orderHonda 
(com.beaHonda.HondaCarDocument HondaCar);

/**
* @jc:protocol form-post="false" form-get="false" 
* @jc:conversation phase="start"
*/
public java.lang.String orderOther 
(com.beaOrderCar.OrderCarDocument OrderCar);

We are now ready to build our car-ordering Web service. This Web service is called by the message-driven EJB and handles ordering the car from the CarSource Web service. To create the Web service, add a new folder called "WebServices" to the WestsideWeb project and add a new Web service called "OrderCarFromWS.jws". In design view of the new Web service, drag and drop Inventory.jcx, CarSourceWSControl.jcx, and WASControlImpl.jcs onto the design service. We will use all of these controls in our Web service. Your design view should look like this:

First we need the method that calls the CarSource Web service. Right-click the design surface and add a new method called "OrderFromCS". Click on the method name to go to source view and alter the method to look like this:

/**
 * @common:operation
 * @jws:conversation phase="start"
 */
public void OrderFromCS (String SKU) throws Exception
{
    // Look up the make and model
    Integer nSKU = new Integer(SKU);
    RowSet orderCar = inventory.detailsCarinventory(nSKU);
    orderCar.next();
    String sMake = orderCar.getString("Make");
    String sModel = orderCar.getString("Model");

    // Order the car from the proper manufacturer
    String OrderNumber = new String();

    if (sMake.equalsIgnoreCase("honda"))
    {
        // order from honda method

        // Prepare the XML to send to the manufacturer        
        HondaCarDocument orderDoc = HondaCarDocument.Factory.newInstance();
        HondaCar order = orderDoc.addNewHondaCar();
        
        order.setEngine("I4");
        order.setModel(sModel);
        order.setOptions("Basic");
        order.setCountrycode(03);
        order.setSKU(nSKU.intValue());
        
        System.out.println("Ordering 1 " + sModel + 
		" from Honda manufacturer.");

        OrderNumber = carSourceWSControl.orderHonda(orderDoc);          
    }
    else
    {
        // order a car through the normal channel

        // Prepare the XML to send to the manufacturer        
        OrderCarDocument orderDoc = 
		OrderCarDocument.Factory.newInstance();
        OrderCar order = orderDoc.addNewOrderCar();
        
        order.setMake(sMake);
        order.setModel(sModel);
        order.setOptions("Loaded");
        order.setYear(2003);
        order.setSKU(nSKU.intValue());

        // Print out the message
        System.out.println("Ordering 1 " + sModel + 
		" from other manufacturer.");
                        
        OrderNumber = carSourceWSControl.orderOther(orderDoc); 
    }
    
    System.out.println("Received Order Number " + OrderNumber );
    
    // Add the car to inventory and set the status as ordered
    wASControl.AddCarToInventory(new Integer(SKU), 
	new Integer(OrderNumber));
}

As you enter the code you will be prompted (via the magic Alt+Enter again) to add the following import statements:

import com.beaHonda.HondaCarDocument;
import com.beaHonda.HondaCarDocument.HondaCar;
import com.beaOrderCar.OrderCarDocument;
import com.beaOrderCar.OrderCarDocument.OrderCar;
import javax.sql.RowSet;

The code for this method first looks up the details of the car using the inventory control, and then determines whether to call the orderHonda or the orderOther method on the CarSource Web service. For either method, first we need to create the XML document we will send. We do this by using the XMLBean's Factory.newInstance() method. We can then get a new XMLBean and use the bean to set the attributes in the XML. Finally we send the XML document to the Web service using our Web service control.

Let's implement the AddCarToInventory method in our WASControl. In WASControlImpl.jcx, add the following code:

/**
 * @common:operation
 */
public void AddCarToInventory(Integer SKU, Integer OrderNumber) 
throws Exception
{
    // Set the status of the car to Ordered and the price to -1
    Car IBean = inventoryEJB.findByPrimaryKey(SKU);
    IBean.setStatus("Ordered: " + OrderNumber.toString());
    System.out.println("Marking Car " + SKU + " as Ordered"); 
}

Once the car has been ordered from the manufacturer's Web service, we set the status to "ordered" along with the order number.

Finally, we need to implement the callback that will set the final price of the car and mark it as available for sale. In OrderCarFromCS.jws, add the following code:

public void carSourceWSControl_finishOrder
(com.beaOrderCar.OrderCarDocument incomingCarDoc) throws Exception
{
    // Turn the XML Doc into an XMLBean
    OrderCar incomingCar = incomingCarDoc.getOrderCar();
    System.out.println("Receiving order number " + 
	incomingCar.getOrderNumber()); 
    
    // Got the car back, use the main controller to set 
	the proper status on it
    wASControl.SetCarAsReady(new Integer(incomingCar.getSKU()), 
	incomingCar.getPrice());
}

Again, we are using XMLBeans to access the information contained in the XML document and then sending that information to our WASControl to update the database.

Here is the code we need to add to WASControlImpl.jcx to implement the SetCarAsReady method:

/**
 * @common:operation
 */
public void SetCarAsReady(Integer SKU, int Price) throws Exception
{
   // Set the status of the car to Available from On Order and the price
   Car IBean = inventoryEJB.findByPrimaryKey(SKU);
   IBean.setStatus("Available");
   IBean.setPrice(Price);
   System.out.println("Marking Car " + SKU + 
   " as Available, Price: " + Price); 
}

Again, we use our EJB to mark the car as available and to set the final price.

All that is left to do is to call our OrderCarFromCS Web service from our message-driven EJB. To do this, we will use .jar files that will enable our EJB to use this Web service as if it were a local Java class. Save any dirty files, then open the OrderCarFromWS.jws file in the editor and hit play. When the test Web service form comes up, select the "Overview" tab. Among the links you will see one for a Java Proxy and another for a Proxy Support Jar. Click on each of these links and save the resulting .jar file in the APP-INF/lib directory of our Westside application. Close the test browser and open ListenBean.ejb from the WASejb project in source view. Change the onMessage method to the following (new text in italics):

public void onMessage(Message msg) {

    try {
        // Print information
        System.out.println("Got a message!");
        System.out.println("Contents of the message:" + 
		((TextMessage)msg).getText());
        
        // Order the car via the OrderCarFromWS Web Service
        OrderCarFromWS_Impl CSImpl = new OrderCarFromWS_Impl();
        OrderCarFromWSSoap soap = CSImpl.getOrderCarFromWSSoap();
        soap.orderFromCS(((TextMessage)msg).getText());
        
    } catch (Exception e) {
        System.out.println("Exception in ListenBean: " + e.getMessage());
    }
}

With our proxy jars added to the application, all we need to do to call the OrderCarFromCS Web service is to use the Impl class to create a new soap object and then use that soap object to call the method we want on the Web service. Hitting Alt+Enter when prompted will add the appropriate import statements for weblogic.jws.proxies.OrderCarFromWSSoap and weblogic.jws.proxies.OrderCarFromWS_Impl.

Our application is now complete. We need to rebuild our EJBs so save any dirty files, then right-click on the top "Westside" folder and choose "Build Application". This will recompile everything and redeploy the application on the server. When the build finishes, open the controller.jpf file from the WestsideWeb folder and click "Start". Click the "View Inventory" link and choose an available car. Click on the buy link. After you log in, you are taken to the confirmation page. If you click on "continue shopping" you will see the car's status has changed to "Sold to WASUser" and that a new car has been created and is waiting to be ordered. As you hit refresh, you can see the status switch to "ordered" and then "available" as the CarSource Web service processes the order. In the console window for the server, you should get something similar to the following as the vehicle moves though the ordering process:

Got a message!
Contents of the message:12
Ordering 1 Range Rover from other manufacturer.
[CarSource]Ordering 1 Land Rover Range Rover from manufacturing.
Received Order Number 8
Marking Car 12 as Ordered
[CarSource]Order 8 Complete. Sending message back to requestor.
Receiving order number 8
Marking Car 12 as Available, Price: 70664

If you order a Honda, you will see something like the following:

Got a message!
Contents of the message:25
Ordering 1 Civic Coupe from Honda manufacturer.
[CarSource]Ordering 1 null Civic Coupe from Honda manufacturing.
Received Order Number 10
Marking Car 25 as Ordered
[CarSource]Order 10 Complete. Sending message back to requestor.
Receiving order number 10
Marking Car 25 as Available, Price: 12337

These messages show that when ordering a Honda, the request is sent to the orderHonda method of the CarSource Web service, which used XQuery to translate the request into the HondaCar schema. As a way of understanding how this all works, you can set breakpoints within the code then step through it watching the process along the way.

As we have seen, the new WebLogic Workshop 8.1 is more than just a tool to build Web services. You can now build many types of projects within the WLW IDE. This gives you the power to create much more complex applications and do it all within a unified editing and debugging environment.

Carl Sjogreen is senior product manager for BEA WebLogic Workshop.


Return to ONJava.com.