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)