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

advertisement

AddThis Social Bookmark Button

Enhancing Web Services Infrastructures with JMS
Pages: 1, 2, 3

ShippingClient

On the other side of the JMS server is the ShippingClient.



This client is a hybrid JMS and Web services client. It extends JMSClientSendReceive and also implements functionality for connecting to, and making a call to, a Web service. The source code for the ShippingClient is:

package org.open3.soap;

import java.net.*;
import java.util.*;

import org.apache.soap.*;
import org.apache.soap.rpc.*;

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;

import org.open3.soap.*;

public class ShippingClient extends JMSClientSendReceive {

  //constants for Web Service
  public static String SERVICE_URL = "http://localhost:8080/soap/servlet/rpcrouter";
  public static String TARGET_URI = "urn:open3soap";
        
  //Constructor
  public ShippingClient() {
      super.init(TO_WS_DEST_NAME, FROM_WS_DEST_NAME);
  }
  
  public void onMessage(javax.jms.Message msg) {
        //a message has been received from the JMS server, need to process this
        //and send it to the Web service 

        try{

            //get the xml data from the TextMessage
            String xmlData = ((TextMessage)msg).getText();

            System.out.println("ShippingClient: received JMS message: " + xmlData);
            
            //parse the data
            //for simplicity the parsing is manual, but we could use SAX or DOM
            String strShipWeight = xmlData.substring(
                xmlData.indexOf(XML_WEIGHT_OPEN_TAG) + XML_WEIGHT_OPEN_TAG.length(),
                xmlData.indexOf(XML_WEIGHT_CLOSE_TAG));

           String strDestDistance = xmlData.substring(
                xmlData.indexOf(XML_DISTANCE_OPEN_TAG) + XML_DISTANCE_OPEN_TAG.length(),
                xmlData.indexOf(XML_DISTANCE_CLOSE_TAG));

           //****DELETE
           System.out.println("shipWeight=" + strShipWeight);
           System.out.println("destDistance=" + strDestDistance);

           //type converstions
           Double shipWeight = new Double(strShipWeight);
           Integer destDistance = new Integer(strDestDistance);
        
           boolean processOK = callWebService(shipWeight, destDistance);
        }
        catch (Exception e){
            System.out.println("ShippingClient.onMessage Error: " + e.toString());
        }
  }
      
  public boolean callWebService(Double shipWeight, Integer destDistance) {
    
    boolean callOK = true;  
    
    System.out.println("ShippingClient: calling Web service: (" + shipWeight + 
        ", " + destDistance + ")");
    
    try {
    
        // Construct the RPC Call
        Call call = new Call();
        call.setTargetObjectURI(TARGET_URI);
        call.setMethodName("calculateShippingCost");
        call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

        Vector params = new Vector();
        params.addElement(new Parameter("shippingWeight", Double.class, shipWeight, null));
        params.addElement(new Parameter("p2", Integer.class, destDistance, null));
        call.setParams (params);

        // peform the call
        URL url = new URL (SERVICE_URL);
        Response response = call.invoke(url, "" );

        // response from the call
        if ( response.generatedFault() ) {
          Fault fault = response.getFault ();
          System.out.println("ShippingClient.callWebService Error");
          System.out.println("FaultCode = " + fault.getFaultCode());
          System.out.println("FaultString = " + fault.getFaultString());
          callOK = false;
        }
        else {
          Parameter returnValue = response.getReturnValue();
          callOK = constructXMLResponse(((Double)returnValue.getValue()).doubleValue());
        }
    }
    catch (Exception e) {
        System.out.println("ShippingClient.callWebService Error: " + e.toString());
        callOK = false;
    }
    
    return callOK;
  }
  
  public boolean constructXMLResponse(double shippingCost) {
      //builds the XML string for the response from the Web service
      String responseXML = XML_ORDER_OPEN_TAG + XML_COST_OPEN_TAG +
        shippingCost + XML_COST_CLOSE_TAG + XML_ORDER_CLOSE_TAG;
  
      System.out.println("ShippingClient: response from Web service. XML: " + 
        responseXML);
      
      return sendJMSMessage(responseXML);
  }
  
  public static void main(String[] args) throws Exception {

     ShippingClient client = new ShippingClient();
  }
}

The Web service location and URI are defined in constant fields:

public static String SERVICE_URL = "http://localhost:8080/soap/servlet/rpcrouter";
public static String TARGET_URI = "urn:open3soap";

The class' constructor calls the parent's init() to set up its JMS client functionality. Notice that the queue destinations for the receiver and sender are the opposite of those defined in the OrderApplication application. The ShippingClient's receiver retrieves messages from the toWS@open3soap queue and sends messages to the fromWS@open3soap queue.

super.init(TO_WS_DEST_NAME, FROM_WS_DEST_NAME);

The ShippingClient waits until an onMessage() event is generated. Upon onMessage(), the method processes the message and extracts the shippingWeight and destinationDistance fields. These fields are transformed to Double and Integer objects, respectively. These objects are utilized as parameters when calling the Web service.

The callWebService method establishes the connection and makes the RPC call to the Web service. The data that is returned from the Web service is processed and converted to an XML document:

Parameter returnValue = response.getReturnValue();
callOK = constructXMLResponse(((Double)returnValue.getValue()).doubleValue())

The XML document is then sent to the fromWS@open3soap queue, which is received by the OrderApplication.

Our final class is ShippingService, a very simple Web service:

package org.open3.soap;

public class ShippingService {

    public double calculateShippingCost(double shippingWeight, int destinationDistance) {
        
        return 5.0 + (shippingWeight * .75) + (destinationDistance * .001);
    }

}

Our example utilizes Tomcat to host the Web service. Setting up the Web service in Tomcat is outside of the scope of this article, but take a look at James Goodwill's article on " Using SOAP with Tomcat."

You can utilize SOAP's graphical admin tool to configure the ShippingService as follows:

Tomcat Configuration:
SOAP Web Administration
Deploy:
ID: urn:open3soap
Scope: Application
Methods: calculateShippingCost
Provider Type: Java
Java Provider: 
    Provider Class: org.open3.soap.ShippingService
    Static: No

Running the Software

  1. Start the Open3.org JMS server.
  2. Start Tomcat, which has been configured with Apache SOAP and the ShippingService Web service.
  3. Start the ShippingClient.
  4. Start the OrderApplication.

Note: The ShippingClient needs both the Open3.org JMS jars and Apache SOAP jars in the classpath. The OrderApplication needs only the Open3.org JMS jars.

Conclusion

This decoupled architecture of JMS and Web service clients is obviously more complex than an application that makes the Web service call directly. Certainly, for this example, the architecture is overkill. However, as the number of applications and Web services grow, the importance of the loosely coupled architecture becomes more evident. JMS forms the backbone of many integration projects for good reason: it simplifies and enhances the handling of data. Since Web services are simply another way to integrate information and functionality, it makes sense that JMS should also be a part of it.

Gunnison Carbone is an experienced Java and Web services developer with Open3 Technologies, Inc.


Return to ONJava.com.