When a JMS message is sent to a topic or queue, a message-driven bean instance will interpret and process the message, as specified in its onMessage method. When a JMS message is sent to a topic, a publish-and-subscribe system, an instance of every message-driven bean class listening to this topic will in principle receive and process this message. However, if the message contains a message selector, only the message-driven bean(s) matching the message selector will process the message. When a JMS message is sent to a queue, a point-to-point system, only one message-driven bean will process the message, even when multiple bean classes are listening to the queue. Again, the use of a message selector might limit the bean processing the message. For more on message selectors, see Sending JMS Messages.
How the JMS message is processed fully depends on the business task that is being modeled. It might range from simply logging the message to executing a range of different tasks which include invoking methods on session and entity beans, or sending JMS messages to be processed by other message-driven beans. The following code sample shows one use of a message-driven bean. This bean responds only to JMS messages delivered via the jms/SamplesAppMDBQ queue and contain the message selector Command= 'Delete'. When processing a JMS message, an instance of this bean invokes the query method findAll of the entity bean SimpleToken, and subsequently deletes all SimpleToken records from the underlying database.
/** * @ejbgen:message-driven * message-selector="Command = 'Delete'" * ejb-name = DeleteViaQMD * destination-jndi-name = jms/SamplesAppMDBQ * destination-type = javax.jms.Queue * * @ejbgen:ejb-local-ref link="SimpleToken" */ public class DeleteViaQMDBean extends GenericMessageDrivenBean implements MessageDrivenBean, MessageListener { private SimpleTokenHome tokenHome; public void ejbCreate() { try { javax.naming.Context ic = new InitialContext(); tokenHome = (SimpleTokenHome)ic.lookup("java:/comp/env/ejb/SimpleToken"); } catch(NamingException ne) { System.out.println("Encountered the following naming exception: " + ne.getMessage()); } } public void onMessage(Message msg) { try { Iterator allIter = tokenHome.findAll().iterator(); while(allIter.hasNext()) { ((SimpleToken) allIter.next()).remove(); } } catch(Exception e) { System.out.println("Encountered the following exception: " + e.getMessage()); } } }
When a message-driven bean instance receives a message, and it is not part of a container-managed transaction, by default it immediately sends an acknowledgement to the JMS provider notifying that the message has been received. This will prevent the JMS provider from attempting to redeliver it. However, the acknowledgement only indicates that a message has been successfully received, but it does not guarantee that the message is successfully processed. For instance, a system exception might occur when attempting to locate an entity bean or update its records, causing the processing to fail.
If you want to ensure that a message is redelivered when processing fails, you can make the message-driven bean be part of a transaction. The easiest approach is to use container-managed transaction, where the EJB container is responsible for transaction management. To enable container-managed transaction for a message-driven bean, make sure that your cursor is placed inside the ejbgen:message-driven tag and use the Property Editor to set the transaction-type to Container and the default-transaction to Required. When JMS message processing executes successfully, any changes made during this business task, such as update to entity bean records, are committed and acknowledgement is sent to the JMS provider. However, when JMS message processing fails due to a system exception, any changes are rolled back and receipt is not acknowledged. In other words, after processing fails, the JMS provider will attempt to resend the JMS message until processing is successfully or until the maximum number of redelivery attempts specified for this topic or queue has been reached.
Note. When a message-driven bean is part of a transaction, it executes as part of its own transaction. In other words, if the transaction fails, changes that were made as part of the onMessage method are rolled back, but the occurrence of an exception has no direct effect on the EJB or client application sending the JMS message, as the sender and the message-driven bean are decoupled.
To learn more about container-managed transactions, see EJBs and Transactions. To learn more about bean-managed transaction (that is, explicit transaction management), please refer to your favorite J2EE documentation.