The following tutorial illustrates how an MDB is written and deployed in an EJB 2.0 Container. The MDB component is invoked by an inbound message from a Java client. This is demonstrated with a sample application that is deployable on Pramati Server 3.0. The application source is provided for better understanding of how MDB components are written. Download sample here.
What is a Message Driven Bean
Structure
Lifecycle
Writing an MDB
Sample application
Defining the MDB class
Implementing the business logic
Implementing the ejbCreate() method
Providing methods for transactional management
Removing the instance
Acknowledging messages
Setting up a response
Deploying the MDB
Elements in the deployment descriptor
Running the sample
Configuring the Message Server
Elements in the deployment descriptor
A message driven bean is a stateless server-side transaction-aware component that is driven by a message (javax.jms.message). It is invoked by the EJB Container when a message is received from a JMS Queue or Topic. It acts as a simple message listener.
A Java client, an enterprise bean or Java ServerPages (JSP) component, or a non-J2EE application may send the message. The client sending the message to the destination need not be aware of the MDBs deployed in the EJB Container. However, the message must conform to JMS specification.
Before MDBs were introduced, JMS described a classical approach to implement asynchronous method invocation. The approach used an external Java program that acted as the listener, and on receiving a message, invoked a session bean method.
However, in this approach, the message was received outside the application server and thus not part of a transaction in the EJB Server. MDB solves this problem.
The EJB Container performs several tasks at the beginning of the life cycle of the MDB:
The lifecycle of an MDB depends on the lifespan of the EJB Server in which it is deployed. As MDBs are stateless, bean instances are typically pooled by the EJB Server and retrieved by the Container when a message becomes available on the topic or queue.
Writing an MDB involves the following tasks:
The tutorial uses a sample application,
An MDB implements two interfaces: javax.jms.MessageListener and javax.ejb.MessageDrivenBean. The MDB class is defined as public and cannot be defined as abstract or final. The MDB class looks like this:
The class must consist of:
The class must not contain the
Business logic for the EJB is triggered by the onMessage() method of the MDB. The onMessage() is called by the Container when the JMS Queue or Topic receives a message. The onMessage() does not return any result and has one argument. The full JMS message object is passed as an argument.
The signature for the method is:
In the sample, when there is a message on the
The following code of the
The
The following code of the BuyAgentMDB performs this function:
The setMessageDrivenContext provides the methods for transaction management. The BuyAgentMDB implements setMessageDrivenContext. This method is called by the EJB Container to associate the BuyAgent instance. The context is maintained by the Container.
The input parameter for setMessageDrivenContext is an instance of the MessageDrivenContext interface. It gives the MDB access to information about the runtime environment.
In Container-managed transactions, de-queuing occurs out of the onMessage(). The only methods on the MessageDrivenContext that are accessible to the MDB are transaction-related methods.
This method is invoked when an MDB is being removed from a pool. Application server vendors may implement an arbitrary algorithm that decides when to remove the MDB instances from the pool.
The following code of the BuyAgentMDB performs this function:
For MDBs that use container-managed transactions, the Container automatically acknowledges a message when the EJB transaction commits. The Container over-rides the acknowledgement mode given in the deployment descriptor. If the EJB uses bean-managed transactions, both the receipt and the acknowledgement of a message occur outside the EJB transaction context.
Some business cases may require responding to the Sender of the message that triggered the MDB. To register the "reply to" destination of the Sender, the client can use getJMSReplyTo header.
The JMSReplyTo header field contains a destination supplied by the client along with the message. It is the destination where a "reply to the message" may be sent. Messages sent with JMSReply value typically expect a response.
The code to use JMSReplyTo header looks like this:
The destination associated with an MDB is specified in the deployment descriptor of the MDB in the ejb-jar.xml file. A destination is a JMS administered object accessible via JNDI.
Here is a sample destination entry in the deployment descriptor:
The description of a MDB in the EJB 2.0 deployment descriptor contains the following specific elements:
The MDB deployment descriptor specifies whether the bean is intended for a Topic or a Queue. A bean set for a Topic can act as a durable subscriber guaranteeing that the listener receives all messages even if the listener is unavailable for some time. The deployment descriptor also sets transaction demarcation and security.
If the transaction type is "container", the transactional behavior of MDB methods is defined as for other enterprise beans in the deployment descriptor.
Here is the entry for transaction type in the deployment descriptor:
For the onMessage method, only the Required or NotSupported transaction attribute must be used as there are no incoming transaction context.
The important thing to notice is that the deployment descriptor contains all the information except the destination name required to deploy a message-driven bean. The destination name is set in an application server's vendor-specific configuration file or as a system property (deploy time mapping).
The configuration file is located in the directory
The following steps will deploy the application on Pramati Server:
When the Server starts, click on the
Select Set the classpath as follows:
Run the file Add the following location of the application classes to the client classpath:
Unix
The stock repository is run by the client
This brings up the stock repository panel which displays the scrip and the price along with a Buy/Sell advisory message.
Observe the price fluctuates every time buying or selling happens.
MDBs overcome the limitations of synchronous messaging using session and entity beans in the EJB 1.1 container. MDBs can be deployed in EJB 2.0 Container, which acts as a message listener and uses inbound messages as a trigger to invoke business methods in an asynchronous manner.
This tutorial outlined the steps involved in writing an MDB using a sample application that may be downloaded from www.pramati.com.
Message processing before (above) and after (below) Message Driven Beans.
Structure of an MDB
Lifecycle of an MDB
Writing an MDB
Sample application
StockTrader, to illustrate the writing of an MDB using a simple message driven bean buyAgentMDB that is contacted by a client which wishes to buy shares. The client looks up the BuyQueue and implements the javax.jms.MessageListener. It provides a private method buy() that takes two arguments: a double value that holds the price and a string stockSymbol that holds the scrip symbol.
Defining the MDB Class
public class BuyAgentMDB
implements MessageDrivenBean, MessageListener {
private MessageDrivenContext mdbContext;
finalize method.
Implementing business logic
public void onMessage(Message msg) {}
BuyQueue, the onMessage() method of the BuyAgent picks up the message and sends it to the topic StockMarket. The StockRepository in turn looks up this topic.
buyAgentMDB performs this function:
public void onMessage(Message msg) {
// Retrieves the text message
TextMessage priceMessage = (TextMessage) msg;
try {
}
catch(JMSException ex)
{ ex.printStackTrace();
}
}
Implementing the ejbCreate method
ejbCreate() is called at the time of bean instantiation, in order to allocate resources such as connection factories if the bean send messages or datasources, if the bean accesses databases. This method is invoked once in the lifecycle - when the bean is created.
public void ejbCreate () throws CreateException
{
}
Providing methods for transactional management
Removing the instance
public void ejbRemove()
{
//Removes the bean from the pool
}
Acknowledging messages
Setting up the response
public void onMessage(Message msg){
try{
destination d = msg.getJMSReplyTo()
}
catch(JMSException jmse){} }
Deploying the MDB
<message-driven-destination>
<destination-type>javax.jms.Topic</destination-type>
<subscription-durability>NonDurable</subscription-durability>
</message-driven-destination>
Elements in the deployment descriptor
<transaction-type>Container</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
Message Server configuration
By default, the following destinations are entered in the configuration file of the Message Server:
[install_dir]/jms/config/jms-config.xml.
Deployment steps
Note: For more detail on operating Pramati Server, refer product documentation.
runadmin.sh from the Server installation directory.
Server > Start from the main menu. This brings up the Start Server dialog where the J2EE Server to start is identified. Check the Start JMS Server option to start the Message Server along with the J2EE Server. This is essential to be able to run the message driven beans.
Deploying the application
Deploy button in the view panel of the Console to start the Deploy Tool.
Archive > Open and open the application stockapp.ear from the following location:
[install_dir]/samples/mdb/
Running the client
Windows
run.bat from the directory
[install_dir]/samples/mdb.
[install_dir]/server/samples/mdb/classes
export CLASSPATH=$install_root/server/samples/mdb/classes:%$CLASSPATH
Starting the stock repository
StockServer.java. Start the client by executing:
java com.pramati.samples.mdb.StockServer
Summary
© Copyright 2001-2002, Pramati Technologies.