[ Team LiB ] Previous Section Next Section

Sample Message-Driven Bean

Let's do an end-to-end implementation and testing of a Message-Driven bean that will simply print out the information about the received messages. The same class will be deployed as two beans: one will listen on a queue and the other will subscribe to a topic. We'll go through the whole process of creating and deploying the beans, issuing test messages, and monitoring how they behave.

The bean class is straightforward, as shown in Listing 23.1.

Listing 23.1 SnoopMDB.java
import java.util.*;
import javax.ejb.*;
import javax.jms.*;
import javax.naming.*;

public class SnoopMDB implements MessageDrivenBean, MessageListener
{
 private MessageDrivenContext context = null;
 private Context jndiContext = null;

 public void ejbCreate () throws CreateException {}
 public void ejbRemove() {}

 public void setMessageDrivenContext(MessageDrivenContext ctxt)
 {
  context = ctxt;
  try
  {
   jndiContext = new InitialContext();
  }
  catch(NamingException ne)
  {
   throw new EJBExceptin(ne);
  }
 }

 /**
  * The business logic
  */
 public void onMessage(Message msg)
 {
  try
  {
   String text = null;

   System.out.println("===== New Message =====");
   System.out.println("Type:    " + msg.getClass().getName());
   System.out.println("Destination: " + msg.getJMSDestination());
   System.out.println("Message ID: " + msg.getJMSMessageID());

   if ( msg instanceof TextMessage )
   {
    text = ((TextMessage)msg).getText();
   }
   else if ( msg instanceof ObjectMessage )
   {
    text = ((ObjectMessage)msg).getObject().toString();
   }
   else if ( msg instanceof MapMessage )
   {
    StringBuffer sb = new StringBuffer("\n");
    MapMessage mm = (MapMessage)msg;
    Enumeration enum = mm.getMapNames();
    while (enum.hasMoreElements())
    {
     String name = (String)enum.nextElement();
     Object val = mm.getObject(name);
     sb.append("> " + name + " = " + val + '\n');
    }
    text = sb.toString();
   }

   if (text != null)
    System.out.println("Content:   " + text);
  }
  catch(Throwable t)
  {
   System.out.println("?! Failed:  " + t.getMessage());
  }
 }

}

In the code's onMessage() method, it prints information about the message and the text content, if available, to System.out. The rest of the class is routine. This is just a test bean; in reality, the type of message is probably predefined or is limited to a few known possibilities. If there are different types of messages to be handled, one option would be to define one MDB for each message type, which would be more efficient and object-oriented. Listing 23.2 shows the EJB deployment descriptor.

Listing 23.2 ejb-jar.xml
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC
 "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
 "http://java.sun.com/j2ee/dtds/ejb-jar_2_0.dtd">

<ejb-jar>

 <enterprise-beans>

 <message-driven>
   <ejb-name>SnoopQueueMDB</ejb-name>
   <ejb-class>SnoopMDB</ejb-class>
   <transaction-type>Container</transaction-type>
   <message-driven-destination>
    <destination-type>javax.jms.Queue</destination-type>
   </message-driven-destination>
   <env-entry>
     <description>This is a bean listening on a queue.</description>
     <env-entry-name>listen_type</env-entry-name>
     <env-entry-type>java.lang.String</env-entry-type>
     <env-entry-value>queue</env-entry-value>
   </env-entry>
  </message-driven>

 <message-driven>
   <ejb-name>SnoopTopicMDB</ejb-name>
   <ejb-class>SnoopMDB</ejb-class>
   <transaction-type>Container</transaction-type>
   <message-driven-destination>
    <destination-type>javax.jms.Topic</destination-type>
   </message-driven-destination>
   <env-entry>
     <description>This is a bean listening on a topic.</description>
     <env-entry-name>listen_type</env-entry-name>
     <env-entry-type>java.lang.String</env-entry-type>
     <env-entry-value>topic</env-entry-value>
   </env-entry>
  </message-driven>

 </enterprise-beans>

</ejb-jar>

In ejb-jar.xml, we defined two Message-Driven beans: SnoopQueueMDB and SnoopTopicMDB. Both beans are implemented by the same Java class, SnoopMDB, but listen for different destination types: javax.jms.Queue and javax.jms.Topic. The vendor-specific deployment descriptor provides further information, as listed in Listings 23.3.

Listing 23.3 weblogic-ejb-jar.xml
<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar
 PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN'
 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>

  <weblogic-enterprise-bean>
   <ejb-name>SnoopQueueMDB</ejb-name>
   <message-driven-descriptor>
    <pool>
     <max-beans-in-free-pool>10</max-beans-in-free-pool>
     <initial-beans-in-free-pool>2</initial-beans-in-free-pool>
    </pool>
    <destination-jndi-name>weblogic.examples.jms.exampleQueue</destination-jndi-name>
   </message-driven-descriptor>
   <jndi-name>SnoopQueueMDB</jndi-name>
  </weblogic-enterprise-bean>

  <weblogic-enterprise-bean>
   <ejb-name>SnoopTopicMDB</ejb-name>
   <message-driven-descriptor>
    <pool>
     <max-beans-in-free-pool>10</max-beans-in-free-pool>
     <initial-beans-in-free-pool>2</initial-beans-in-free-pool>
    </pool>
    <destination-jndi-name>weblogic.examples.jms.exampleTopic</destination-jndi-name>
   </message-driven-descriptor>
   <jndi-name>SnoopTopicMDB</jndi-name>
  </weblogic-enterprise-bean>

</weblogic-ejb-jar>

In weblogic-ejb-jar.xml, each bean is designated its respective destination's JNDI names, and we used the JMS example queue and topic in WebLogic 8.1's examples domain.

Let's build and test the beans. Building Message-Driven beans is much simpler than building Entity and Session beans. Simply compile the Java source files, put them (along with deployment descriptor files) under the META-INF/ directory into a single JAR file. We've included the JAR file on the CD at ch23/snoopmdb.jar.

To test run, follow these steps. First, make sure that the JMS destinations are available before deploying the Message-Driven beans. After the beans are deployed, they become listeners of these JMS destinations. You can check and monitor JMS destinations using the WebLogic Console Web application. If all goes well, use a JMS client program to send messages to test.

TIP

If you haven't done it yet, create an instance of the examples domain. You can do this by running the Configuration Wizard. Take note of the administrator username and password because we'll need them shortly.


The examples domain contains a JSM queue and a topic, which are used by our Message-Driven beans. In the WebLogic console, you can check their existence and monitor their status, as shown in Figure 23.1.

Figure 23.1. Checking JMS destinations.

graphics/23fig01.jpg

Watch for exampleQueue and exampleTopic under ServicesJMSexamplesJMSServerDestinations in the left pane, and check the JNDI name for them in the right. You can click on the Monitor tab in the right pane to monitor their status.

Now deploy the Message-Driven beans by clicking on Deployments in the left pane. Follow the instructions in the right pane to pick our snoopmdb.jar file, and deploy the Message-Driven beans to the examplesServer server. Navigate to DeploymentsEJB Modulessnoopmdb in the left pane to verify that the beans are deployed successfully and are running, like that in Figure 23.2.

Figure 23.2. Checking Message-Driven bean deployment.

graphics/23fig02.jpg

If so, you should also see that the destinations have listeners attached. Figure 23.3 shows the exampleQueue.

Figure 23.3. Monitoring JMS destinations.

graphics/23fig03.jpg

Finally, let's send some messages to the destination and see the response from the beans. Listing 23.4 shows a standalone JMS client. The source file and class file can be found on the CD in the ch23/Test/ directory.

Listing 23.4 JMSQueueSend.java
import java.util.*;
import java.io.*;
import javax.jts.*;
import javax.jms.*;
import javax.naming.*;

public class JMSQueueSend
{
 public static void main(String[] args)
 {
  try
  {
   Properties props = System.getProperties();
   props.put(Context.INITIAL_CONTEXT_FACTORY,
    "weblogic.jndi.WLInitialContextFactory");
   props.put(Context.PROVIDER_URL, "t3://localhost:7001");
   props.put(Context.SECURITY_PRINCIPAL, "weblogic");
   props.put(Context.SECURITY_CREDENTIALS, "password");
   InitialContext ctx = new InitialContext(props);

   QueueConnectionFactory qconfactory =
    (QueueConnectionFactory)ctx.lookup(
      "javax.jms.QueueConnectionFactory");
   QueueConnection qcon = qconfactory.createQueueConnection();
   QueueSession qsession = qcon.createQueueSession(false,
      Session.AUTO_ACKNOWLEDGE);
   Queue queue = (Queue)ctx.lookup("weblogic.examples.jms.exampleQueue");
   QueueSender qsender = qsession.createQueueSender(queue);
   TextMessage msg = qsession.createTextMessage();
   qcon.start();
   msg.setText("Hello JMS Queue World!");
   qsender.send(msg);
  }
  catch(Throwable t)
  {
   System.out.println("Exception caught: " + t);
  }
 }
} // end of class JMSQueueSend.

For the principal and credentials, use the administrator username and password set for this domain. Our Message-Driven beans simply print out the message information and content to System.out of the server. Run the client and you'll see this output in the console running your server (see Figure 23.4).

Figure 23.4. The Message-Driven bean output.

graphics/23fig04.gif

    [ Team LiB ] Previous Section Next Section