Exploring EJB3 With JBoss Application Server Part -4

Arya MirServers

May 15, 2012 (5 years and 1 month ago)

913 views

A Message driven bean is a type of EJB that executes business logic on receipt of an asynchronous request. A client cannot directly initiate an action on a Message driven bean. Instead, a client sends a request to a messaging end-point managed by the EJB container and the container on behalf of the client invokes the appropriate Message driven bean configured for that messaging end-point. The messaging end-point we would be dealing with is Java Message Service (JMS).

Exploring EJB3 With JBoss Application Server
Part -4
By Swaminathan Bhaskar
12/12/2008
6. Message Driven Bean
A Message driven bean is a type of EJB that executes business logic on receipt of an asynchronous

request. A client cannot directly initiate an action on a Message driven bean. Instead, a client sends a

request to a messaging end-point managed by the EJB container and the container on behalf of the

client invokes the appropriate Message driven bean configured for that messaging end-point. The

messaging end-point we would be dealing with is Java Message Service (JMS).
Before we dive into Message driven beans, we need to understand the core concepts of Java Message

Service (JMS).
A Java Message Service (JMS in short) is a standard enterprise api for asynchronous messaging. It

allows one or more applications in different networks to communicate with each other using messages.

Messages can be thought of as wrappers around application data. One or more applications publish or

send messages, while one or more applications consume or receive messages. This message exchange

happens via a messaging destination. A messaging Destination is analogous to a mailbox which has an

unique address. As a result the Publisher and Consumer are decoupled and this facilitates asynchronous

communication.
A JMS Message consists of three parts: header, properties, and data payload. Message header contains

a set of predefined meta information such as the message creation time, senders identification, etc.

Message properties is optional and can contain application specific meta information. Data payload

contains the actual application data. It can contain data as text, xml, bytes, stream, or map. and

accordingly the JMS api supports different messages to support these data payload types.
With JMS, there are two modes of asynchronous communication: Publish-Subscribe and Point-to-
Point. In Publish-Subscribe mode, there can be many publishers and many subscribers. A message sent

by a publisher is consumed by all the subscribers. The messaging destination in the Publish-Subscribe

mode is called a
Topic
. In the Point-to-Point mode, there can be many publishers but only one

subscriber. A message sent by a publisher is consumed by only one subscriber. The messaging

destination in the Point-to-Point mode is called a
Queue
.
In Part-1, we setup two JMS destinations – one was a Topic called
Part4Topic
and the other was a

Queue called
Part4Queue
. We will be using these JMS destinations in the following examples.
We will now look at a simple JMS example using the Publish-Subscribe model. In this example, a hot

deals publisher sends deal alerts to the topic
Part4Topic
while one or more deal subscribers are waiting

to consume the deal alerts. Both the publisher and the subscriber are standalone JVM instances that run

outside the JBoss Application Server and access the JMS messaging infrastructure inside the JBoss

Application Server instance.
The following shows the JMS deal publisher called DealPublisher:
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/
package deal.jms;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.Session;
import javax.jms.TopicSession;
import javax.jms.TopicPublisher;
import javax.jms.Topic;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DealPublisher {
private TopicConnectionFactory _tcf;
private TopicConnection _tc;
private TopicSession _ts;
private TopicPublisher _tp;

public static void main(String[] args) {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
DealPublisher pub = new DealPublisher();
pub.init();

boolean exit = false;
while (! exit) {
System.out.print("Enter Deal or q to Quit: ");

String choice = input.readLine();
if (choice.equalsIgnoreCase("q")) {
exit = true;
}
else {
pub.send(choice);
}
}

pub.destroy();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}

public void init()
throws Exception {
Context ctx = new InitialContext(); // 1

_tcf = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); // 2

_tc = _tcf.createTopicConnection(); // 3

_ts = _tc.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // 4

Topic topic = (Topic) ctx.lookup("topic/Part4Topic"); // 5

_tp = _ts.createPublisher(topic); // 6
}

public void send(String deal) {
try {
TextMessage msg = _ts.createTextMessage(deal); // 7

_tp.publish(msg); // 8

System.out.println("Sent Alert @ Time: " + new Date() + ", Deal: " + deal);
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}

public void destroy() {
try {
_tc.close();
}
catch (Exception e) {
}
}
}
When the above code is executed, it prompts the user for deals and then publish it to the topic which is

consumed by subscriber(s) listening on the topic.
The following are some of the steps performed in the “
init()
” and “
send()
” methods of the publisher:
1.
Initialize the JNDI context so that we can lookup JMS resources from the JBoss Application

Server
2.
Lookup the JMS resource TopicConnectionFactory. TopicConnectionFactory is a factory object

that creates instances of TopicConnection object
3.
Use the TopicConnectionFactory to create an instance of TopicConnection. TopicConnection

enables us to connect to the JMS messaging server
4.
Use the TopicConnection to create an instance of TopicSession. TopicSession is a factory object

for creating an instance of TopicPublisher or JMS Message. The first parameter to the method

createTopicSession indicates whether we want transaction. In our example we set it to false (no

transaction). The second parameter is the mode of message acknowledgement. In our case we

set it to auto acknowledge
5.
Lookup the JMS Topic where we are going to publish deal alerts. In our case it is


topic/Part4Topic
”. It is the JMS destination where the deal alerts will be published and

consumed
6.
Create an instance of TopicPublisher. Using TopicPublisher we can send deal alerts to the

associated Topic asynchronously
7.
Create an instance of the JMS TextMessage. The JMS TextMessage allows us to send messages

containing text data. In our case, deal alerts will be sent out as text
8.
Use the instance of TopicPublisher to send the message to our Topic called
Part4Topic
The following shows the JMS deal subscriber called DealSubscriber:
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/
package deal.jms;

import java.util.Date;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.Session;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.jms.Topic;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.jms.MessageListener;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DealSubscriber {
private String _name;

private TopicConnectionFactory _tcf;
private TopicConnection _tc;
private TopicSession _ts;
private TopicSubscriber _tsb;

public static void main(String[] args) {
if (args.length != 1) {
System.out.println("java deal.jms.DealSubscriber <name>");
System.exit(1);
}

try {
DealSubscriber sub = new DealSubscriber();
sub.init(args[0]);
sub.start();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}

public void init(String name)
throws Exception {
_name = name;

Context ctx = new InitialContext();

_tcf = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");

_tc = _tcf.createTopicConnection();

_ts = _tc.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

Topic topic = (Topic) ctx.lookup("topic/Part4Topic");

_tsb = _ts.createSubscriber(topic); // 1
_tsb.setMessageListener(new DealCatcher()); // 2
}

public void start()
throws Exception {
System.out.println("Started subscriber " + _name + " for deals");

_tc.start(); // 3
}

private class DealCatcher implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
TextMessage deal = (TextMessage) msg;

System.out.println(_name + ": Got Alert @ Time: " + new Date() + ", Deal:

" + deal.getText());
}
catch (Exception e) {
}
}
}
}
When the above code is executed, it consumes any deal alert messages on the topic and displays it on

the screen.
The following are some of the steps performed in the “
init()
” and “
start()
” methods of the subscriber:
1.
Create an instance of TopicSubscriber. TopicSubscriber allows us to consume messages from a

Topic
2.
When the TopicSubscriber receives a message asynchronously from the JMS messaging server,

it will dispatch the message to a registered listener. The listener is any class that implements the

MessageListener interface. The MessageListener interface has one method called


onMessage()
” that is invoked each time a message is received. Here we are setting the

message listener class. In our case the inner class DealCatcher implements the MessageListener

interface
3.
Start consumption of messages from the JMS destination. This is a very important step. Without

this no messages will be delivered by the JMS messaging server
Next, we will compile the code and bundle it into a single client jar called “
my_ejb_clients.jar
”.
Now, open a Terminal window and execute the script “
DealPublisher.sh
” as illustrated below:
$ DealPublisher.sh
Enter Deal or q to Quit: Free Coffee @ Cool Coffee Spot
Sent Alert @ Time: Wed Dec 12 22:42:47 EST 2008, Deal: Free Coffee @ Cool Coffee Spot
Enter Deal or q to Quit: Free T-Shirt @ T-Fashions
Sent Alert @ Time: Wed Dec 12 22:44:16 EST 2008, Deal: Free T-Shirt @ T-Fashions
Enter Deal or q to Quit: q
Now, open two other Terminal windows and execute the script “
DealSubscriber.sh
” as illustrated

below:
$ DealSubscriber.sh Sub-1
Started subscriber Sub-1 for deals
Sub-1: Got Alert @ Time: Wed Dec 12 22:42:47 EST 2008, Deal: Free Coffee @ Cool Coffee Spot
Sub-1: Got Alert @ Time: Wed Dec 12 22:44:16 EST 2008, Deal: Free T-Shirt @ T-Fashions
$ DealSubscriber.sh Sub-12
Started subscriber Sub-1 for deals
Sub-2: Got Alert @ Time: Wed Dec 12 22:42:47 EST 2008, Deal: Free Coffee @ Cool Coffee Spot
Sub-2: Got Alert @ Time: Wed Dec 12 22:44:16 EST 2008, Deal: Free T-Shirt @ T-Fashions
The point we want to make here is that both the subscribers Sub-1 and Sub-2 see the deal alerts at the

same time its published. This illustrates the Publish-Subscribe model.
Now, we will look at another simple JMS example using the Point-to-Point model. In this example, a

publisher sends Pizza orders (hmm, yummy !!!) to the queue
Part4Queue
which is consumed and

processed by a Pizza delivery agent. Both the publisher and the subscriber are standalone JVM

instances that run outside the JBoss Application Server and access the JMS messaging infrastructure

inside the JBoss Application Server instance.
The following shows the JMS Pizza order sender called OrderPizza:
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/
package pizza.jms;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueConnection;
import javax.jms.Session;
import javax.jms.QueueSession;
import javax.jms.QueueSender;
import javax.jms.Queue;
import javax.jms.MapMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
public class OrderPizza {
private int _orderNo = 0;

private QueueConnectionFactory _qcf;
private QueueConnection _qc;
private QueueSession _qs;
private QueueSender _qsnd;

public static void main(String[] args) {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

OrderPizza order = new OrderPizza();
order.init();

boolean exit = false;
while (! exit) {
System.out.print("Enter Pizza Order or q to Quit: ");

String choice = input.readLine();
if (choice.equalsIgnoreCase("q")) {
exit = true;
}
else {
order.send(choice);
}
}

order.destroy();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}

public void init()
throws Exception {
Context ctx = new InitialContext();

_qcf = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");

_qc = _qcf.createQueueConnection();

_qs = _qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

Queue queue = (Queue) ctx.lookup("queue/Part4Queue");

_qsnd = _qs.createSender(queue);
}

public void send(String arg) {
try {
_orderNo++;

MapMessage msg = _qs.createMapMessage();
msg.setInt("OrderNo", _orderNo);
msg.setString("Order", arg);

_qsnd.send(msg);

System.out.println("Sent Pizza Order @ Time: " + new Date() + ", Order #: " +

_orderNo + ": " + arg);
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}

public void destroy() {
try {
_qc.close();
}
catch (Exception e) {
}
}
}
When the above code is executed, it prompts the user for yummy Pizza orders and then sends it to the

queue for processing and delivery.
This is similar to the DealPublisher except that its uses JMS QueueConnectionFactory,

QueueConnection, QueueSession, etc. In this example, we are using JMS MapMessage to send and

receive Pizza orders. MapMessage contains name-value pairs and in our example we have the


OrderNo
” and “
Order
” information tucked into the MapMessage.
The following shows the JMS Pizza delivery agent called DeliverPizza:
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/
package pizza.jms;
import java.util.Date;

import javax.jms.QueueConnectionFactory;
import javax.jms.QueueConnection;
import javax.jms.Session;
import javax.jms.QueueSession;
import javax.jms.QueueReceiver;
import javax.jms.Queue;
import javax.jms.Message;
import javax.jms.MapMessage;
import javax.jms.MessageListener;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DeliverPizza {
private String _name;

private QueueConnectionFactory _qcf;
private QueueConnection _qc;
private QueueSession _qs;
private QueueReceiver _qrcv;

public static void main(String[] args) {
if (args.length != 1) {
System.out.println("java deal.jms.DealSubscriber <name>");
System.exit(1);
}

try {
DeliverPizza delivery = new DeliverPizza();
delivery.init(args[0]);
delivery.start();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}

public void init(String arg)
throws Exception {
_name = arg;

Context ctx = new InitialContext();

_qcf = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");

_qc = _qcf.createQueueConnection();

_qs = _qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

Queue queue = (Queue) ctx.lookup("queue/Part4Queue");

_qrcv = _qs.createReceiver(queue);
_qrcv.setMessageListener(new PizzaDelivery());
}

public void start()
throws Exception {
System.out.println("Started Pizza Delivery " + _name);

_qc.start();
}

private class PizzaDelivery implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
MapMessage order = (MapMessage) msg;

System.out.println(_name + ": Delivered Pizza @ Time: " + new Date() + ",

Order #: " + order.getInt("OrderNo") + ": " + order.getString("Order"));
}
catch (Exception e) {
}
}
}
}
When the above code is executed, it consumes Pizza order messages on the queue and displays it on the

screen.
This is similar to the DealSubscriber except that it uses a JMS queue related objects.
Next, we will compile the code and bundle it into a single client jar called “
my_ejb_clients.jar
”.
Now, open a Terminal window and execute the script “
OrderPizza.sh
” as illustrated below:
$ OrderPizza.sh
Enter Pizza Order or q to Quit: Large Pizza for Martin
Sent Pizza Order @ Time: Thu Dec 12 22:59:14 EST 2008, Order #: 1: Large Pizza for Martin
Enter Pizza Order or q to Quit: Medium Pizza/w Onions for Anna
Sent Pizza Order @ Time: Thu Dec 12 22:59:47 EST 2008, Order #: 2: Medium Pizza/w Onions for

Anna
Enter Pizza Order or q to Quit: Small Pizza for James
Sent Pizza Order @ Time: Thu Dec 12 23:00:07 EST 2008, Order #: 3: Small Pizza for James
Enter Pizza Order or q to Quit: q
Now, open two other Terminal windows and execute the script “
DeliverPizza.sh
” as illustrated below:
$ DeliverPizza.sh John
Started Pizza Delivery John
John: Delivered Pizza @ Time: Thu Dec 12 22:59:14 EST 2008, Order #: 1: Large Pizza for Martin
John: Delivered Pizza @ Time: Thu Dec 12 22:59:47 EST 2008, Order #: 2: Medium Pizza/w Onions

for Anna
John: Delivered Pizza @ Time: Thu Dec 12 23:00:07 EST 2008, Order #: 3: Small Pizza for James
$ DeliverPizza.sh Martin
We have two DeliverPizza instances running – one called John and the other called Martin. As you can

see only John gets the orders and delivers Pizzas while Martin does nothing. This illustrates the Point-
to-Point model.
With this we have covered the core concepts of JMS and are now ready to explore Message Driven

Beans. Message Driven Beans are container managed enterprise components that perform some action

upon receipt of an asynchronous message via JMS destination on which they are listening. They do not

maintain any conversation state and hence are similar to stateless session beans. Although there is an

implementation class for Message Driven Beans, they do not implement any business specific Remote

or Local interfaces as is the case with Session Beans. They only implement the JMS listener interface

javax.jms.MessageListener. As a result clients cannot directly invoke any method on the Message

Driven Beans. Clients can only send a message to a JMS destination, which causes the EJB container to

invoke the “
onMessage()
” method on the Message Driven Bean that is configured as a consumer for

that JMS destination.
Now, we will look at our first example on message driven beans using EJB3 annotations. This

hypothetical example illustrates the case of a new employee hire in a firm. When a new employee is

hired, the IT department needs to be notified for PC setup and the HR department needs to be notified

of Benefits enrollment. For this example, we have two message driven beans – one that represents the

IT department and the other represents the HR department and both consume messages from the JMS

topic Part4Topic.
The following shows the message driven bean implementation for HR department:
T
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/

package hire.ejb;
p
import javax.jms.Message;
import javax.jms.MapMessage;
import javax.jms.MessageListener;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.ejb.ActivationConfigProperty;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
i
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="destination", propertyValue="topic/Part4Topic")
})
public class HRDeptBean implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
if (msg instanceof MapMessage) {
MapMessage mapMsg = (MapMessage) msg;
M
String emp = mapMsg.getString("Employee");
String hdt = mapMsg.getString("HireDate");
S
System.out.println("Enroll new employee: " + emp + " in Benefits by " +

hdt);
}
}
catch (Exception ex) {
throw new EJBException(ex);
}
}
}
@PostConstruct
public void init() {
System.out.println("Post Construct on HR Department Message Driven Bean");
}
}
@PreDestroy
public void destroy() {
System.out.println("Pre Destroy on HR Department Message Driven Bean");
}
}
The
@MessageDriven
annotation configures the bean to be a message driven bean. This annotation

specifies configuration properties for the message driven bean such as the destination type, the

destination end-point, etc., by specifying one or more @ActivationConfigProperty annotations. In the

above example, we specify one
@ActivationConfigProperty
for the destination type to be a JMS Topic

and the other
@ActivationConfigProperty
for the destination end-point to be “
topic/Part4Topic
”.
In the “onMessage()” method, we get the employee name and the hire date from the MapMessage and

display a message.
The following shows the message driven bean implementation for IT department:
T
/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/

package hire.ejb;
p
import javax.jms.Message;
import javax.jms.MapMessage;
import javax.jms.MessageListener;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.ejb.ActivationConfigProperty;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
i
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="destination", propertyValue="topic/Part4Topic")
})
public class ITDeptBean implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
if (msg instanceof MapMessage) {
MapMessage mapMsg = (MapMessage) msg;
M
String emp = mapMsg.getString("Employee");
String hdt = mapMsg.getString("HireDate");
S
System.out.println("PC setup for new employee: " + emp + " by " + hdt);
}
}
catch (Exception ex) {
throw new EJBException(ex);
}
}
}
@PostConstruct
public void init() {
System.out.println("Post Construct on IT Department Message Driven Bean");
}
}
@PreDestroy
public void destroy() {
System.out.println("Pre Destroy on IT Department Message Driven Bean");
}
}
It is similar to the HR department message driven bean in that we get the employee name and the hire

date from the MapMessage and display a message.

The following shows a standalone client that publishes a map message to the JMS destination


topic/Part4Topic
” each time a new employee is hired:

/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/

package hire.client;
p
import java.io.BufferedReader;
import java.io.InputStreamReader;
i
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.Session;
import javax.jms.TopicSession;
import javax.jms.TopicPublisher;
import javax.jms.Topic;
import javax.jms.MapMessage;
i
import javax.naming.Context;
import javax.naming.InitialContext;
i
public class HireEmployee {
private TopicConnectionFactory _tcf;
private TopicConnection _tc;
private TopicSession _ts;
private TopicPublisher _tp;
p
public static void main(String[] args) {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
B
HireEmployee hire = new HireEmployee();
hire.init();
h
boolean exit = false;
while (! exit) {
System.out.print("Enter Name or q to Quit: ");
S
String name = input.readLine();
if (name.equalsIgnoreCase("q")) {
exit = true;
}
else {
System.out.print("Enter Hire Date (mm/dd/yyyy): ");
S
String date = input.readLine();
S
hire.send(name, date);
}
}
}
hire.destroy();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}
}
public void init()
throws Exception {
Context ctx = new InitialContext();
C
_tcf = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");
_
_tc = _tcf.createTopicConnection();
_
_ts = _tc.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
_
Topic topic = (Topic) ctx.lookup("topic/Part4Topic");
T
_tp = _ts.createPublisher(topic);
}
}
public void send(String name, String date) {
try {
MapMessage msg = _ts.createMapMessage();
msg.setString("Employee", name);
msg.setString("HireDate", date);
m
_tp.publish(msg);
_
System.out.println("Hire new employee, Name: " + name + ", Date: " + date);
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
public void destroy() {
try {
_tc.close();
}
catch (Exception e) {
}
}
}
On executing the client, it prompts for the new employee name the hire date and publishes a map

message to the topic “
topic/Part4Topic
”.
Next, we will compile and deploy the EJB jar “
my_ejb_beans.jar
” into the JBoss Application Server.

Note that all the EJBs we develop will be bundled into a single jar called “
my_ejb_beans.jar
” for

convenience.
Now, open a Terminal window and execute the script “
HireEmployee.sh
” as illustrated below:
$ HireEmployee.sh
Enter Name or q to Quit: Bhaskar
Enter Hire Date (mm/dd/yyyy): 12/12/2008
Hire new employee, Name: Bhaskar, Date: 12/12/2008
Enter Name or q to Quit: q
From the JBoss Application Server log (server/default/log/server.log), we can see the following lines

when the client publishes the new hire message to the JMS destination “
topic/Part4Topic
”:
23:31:25,062 INFO [STDOUT] Post Construct on IT Department Message Driven Bean
23:31:25,062 INFO [STDOUT] PC setup for new employee: Bhaskar by 12/12/2008
23:31:25,064 INFO [STDOUT] Post Construct on HR Department Message Driven Bean
23:31:25,065 INFO [STDOUT] Enroll new employee: Bhaskar in Benefits by 12/12/2008
Like the stateless session beans, the message driven beans do not maintain client conversational state

between method calls. But this does not mean the message driven bean cannot have references to

resources such as a database connection object or a socket connection object, etc. To do that, message

From the above XML deployment descriptor file, it is clear that the EJB is named “
ComplianceAudit


and it is a message driven bean. In additional, the configuration indicates the bean implementation class

and the JMS destination “
queue/Part4Queue
”.
The following shows a standalone client that publishes a map message to the JMS destination “
queue/
Part4Queue
” each time an online transaction is performed:

/*
* Name: Bhaskar S
*
* Date: 12/12/2008
*/

package comply.client;
p
import java.io.BufferedReader;
import java.io.InputStreamReader;
i
import java.util.Date;
i
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueConnection;
import javax.jms.Session;
import javax.jms.QueueSession;
import javax.jms.QueueSender;
import javax.jms.Queue;
import javax.jms.MapMessage;
i
import javax.naming.Context;
import javax.naming.InitialContext;
i
public class OnlineAccount {
private String _name;
private String _acctNo;
p
private double _balance = 0.0;
p
private QueueConnectionFactory _qcf;
private QueueConnection _qc;
private QueueSession _qs;
private QueueSender _qsnd;
p
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Usage: java comply.client.OnlineAccount <name> <acct-no>");
System.exit(1);
}
}
try {
OnlineAccount acct = new OnlineAccount();
acct.init(args[0], args[1]);
acct.transaction();
acct.destroy();
}
catch (Throwable ex) {
ex.printStackTrace(System.err);
}
}
}
public void init(String name, String num)
throws Exception {
_name = name;
_acctNo = num;
_
Context ctx = new InitialContext();
C
_qcf = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
_
_qc = _qcf.createQueueConnection();
_
_qs = _qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
_
Queue queue = (Queue) ctx.lookup("queue/Part4Queue");
Q
_qsnd = _qs.createSender(queue);
}
}
public void transaction()
throws Exception {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
B
boolean exit = false;
while (! exit) {
System.out.println("1. Credit");
System.out.println("2. Debit");
System.out.println("3. Quit");
S
String choice = input.readLine();
S
if (choice.equals("1")) {
System.out.print("Amount: ");
String amtStr = input.readLine();
double amt = Double.parseDouble(amtStr);
if (amt > 0.0) {
_balance += amt;
}
System.out.println("-> Balance after credit: " + _balance);
send(amt);
}
else if (choice.equals("2")) {
System.out.print("Amount: ");
String amtStr = input.readLine();
double amt = Double.parseDouble(amtStr);
if (_balance > amt) {
_balance -= amt;
}
System.out.println("-> Balance after debit: " + _balance);
send(amt);
}
else if (choice.equals("3")) {
exit = true;
}
}
}
}
public void destroy() {
try {
_qc.close();
}
catch (Exception e) {
}
}
}
void send(double amt) {
try {
MapMessage msg = _qs.createMapMessage();
msg.setString("AccountNo", _acctNo);
msg.setString("AccountOwner", _name);
msg.setDouble("TransactionAmount", amt);
m
_qsnd.send(msg);
_
System.out.println("Sent Transaction @ Time: " + new Date() + ", Acct #: " +

_acctNo + ", Amount: " + amt);
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
Next, we will compile and deploy the EJB jar “
my_ejb_beans.jar
” into the JBoss Application Server.
Now, open a Terminal window and execute the script “
OnlineAccount.sh
” as illustrated below:
$ OnlineAccount.sh Bhaskar 12345
1. Credit
2. Debit
3. Quit
1
Amount: 1000
-> Balance after credit: 1000.0
Sent Transaction @ Time: Fri Dec 12 23:55:25 EST 2008, Acct #: 12345, Amount: 1000.0
1. Credit
2. Debit
3. Quit
1
Amount: 20000
-> Balance after credit: 21000.0
Sent Transaction @ Time: Fri Dec 12 23:55:41 EST 2008, Acct #: 12345, Amount: 20000.0
1. Credit
2. Debit
3. Quit
2
Amount: 200
-> Balance after debit: 20800.0
Sent Transaction @ Time: Fri Dec 12 23:56:03 EST 2008, Acct #: 12345, Amount: 200.0
1. Credit
2. Debit
3. Quit
2
Amount: 11000
-> Balance after debit: 9800.0
Sent Transaction @ Time: Fri Dec 12 23:56:10 EST 2008, Acct #: 12345, Amount: 11000.0
1. Credit
2. Debit
3. Quit
3
From the JBoss Application Server log (server/default/log/server.log), we can see the following lines

when the client publishes the new transaction message to the JMS destination “
queue/Part4Queue
”:
23:55:25,078 INFO [STDOUT] Post Construct on Compliance Audit Message Driven Bean
23:55:41,097 INFO [STDOUT] Audit Account Number: 12345, Owner: Bhaskar, Amount: 20000.0, Date: Fri

Dec 12 23:55:41 EST 2008
23:56:10,771 INFO [STDOUT] Audit Account Number: 12345, Owner: Bhaskar, Amount: 11000.0, Date: Fri

Dec 12 23:56:10 EST 2008
For the above JBoss Application Server log (server/default/log/server.log), it is clear that the first

transaction of credit 1000 and the third transaction of debit 200 are not audited. Only the large amount

transactions of credit 20000 and debit 11000 are audited by the Compliance.
This concludes our journey into Message Driven Beans.
We will explore EJB Timers and Interceptors in Part-5 of this series.