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)