EJB Inheritance, Part 4
by Emmanuel Proulx
01/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.
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)
• Canada
• Mexico
|
EDI |
| Pacific Ocean Air (POA) |
• Hawaii
• Asia
• Oceania
|
EDI |
| Continent Air (CA) |
• Europe
• Africa
• Other
|
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
What's the best platform for J2EE development? Emmanuel Proulx finds himself answering that question time after time. In this article, he explores several free-as-in-speech and free-as-in-beer EJB 2.0 tools and gives his suggestions for choosing an application server.
EJB Inheritance, Part 3
Session beans can take advantage of inheritance, just like entity beans. Indeed, implementing session bean inheritance is nowhere near as hard as it is with entity beans. Part 3 of this series shows the proper technique for implementing inheritance in session beans and addresses the use of factories.
EJB Inheritance, Part 2
Part two of this series on inheritance with Entity Java Beans focuses on the various options for table mapping.
EJB Inheritance, Part 1
The principles of object-oriented programming are encapsulation and inheritance. Enterprise JavaBeans handle encapsulation just fine, but what about inheritance? In this article, the author attempts to apply inheritance to EJBs.
|
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
company field 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
company field set to the proper value.
- Finally, one of the other listeners picks up the order, based on the value
in the
company field.
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(), and ejbRemove() 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>
<![CDATA[ company = 'NAF' </XMLCDATA>
</message-selector>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
<!-- POA Order (Message-Driven) -->
<message-driven>
<ejb-name>POAOrderEJB</ejb-name>
<ejb-class>poaorder.POAOrderBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-selector>
<![CDATA[ company = 'POA' </XMLCDATA>
</message-selector>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
<!-- CA Order (Message-Driven) -->
<message-driven>
<ejb-name>CAOrderEJB</ejb-name>
<ejb-class>caorder.CAOrderBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-selector>
<![CDATA[ company = 'CA' </XMLCDATA>
</message-selector>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
Delegate or Factory
The OrderDelegate bean is a delegate; it forwards messages to
the real workers. We use it only to inject the needed message selection fields
in the message. This delegate is really a factory for creating messages. There
are many ways to implement such message factories:
- A
Business Delegate or Service Locator
(client-side object that handles the message creation).
- A
Service Activator (a session bean that serves a similar
purpose to our OrderDelegate).
- Etc.
I don't want to get too deep into the details of writing the
OrderDelegate object, mainly because the data is hardcoded in the
bean, which is a bad practice. The point is this: a message arrives, the data is
analyzed. Then, a new message is sent with with one JMS message field added to
the existing content.
Let's not forget a small but important detail. We don't want our delegate to
process the same message over and over again. For this, attach a mutually-exclusive message selector to this delegate. Here's the one we use for our
OrderDelegate:
<message-selector>
<![CDATA[ company IS NULL </XMLCDATA>
</message-selector>
The Last Episode?
This is the last article of the series. Or is it? There's a lot more to be
said about EJB inheritance than there is space in these articles, but I think
at least I provided you with a good push in the right direction. If you have
ideas that you feel are interesting, or if you find I overlooked something,
feel free to drop me a line. Your technical tips are welcome. In particular,
I'm looking for:
- How to automate locate methods. (We shouldn't have to write them.)
- How to use inheritance in container-managed relationships for entity
EJBs.
- Tools and plug-ins that enable EJB inheritance for specific J2EE application
servers.
In the future, I may continue this series if I gather enough interesting
content. EJB inheritance is a fun concept to play with. It requires some work,
but can be very useful. I hope this has been fun, engaging, and useful for you
too.
Emmanuel Proulx
is an expert in J2EE and Enterprise JavaBeans, and is a certified WebLogic Server 7.0 engineer. He
works in the fields of telecommunications and web development.
Return to ONJava.com.