Chapter 7.
Creating a Message Driven BeanThis chapter covers how to create a Message Driven Bean (MDB) EJB component. We will create two MDB beans, DeliverItems and RequestItems as shown below. The DeliverItems bean will replenish the stocks of various items within MyStore, and the RequestItems bean will send requests to various suppliers to deliver items which are out of stock. The MyStore manager will issue/send this request.
Note : Both message-driven beans access the StoreAccess bean through its remote interface, even though the StoreAcessBean is in the same JVM. This is because we have implemented StoreAccessBean as a Remote Bean, so it only exposes its remote interface. However, in accessing the Manager and Item beans, which are also used by these message-driven beans we can use their local interfaces as they are in the same JVM, and we have exposed their local interfaces.
Tasks :Create a MD bean named RequestItems under package au.com.tusc.mdb.
Create an Immutable Value Object named RequestItem under package au.com.tusc.mdb. Add attributes and implement their accessor and mutator methods. The attributes are:
private String username
private String passwd
private String itemID
private int quantity
Implement the onMessage method.
Deploy the RequestItems Bean.
Create your test client named RequestMDBClient under package au.com.tusc.mdb.
Add a method named testMDBBean with the following signature and implement it.
public void testMDBBean
Run your client and test the bean.
Create RequestItems MDB Bean :
Go To Package Explorer > Expand Mystore (project) node > select src, right click and a menu will pop up.
On the pop up menu > New > Lomboz EJB Creation Wizard.
Enter package name au.com.tusc.mdb, bean name RequestItems and select bean type as Message Drive Bean (Queue) as shown below.
Press Finish.
This will create a package named au.com.tusc.mdb under src and RequestItemsBean within that package as shown below.
Note : Message-driven beans listen for messages from a JMS Producer, which gets information from a producer (perhaps another bean) and transfers it to the relevant Consumer bean. Since it is only responsible for processing such messages, it doesn't need any helper classes such as Remote and RemoteHome interfaces, Util classes, DAO class, etc. like our previous types of beans. The only helper classes we have to create are immutable value objects, which will be responsible for holding the information extracted from messages and then transferred to the bean(s).
Let's examine what methods and tags are generated by the EJB creation wizard..
It creates one @ejb.bean tag which assigns the name, transaction type, destination type and some other properties as shown below.
Unlike our previous beans it has a setMessageContext method for setting the context.
It has ejbCreate and ejbRemove methods like the other types of beans, as shown below.
It has a new method named onMessage which is the one of significance to us, where all the business logic will be written (as shown below).
Once a message is received from the JMS producer as a Message object, its data is extracted and filled into the immutable value object and then transferred to the relevant bean. This is covered later on in this chapter.
Now, before we add any functionality, create a class or immutable value object for extracting information from the message.
Create Immutable Value Object RequestItem : Go to src > under package au.com.tusc.mdb > New >Class.
The java class wizard will pop up > Add class name as RequestItem, Superclass as java.lang.Object and Interfaces as Serializable as as shown below in figure.
This will generate a RequestItem class under au.com.tusc.mdb as shown below.
Add the following attributes to the RequestItem class as shown below.
private String username;
private String passwd;
private String itemID;
private int quantity;
Add accessor and mutator method for these attributes.
Select all attributes > Right click> Select source > Generate Getter and Setter as shown below.
Add a constructor for the class which has parameters with the same type as the attributes and assigns them to the attributes as shown below.
The RequestItem constructor is complete. Now to implement the onMessage method in the RequestItem Bean.
Implement onMessage Method :This method is responsible for extracting the information from the message and transferring it to the relevant bean.
The MyStore Manager will check for items which are out of stock and generate a request to suppliers specifying the itemID and quantity required.
First import the packages java.util.ArrayList and java.util.Iterator .
Add the following variables to store references.
ArrayList outOfStockItems = null;
Iterator itemsIterator = null;
private StoreAccessHome storeAccess = null;
private SupplierLocalHome suppLocalHome = null;
private ItemLocalHome itemLocalHome = null;
Extract the data from the message into the immutable value object as shown below.
RequestItem ri = (RequestItem) ((ObjectMessage) message).getObject();
Add the lines of code shown below, so that the manager can login.
StoreAccess access = StoreAccessUtil.getHome().create();
String mgrAccessID = access.loginUser(ri.getUsername(),ri.getPasswd());
Get items with zero quantity (no stock), by invoking getOutOfStockItems() on the StoreAccess Bean (which returns a Collection).
outOfStockItems = access.getOutOfStockItems();
Now, iterating over each item, get the supplierId associated with it by invoking the finder methods on the Supplier Bean, finally sending the required message to that supplier by invoking the business method requestItem() on the Supplier Bean.
itemsIterator = outOfStockItems.iterator();
while ( itemsIterator.hasNext() ) {
ItemData itemData= ( ItemData ) itemsIterator.next();
String suppID = itemData.getSupplierID();
SupplierLocal supplier = this.suppLocalHome.findByPrimaryKey(suppID);
Integer quantity = new Integer (ri.getQuantity());
String itemID = ri.getItemID();
supplier.requestItem( itemID, quantity);
}
Code snippet of onMessage is shown below.
Now our bean is complete, and all that remains are the deployment descriptors for the bean.
Deploy RequestItems Bean :In order to deploy this bean we have to add a few deployment descriptors. As shown below, five tags have been added.
First add the tag shown below at class level in the RequestItems Bean, to obtain a reference to StoreAccessBean, so that methods can be invoked on that bean.
@ejb.ejb-ref
ejb-name="StoreAccess"
view-type="remote"
ref-name="StoreAccess"
This tag will generate deployment descriptors in ejb-jar.xml when you generate your ejb classes, as this message bean has to authenticate, before transferring information to the relevant bean. This will generate these descriptors as shown below.
Add another tag as shown below, to obtain a reference to the Supplier Bean from this bean.
@ejb.ejb-ref
ejb-name="Supplier"
view-type="local"
ref-name="SupplierLocal"
This tag will generate also generate descriptors in ejb-jar.xml when you generate your ejb classes, as this message bean transfers information to the Supplier bean. The following descriptors are generated as shown below.
Note : Another descriptor which has been generated is <ejb-name>, which is generated by the tag @ejb.bean that was added by the EJB creation wizard.
This tag generates the following descriptors in ejb-jar.xml:
Add another tag as shown below. This tag is JBOSS-specific, and is used to register a message-driven bean with a jndi-name, using the format "queue/name".
@jboss.destination-jndi-name
name="queue/MdbQueue"
This will generate the following deployment descriptors in jboss.xml:
Note : For further documentation on MDB development with JBOSS, please refer to the JBOSS documentation.
Add another tag as shown below, required by JBOSS, for finding the Supplier bean using its JNDI NAME.
@jboss.ejb-ref-jndi ref-name="SupplierLocal"
jndi-name="SupplierLocal"
Note : As discussed in chapter5, this tag generates incorrect descriptors within jboss.xml. For view-type="local" it generates an <ejb-ref> tag rather than an <ejb-local-ref> tag.
Correct the following tags:
Find these tags in jboss.xml and change them to <ejb-local-ref> as shown below.
Now add this last tag as shown below for our StoreAccess Bean, to reference the StoreAccess bean using its JNDI NAME .
@jboss.ejb-ref-jndi ref-name="StoreAccess"
jndi-name="StoreAccessBean"
This tag will generate the following descriptors in jboss.xml:
Now our RequestItems Bean is complete, so now add your bean and generate your EJB classes.
Go to the RequestItemsBean node under au.com.tusc.mdb > right click > select Lomboz J2EE... > Add EJB to Module > Ok.
Go to the MyStoreMgr node in Package Explorer > right click > select Lomboz J2EE... > Generate EJB classes.
Note : Since you have generated your classes you have to again fix the incorrectly-generated deployment descriptors in jboss.xml, under <message-driven> and <session>.
Now, let's deploy our bean. Go to Lomboz J2EE View, start your server if it is not running, and deploy your bean.
Messages will appear in console showing deployment status.
Note : Steps for deploying beans have been detailed in previous chapters.
Once the bean is deployed successfully, create your test client.
Create Test Client :Now, to create a test client in this case, the Test Client Wizard can't help us, because it requires a Home interface and EJB interface to be selected, whereas for Message Driven Beans there is no Home interface and EJB interface required (as discussed above).
So, write a class and the necessary methods to invoke operations on the RequestItems Bean.
Add a class named RequestMDBClient under the package au.com.tusc.mdb.
Add a method named getContext with the following signature:
private InitialContext getContext() throws NamingException
Add the following lines of code to get the instance of IntialContext as shown below.
Add a method named testMDBBean with the following signature.
public void testMDBBean()
Now implement this method, in which the following steps are needed:
Add a Data Object which is to be sent as the message.
Create the Initial context reference.
Create the Connection factory reference.
Use this context to perform the lookup, where the lookup string is "queue/MdbQueue".
Create the QueueConnection.
Create the QueueSender.
Create the QueueSession for the bean.
Create the Object Message and pass the Data Object in message.
Send the message.
Finally, commit the session, and then close both the session and the connection. A code snippet of the testMDBean method is shown below.
Now your test client is complete, so let's test the client.
Test your Client :To test your client, Select RequestMDBClient node > Go to the top level menu and select the 'Running Man' icon.
On that select 'Run as' > select Java Application.
Note : The steps to run test clients have been covered in previous chapters.
Now, under your console, you should get the following messages:
This message on the console doesn't tell us whether the message has been delivered to relevant beans or not. In order to verify that, go to the database using JMX Management Console View > Hypersonic > Invoke Database Manager and then run a query on table 'supplier' to see if a message has been added for the supplier.
Note: Details on accessing this Database Manager are provided in chapter 1.
Since a supplier named Sebastian has received our message, our message has been transferred successfully.
Exercise :Now, to progress further, please complete the following exercise. Implement DeliverItems as an MD bean. Detailed tasks are given below.
Create an MD Bean named DeliverItems under the package au.com.tusc.mdb.
Create an Immutable Value Object named DeliverItem under the package au.com.tusc.mdb. Add some attributes and implement their accessor and mutator methods. The attributes are:
private String username
private String passwd
private String itemID
private int quantity
Implement the onMessage method in your DeliverItems Bean.
Add these two variables to store references.
private StoreAccessHome storeAccess = null;
private ItemLocalHome itemLocalHome = null;
Extract the data from the message into your immutable value object as shown below.
DelieverItem di = (DeliverItem) ((ObjectMessage) message).getObject();
Get the references for the StoreAccess and Item beans.
StoreAccess access = StoreAccessUtil.getHome().create();
itemLocalHome = ItemUtil.getLocalHome();
Invoke the loginUser method for supplier to get the Supplier's userid(accessID) and then find the Supplier's ID by invoking the getSupplierData method.
String suppAcessID = access.loginUser(di.getUsername(), di.getPasswd());
SupplierData sd = access.getSupplierData(suppAccessID);
String suppID = sd.getSupplierID();
If suppID is not equal to null, then invoke the finder method on the Item bean to get the details of the item to be delivered, by extracting itemID from message.
ItemLocal item = this.itemLocalHome.findByPrimaryKey(di.getItemID());
Get the supplier ID associated with the item found, so we can fill up the stock.
String itemSuppID = item.getSupplierID();
Compare itemSuppID and ItemID, if these are the same then fill the stock for that item by invoking the fillStock method in Item bean.
if ( suppID.equals(itemSuppID)) {
System.out.println ("Delivering items in store now... :");
Integer quantity = new Integer (di.getQuantity());
item.fillStock(quantity);
System.out.println ("Stock of iten after dleivery is :" + item.getItemData());
}
Add the following tags for deployment at the class level for linking/referencing Supplier.
1. @ejb.ejb-ref
ejb-name="StoreAccess"
view-type="remote"
ref-name="StoreAccess"
2. @ejb.ejb-ref
ejb-name="Item"
view-type="local"
ref-name="ItemLocal"
3. @jboss.ejb-ref-jndi ref-name="ItemLocal"
jndi-name="ItemLocal"
4. @jboss.ejb-ref-jndi ref-name="StoreAccess"
jndi-name="StoreAccessBean"
5. @jboss.destination-jndi-name
name="queue/DelMdbQueue"
Deploy your DeliverItems Bean.
Create a test client named DeliverMDBClient under the package au.com.tusc.mdb.
Add a method named testMDBBean with the following signature.
public void testMDBBean
Implement testMDBBean, for this a few steps have to be carried out.
Add a Data Object which is to be sent as the message.
Create Initial context.
Create Connection factory.
Using this context perform the JNDI lookup, where the lookup string is "queue/DelMdbQueue".
Create QueueConnection.
Create QueueSender.
Create QueueSession for the bean.
Create Object Message and pass the Data Object in the message.
Send the message.
Finally, commit the session and close both the session and the connection.
Run your client and test the bean.