Thursday, December 21, 2006

Message Driven Bean in Java EE 5

In the past, I posted a few examples of implementing Messaging using J2EE and Spring. In this post, I will give an example of how to implement Message Driven beans using Java EE 5. I used Eclipse 3.2 and Glassfish for this example. Follow these steps to run the example:
  1. Download and Install Glassfish: You can download the latest build of Glassfish from the Glassfish Download site. To install follow these steps
    1. In the download directory, run the following command
      java -Xmx256m -jar glassfish-installer-version-build.jar
    2. The previous command will create a directory by the name glassfish. Go to the glassfish directory and run this command
      ant -f setup-cluster.xml
    3. The admin console for the default installation will be at http://localhost:4848/asadmin, and the default username and password are "admin" and "adminadmin" respectively.
  2. Download and Install the Glassfish Plugin for Eclipse from here.
  3. Create a Glassfish Server in Eclipse: (For some reason, Eclipse did not detect the Server Runtime without creating a Server, we'll worry about that later)
  4. Creating the EJB 3 Message Driven Bean:
    1. Create a "Java project" in Eclipse.
    2. Add the Glassfish runtime library as a dependency for the project.
    3. The following is the code for the Message Driven Bean that I used for the Example. This is in the jms package of the Java project.
      package jms;

      import javax.annotation.Resource;
      import javax.ejb.MessageDriven;
      import javax.ejb.MessageDrivenContext;
      import javax.jms.JMSException;
      import javax.jms.Message;
      import javax.jms.MessageListener;
      import javax.jms.TextMessage;

      @MessageDriven(mappedName = "jms/testQueue")
      public class Messaging3Mdb implements MessageListener {

      @Resource
      private MessageDrivenContext mdc;

      public Messaging3Mdb() {
      }
      public void onMessage(Message inMessage) {
      TextMessage msg = null;
      try {
      msg = (TextMessage) inMessage;
      System.out.println("Message received : " + msg.getText());
      } catch (JMSException e) {
      e.printStackTrace();
      mdc.setRollbackOnly();
      }
      }
      }
      Messaging3Mdb.java
  5. Creating the Client: I used a Servlet for the client, so that I could also use JMS resource injection. To create the Client
    1. Create a "Dynamic Web Project" in Eclipse.
    2. Change the Web.xml file to Reflect Java EE 5 descriptor, as shown below
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
      <display-name>Messaging3Web</display-name>
      <servlet>
      <description></description>
      <display-name>MessagingClient</display-name>
      <servlet-name>MessagingClient</servlet-name>
      <servlet-class>servlets.MessagingClient</servlet-class>
      </servlet>
      <servlet-mapping>
      <servlet-name>MessagingClient</servlet-name>
      <url-pattern>/MessagingClient</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
      <welcome-file>index.html</welcome-file>
      <welcome-file>index.htm</welcome-file>
      <welcome-file>index.jsp</welcome-file>
      <welcome-file>default.html</welcome-file>
      <welcome-file>default.htm</welcome-file>
      <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
      </web-app>
      web.xml
    3. This is the code for the Servlet that acts as a client to the MDB created above
      package servlets;

      import java.io.IOException;

      import javax.annotation.Resource;
      import javax.jms.Connection;
      import javax.jms.ConnectionFactory;
      import javax.jms.Destination;
      import javax.jms.JMSException;
      import javax.jms.MessageProducer;
      import javax.jms.Queue;
      import javax.jms.Session;
      import javax.jms.TextMessage;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      public class MessagingClient extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {

      @Resource(mappedName = "jms/testQueue")
      private Queue queue;

      @Resource(mappedName = "jms/connectionFactory")
      private ConnectionFactory jmsConnectionFactory;

      public MessagingClient() {
      super();
      }

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

      }

      public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      Connection connection = null;
      Destination dest = (Destination) queue;
      try {
      connection = jmsConnectionFactory.createConnection();
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer producer = session.createProducer(dest);
      TextMessage message = session.createTextMessage();

      message.setText("Hello");
      response.getOutputStream().println("Sending message: " + message.getText());
      System.out.println("Sending message: " + message.getText());
      producer.send(message);

      producer.send(session.createMessage());
      } catch (JMSException e) {
      e.printStackTrace();
      } finally {
      if (connection != null) {
      try {
      connection.close();
      } catch (JMSException e) {
      }
      }
      }
      }
      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub
      }
      }
      MessagingClient.java
  6. Create the JMS Connection Factory and Queue: The connection factory and the queue can be created using the admin console or from the command line. The admin console is quite easy, you just have to go to the Resources->JMS Resources->Connection Factories and Resources->JMS Resources->Destination Resources. From the command line you have to use the following two commands from the GLASSFIS_HOME/bin directory.
    asadmin create-jms-resource --user admin --restype javax.jms.Queue --property imqDestinationName=testQueue jms/testQueue
    asadmin create-jms-resource --user admin --restype javax.jms.ConnectionFactory --property imqDestinationName=connectionFactory jms/connectionFactory
  7. Deploy the MDB: Since we created a Java Project, eclipse does not allow you to install from the IDE, so you have to export the Java jar file and use the admin console to deploy. Deploy it as an "EJB Module".
  8. Deploy the Client as a Web application

7 comments:

  1. Very useful example. Thanks for sharing.

    On another note, is there a way to annotate a servlet to listen for a queue over JMS? After looking over the servlet 2.5 nothing really jumped out at me.

    For example a MDB is annotated as follows:

    @MessageDriven(mappedName = "jms/myQueue", activationConfig =
    {
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
    })
    public class NewMessage implements MessageListener
    {

    /** Creates a new instance of NewMessage */
    public NewMessage ()
    {
    }

    public void onMessage (Message message)
    {

    System.out.println ("myQueue Received");
    }

    }

    Is there a similar annotation scheme for servlets or do we do it the old fashioned way be implementing a MessageListener?

    ReplyDelete
  2. Well, you will not find any such information the servlet specificaton, as it does not have anything to do with Messaging. I would rather not have a servlet do a dual job for messaging too. But if you don't have any other choice then you will have to go by the old way. I haven't tried it though.

    ReplyDelete
  3. Why does all examples shows the "mappedName=.." usage and no one example of binding jndi name in server specific file (sun-web.xml)? Using "mappedName" is not a portable way, and you will not use it in a real application. Is anybody know where to look at for binding example of using jms in a servlet in dd file?

    ReplyDelete
  4. Nice Abhi.
    this is good Example
    and perfect analysis


    Thanks

    Anil Kumar Shukla

    ReplyDelete
  5. You are inconsistent in the way the steps are presented. In some steps you give excellent detail, yet in others your brevity is infuriating. I can understand if you want to assume some things.. but be consistent with this. If you want to give instructions on how to perform these things, read your own steps and follow them.. you'll find that step 6 onwards is too brief to be useful. yet step 1-4 is fine, it even says which project to select. Perhaps you just lost interest...

    ReplyDelete
  6. in my project i found 1 error in
    MessageProducer messageProducer= session.createroducer(queue);

    plz helm me to solve this error...

    ReplyDelete

Popular Posts