EJB Inheritance, Part 4
by Emmanuel Proulx01/29/2003
Message-Driven Bean Inheritance
So far, we've seen how inheritance can be used when calling an EJB directly through RMI. However, SOAP (web services) and JMS also allow you to invoke objects remotely. Recognizing this, the EJB committee introduced JMS consumer beans (message-driven beans) in version 2.0 of the specification, and, in version 2.1, a generic asynchronous mechanism allowing web service invocations.
This article discusses the steps involved in using inheritance in message-driven beans.
The Problem with JMS
In order for the inheritance to occur, there has to be a key element present: object referencing. In the case of message-driven beans, there's no such thing! The main characteristic of message-driven beans is that they are not invoked synchronously through RMI, but rather asynchronously through JMS messages. These messages are processed by message-driven beans and are completely independent of their source. Plus, the JMS container makes the branching decision -- "which object processes which message?" -- not the programmer. Often, message-driven beans are managed as a pool of objects created in advance, to speed up processing.
|
A Note About the Example Source Code Download the source code for this article. This .zip file contains a WebLogic Server domain, EJB source code, and a PointBase database. Install this under C:\inherit. The start scripts contain the newest PointBase drivers. For the administration console, the username is still |
How can we take advantage of the abstraction, reuse, and maintainability promises of inheritance? If we can't control the way a message will be processed by creating objects, we can control this at the time of the bean invocation. I know of two techniques to control invocation:
- Use a single type of message-driven bean as a Delegate, which branches to a hierarchy of objects.
- Use message selectors to let JMS do the branching for us, sending the message to the proper object in a hierarchy of message-driven beans.
In our example, we'll use a combination of techniques 1 and 2. We will have a Delegate message-driven bean, but this will re-post the message while setting a field for the message selection to occur. Our hierarchy of message-driven beans will pick up those messages.
RTM Ordering System
The folks at RTM are very happy about the system so far, but the back-end ordering system is done manually, which is not a good feature for a web application. RTM needs an ordering subsystem.
RTM has exclusive contracts with the following fictive companies:
| Company | Coverage | Ordering Method |
| North-American Flights (NAF) |
• USA (except Hawaii) |
EDI |
| Pacific Ocean Air (POA) |
• Hawaii |
EDI |
| Continent Air (CA) |
• Europe |
Manually, through a broker. |
NAF handles the vast majority of flights, so it's the ideal candidate for modeling our base class. POA and CA are special cases, reusing some functionality from NAF; these will be the models of our subclasses. Figure 1 shows how the RTM ordering system will work.

Figure 1 -- ordering system flow
|
In This Series
EJB Free and Open Source Tools Summary
EJB Inheritance, Part 3
EJB Inheritance, Part 2
EJB Inheritance, Part 1 |
In this system, the following events occur:
- An order message is received from the RTM application to the order JMS queue.
- There are four listeners for this queue. One of them is the delegate,
which is invoked when the
companyfield is not set. The role of the delegate is to figure out which company will handle the order. - Once this has been decided, the delegate re-sends the message with the
companyfield set to the proper value. - Finally, one of the other listeners picks up the order, based on the value
in the
companyfield.
Before we go on, one last detail needs to be clarified. What will be the format for the messages? We'll use a class to represent our message. This class will contain the following information:
- Name of client
- Departure airport
- Arrival airport
Figure 2 shows the traditional class diagram. Here we can see that the
message sent is an ObjectMessage, containing a Serializable
OrderMessage object.

Figure 2 -- ordering system class diagram
Overview of the Steps
Still following the tradition, here's the list of steps required to use inheritance in message-driven beans. We're following the second technique, using message selectors.
- Create a base bean class implementing
SessionBean. Write bean subclasses extending the base bean class. - Write the classes'
setMessageDrivenContext(),ejbCreate(), andejbRemove()methods. These can be inherited. Overridden methods can call the corresponding super method first. - Write the
onMessage()and any business logic methods. - Choose a message selector condition for each bean of the hierarchy.
Bean Classes
The base bean class implements the normal interfaces:
MessageDrivenBean and MessageListener. The extra
short subclasses extend this base class. Here I show all three class
skeletons:
Example 1 - OrderBean declaration
public class OrderBean implements MessageDrivenBean, MessageListener
{
public OrderBean() {}
...
}
Example 2 -- POAOrderBean declaration
public class POAOrderBean extends baseorder.OrderBean {
public POAOrderBean() {}
...
}
Example 3 -- CAOrderBean declaration
public class CAOrderBean extends baseorder.OrderBean {
public CAOrderBean() {}
...
}
Lifecycle Methods
When I say "lifecycle methods," I of course mean
setMessageDrivenContext(), ejbCreate(),
ejbRemove(), and the like. These usually support the bean without
actually doing any business processing. Here, we write these methods in the
base class, inheriting them in the subclasses. This is why I only show you the
class OrderBean:
Example 4 -- OrderBean lifecycle methods
public class OrderBean implements MessageDrivenBean, MessageListener
{
...
public void setMessageDrivenContext(MessageDrivenContext ctx) {
this.ctx = ctx;
}
public void ejbRemove() {}
public void ejbCreate() throws CreateException {}
...
}
These methods don't do much here, but they could maintain connections to EDI systems, set up the necessary configuration to get ready to send an email, or prepare anything else needed before the real processing occurs.
onMessage() and Business Logic Methods
So far the code isn't very interesting. The real work happens in
onMessage() and the methods it calls. Let's start with the bulk of
the work, in the OrderBean class:
Example 5 -- OrderBean onMessage and business
logic methods
public class OrderBean implements MessageDrivenBean, MessageListener {
...
public void onMessage(Message m) {
ObjectMessage objMsg = (ObjectMessage) m;
OrderMessage order;
try {
order = (OrderMessage) objMsg.getObject();
processOrder(order);
} catch (JMSException e) {
System.out.println("Error getting a message object in CAOrderBean." + e);
e.printStackTrace();
}
}
static int transNum = 0;
public void processOrder(OrderMessage o) {
transNum ++;
String ediMessage = "EDI TRANSACTION " + transNum;
ediMessage += ", FOR COMPANY: '" + getCompany() + "'.";
ediMessage += " BUY TICKET FOR: '" + o.name + "', ";
ediMessage += "FROM: '" + o.departureAirport + "', ";
ediMessage += "TO: '" + o.arrivalAirport + "'.";
// This simulates the sending of an EDI message.
PrintStream ediProcessor = System.out;
ediProcessor.print(ediMessage);
}
protected String getCompany() {
// The default is North-American Flights.
return "NAF";
}
}
Although static variables are not recommended (as they can misbehave), this is just a simulation so I'll use one anyway.
Notice how electronic document interchange (EDI) is being simulated (very
poorly) by printing to System.out. Also worth noting is the
separation of the processing in three methods. Why did we do that? To allow for
more reuse. onMessage() is the same in all three classes.
processOrder() is the same in OrderBean and
POAOrderBean. Only getCompany() (a single line) is
different in all three classes. So now let's have a look at these two last (and
extremely small) classes:
Example 6 -- POAOrderBean business logic methods
public class POAOrderBean extends baseorder.OrderBean {
...
protected String getCompany() {
return "POA";
}
}
Example 7 -- CAOrderBean business logic methods
public class CAOrderBean extends baseorder.OrderBean {
...
public void processOrder(OrderMessage o) {
// This order is handled by sending an email to this address:
String orderingBroker = "broker@FictiveCompany.com";
String messageBody = "Dear Fictive Company,\n\n";
messageBody += "Please send a ticket to this customer: " + o.name + "\n";
messageBody += " Going from: " + o.departureAirport + "\n";
messageBody += " To: " + o.arrivalAirport + "\n";
messageBody += " Aboard a " + getCompany() + " flight.\n\n";
messageBody += "Bill me to this account number: 3920938402192.\n\n";
messageBody += "Thank you so much,\n\n";
messageBody += "RTM automatic ordering system.";
// Here we would use the Mail API to send this email but this
// is not the purpose of this example so we'll just print the message.
System.out.println("\n============");
System.out.println("Sent this message to " + orderingBroker + " : ");
System.out.println(messageBody);
System.out.println("\n============");
}
protected String getCompany() {
return "CA";
}
}
Forgive my poor simulation of sending an email.
Message Selectors
All classes are now written. Lastly, we write the deployment descriptors.
In particular, the content of ejb-jar.xml interests us, because we
want to do branching based on the content of a JMS message field. This is done
with the <message-selector> tag. A message selector is a
string resembling the inside of an SQL WHERE clause. It contains a condition. When a message arrives, the JMS server will find a message listener for which the message fulfills the condition. For more information about message selector syntax, check out Sun's
documentation for the Message class.
Now I'll just list the three beans' <message-driven>
tags, with the message selector in red.
Example 8 -- ejb-jar.xml, message-driven bean descriptors
<!-- Base Order (Message-Driven) -->
<message-driven>
<ejb-name>OrderEJB</ejb-name>
<ejb-class>baseorder.OrderBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-selector>
<