Shahzad Bhatti Welcome to my ramblings and rants!

June 16, 2006

Integrating ActiveMQ with JBoss

Filed under: Computing — admin @ 8:49 am

Integrating ActiveMQ with JBoss
Recently, I had to integrate ActiveMQ 4 with JBoss 4
Here is how I did it:

Download and install JBoss 4.0.4

set JBOSS_HOME environment variable to point to installation directory of JBoss.

Download and install ActiveMQ 4.0

set ACTIVEMQ_HOME environment variable to point to installation directory of ActiveMQ.

Copy ActiveMQ JCA (rar) file to JBoss’s deploy directory, e.g.

cp $ACTIVEMQ_HOME/lib/optional/optional/activemq-ra-4.0-RC2.rar $JBOSS_HOME/server/all/deploy

Start Active MQ Server

cd $ACTIVEMQ_HOME/bin
sh activemq

Start JBoss Server

cd $JBOSS_HOME
sh bin/run.sh -c all
You need to keep the window open as you will see some debug messages on the console.

Create a folder for all source code, e.g.

mkdir mdbtest
cd mdbtest

Create a source, build and META-INF folder, e.g.

mkdir src
mkdir build
mkdir build/META-INF

Create a source package directory for Message-Driven Bean and Client

mkdir src/mdb
mkdir src/publisher

Define Message Driven Bean, in src/mdb/TestMessageBean.java e.g.

 1  package mdb;
 2  import java.io.PrintStream;
 3  import java.rmi.RemoteException;
 4  import java.util.Hashtable;
 5  import java.util.Properties;
 6  import javax.ejb.CreateException;
 7  import javax.ejb.MessageDrivenBean;
 8  import javax.ejb.MessageDrivenContext;
 9  import javax.jms.JMSException;
10  import javax.jms.Message;
11  import javax.jms.MessageListener;
12  import javax.jms.TextMessage;
13  import javax.naming.InitialContext;
14  import javax.naming.NamingException;
15  import javax.rmi.PortableRemoteObject;
16  import org.apache.commons.logging.Log;
17  import org.apache.commons.logging.LogFactory;
18 
19  /**
20   * @ejb.bean name="TestMessageEJB"
21   */
22  public class TestMessageBean implements MessageDrivenBean, MessageListener {
23    public TestMessageBean() {
24    }
25    public void onMessage(Message message)  {
26      try {
27        TextMessage textMessage = (TextMessage) message;
28        System.out.println(">>>Received " + textMessage.getText());
29      } catch (Exception e) {
30        e.printStackTrace();
31      }
32    }
33 
34    public void ejbRemove() {
35    }
36 
37    public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) {
38    }
39 
40    public void ejbCreate() {
41    }
42  }

Define Client Publisher in src/client/Publisher.java, e.g.

 1  package client;
 2  import java.io.PrintStream;
 3  import java.util.Properties;
 4  import javax.jms.ConnectionFactory;
 5  import javax.jms.JMSException;
 6  import javax.jms.Message;
 7  import javax.jms.Session;
 8  import javax.jms.TextMessage;
 9  import javax.naming.InitialContext;
10  import javax.rmi.PortableRemoteObject;
11  import org.apache.activemq.ActiveMQConnectionFactory;
12  import org.springframework.jms.core.JmsTemplate;
13  import org.springframework.jms.core.MessageCreator;
14 
15  public class Publisher {
16    private static final String URL = "tcp://localhost:61616";
17    private static final String DEST = "destQ";
18    private static final boolean topic = false;
19    public static void main(String[] args) throws Exception {
20      ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
21      connectionFactory.setBrokerURL(URL);
22      JmsTemplate jt = new JmsTemplate(connectionFactory);
23      if (topic) jt.setPubSubDomain(true);
24      jt.send( DEST, new MessageCreator() {
25        public Message createMessage(Session session) throws JMSException {
26          Message m = session.createTextMessage("hello world");
27            m.setIntProperty("add_id", id);
28           return m;
29          }
30        }
31       );
32    }
33  }

Define META-INF/ejb-jar.xml as follows:

 <?xml version="1.0" encoding="US-ASCII"?>

 <ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
    version="2.1">

    <description> Test ActiveMQ </description>

    <enterprise-beans>
       <message-driven>
          <description>TestMDB</description>
          <ejb-name>TestMessageEJB</ejb-name>
          <ejb-class>mdb.TestMessageBean</ejb-class>
          <messaging-type>javax.jms.MessageListener</messaging-type>
          <transaction-type>Container</transaction-type>
          <activation-config>
             <activation-config-property>
                <activation-config-property-name>destination</activation-config-property-name>
                <activation-config-property-value>destQ</activation-config-property-value>
             </activation-config-property>
             <activation-config-property>
                <activation-config-property-name>destinationType</activation-config-property-name>
                <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
             </activation-config-property>
             <activation-config-property>
                <activation-config-property-name>acknowledgeMode</activation-config-property-name>
                <activation-config-property-value>Auto-acknowledge</activation-config-property-value>
             </activation-config-property>
             <activation-config-property>
                <activation-config-property-name>messageSelector</activation-config-property-name>
                <activation-config-property-value/>
             </activation-config-property>
          </activation-config>
       </message-driven>
    </enterprise-beans>
    <assembly-descriptor>
      <security-role>
         <description>Open</description>
         <role-name>everyone</role-name>
      </security-role>
      <method-permission>
         <role-name>everyone</role-name>
         <method>
           <ejb-name>TestMessageEJB</ejb-name>
           <method-name>*</method-name>
         </method>
      </method-permission>
      <container-transaction>
        <method>
          <ejb-name>TestMessageEJB</ejb-name>
          <method-name>*</method-name>
        </method>
        <trans-attribute>Required</trans-attribute>
      </container-transaction>

       <message-destination>
          <message-destination-name>jbossQ</message-destination-name>
       </message-destination>
    </assembly-descriptor>
 </ejb-jar>
Define META-INF/jboss.xml as follows:

 <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE jboss PUBLIC
       "-//JBoss//DTD JBOSS 4.0//EN"
       "http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd">
   <jboss>
      <jmx-name>activemq.rar:name=iTests</jmx-name>
      <enterprise-beans>
        <message-driven>
          <ejb-name>TestMessageEJB</ejb-name>
          <resource-adapter-name>activemq-ra-4.0.rar</resource-adapter-name>
          <configuration-name>ActiveMQ Message Driven Bean</configuration-name>
        </message-driven>
      </enterprise-beans>
      <assembly-descriptor>
         <message-destination>
          <message-destination-name>jbossQ</message-destination-name>
          <jndi-name>activemq/queue/outbound</jndi-name>
         </message-destination>
      </assembly-descriptor>
      <resource-managers>
         <resource-manager>
            <res-name>queuefactoryref</res-name>
            <res-jndi-name>java:/activemq/QueueConnectionFactory</res-jndi-name>
         </resource-manager>
         <resource-manager>
            <res-name>topicfactoryref</res-name>
            <res-jndi-name>java:/activemq/TopicConnectionFactory</res-jndi-name>
         </resource-manager>
      </resource-managers>

      <invoker-proxy-bindings>
         <invoker-proxy-binding>
            <name>activemq-message-driven-bean</name>
            <invoker-mbean>default</invoker-mbean>
            <proxy-factory>org.jboss.ejb.plugins.inflow.JBossMessageEndpointFactory</proxy-factory>
            <proxy-factory-config>
              <endpoint-interceptors>
                <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
                <interceptor>org.jboss.ejb.plugins.inflow.MessageEndpointInterceptor</interceptor>
                <interceptor>org.jboss.proxy.TransactionInterceptor</interceptor>
                <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
             </endpoint-interceptors>
           </proxy-factory-config>
         </invoker-proxy-binding>
      </invoker-proxy-bindings>

      <container-configurations>
         <container-configuration>
            <container-name>ActiveMQ Message Driven Bean</container-name>
            <call-logging>false</call-logging>
            <invoker-proxy-binding-name>activemq-message-driven-bean</invoker-proxy-binding-name>
            <container-interceptors>
               <interceptor>org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor</interceptor>
               <interceptor>org.jboss.ejb.plugins.LogInterceptor</interceptor>
               <interceptor>org.jboss.ejb.plugins.RunAsSecurityInterceptor</interceptor>
               <!-- CMT -->
               <interceptor transaction="Container">org.jboss.ejb.plugins.TxInterceptorCMT</interceptor>
               <interceptor transaction="Container">org.jboss.ejb.plugins.CallValidationInterceptor</interceptor>
               <interceptor transaction="Container" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
               <interceptor transaction="Container">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
               <!-- BMT -->
               <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenInstanceInterceptor</interceptor>
               <interceptor transaction="Bean">org.jboss.ejb.plugins.MessageDrivenTxInterceptorBMT</interceptor>
               <interceptor transaction="Bean">org.jboss.ejb.plugins.CallValidationInterceptor</interceptor>
               <interceptor transaction="Bean" metricsEnabled="true">org.jboss.ejb.plugins.MetricsInterceptor</interceptor>
               <interceptor>org.jboss.resource.connectionmanager.CachedConnectionInterceptor</interceptor>
            </container-interceptors>
            <instance-pool>org.jboss.ejb.plugins.MessageDrivenInstancePool</instance-pool>
            <instance-cache></instance-cache>
            <persistence-manager></persistence-manager>
            <container-pool-conf>
             <MaximumSize>100</MaximumSize>
            </container-pool-conf>
         </container-configuration>
      </container-configurations>
 </jboss>
Define activemq-jms-ds.xml in JBoss’s deployment directory as follows:


 <?xml version="1.0" encoding="UTF-8"?>

 <!DOCTYPE connection-factories
     PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
     "http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">

 <connection-factories>

    <tx-connection-factory>
       <jndi-name>activemq/QueueConnectionFactory</jndi-name>
       <xa-transaction/>
       <track-connection-by-tx/> <!-- Thanks to Adrian Brock for pointing this one out! -->
       <rar-name>activemq-ra-4.0.rar</rar-name>
       <connection-definition>javax.jms.QueueConnectionFactory</connection-definition>
       <security-domain-and-application>JmsXARealm</security-domain-and-application>
    </tx-connection-factory>

    <tx-connection-factory>
       <jndi-name>activemq/TopicConnectionFactory</jndi-name>
       <xa-transaction/>
       <track-connection-by-tx/> <!-- Thanks to Adrian Brock for pointing this one out too! -->
       <rar-name>activemq-ra-4.0.rar</rar-name>
       <connection-definition>javax.jms.TopicConnectionFactory</connection-definition>
       <security-domain-and-application>JmsXARealm</security-domain-and-application>
    </tx-connection-factory>

    <!--
    <mbean code="org.jboss.resource.deployment.AdminObject" name="activemq.topic:name=topicSearchRequest">
       <attribute name="JNDIName">topic/search.request</attribute>
       <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='activemq-ra-4.0.rar'</depends>
       <attribute name="Type">javax.jms.Topic</attribute>
       <attribute name="Properties">PhysicalName=topic.search.request</attribute>
    </mbean>

    <mbean code="org.jboss.resource.deployment.AdminObject" name="activemq.topic:name=topicSearchResponse">
       <attribute name="JNDIName">topic/search.response</attribute>
       <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='activemq-ra-4.0.rar'</depends>
       <attribute name="Type">javax.jms.Topic</attribute>
       <attribute name="Properties">PhysicalName=topic.search.response</attribute>
    </mbean>
    -->

 </connection-factories>
Compile your code as follows:

javac -d build -classpath $JBOSS_HOME/server/all/lib/jboss-j2ee.jar:$ACTIVEMQ_HOME/lib/optional/spring-1.2.4.jar:\
$ACTIVEMQ_HOME/lib/optional/activemq-optional-4.0.jar:$ACTIVEMQ_HOME/lib/activeio-core-3.0.jar:\
$ACTIVEMQ_HOME/lib/activemq-core-4.0.jar:$ACTIVEMQ_HOME/lib/activemq-console-4.0.jar src/*/*java

Package EJB as follows:

jar -C build -cf mdbtest.jar *

Deploy EJB as follows:

cp mdbtest.jar $JBOSS_HOME/server/all/deploy

Verify that EJB was deployed successfully in JBoss console logs
Run publisher as follows:

java -classpath build:$JBOSS_HOME/server/all/lib/jboss-j2ee.jar:$ACTIVEMQ_HOME/lib/optional/spring-1.2.4.jar:\
$ACTIVEMQ_HOME/lib/optional/activemq-optional-4.0.jar:$ACTIVEMQ_HOME/lib/activeio-core-3.0.jar:\
$ACTIVEMQ_HOME/lib/activemq-core-4.0.jar:$ACTIVEMQ_HOME/lib/activemq-console-4.0.jar client.Publisher

Verify debug message on the JBoss Console
Voila

(Note that you could use xdoclet and ant script, but I tried to focus on integration here)

See inbound-communication.html

See outbound-communication

1 Comment

No comments yet.

RSS feed for comments on this post. TrackBack URL

Sorry, the comment form is closed at this time.

Powered by WordPress