- What's New in EJB 2.0
- The EJB Query Language (EJBQL)
- Container-Managed Persistence
- Message-Driven Beans
Message-Driven Beans
The other interesting feature of EJB 2.0 is the introduction of message-driven beans. J2EE includes a messaging API called Java Message Service (JMS) that enables you to send messages between EJBs either within the same container or across different containers. Unlike remote method calls, messages may be processed at a later time. You can send a message to your order-fulfillment service that may not be handled for several hours. The messaging service acts as a buffer between two beans, allowing a fast-response bean to interact with a bean that performs slow operations.
Because so many applications use messages to perform various operations, EJB 2.0 adds a bean whose sole purpose in life is to react to messages. A message-driven bean isn't persistent and isn't even visible to clients. It has no Home or Remote interfaces. Like other EJBs, it must have ejbCreate, ejbRemove, ejbActivate, and ejbPassivate methods. It must also have setMessageDrivenContext and onMessage methods. The onMessage method is the workhorse of the message-driven bean. Every time a message comes in, the container calls the bean's onMessage method, passing it the incoming message.
The following listing, from my upcoming book Special Edition Using Java 2 Enterprise Edition, shows a message-driven bean that echoes messages back to the sender.
package usingj2ee.messages; import javax.ejb.*; import javax.jms.*; import javax.naming.*; public class EchoMessageBean implements MessageDrivenBean { private MessageDrivenContext mdContext; // The following Queue objects are needed only because this bean // sends a reply message back to the sender. For a message-driven bean, // the EJB container handles the Queue and Topic objects for the incoming // messages. protected QueueConnection qConn; protected QueueSession qSession; protected QueueSender qSender; public EchoMessageBean() { } public void ejbCreate() throws CreateException { try { // Locate the JNDI naming instance InitialContext context = new InitialContext(); // Locate the Queue Connection Factory QueueConnectionFactory qcFact = (QueueConnectionFactory) context.lookup("javax.jms.QueueConnectionFactory"); // Create a Queue Connection qConn = qcFact.createQueueConnection(); // Create a nontransactional Queue Sender qSession = qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); // Create an unidentified producer (a producer that isn't associated // with a particular queue) qSender = qSession.createSender(null); } catch (Exception exc) { exc.printStackTrace(); throw new CreateException( "Error initializing EchoMessageBean: "+ exc.toString()); } } public void setMessageDrivenContext(MessageDrivenContext ctx) { mdContext = ctx; } public void ejbActivate() { } public void ejbPassivate() { } public void ejbRemove() { try { // Close the Queue connection qConn.close(); } catch (Exception exc) { exc.printStackTrace(); } } public void onMessage(Message message) { try { // Set a property that lets the client know for sure that the // message bean saw the message message.setStringProperty("MessageBeanACK", "The message bean saw this message"); // Figure out where to send the reply Destination replyTo = message.getJMSReplyTo(); if ((replyTo != null) && (replyTo instanceof Queue)) { // Send the reply qSender.send((Queue) replyTo, message); } } catch (Exception exc) { exc.printStackTrace(); } } }
Message-driven beans are great for sending email confirmation or order fulfillment, things that may take some time. When you save an order, you can send a message to the fulfillment service telling it about your order. Sometime later, a message-driven fulfillment bean receives your message and begins processing the order.
As you can see, EJB 2.0 makes significant strides in improving and expanding the capabilities of Enterprise Java Beans.