EJB Message Bean
Resin 3.0

Features
Installation
Configuration
Web Applications
IOC/AOP
Resources
JSP
Quercus
Servlets and Filters
Databases
Admin (JMX)
CMP
EJB
Amber
EJB 3.0
Security
XML and XSLT
XTP
JMS
Performance
Protocols
Third-party
Troubleshooting/FAQ

Tutorials
Burlap Clients
Hessian Clients
CORBA/IIOP Server
Scrapbook

Stateless Session Hello
Entity Bean Home methods
Local Session Counter
Message Bean
Local Session Counter
Tutorials
Burlap Clients

Find this tutorial in: /usr/local/resin/webapps/resin-doc/ejb/tutorial/ejb-messaging-queue
Try the Tutorial

EJB message beans are used to process message received through JMS. The message-driven bean server processes messages as they become available. The Resin-EE server calls the bean's onMessage() method with each new message.

In this example, a simple message-driven bean is created and deployed, and a simple servlet is used to send messages.

  1. Files in this tutorial
  2. Configuring JMS
  3. The message-driven bean class
  4. Deployment descriptor for the bean
  5. Configure the EJB Server
  6. The client
  7. Using Logging
  8. Results

Files in this tutorial

WEB-INF/web.xml Configure JMS, the EJB server, and the simple message sending servlet
WEB-INF/message.ejb Configure the SimpleMessageBean
WEB-INF/classes/example/SimpleMessageBean.java The message bean
WEB-INF/classes/example/MessageSenderServlet.java A simple servlet that sends messages

Configuring JMS

EJB message beans use the facilities provided by JMS. JMS, the Java Messaging Service, is an elaborated queueing system. Clients add messages to the queues and servers remove the messages.

There are two types of messaging supported by JMS. A Queue is used when there is one consumer of the message. A sender sends the message, and the message remains in the queue until a consumer reads the message or the message times out. A Topic is used when there may be more than one subscriber. The server distributes the message to all of the registered subscribers.

The server needs to have both a ConnectionFactory and a Destination. Destinations are either Queue or Topic objects and ConnectionFactories are either QueueConnectionFactory or TopicConnectionFactory.

Like other JNDI resources, JMS objects are configured with resource directives. In this example, the configuration is in web.xml, which creates the JMS resources specifically for the web-app. The JMS objecs could just as easily be created at the host or server level, and thus shared in common with many web applications.

See it in: WEB-INF/web.xml
<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <!-- 
     - JMS  
    -->
  <resource jndi-name="jms/queue-connection-factory"
    type='com.caucho.jms.JVMQueueConnectionFactory'/>

  <resource jndi-name="jms/queue"
    type='com.caucho.jms.memory.MemoryQueue'/>

  ...
  

Resin-EE's EJB message-bean implementation can use any JMS implementation which conforms to the specifications. Resin-EE also includes a basic memory-based JMS implementation.

The following are the factories for Resin-EE's JMS objects:

ClassDescription
com.caucho.jms.JVMQueueConnectionFactoryThe connection factory for queues.
com.caucho.jms.memory.MemoryQueueA memory-based queue.
com.caucho.jms.JVMTopicConnectionFactoryThe connection factory for topics.
com.caucho.jms.memory.MemoryTopicA memory-based topic.

The message-driven bean class

The message-driven bean server processes messages as they become available. The Resin-EE server calls a message-driven bean's onMessage() method with each new message.

Unlike session and entity beans, EJB message-driven beans are implemented with a single class. They do not have a separate interface, implementation class, and home class.

See it in: WEB-INF/classes/example/SimpleMessageBean.java
package example;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class SimpleMessageBean implements MessageDrivenBean, MessageListener {
  static protected final Logger log = 
    Logger.getLogger(SimpleMessageBean.class.getName());

  public void ejbCreate()
    throws EJBException
  {
    log.fine("ejbCreate()");
  }

  public void setMessageDrivenContext(MessageDrivenContext cxt)
    throws EJBException
  {
    log.fine("setMessageDrivenContext()");
  }

  public void onMessage(Message msg)
  {
    // process the message
    String text = null;

    if (msg instanceof TextMessage) {
      try {
        text = ((TextMessage) msg).getText();
      } catch (Exception ex) {
        log.log(Level.WARNING,null,ex);
      }
    }
    else {
      text = msg.toString();
    }

    log.fine("onMessage(): " + text);
  }

  public void ejbRemove()
    throws EJBException
  {
    log.fine("ejbRemove()");
  }
}

Deployment descriptor for the bean

The message bean is described in a deployment descriptor. The Resin-EE ejb server will process an file in the WEB-INF directory with the ".ejb" extension as an ejb deployment descriptor.

In this case, the file WEB-INF/message.ejb is used to configure the message-driven bean SimpleMessageBean.

See it in: WEB-INF/message.ejb
<ejb-jar xmlns="http://caucho.com/ns/resin">
<enterprise-beans>
  <message-driven>
    <ejb-name>SimpleMessageBean</ejb-name>
    <ejb-class>example.SimpleMessageBean</ejb-class>
    <destination>jms/queue</destination>
  </message-driven>
</enterprise-beans>
</ejb-jar>

Configure the EJB Server

The Resin-EE ejb server is responsible for recognizing the message.ejb file and deploying the bean.

See it in: WEB-INF/web.xml
<web-app xmlns="http://caucho.com/ns/resin">

  ...

  <ejb-server config-directory="WEB-INF">
    <jms-connection-factory>jms/queue-connection-factory</jms-connection-factory>
  </ejb-server>

The client

The client creates messages and sends them to a destination.

A client needs to:

  • Get a Destination and ConnectionFactory, usually with a lookup using JNDI
  • Create a Sender (or Publisher for Topics)
  • Create a message
  • Send the message

For this example, a simple servlet is used to perform the above steps, sending 5 messages.

The JNDI lookup is done in the init() method, and the resulting objects are stored as member variables:

See it in: WEB-INF/classes/example/MessageSenderServlet.java
  ...

  Queue _queue;
  QueueConnectionFactory _factory;
  
  public void init()
    throws ServletException
  {
    super.init();

    // look up the objects.
    try {
      Context env = (Context) new InitialContext().lookup("java:comp/env");
      _queue = (Queue) env.lookup("jms/queue");
      if (_queue == null)
        throw new ServletException("`java:comp/env/jms/queue' lookup failed");

      _factory = (QueueConnectionFactory) env.lookup("jms/queue-connection-factory");
      if (_factory == null)
        throw new ServletException("`java:comp/env/jms/queue-connection-factory' lookup failed");

    } catch (NamingException ex) {
      throw new ServletException(ex);
    }
  }

  ...

The 5 messages are sent in the service() method:

See it in: WEB-INF/classes/example/MessageSenderServlet.java
  ...

  public void service(ServletRequest request, ServletResponse response)
    throws ServletException, IOException
  {
    int count = 5;

    try {
      QueueConnection connection = _factory.createQueueConnection();
      QueueSession jmsSession = connection.createQueueSession(false, 0);

      QueueSender sender = jmsSession.createSender(_queue);

      for (int i = 1; i <= count; i++) {
        String text = "hello, world: message #" + String.valueOf(i);
        sendMessage(jmsSession,sender,text);
      }
    } catch (JMSException ex) {
      throw new ServletException(ex);
    }

    PrintWriter out = response.getWriter();
    out.print("Sent " + String.valueOf(count) + " messages.");
  }

  protected void sendMessage(QueueSession jmsSession, QueueSender sender, String text)
    throws JMSException
  {
    // create the message
    Message message = jmsSession.createTextMessage(text);

    // send the message
    sender.send(message);

    log.fine("Sent message: " + text);
  }
  ...

Using Logging

Logging is an extremely useful debugging aid when working with JMS. In this case, logging is used in both the message-driven bean and the sender.

The log configuration in web.xml is used to log both the class name and the message in the file WEB-INF/debug.log.

See it in: WEB-INF/web.xml
<web-app xmlns="http://caucho.com/ns/resin">

  <log name="example" level="fine" path="WEB-INF/debug.log" timestamp="[%M:%S.%s] "
    format="${log.loggerName} ${log.message}"/>

  ...
</web-app>

The use of the JDK logging API is quite straightforward, here is an example from SimpleMessageBean:

See it in: WEB-INF/classes/example/SimpleMessageBean.java
public class SimpleMessageBean implements MessageDrivenBean, MessageListener {
  static protected final Logger log = 
    Logger.getLogger(SimpleMessageBean.class.getName());

  ...

  public void onMessage(Message msg)
  {
    ...

    log.fine("onMessage(): " + text);
  }

Results

The WEB-INF/debug.xml log shows the results of using the MessageSenderServlet:

[41:41.618] example.SimpleMessageBean setMessageDrivenContext()
[41:41.618] example.SimpleMessageBean ejbCreate()
[41:41.638] example.SimpleMessageBean onMessage(): hello, world: message #1
[41:41.638] example.MessageSenderServlet Sent message: hello, world: message #1
[41:41.638] example.SimpleMessageBean onMessage(): hello, world: message #2
[41:41.638] example.MessageSenderServlet Sent message: hello, world: message #2
[41:41.638] example.SimpleMessageBean onMessage(): hello, world: message #3
[41:41.638] example.MessageSenderServlet Sent message: hello, world: message #3
[41:41.638] example.SimpleMessageBean onMessage(): hello, world: message #4
[41:41.638] example.MessageSenderServlet Sent message: hello, world: message #4
[41:41.638] example.SimpleMessageBean onMessage(): hello, world: message #5
[41:41.638] example.MessageSenderServlet Sent message: hello, world: message #5

Try the Tutorial


Local Session Counter
Tutorials
Burlap Clients
Copyright © 1998-2006 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.