In this article we will look more in depth at Message Driven Beans as well as the key aspects around messaging that a developer will need to know for the Component Developer Exam. We will first focus on messaging and specifically the Java Messaging Service (JMS) before we will dive into the main component within the EJB 3 specification dealing with messaging, Message Driven Beans. Finally we will look at how it fits into the Tudo List application that we started building in the previous article, Tutorial: Review of Session Beans for the Component Developer Exam.

Messaging and Message Driven Beans

When a client uses a session bean that after processing the requests, returns control back to the client along with the information requested, this is called synchronous communication. This concept is based on the idea that the client must wait for the object of the request to complete before proceeding. It is the equivalent of you waiting for a bank teller to complete your request for funds before you leave the bank. With asynchronous communication, there is no waiting. You make a request for funds, the teller acknowledges your request and you leave the bank. At sometime later she contacts you to tell you the funds are available on your debit card and you can now go shopping. In the Java, asynchronous communication takes the primary form of Message-oriented Middleware (MOM) systems. MOM enables messaging by facilitating the asynchronous transfer of messages between a message sender and the receiver without the need of both parties being available simultaneously. A message is a self contained package of business data that includes headers for routing the message around the network. Messages tend to be used to inform another system of an event in another system. Messaging provides organizations with solutions for eliminating or significantly reducing system bottlenecks, system scalability as well as increasing user productivity. The primary reason for this is due to the decoupling of the components and systems allows for a high degree of agility and flexibility.

Message-oriented middleware

The best way to define Message-oriented middleware is software that enables asynchronous messages to be transmitted from one application to another across a network. When a message is sent, the software stores the message in a location specified by the sender and acknowledges receipt immediately. The message sender is called a producer, and the location where the message is stored is called a destination. A message consumer is any application that subscribes or registers an interest in the destination and may possibly receive the message. At a later point in time, any software component interested in messages at that particular destination can retrieve currently stored messages.

Messaging models

A messaging model is simply a way of messaging when a number of senders and consumers are involved. It will be more obvious what this means as we describe each model. Two popular messaging models are standardized in Java EE: Point- to-Point (PTP) Messaging and Publish-Subscribe Messaging. We’ll discuss each of these messaging models next.

Point-to-Point Model

In this mode, messages are sent directly to a queue by a message producer. Once there is a message in a queue, a consumer, when active, will pull the message off the queue, read the message and delete it off the queue. Sometimes there may be more than one possible consumer. Irrespectively once a message has been read by one consumer it cannot be read by any of the remaining consumers. Consumers don’t need to be registered with the queue at the time the message is sent. If there are no consumers active, the message will sit on the queue until a consumer becomes active, and accesses the message on the queue.

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-point-point-model.jpg
Figure: Point to Point Messaging Model

Publish/Subscribe (Pub-Sub) Model

In the publish/subscribe mode, messages are sent to what is known as a topic by the message producer. Topics can be read by one or more consumers who have registered with, or subscribed to, the particular topic. The message will remain in the topic until all consumers have read the message. Consumers who have not registered with a topic by the time the message is sent will be unable to read the message.

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-publish-subscribe-model.jpg
Figure: Publish-Subscribe Messaging Model

It is important to note that consumers for either a queue or topic consumer can be either synchronous or asynchronous. When a consumer is working in synchronous mode, it will hang until a message arrives in the queue or topic. When the consumer is operating in asynchronous mode, it is considered registered as a listener and is notified when a message arrives. At this point it will then read the message. Note that JMS will not guarantee the order in which messages will arrive so your consumer will need to do a bit of processing if the information is broken up over several messages.

Which Messaging Models Should You Use

In order to determine the best approach for determining the proper messaging model for your application is to determine what you are looking to achieve with you application by using messaging. As was mentioned above, if you are using point to point, there will be a one to one conversation between two application. In this situation, you need to consider the range and variety of data that will be sent in the messages as well as the volume of messages being sent. A point to point model is best when you are looking to process and provide information to one system in the most efficient manner possible. That means you want to send it only once and you want to guarantee that it has been received.

For the publish/subscribe model, you will be publishing messages to a number of consumers who will be divided up based on their topics of interest. There are times when even though the intent is for a one to one conversation between two systems that you may want to have the flexibility of allowing other systems to have access to these message for monitoring purposes. It is always possible to segregate who is listening by sending different kinds of messages to different topics.

The Java Messaging Service (JMS) API

In order to develop systems that take advantage of the different models available for message oriented middleware, the creators of the Java Enterprise came up with a vendor agnostic API that java developers could use with the different enterprise messaging systems. Similar to JDBC in many ways in that irrespective of the final messaging system that a developer is using, they can use the Java Messaging Service (JMS) API in order to send and receive message to and from the various vendors who support the API in their systems.

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-messageorientedmiddleware.jpg
Figure: Message Oriented Middleware with Client using JMS API

The JMS API consists of three main parts:
General API
This API deals with the seven main interfaces related to sending and receiving messages. These are: 1. ConnectionFactory; 2. Destination; 3. Connection; 4. Session; 5. Message; 6. MessageProducer; 7. MessageConsumer. Two of these interfaces (i.e. ConnectionFactory and Connection) can only be obtained via JNDI.
  • Point-to-Point API
 - This handles all methods related to point-to-point messaging model.
  • Publish-and-Subscribe API - 
This handles all methods related to publish-and-subscribe messaging model.

An diagram outlining the relation between JMS core interfaces is shown below:
Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-jms-api-interfaces.jpg
Figure: Core JMS API Interfaces

The session object within JMS holds the transactional unit of work. This is in contrast to JDBC where the transactional unit of work is held in the Connection. There are a number of other interfaces for message priority, message persistence and exception handling. But within the scope of our discussion of MDBs, they are not necessary. Now that we have a decent understanding of how JMS works, we will look at JMS messages within the context of looking a message driven beans, which plays the role of a message consumers within both messaging models.

Working with message-driven beans

Basically a message-driven beans is a EJB component designed to asynchronously listen for and consume messages. MDBs can be designed to handle the many kinds of messages that can be transferred over a network. For the sake of brevity we will focus on MDBs that process JMS messages because most enterprise applications use JMS. Note that just because we are using MDBs as a means of consuming messages doesn’t mean that there are not other means of consuming messages within Java. There are in fact a number of ways that this can be done. However since we are focused on preparing you for the Component Developer Exam, we will focus on developing a MDB that can be used in conjunction with the Tudo List application that we introduced in the previous article, “Tutorial: Review of Session Beans for the Component Developer Exam”. We will build a MDB that can consume simple messages of new or updated Todos arriving from the various users of the Tudo List application. As well we will show you how to use the @MessageDriven annotation, the MessageListener interface, activation configuration properties, and the MDB lifecycle. Below is a pool of MDB with one being used to listen for events on a messaging system.

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-poolofmessagedrivenbeans.jpg
Figure: Pool of MDBs with one MDB used for listening for events on messaging system

The Benefit of MDBs for Messaging

Even if session beans are very useful for a number of aspects of an application, there is still an important place for message driven beans. Here are some of it’s key benefits to Java Enterprise Edition systems that use EJB3.

Multithreading

Often a business application will require multithreaded message consumers in order to concurrently process messages. If you use MDBs the complexity of multithreading is avoided since this is done automatically without any additional code. Incoming messages are handled among the multiple instances of beans that similarly to stateless session beans are sitting in a pool ready for use. When a message arrives in either the queue or topic, an MDB instance is pulled from the pool to handle the message. There is no need for any code to deal with the intricacies of multithreading.

Simplified Messaging Code

Another benefit of using MDBs is that you can avoid all the aspects usually associated with messaging involving finding connection factories or destinations, opening sessions, creating connections or consumers, and attaching listeners. These tasks are handled primarily by the EJB container for you or in the worst-case scenario, you can use annotations or a deployment descriptor to supply configuration information.

Message Consumption

The process of bootstrapping and bringing down message driven beans is handled by the EJB container when the server starts up or is stopped. This means that the developer doesn’t need to concern themselves with needing a client to invoke any methods on the MDBs. This will happen in a manner similar to the lifecycle callbacks in session beans (i.e. automatically) when a message is received in a queue or topic.

Rules for Developing MDBs

Message Driven Beans are basically plain old java objects (POJOs). As such there are a set of rules that need to be followed in order to ensure that it can be properly managed by the EJB Container. These rules are the following:
  • The MDB class must implement the messagelistener interface either directly in the class or indirectly by annotations or in the deployment descriptor.
  • The MDB class cannot use either final or abstract in its definition. It must be concrete a concrete class.
  • The MDB class must be a public declared POJO class. It cannot be a subclass of another MDB. s
  • The MDB bean class must have a no-argument constructor. If you not provided, the compiler will create a default constructor for the MDB to be used by the container to create a bean instance.
  • The MDB class cannot have a method defined as finalize in the bean class. If you want to do any cleanup code, you need to define a method annotated as PreDestroy.
  • The MDB class implement the methods defined in the message listener interface. You cannot alter these methods with static or final. They must be public.
  • The MDC class cannot throw a javax.rmi.RemoteException or any other runtime exceptions. This will cause the MDB instance to terminate.


Developing a Message Driven Bean (MDB)

We will make for the Tudu List application server as a JMS message consumer as an MDB. The listing is shown below:

Java Code: Message Driven Bean - TodoDistributionProcessor
package com.acme.tudo.buslogic;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import com.acme.tudo.domain.jms.TudoMessage;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.sql.DataSource;

@MessageDriven(name = "TodoDistributionProcessor", activationConfig = {
		@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
		@ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/TodoDistributionTopic") })
public class TodoDistributionProcessorMDB implements MessageListener {
	private Connection connection;

	private DataSource dataSource;

	@Resource
	private MessageDrivenContext context;

	@Resource(name = "jdbc/TodoDS", mappedName = "java:/TodoDefaultDS")
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	@PostConstruct
	public void initialize() {
		try {
			connection = dataSource.getConnection();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	@PreDestroy
	public void cleanup() {
		try {
			connection.close();
			connection = null;
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void onMessage(Message message) {
		try {
			ObjectMessage objectMessage = (ObjectMessage) message;
			processTodoInformations(objectMessage);
			System.out.println("Todo message processed.");
		} catch (JMSException jmse) {
			jmse.printStackTrace();
			context.setRollbackOnly();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
			context.setRollbackOnly();
		}
	}

	private boolean containsException(ObjectMessage objMessage) throws JMSException {
		return (objMessage.getObject() instanceof JMSException);
	}

	private void processTodoInformations(ObjectMessage objMessage) throws JMSException {
		Statement statement = connection.createStatement();
		String sql = "INSERT INTO " + "TODO(" + "ID, "
				+ "CREATION_DATE, " + "DESCRIPTION, " + "PRIORITY, "
				+ "COMPLETED, " + "COMPLETION_DATE, "
				+ "DUE_DATE) " + "VALUES ( " + message.getTodoId() + ", "
				+ "'" + message.getTodoCreationDate() + "', " + "' "
				+ message.getTodoDescription() + "', "
				+ message.getTodoPriority() + "', "
				+ message.isTodoCompleted() + "', "
				+ "'" + message.getTodoCompletionDate() + "', " + "' "
				+ "'" + message.getTodoDueDate() + "’)";
		System.out.println(sql);
		statement.execute(sql);
	}
}
The listing shows an MDB that retrieves the Tudo message from the Topic and updates the Todo database table with the information. In this example I have used JDBC in order to show the insert into the database. I could just as easily use JPA in the form of an Entity Access Object that was shown in the previous article, “Tutorial: Review of Session Beans for the Component Developer Exam”.

Further things to highlight are the @MessageDriven annotation above the class definition that identifies this POJO as an MDB and as well specifies the configuration for the MDB. If you look at the configuration, you will note that it specifies that the MDB is listening on the todo topic. If you remember from earlier we mentioned that a topic can have one or more message consumers who will be consuming the same messages from this topic. So if you look at the diagram below, you can see that there are a number of users in this group who have setup a topic for them to share todos. Note that in this group it is Client A that is the producer of messages for this topic shared to other members of the group that he has defined..

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-todoclients-topic.jpg
Figure: Group of Todo Clients Interchanging Todo Messages

Getting back to the MDB code, we have marked this MDB as a JMS message listener by declaring that this bean implements the JMS listener interface. We have now dutifully implemented the onMessage method for processing the incoming messages. We have used the @Resource annotation to inject a message-driven context into the bean as well as declare database resources. This is important as it is used within the onMessage method to roll back transactions if needed. A database resource is also injected. We take advantage of the lifecycle callbacks to open and close the database connection derived from the previous declaration of database. The JDBC connection is used by the business method, processTodoInformations in order to save each Todo message into the database.
Below is the Todo message that is being processed by the MDB:

Java Code: Tudo Message based on Todo domain object
package com.acme.tudo.domain.jms;
import java.io.Serializable;
import java.util.Date;

public class TuduMessage implements Serializable {
    private String operationType;
    private String todoId;
    private Date todoCreationDate;
    private String todoDescription;
    private int todoPriority;
    private boolean todoCompleted;

	public String getOperationType() {
		return operationType;
	}

	public void setOperationType(String operationType) {
		this.operationType = operationType;
	}

	public String getTodoId() {
		return todoId;
	}

	public void setTodoId(String todoId) {
		this.todoId = todoId;
	}

	public boolean isTodoCompleted() {
		return todoCompleted;
	}

	public void setTodoCompleted(boolean completed) {
		this.todoCompleted = completed;
	}

	public Date getTodoCreationDate() {
		return todoCreationDate;
	}
	
	public void setTodoCreationDate(Date creationDate) {
		this.todoCreationDate = creationDate;
	}
	
	public Date getTodoCompletionDate() {
		return todoCompletionDate;
	}

	public void setTodoCompletionDate(Date completionDate) {
		this.todoCompletionDate = completionDate;
	}

	public String getTodoDescription() {
		return todoDescription;
	}

	public void setTodoDescription(String description) {
		this.todoDescription = description;
	}

	public int getTodoPriority() {
		return todoPriority;
	}

	public void setTodoPriority(int priority) {
		this.todoPriority = priority;
	}
	
	public Date getTodoDueDate() {
		return todoCompletionDate;
	}
	
	public void setTodoDueDate(Date dueDate) {
		this.todoDueDate = dueDate;
	}
}
Now let’s look more in depth at the key features that you will be required to know for the Component Developer exam.

The @MessageDriven Annotation

As MDBs are just POJOs similar to it’s session bean EJB cousins, there are some annotations that need to decorate an POJO in order for the container to know that it is a MDB and to be able to manage it’s lifecycle as well as provide it with EJB container services effectively. Starting from the beginning, the first annotation that any MDB will require is the @MessageDriven annotation. The code from our TodoDistributionProcessorMDB is shown below:

Java Code: Bean annotated with @MessageDriven
@MessageDriven
public class TodoDistributionProcessorMDB implements MessageListener
Note that I have given the most simple annotation possible for this. In general the @MessageDriven will be combined with the @ActivationConfigProperty annotation nested inside it are the only MDB-specific annotations. You have the option of providing the name of the MDB as well as the message listener interface the MDB will implement. The MDB must always implements a message listener interface as mentioned in the rules for MDBs. The reason is that the EJB container uses the listener interface to register the MDB with the message provider and to pass incoming messages by invoking the implemented message listener methods. The last parameter would be the activation configuration properties that are specific to the listener. Again taking from the code above, the full version looks like the following:

Java Code: Bean annotated with @MessageDriven and parameters
@MessageDriven(name = "TodoDistributionProcessor", activationConfig = {
		@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
		@ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/TodoDistributionTopic") })
public class TodoDistributionProcessorMDB implements MessageListener {
Message Listeners

As mentioned above, all MDBs must implement the message listener method in order for it to be register the MDB with the message provide and to be able to pass it incoming messages. There are a number of ways to implement to implement this either directly in the class or by use of annotations. We know from the TudoDistritbutionProcessMDB that it can be declared as shown above. It can just as well be done in the following manner:

Java Code: Example of implementing javax.jsm.MessageListener
@MessageDriven( name="TodoDistributionJMSProcessor", messageListenerInterface="javax.jms.MessageListener")
public class TodoDistributionProcessorMDB {
Irrespective of how you choose to implement it, you need to provide valid implementations of all the methods required by the message listener especially as there are no compile time checks.

The @ActivationConfigProperty

In the code for TodoDistributionProcessorMDB, you see that the activationConfig property is used to provide messaging system–specific configuration information to the EJB container. The way in which it does this is by an array of ActivationConfigProperty instances. The instances are always in the form of name-value pairs that are used by the messaging provide to setup the MDB. If you look at the code for the TodoDistributionProcessorMDB, you see that the destinationType property informs the container this JMS MDB is listening to a topic. The other name-value pair, connectionFactoryJndiName specifies the JNDI name of the connection factory that needs to be used to create JMS connections for the MDB. The last name-value pair is the destinationName parameter used to specify we are consuming messages arriving at a destination jms/TodoDistributionTopic. Below are some of the other configuration properties that you can setup using the @ActivationConfigProperty annotation.

AcknowledgeMode

There are many “modes” by which messages that have been received by the MDB can be acknowledged. The default is to AUTO_ACKNOWLEDGE. This is the acknowledge mode for the underlying JMS session that implies that the session acknowledges messages on our behalf in the background. The proper method for including this information in the @ActivationConfigProperty is shown below:

Java Code: ActivationConfigProperty with AcknowledgeMode
@ActivationConfigProperty( 
	propertyName="acknowledgeMode", 
	propertyValue="DUPS_OK_ACKNOWLEDGE")
The valid acknowledgment modes supported by JMS are listed in the table below:

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-messageacknowledgements.jpg
Table: JMS Acknowledgment Modes

SubscriptionDurability

This is to specify if the topic subscription is durable or nondurable for the MDB that is listening. This means that the system will retain the message for the MDB even if it is not active and are guaranteed to be delivered. Below is an example of a durable subscriber:

Java Code: Creation of durable subscriber
 MessageConsumer busyTodoSubscriber = session.createDurableSubscriber( busyTodoTopic, "JamesCEO");
Now when you are ready, you can remove this subscription with the following code:

Java Code: Unsubscribe for subscription durability
 session.unsubscribe("JamesCEO");
The ActivationConfigProperty for a durable subscriber would look like this:

Java Code: ActivationConfigProperty with Subscription Durability
@ActivationConfigProperty( propertyName="destinationType", propertyValue="javax.jms.Topic"),
@ActivationConfigProperty( propertyName="subscriptionDurability", propertyValue="Durable")
For nondurable subscriptions it is not necessary to set this value as it is the default.

MessageSelector

The messageSelector property allows you to setup a criterion to headers and properties of messages to filter the messages retrieved by using a message selector. So if for example, if we want to receive all todo updates messages only from James, you could do the following:

Java Code: Creation of message selector
MessageConsumer consumer = session.createConsumer(destination, "login = JamesCEO");
Note that the syntax corresponds to that of an SQL WHERE clause. It does but the selector syntax uses message header and property names instead of column names. Your selector expressions can be as complex and expressive as you want. You can include literals, identifiers, whitespace, expressions, standard brackets, logical and comparison operators, arithmetic operators, and null comparisons.
The @ActivationConfigProperty for a JMS message selector would look like the following:

Java Code: ActivationConfigProperty with message selector
@ActivationConfigProperty( propertyName="messageSelector", propertyValue="login = JamesCEO")
Below is the list of selector expressions that you can use:

Tutorial: Review of the Message Driven Bean for the Component Developer Exam-a4-selectorexpression.jpg
Table: Valid Selector Expression

Using Bean Lifecycle Callbacks
If you remember from the previous article, “Tutorial: Review of Session Beans for the Component Developer Exam”, MDBs have a lifecycle similar to stateless session beans:
  1. The Message Driven Bean is instantiated
  2. The EJB container injects the bean’s MessageDrivenContext if required
  3. The EJB container performs any other dependency injection needed by any other the bean’s metadata
  4. The container invokes a PostConstruct callback method if it is present in the message driven bean. The PostConstruct method can then be used for initializing any resources used by the bean. The PostConstruct method is only called once during the lifecycle of the instance when it transitions from the does-not-exist state to the method-ready pool. The method can have any name but must have no arguments and have void as a return.


The MDB have two lifecycle callbacks:
  • PostConstruct - called immediately after an MDB is created and set up and all the resources are injected.
  • PreDestroy - called right before the bean instance is retired and removed from the pool.


The typical use of these callbacks is for allocating and releasing injected resources that are used by the onMessage method. Note this is what we have done in the TodoDistributionProcessorMDB. Review the MDB code listing above for more information.

Sending JMS messages from MDBs

Often an MDB will be required during it’s processing to send JMS messages. Although it wasn’t the case in our example, often it will be necessary to provide notification to a third party if there is a problem. The simplest manner to handle this is to send a JMS message to an error queue that the interested party is listening to. In this case, we can inject the queue named jms/TodoErrorQueue and the connection factory named jms/QueueConnectionFactory by using the @Resource annotation:

Java Code: Setting up Queue Connection Factory
@Resource(name="jms/TodoErrorQueue") 
private javax.jms.Destination errorQueue; 
@Resource(name="jms/QueueConnectionFactory") 
private javax.jms.ConnectionFactory connectionFactory;
We create a second javax.jms.Connection instance using life- cycle callbacks,in a manner similar to what was done with the JDBC connection in the TodoDistributionProcessorMDB:

Java Code: Lifecycle for creation and destruction of javax.jms.Connection
@PostConstruct public void initialize() {
... 
jmsConnection = connectionFactory.createConnection(); ...
} 
@PreDestroy public void cleanup() {
... 
jmsConnection.close(); ...
}
Then we just implement a business method to send the error message:

Java Code: Sending of error message via JMS
 private void sendErrorMessage(TodoError error) { 
Session session = jmsConnection.createSession(true,
Session.AUTO_ACKNOWLEDGE); 
MessageProducer producer = session.createProducer(errorQueue);
 ... 
producer.send(message); session.close();
}
Managing MDB transactions

In the TodoDistributionProcessorMDB we let the EJB container use the default transactional behavior for MDBs. The default is for the container to start a transaction before the onMessage method is invoked and will commit the transaction when the method returns, unless the transaction was marked as rollback through the message-driven context. There is more about transactions to discuss but for our discussion of MDBs, this will suffice. In a later article, I will cover transaction management.

Best Practices FOR MDBs

To finish up, I will provide you with a list of session bean best practices that will serve you well for the component developer exam. They are the following:
  • Choose wisely the messaging model. Often is situations where there is no need to distribute among a large numbers of consumers, a point to point model will suit your needs. The publish-subscribe model is primarily a mechanism for broadcasting a message to a large number of consumers. This should help in determining which model best suits your needs.
  • Follow good O-O practice with your MDBs. The message listener methods already has a clearly defined purpose which is to receive the message back from the queue or topic. Don’t look to stuff all the business logic into the same method. Instead follow good OO practices by breaking down the logic into specific areas of concerns. The best practice is to put business logic in session beans and invoke them from the onMessage method.
  • Use message filters. Message selectors are very useful for filtering message among various parties especially when you might have large numbers of users listening for a particular topic. It is also useful if you are reusing a queue for various purposes. You can then isolate the messages handled by two different MDBs. Be wary that this can adversely affect the performance of your system.
  • Choose message types carefully. It’s best to use a tool to facilitate Object/XML mapping similar to what exist for object/relational mapping. This promotes loose coupling between systems. Be wary though if the objects are quite large because this will create XML bloat, which significantly affects the performance of your system. There is alot more that I can say about messages but I think it best to refer to articles and books on JMS or Java Web Services to learn more about how to best manage this issue.
  • Watch out for poison messages. Sometimes you will receive a message that the MDB is unable to consume. Instead the attempt to cast the message to the appropriate type will throw a java.lang.ClassCastException:

    Java Code: Example of method producing a java.lang.ClassCastException
     try { 
       ObjectMessage objectMessage = (ObjectMessage)message; 
       TodoMessage todoMessage = (TodoMessage)objectMessage.getObject(); 
       processTodoInformations(todoMessage);
    } catch (JMSException jmse) {
      jmse.printStackTrace(); 
      context.setRollBackOnly();
    }
    As the onMessage will not complete normally, the EJB container will roll back the transaction and put the message back on the queue instead or worse the bean instance will be removed from the pool. This will cause an infinite loop since the next MDB who picks up the same message will run into the same problem. Fortunately most EJB containers and middleware provide mechanisms for dealing with poison messages. These include “redelivery” counts and “dead message” queues. What this means if after attempted delivery is made a certain number of times, it will exceed the redelivery count and the message will be moved to a “dead message” queue. Note this is not standard to all vendors.
  • Optimize MDB pool size. The goal here is to tweak the EJB containers to facilitate the concurrent handling of enough messages so that the performance of the system is within your performance specifications. This is something that you will need to do with your vendor as each JEE server is different.


OK. That’s it for our review of Message Driven Beans. Next we are on to Entities and Java Persistence API.