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

Java Message Service Topics

When a user purchases a car, we want to order another car from the manufacturer to replace the car purchased. However, we don't need to order the car immediately. In fact, it's more important to return a confirmation to the user as soon as possible. We really just want to send a message to the car ordering system that a new car needs to be ordered whenever they can get around to it. This scenario is perfect for JMS because of the disconnected nature of messaging.

We will build two controls to enable this: a Java control to send messages to the topic, and a message-driven EJB to pick the messages up and initiate the ordering of the new vehicle.

The first thing we need is a way to get messages to the JMS topic. We can easily do this by creating a JMS control. Right-click the Controls directory and select "New Java Control". Choose "JMS" and name it "MessageSender". The message type will be "Text/XMLBean" and the destination type is "Topic". Browse for the send-jndi-name and choose "WASTopic" (the topic we created in the Workshop domain earlier). Ignore the receive topic (since our EJB will receive the message) and scroll down to click on "browse" for the connection-factory (use the default: "weblogic.jws.jms.QueueConnectionFactory"). Click "Create". Now, switch back to the WASControl and in design view, drag the new "MessageSender.jcx" onto the control. All we need to do to send a message to the JMS topic is add the following in our purchase car method (new code in italics):

	NewBean.setPrice(-1);
	NewBean.setStatus("Waiting to be ordered");	
                
       // Send a message to the topic to order another car
       messageSender.sendTextMessage(NewBean.getSku().toString());
}

Now we just need something to listen for the message. We will do this with a message-driven EJB. Back in our EJB project, right-click on the "Westside" folder and choose "New/Message-Driven Bean". We will name this "ListenerBean.ejb". First we need to tell the bean which topic to listen to. In the EJBGen properties pane, change the destination-type to "javax.jms.Topic" and the destination-jndi-name to "WASTopic". We will add code later to order the new vehicle once we build our Web service. For now, just add the following code to the onMessage method to show everything is working.

/**
 * @ejbgen:message-driven
 *   ejb-name = Listener
 *   destination-jndi-name = "WASTopic"
 *   destination-type="javax.jms.Topic" 
 *
 */
public class ListenerBean
  extends GenericMessageDrivenBean
  implements MessageDrivenBean, MessageListener
{
 public void onMessage(Message msg) {

  try {
      // Print information
      System.out.println("Got a message!");
      System.out.println("Contents of the message:" + 
	  ((TextMessage)msg).getText());
  } catch (Exception e) {
      System.out.println("Exception in ListenBean: " + e.getMessage());
  }
 }
}

Let's give it a try. First save any dirty files and build your EJB project again. Now fire up the application, go to inventory, select a car, and click the "buy" link. You should get a confirmation that you successfully purchased the car along with your bill. Again, a new car will be added to the inventory of the same make and model with a status of "Waiting to be ordered". If you go to your WebLogic Server window, you should see a message in the console like the following:

Got a message!
Contents of the message:11

The content of the message is the SKU of the car that was purchased.

Web Services

The next part of the application to build is the manufacturer's Web service that allows for ordering of cars. We'll create this as a separate application. Close the Westside application, then choose File/New/Application and create a new empty application called "CarSource". Now right-click on "CarSource" and choose New\Project\Web Service Project. Call the new project "CarSourceWS". This is the Web service that will receive the request for a new car. To create a new Web service in the Web service project, right-click on the CarSourceWS project and choose New/Web Service. Call the new Web service "CarSourceWS.jws".

We will have two different methods for ordering cars - one for Hondas, and one for all other cars. We will do this to show how you can use XQuery to map between two different XML schemas. In design view of CarSourceWS.jws, right-click and add a method called "orderHonda" and another method called "orderOther". This Web service will use asynchronous callbacks. We do this because when a new car is ordered from the manufacturer, there is often a time lag between when the car is ordered and when the car is shipped. For our application we will simulate that time lag with a timer control. Right-click in design view and choose "Add Callback". Name the callback "finishOrder".

XML Schemas and XMLBeans

To communicate between our Westside application and the CarSource Web service, we need to pass information back and forth about the car to be ordered. We will pass this information as XML. The following is the schema we will use to order a car.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.BEA-OrderCar.com" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:fn="http://www.BEA-OrderCar.com" 
elementFormDefault="qualified">
	<xs:element name="OrderCar">
		<xs:complexType>
			<xs:sequence>
                <xs:element name="SKU" type="xs:int"/>
                <xs:element name="Year" type="xs:int"/>
                <xs:element name="Make" type="xs:string"/>                
                <xs:element name="Model" type="xs:string"/>                
                <xs:element name="Options" type="xs:string"/>                
                <xs:element name="Price" type="xs:int"/>
                <xs:element name="OrderNumber" type="xs:int"/>
                <xs:element name="Status" type="xs:string"/>                
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Rather than using this XML directly, we will use an XMLBean to abstract the XML into a Java class. To do this, create a new schema project called "Schemas" under the main "CarSource" folder. Right-click on this new project and choose New/XML Schema called "OrderCar.xsd". Paste the code above into this new file and click on "Save". WebLogic Workshop immediately creates an XMLBean for this schema. We will use this new XMLBean in the orderOther method of our Web service. Modify the method declaration to the following:

public String orderOther(OrderCarDocument newCar)
{
	return "";
}

Again, hit Alt+Enter to add the appropriate import statement for com.beaOrderCar.OrderCarDocument to the file.

Database Control

When we receive the order for the new car, we will record the order in the database, start the timer to wait 10 seconds, and then retrieve the information back out of the database and send the it to the requestor's callback. We will need a database control to talk to our data source. Right-click on the CarSourceWS folder and create a new folder called "CSControls". Now, right-click on this new folder and choose New/Java Control/Database. Name it "CSDataAccess" and then browse for the WASDataSource. Finally, click "create". We need three methods in this control: getPrice, createOrder, and sendOrder. We also need a new Order class within the control to pass back information to the caller. Create the three methods by right-clicking on the control, then go to source view and edit the file to the following:

package CSControls; 

import com.bea.control.*; 
import java.sql.SQLException; 

/** 
 * @jc:connection data-source-jndi-name="WASDataSource" 
 */ 
public interface CSDataAccess extends DatabaseControl, 
com.bea.control.ControlExtension
{ 
    static public class Order
    { 
       public int SKU; 
       public int Price;
    } 

    static final long serialVersionUID = 1L;

    /** 
     * @jc:sql statement="exec UpdateOrder {OrderNumber}"
     */ 
    Order sendOrder(int OrderNumber);

    /**
     * @jc:sql statement="exec AddOrder {SKU}, {Make}, {Model}, 
	 {Price}, {Status}"
     */
    int createOrder(int SKU, String Make, String Model, 
	int Price, String Status);

    /**
     * @jc:sql statement="Select Price from BasePrices where Make = 
	 {Make} and Model = {Model}"
     */
    int getPrice(String Make, String Model);
}

Notice in the sendOrder and createOrder methods, we are calling stored procedures and in the getPrice method, we are using in-line SQL. The sendOrder method returns a SKU and a price so we use the Order class to transmit that information back to the caller. The other two methods simply return int values.

Now, to use this control in our Web service, drag and drop the control onto the design view of the Web service. This gives us a new private variable to access the control called "cSDataAccess".

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow