JBoss Messaging

How to configure EJB3 MDBs on JBoss AS 5.1 for remote IBM Websphere MQ 7?

As promised in our previous article we have come up with the configuration from JBoss AS 5.1 side which would help everyone to consume messages from Websphere MQ 7 which is residing on a remote box. In this article we will see how can one send messages (i.e. using a JAVA standalone code) to a remote queue on Box-1 having Websphere MQ 7 and those messages can be received by the consumer (i.e. using EJB3 MDB deployed on JBoss) from Box-2 which is a very basic scenario in most of the people.

The main concept for this is that we would be sending messages to the remote queue of Websphere MQ 7 on box-1 and on box-2 we would be creating a Websphere MQ provider which would have the URL and InitialContextFactory of the Websphere MQ having the queue on box-1 and using that Websphere MQ provider we would connect to the connection factory and would connect to the queue for Websphere MQ which is on box-1. Once we get the access of connection factory and queue we would just create an MDB which would using the Websphere MQ provider details and would be able to consume message from box-2 easily.

In Box-1 (10.10.10.10)

Lets say you have your Websphere MQ 7 running in this box and you can configure the remote queue in MQ 7 by following the steps given in the below article

Steps to Create A Remote Queue in WebSphere MQ 7

In Box-2 (20.20.20.20)

In this box we have a JBoss node called Node-1 and following things has to be done on this box.

Note: You would need the following jar files from Websphere MQ side to put in the /Node-1/lib directory

  • dhbcore.jar
  • mqcontext.jar
  • com.ibm.mq.jar
  • com.ibm.mqjms.jar
  • com.ibm.mq.pcf.jar
  • com.ibm.mq.jmqi.jar
  • com.ibm.mq.headers.jar
  • com.ibm.mq.commonservices.jar

.

  1. Put the “wsIBMmq-provider-service.xml” file in the “Node-1/deploy” folder
  2. wsIBMmq-provider-service.xml

    <server>
     <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.jms:service=JMSProviderLoader,name=WSIBMMQJMSProvider">
     <attribute name="ProviderName">WSIBMMQJMSProvider</attribute>
     <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
    <!-- Connection Factories name created on MQ, "JMS Administered Objects => <IP_ADDRESS>:<PORT>/<CHANNELS_NAME> => Connection Factoiries => <CONNECTION_FACTOIRIES_NAME> "-->
     <attribute name="FactoryRef">MyRemoteMQMgr</attribute>
     <attribute name="QueueFactoryRef">MyRemoteMQMgr</attribute>
     <attribute name="TopicFactoryRef">MyRemoteMQMgr</attribute>
     <attribute name="Properties">
          java.naming.factory.initial=com.ibm.mq.jms.context.WMQInitialContextFactory
          java.naming.provider.url=10.10.10.10:1415/MyRemoteChannel
          java.naming.security.authentication=none
     </attribute>
     </mbean>
     </server>
    

    Note: In “wsIBMmq-provider-service.xml” file you have to change the 10.10.10.10 with the your remote server name/IP address of the remote server on which MQ 7 is running and same goes for 1415 and MyRemoteChannel.

  3. Put the “MDB_30.ear” files in the “Node-1/deploy” folder
    1. Create a folder called “MDB_30.ear
    2. Under it create 2 folders called “MDB_30.jar” and “META-INF
    3. Inside “META-INF” create a “application.xml” file and update this file with the below details
    4. <?xml version="1.0" encoding="UTF-8"?>
      <application version="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/application_5.xsd">
         <module>
             <ejb>MDB_30.jar</ejb>
         </module>
      </application>
      
    5. Inside “MDB_30.jar” create a “MyMDB.java” file and update this file with the below details
    6. import javax.ejb.MessageDriven;
      import javax.jms.JMSException;
      import javax.jms.Message;
      import javax.jms.MessageListener;
      import javax.jms.TextMessage;
      import javax.ejb.ActivationConfigProperty;
      
      @MessageDriven(
          activationConfig={
              @ActivationConfigProperty(propertyName="providerAdapterJNDI", propertyValue="WSIBMMQJMSProvider"),
              @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
              @ActivationConfigProperty(propertyName="destination", propertyValue="MyRemoteQueue"),  
              @ActivationConfigProperty(propertyName="useDLQ", propertyValue="false"),
      	@ActivationConfigProperty(propertyName="reconnectAttempts", propertyValue="60"),
      	@ActivationConfigProperty(propertyName="reconnectInterval", propertyValue="10")
          }
      )
      
      public class MyMDB implements MessageListener{
      
          public void onMessage(Message message) {
              TextMessage textMessage = (TextMessage) message;
              try {
                  System.out.println("nnt Message Received by MDB : "+ textMessage.getText());
              } catch (JMSException e) {
                  e.printStackTrace();
              }
          }
      }
      
    7. Once every thing has been put at its place, then you compile the MyMDB.java code and if you want then you can also create an EAR archive file for above folder
  4. After following the above given steps, we have successfully configured all the setting from JBoss end. Now its time to test our configuration by following the below steps.

    Testing

    1. Create a Directory somewhere in your file system like: “/urs/JBoss/JBM/Queue” to write the QueueSend.java and as we have an MDB we would not need a QueueReceive.java programs.
    2. In QueueSend.java copy the below program
      import java.io.*;
      import java.io.*;
      import java.util.Hashtable;
      import javax.jms.JMSException;
      import javax.jms.Queue;
      import javax.jms.QueueConnection;
      import javax.jms.QueueConnectionFactory;
      import javax.jms.QueueSender;
      import javax.jms.QueueSession;
      import javax.jms.Session;
      import javax.jms.TextMessage;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      public class QueueSend
      {
      public final static String JNDI_FACTORY="com.ibm.mq.jms.context.WMQInitialContextFactory";
      
      //*************** Connection Factory JNDI name *************************
      public final static String JMS_FACTORY="MyRemoteMQMgr"; 
      
      //*************** Queue Factory JNDI name *************************
      public final static String QUEUE="MyRemoteQueue";
      
      
      private QueueConnectionFactory qconFactory;
      private QueueConnection qcon;
      private QueueSession qsession;
      private QueueSender qsender;
      private Queue queue;
      private TextMessage msg;
      
      public void init(Context ctx, String queueName)throws NamingException, JMSException
      {
      qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
      qcon = qconFactory.createQueueConnection();
      qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      queue = (Queue) ctx.lookup(queueName);
      qsender = qsession.createSender(queue);
      msg = qsession.createTextMessage();
      qcon.start();
      }
      
      public void send(String message) throws JMSException {
      msg.setText(message);
      qsender.send(msg);
      }
      
      public void close() throws JMSException {
      qsender.close();
      qsession.close();
      qcon.close();
      }
      
      public static void main(String[] args) throws Exception {
      if (args.length != 1) {
      System.out.println("Usage: java QueueSend URL");
      return;
      }
      InitialContext ic = getInitialContext(args[0]);
      QueueSend qs = new QueueSend();
      qs.init(ic, QUEUE);
      readAndSend(qs);
      qs.close();
      }
      
      private static void readAndSend(QueueSend qs) throws IOException, JMSException
      {
      String line="Test Message Body with counter = ";
      BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
      boolean readFlag=true;
      System.out.println("ntStart Sending Messages (Enter QUIT to Stop):n");
      while(readFlag)
      {
      System.out.print("<Msg_Sender> ");
      String msg=br.readLine();
      if(msg.equals("QUIT") || msg.equals("quit"))
      {
      qs.send(msg);
      System.exit(0);
      }
      qs.send(msg);
      System.out.println();
      }
      br.close();
      }
      
      private static InitialContext getInitialContext(String url) throws NamingException
      {
      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
      env.put(Context.PROVIDER_URL, url);
      return new InitialContext(env);
      }
      }
      
    3. Now open just 1 – command prompt and run the “. ./setMQ_CLASSPATH.sh” by adding two DOTs separated by a single space, in both the prompts to set the Environment (PATH & CLASSPATH).
    4. Note: The same jar files shown above would be required here as well, hence change the path given in the below script under MQ_LIB

      setMQ_CLASSPATH.sh

      #!/bin/sh
      
      echo "Exporting CLASSPATH for IBM MQ...."
      
      MQ_LIB=/home/urs/Remote_MQ/lib
      
      export CLASSPATH=$CLASSPATH:$MQ_LIB/com.ibm.mq.commonservices.jar:$MQ_LIB/com.ibm.mq.headers.jar:$MQ_LIB/com.ibm.mq.jmqi.jar:$MQ_LIB/com.ibm.mq.pcf.jar:$MQ_LIB/com.ibm.mqjms.jar:$MQ_LIB/dhbcore.jar:$MQ_LIB/mqcontext.jar:$MQ_LIB/com.ibm.mq.jar:.:
      echo "====================================="
      echo "CLASSPATH =" $CLASSPATH
      echo "====================================="
      
    5. Then compile the QueueSend.java programs.
    6. Now run the code with the following command
    7. Prompt-1

      java QueueSend 10.10.10.10:1415/MyRemoteChannel
       

    Once everything is up and running properly you just have to send around few messages in “Prompt-1” and you would notice that those messages would be shown in shell on which the Node-1 is running which is on Box-2. Hence when you are sending a messages to the Websphere MQ 7 queue which is on Box-1 the same messages are been consumed by the MDB which is been deployed on Node-1 running on Box-2.


How to Configure JBoss Messaging Bridge in JBoss AS 5 ?


In this article we would be talking about JBoss messaging bridge and how to configure it in JBoss AS5. Hence in simple words JBoss messaging bridge is a type of forwarding mechanism for messages, which also provides interoperability between JBoss JMS implementations and between any non JBoss Messaging JMS servers, as long as they are JMS 1.1 compliant like MQ or even can be used between two different JBoss nodes on the same box or different boxes.

The JBoss messaging bridge also has built in resilience to failure so if the source or the target server connection is lost, which can be due to network failure or the any one of them have gone down then the JBoss messaging bridge can retry connecting to the source and/or target until they come back on-line. When this happens it will resume operation as normal.

How does Messaging Bridge works?

As I told you that messaging bridge is a type of forwarding mechanism in which it has a Source Destination and a Target Destination which is been used to send the messages from one place to other.

Source Destination – Means from where the messages are been read/picked up.

Target Destination – Means where the picked up messages has to be sent.

So its totally dependent on once usage how to use the JBoss messaging bridge for pulling the messages or for sending the messages you can use it in both ways.

Features To Discuss

  1. We would be using JBoss messaging bridge between two boxes which has a JBoss nodes configured with queue in them on each boxes, hence Box-1 = JBoss_Node-1 having “remoteTestQ” and Box-2 = JBoss_Node-2 having “TestQ
  2. Now we would send messages to TestQ and consume messages from remoteTestQ
  3. So for this configuration Source Destination= TestQ and Target Destination= remoteTestQ
  4. As we are comunicating with a remote Queue here we would need to use remote queue configuration
  5. At end would test if we send messages to TestQ we should consume messages from remoteTestQ

Steps to configure JBoss Messaging Bridge:

In Box-1 [10.10.10.10:1099]

Lets say we have a JBoss node in this box called JBoss_Node-1 and following things has to be done on this box-1

  1. Just put “TestQueue-service.xml” file in the “Node-1/deploy” folder
  2. TestQueue-service.xml

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <server>
        <mbean xmbean-dd="xmdesc/Queue-xmbean.xml" name="jboss.messaging.destination:service=Queue,name=remoteTestQ" code="org.jboss.jms.server.destination.QueueService">
            <attribute name="DLQ"> jboss.messaging.destination:name=DLQ,service=Queue</attribute>
            <attribute name="ExpiryQueue">jboss.messaging.destination:name=ExpiryQueue,service=Queue</attribute>
            <attribute name="JNDIName">remoteTestQ</attribute>
            <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
            <depends>jboss.messaging:service=PostOffice</depends>
        </mbean>
    </server>
    

In Box-2 [20.20.20.20:1099]

In this box we have another JBoss node called Node-2 and following things has to be done on this box

  1. Put the “remote-jms-ds.xml” file in the “Node-2/deploy” folder, so that we can communicate with the remote queue
  2. remote-jms-ds.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <connection-factories>
      <mbean code="org.jboss.jms.jndi.JMSProviderLoader" name="jboss.messaging:service=JMSProviderLoader,name=RemoteJMSProvider">
        <attribute name="ProviderName">RemoteJMSProvider</attribute>
        <attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
        <attribute name="FactoryRef">remote/ConnectionFactory</attribute>
        <attribute name="QueueFactoryRef">remote/ConnectionFactory</attribute>
        <attribute name="TopicFactoryRef">remote/ConnectionFactory</attribute>
        <depends>jboss.jndi:service=ExternalContext,jndiName=remote</depends>
      </mbean>
    
      <mbean code="org.jboss.naming.ExternalContext" name="jboss.jndi:service=ExternalContext,jndiName=remote">
        <attribute name="JndiName">remote</attribute>
        <attribute name="Properties">
          java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
          java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
          java.naming.provider.url=jnp://10.10.10.10:1099
        </attribute>
      </mbean>
    
    </connection-factories>
    

    Note: In “remote-jms-ds.xml” file you have to change the 10.10.10.10 with the your remote server name/IP address of the remote server.

  3. Put the TestQ-service.xml file in the “Node-2/deploy” folder, which would create a queue for us and this would be our Source Destination
    so that we can communicate with the remote queue
  4. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <server>
        <mbean xmbean-dd="xmdesc/Queue-xmbean.xml" name="jboss.messaging.destination:service=Queue,name=TestQ" code="org.jboss.jms.server.destination.QueueService">
            <attribute name="DLQ"> jboss.messaging.destination:name=DLQ,service=Queue</attribute>
            <attribute name="ExpiryQueue">jboss.messaging.destination:name=ExpiryQueue,service=Queue</attribute>
            <attribute name="JNDIName">TestQ</attribute>
            <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
            <depends>jboss.messaging:service=PostOffice</depends>
        </mbean>
    </server>
    
  5. And at last put the TestBridge-service.xmlfile in the “Node-2/deploy” folder, which would create a Bridge defining the Source and Traget destination
  6. <?xml version="1.0" encoding="UTF-8"?>
    <server>
       <mbean code="org.jboss.jms.server.bridge.BridgeService" name="jboss.messaging:service=Bridge,name=TestBridge" xmbean-dd="xmdesc/Bridge-xmbean.xml">
    	<depends optional-attribute-name="SourceProviderLoader">jboss.messaging:service=JMSProviderLoader,name=JMSProvider</depends>
    	<depends optional-attribute-name="TargetProviderLoader">jboss.messaging:service=JMSProviderLoader,name=RemoteJMSProvider</depends>
    		<attribute name="SourceDestinationLookup">/TestQ</attribute>
    		<attribute name="TargetDestinationLookup">/remote/remoteTestQ</attribute>
    		<attribute name="QualityOfServiceMode">1</attribute>
    		<attribute name="MaxBatchSize">5</attribute>
    		<attribute name="MaxBatchTime">1</attribute>
    		<attribute name="FailureRetryInterval">5000</attribute>
    		<attribute name="MaxRetries">-1</attribute>
    		<attribute name="AddMessageIDInHeader">false</attribute>
       </mbean>
    </server>
    

    To get more information on each attributes names and function of it would suggest you to have a look at the below link which has all the details regarding it

    Bridge Configuration

    Testing

    After following the above given steps, we have successfully configured all the setting from JBoss end. Now its time to test our configuration by following the below steps.

    1. Create a Directory somewhere in your file system like: “/urs/JBoss/JBM/Queue” to write the QueueSend.java to send messages to the source destination which is on Box-2’s queue which is TestQ and then we would use QueueRecerive.java to receive messages from the target destination which is on Box-1’s queue which is remoteTestQ.
    2. In QueueSend.java copy the below program
      import java.io.*;
      import java.util.Hashtable;
      import javax.jms.JMSException;
      import javax.jms.Queue;
      import javax.jms.QueueConnection;
      import javax.jms.QueueConnectionFactory;
      import javax.jms.QueueSender;
      import javax.jms.QueueSession;
      import javax.jms.Session;
      import javax.jms.TextMessage;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      public class QueueSend
      {
      public final static String JNDI_FACTORY="org.jnp.interfaces.NamingContextFactory";
      //*************** Connection Factory JNDI name *************************
      public final static String JMS_FACTORY="/ConnectionFactory";
      //*************** Queue JNDI name *************************
      public final static String QUEUE="/TestQ";
      
      private QueueConnectionFactory qconFactory;
      private QueueConnection qcon;
      private QueueSession qsession;
      private QueueSender qsender;
      private Queue queue;
      private TextMessage msg;
      
      public void init(Context ctx, String queueName)throws NamingException, JMSException
      {
      qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
      qcon = qconFactory.createQueueConnection();
      qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      queue = (Queue) ctx.lookup(queueName);
      qsender = qsession.createSender(queue);
      msg = qsession.createTextMessage();
      qcon.start();
      }
      
      public void send(String message) throws JMSException {
      msg.setText(message);
      qsender.send(msg);
      }
      
      public void close() throws JMSException {
      qsender.close();
      qsession.close();
      qcon.close();
      }
      
      public static void main(String[] args) throws Exception {
      if (args.length != 1) {
      System.out.println("Usage: java QueueSend URL");
      return;
      }
      InitialContext ic = getInitialContext(args[0]);
      QueueSend qs = new QueueSend();
      qs.init(ic, QUEUE);
      readAndSend(qs);
      qs.close();
      }
      
      private static void readAndSend(QueueSend qs) throws IOException, JMSException
      {
      String line="Test Message Body with counter = ";
      BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
      boolean readFlag=true;
      System.out.println("ntStart Sending Messages (Enter QUIT to Stop):n");
      while(readFlag)
      {
      System.out.print("<Msg_Sender> ");
      String msg=br.readLine();
      if(msg.equals("QUIT") || msg.equals("quit"))
      {
      qs.send(msg);
      System.exit(0);
      }
      qs.send(msg);
      System.out.println();
      }
      br.close();
      }
      
      private static InitialContext getInitialContext(String url) throws NamingException
      {
      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
      env.put(Context.PROVIDER_URL, url);
      return new InitialContext(env);
      }
      }
      
    3. In QueueReceive.java copy the below program
      import java.util.Hashtable;
      import javax.jms.*;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      
      public class QueueReceive implements MessageListener
      {
      public final static String JNDI_FACTORY="org.jnp.interfaces.NamingContextFactory";
      
      //*************** Connection Factory JNDI name *************************
      public final static String JMS_FACTORY="/ConnectionFactory";
      
      //*************** Connection Factory JNDI name *************************
      public final static String QUEUE="/remoteTestQ";
      
      
      private QueueConnectionFactory qconFactory;
      private QueueConnection qcon;
      private QueueSession qsession;
      private QueueReceiver qreceiver;
      private Queue queue;
      private boolean quit = false;
      
      public void onMessage(Message msg)
      {
      try {
      String msgText;
      if (msg instanceof TextMessage)
      {
      msgText = ((TextMessage)msg).getText();
      }
      else
      {
      msgText = msg.toString();
      }
      System.out.println("nt<Msg_Receiver> "+ msgText );
      if (msgText.equalsIgnoreCase("quit"))
      {
      synchronized(this)
      {
      quit = true;
      this.notifyAll(); // Notify main thread to quit
      }
      }
      }
      catch (JMSException jmse)
      {
      jmse.printStackTrace();
      }
      }
      public void init(Context ctx, String queueName) throws NamingException, JMSException
      {
      qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
      qcon = qconFactory.createQueueConnection();
      qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      queue = (Queue) ctx.lookup(queueName);
      qreceiver = qsession.createReceiver(queue);
      qreceiver.setMessageListener(this);
      qcon.start();
      }
      
      public void close()throws JMSException
      {
      qreceiver.close();
      qsession.close();
      qcon.close();
      }
      
      public static void main(String[] args) throws Exception
      {
      if (args.length != 1)
      {
      System.out.println("Usage: java QueueReceive URL");
      return;
      }
      InitialContext ic = getInitialContext(args[0]);
      QueueReceive qr = new QueueReceive();
      qr.init(ic, QUEUE);
      System.out.println("JMS Ready To Receive Messages (To quit, send a "quit" message from QueueSender.class).");
      // Wait until a "quit" message has been received.
      synchronized(qr)
      {
      while (! qr.quit)
      {
      try
      {
      qr.wait();
      }
      catch (InterruptedException ie)
      {}
      }
      }
      qr.close();
      }
      
      private static InitialContext getInitialContext(String url) throws NamingException
      {
      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
      env.put(Context.PROVIDER_URL, url);
      return new InitialContext(env);
      }
      }
      
    4. Now open just 2 – command prompt and run the “. ./setJBossEnv.sh” by adding two DOTs separated by a single space, in both the prompts to set the Environment (PATH & CLASSPATH).
    5. setJBossEnv.sh

      #!/bin/sh
      echo "Exporting JBOSS_HOME...."
      export JBOSS_HOME=/Jboss/AS6/jboss-as   #<---- Change as per your environment
      echo "JBOSS_HOME Exported....!!!"
      echo ""
      echo "Exporting JAVA_HOME...."
      export JAVA_HOME=/Jdk/jdk1.6.0_21    #<---- Change as per your environment
      echo "JBOSS_HOME Exported....!!!"
      echo ""
      echo "Exporting CLASSPATH...."
      export CLASSPATH=$JBOSS_HOME/client/jbossall-client.jar:$JBOSS_HOME/client/jboss-javaee.jar:$JBOSS_HOME/common/lib/jnpserver.jar:$JBOSS_HOME/client/jboss-logging-spi.jar:$JBOSS_HOME/lib/jboss-javaee.jar:$JBOSS_HOME/common/lib/servlet-api.jar:$JBOSS_HOME/common/lib/log4j.jar:$CLASSPATH:.:
      echo "CLASSPATH Exported....!!!"
      echo ""
      echo "Exporting PATH...."
      export PATH=$JAVA_HOME/bin:$PATH
      echo "PATH Exported....!!!"
      echo ""
      echo "========================================================================"
      echo "JBOSS_HOME = " $JBOSS_HOME
      echo ""
      echo "JAVA_HOME = " $JAVA_HOME
      echo ""
      echo "CLASSPATH = " $CLASSPATH
      echo ""
      echo "PATH = " $PATH
      echo "========================================================================"
      
    6. Then compile both the codes the QueueSend.java and QueueReceive.javaprograms.
    7. Now run the code with the following command
    8. Prompt-1

      java QueueReceive jnp://10.10.10.10:1099
       

      Prompt-2

      java QueueSend jnp://20.20.20.20:1099
       
    9. Once this is been done try to sending some messages in the Prompt-1 which can be revived on Prompt-2.

    Once everything is up and running properly you just have to send around few messages in “Prompt-1” and you would notice that those messages would be shown Prompt-2 which is running is on Box-1. Hence when you are sending a messages to the Source Destination and the those messages are been consumed by Target Destination.


Working example of Expiry Queue in JBoss AS 5.1

In this article we would see how and why a expiry queue is given in JBoss. So let’s answer the why first, expiry queue is given because some messages has an expiry period too (i.e. when setTimeToLive is been used) now JMS specification states that clients should not receive messages that have been expired however it does not grantee that. Hence JBoss messaging makes user that once the messages gets expiries are been moved to the expiry queue which has been assigned to the given queue. Now these “expired” messages can later be consumed from the expiry destination for further inspection.

Make sure you do not confuse Expiry Queue with Dead Letter Queue in JBoss because they both have a specific jobs, where DLQ comes into picture when a message does not get delivered in specified delivery attempts (i.e. MaxDeliveryAttempts) to get more information on DLQ you can have a look at the below article

Working example of Dead Letter Queue in JBoss

Features To Discuss

  1. We would be using the default Expiry Queue which comes with JBoss
  2. In this example we will send 1 message with a short time-to-live to a queue.
  3. We will wait for the message to expire and checks that the message is no longer in the queue it was sent to.

Working example of Expiry Queue in JBoss

  1. Create a queue from the Admin-console or even create “*-service.xml” file and place it in the “/profile/deploy” directory. Where * means your Queue name as shown in the below example

    TestQueue-service.xml

  2. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <server>
        <mbean xmbean-dd="xmdesc/Queue-xmbean.xml" name="jboss.messaging.destination:service=Queue,name=TestQueue" code="org.jboss.jms.server.destination.QueueService">
    	<!-- Defining the ExpiryQueue for this TestQueue -->
            <attribute name="ExpiryQueue">jboss.messaging.destination:name=ExpiryQueue,service=Queue</attribute>
            <attribute name="JNDIName">TestQueue</attribute>
            <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
            <depends>jboss.messaging:service=PostOffice</depends>
        </mbean>
    </server>
    
  3. That’s it !!! You are done configuring a simple queue with ExpiryQueue, now let’s test this out using the sender and receiver Java code.

Testing

  1. Create a Directory somewhere in your file system like: “/urs/JBoss/JBM/Queue” to write the QueueSend.java and QueueReceive.java programs.
  2. In QueueSend.java copy the below program, where we are setting the first messages to live for 1s (1000ms) before expiration
    import java.io.*;
    import java.io.*;
    import java.util.Hashtable;
    import javax.jms.JMSException;
    import javax.jms.Queue;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueSender;
    import javax.jms.QueueSession;
    import javax.jms.Session;
    import javax.jms.TextMessage;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    
    public class QueueSend
    {
    public final static String JNDI_FACTORY="org.jnp.interfaces.NamingContextFactory";
    
    //*************** Connection Factory JNDI name *************************
    public final static String JMS_FACTORY="/ConnectionFactory";
    
    //*************** Connection Factory JNDI name *************************
    public final static String QUEUE="/TestQueue";
    
    
    private QueueConnectionFactory qconFactory;
    private QueueConnection qcon;
    private QueueSession qsession;
    private QueueSender qsender;
    private Queue queue;
    private TextMessage msg;
    
    public void init(Context ctx, String queueName)throws NamingException, JMSException
    {
    qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
    qcon = qconFactory.createQueueConnection();
    qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    queue = (Queue) ctx.lookup(queueName);
    qsender = qsession.createSender(queue);
    
    //Messages sent by this sender will be live for 1s (1000ms) before expiration
    qsender.setTimeToLive(1000);
    
    msg = qsession.createTextMessage();
    qcon.start();
    }
    
    public void send(String message) throws JMSException {
    msg.setText(message);
    qsender.send(msg);
    System.out.println("Message="+message+ " Time to live ="+qsender.getTimeToLive());
    }
    
    public void close() throws JMSException {
    qsender.close();
    qsession.close();
    qcon.close();
    }
    
    public static void main(String[] args) throws Exception {
    if (args.length != 1) {
    System.out.println("Usage: java QueueSend URL");
    return;
    }
    InitialContext ic = getInitialContext(args[0]);
    QueueSend qs = new QueueSend();
    qs.init(ic, QUEUE);
    readAndSend(qs);
    qs.close();
    }
    
    private static void readAndSend(QueueSend qs) throws IOException, JMSException
    {
    String line="Test Message Body with counter = ";
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    boolean readFlag=true;
    System.out.println("ntStart Sending Messages (Enter QUIT to Stop):n");
    while(readFlag)
    {
    System.out.print("<Msg_Sender> ");
    String msg=br.readLine();
    if(msg.equals("QUIT") || msg.equals("quit"))
    {
    qs.send(msg);
    System.exit(0);
    }
    qs.send(msg);
    System.out.println();
    }
    br.close();
    }
    
    private static InitialContext getInitialContext(String url) throws NamingException
    {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
    }
    }
    
  3. In QueueReceive.java copy the below program, if you notice that before we are creating the Receiver we are making sure that the program starts 5 seconds late so that the first message sent gets expired as its time to live is 1 second. So the first messages is never consumed and that messages is been moved to expiry queue. But other messages would get consumed as the consumer is up and listening to the TestQueue
    import java.util.Hashtable;
    import javax.jms.*;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    
    public class QueueReceive implements MessageListener
    {
    public final static String JNDI_FACTORY="org.jnp.interfaces.NamingContextFactory";
    
    //*************** Connection Factory JNDI name *************************
    public final static String JMS_FACTORY="/ConnectionFactory";
    
    //*************** Connection Factory JNDI name *************************
    public final static String QUEUE="/TestQueue";
    
    
    private QueueConnectionFactory qconFactory;
    private QueueConnection qcon;
    private QueueSession qsession;
    private QueueReceiver qreceiver;
    private Queue queue;
    private boolean quit = false;
    
    public void onMessage(Message msg) 
    {
    	try 
    	{
    		String msgText;
    		if (msg instanceof TextMessage)
    		{
    			msgText = ((TextMessage)msg).getText();
    		}
    		else
    		{
    			msgText = msg.toString();
    		}
    
    	 	
    
    		System.out.println("nt<Msg_Receiver> "+ msgText );
    
    		if (msgText.equalsIgnoreCase("quit"))
    		{
    			synchronized(this)
    			{
    				quit = true;
    				this.notifyAll(); // Notify main thread to quit
    			}
    		}
    	}
    	catch (JMSException jmse)
    	{
    		jmse.printStackTrace();
    	}
    }
    
    public void init(Context ctx, String queueName) throws NamingException, JMSException
    {
    	try 
    	{
    		qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
    		qcon = qconFactory.createQueueConnection();
    		qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
    		queue = (Queue) ctx.lookup(queueName);
    
    		//Sleeping for 5's so that the message gets expired.
    		System.out.println("Sleeping for 5's till the message expire...");
    		Thread.sleep(5000);
    		
    		qreceiver = qsession.createReceiver(queue);
    		qreceiver.setMessageListener(this);
    		qcon.start();
    	}
    	catch (InterruptedException jmse)
    	{
    		jmse.printStackTrace();
    	}
    
    }
    
    public void close()throws JMSException
    {
    qreceiver.close();
    qsession.close();
    qcon.close();
    }
    
    public static void main(String[] args) throws Exception
    {
    if (args.length != 1)
    {
    System.out.println("Usage: java QueueReceive URL");
    return;
    }
    InitialContext ic = getInitialContext(args[0]);
    QueueReceive qr = new QueueReceive();
    qr.init(ic, QUEUE);
    System.out.println("JMS Ready To Receive Messages (To quit, send a "quit" message from QueueSender.class).");
    
    synchronized(qr)
    {
    while (! qr.quit)
    {
    try
    {
    qr.wait();
    }
    catch (InterruptedException ie)
    {}
    }
    }
    qr.close();
    }
    
    private static InitialContext getInitialContext(String url) throws NamingException
    {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
    env.put(Context.PROVIDER_URL, url);
    return new InitialContext(env);
    }
    }
    
  4. Now open 2– command prompt and run the “. ./setJBossEnv.sh” by adding two DOTs separated by a single space, in both the prompts to set the Environment (PATH & CLASSPATH).
  5. setJBossEnv.sh

    #!/bin/sh
    echo "Exporting JBOSS_HOME...."
    export JBOSS_HOME=/Jboss/AS5.1/jboss-as   <---- Change as per your environment
    echo "JBOSS_HOME Exported....!!!"
    echo ""
    echo "Exporting JAVA_HOME...."
    export JAVA_HOME=/Jdk/jdk1.6.0_21    <---- Change as per your environment
    echo "JBOSS_HOME Exported....!!!"
    echo ""
    echo "Exporting CLASSPATH...."
    export CLASSPATH=$JBOSS_HOME/client/jbossall-client.jar:$JBOSS_HOME/client/jboss-javaee.jar:$JBOSS_HOME/common/lib/jnpserver.jar:$JBOSS_HOME/client/jboss-logging-spi.jar:$JBOSS_HOME/lib/jboss-javaee.jar:$JBOSS_HOME/common/lib/servlet-api.jar:$JBOSS_HOME/common/lib/log4j.jar:$CLASSPATH:.:
    echo "CLASSPATH Exported....!!!"
    echo ""
    echo "Exporting PATH...."
    export PATH=$JAVA_HOME/bin:$PATH
    echo "PATH Exported....!!!"
    echo ""
    echo "========================================================================"
    echo "JBOSS_HOME = " $JBOSS_HOME
    echo ""
    echo "JAVA_HOME = " $JAVA_HOME
    echo ""
    echo "CLASSPATH = " $CLASSPATH
    echo ""
    echo "PATH = " $PATH
    echo "========================================================================"
    
  6. Then compile the QueueSend.java and QueueReceive.java programs.
  7. Now run the code with the following command
  8. Prompt-1

    java QueueSend jnp://localhost:1099
     
  9. Now send one message when the QueueReceive is not started, this way the message which has sent to the TestQueue would have the Time To Live as 1’s second. But this time would not start till the QueueReceive has been startred
  10. Now start the QueueReceive using the below command
  11. Prompt-2

    java QueueReceive jnp://localhost:1099
     

    Note:
    With the “java QueueSend” and “java QueueReceive” command you have to give the<Protocol>://<IP-address>:<Port number>of the managed servers in different prompts.

  12. Once the QueueReceive has been started for the first time it would sleep for 5 second, hence the message which was in the TestQueue would get expired as its time to live was 1 second, hence the messages would get moved to expire queue, which can be seen in the console under
    Admin console path:
    Resources – JBoss Messaging – ExpiryQueue – “Message Count”
  13. However other messages would get consumed as the consumer is up and listening to the TestQueue

Copyright © 2010-2012 Middleware Magic. All rights reserved. |