I have following systems defined in my docker-compose.yml
for better reproducibility.
version: '2.2'
services:
jmstool:
image: spx01/jmstool-activemq
container_name: jmstool
ports:
- 8181:8080
volumes:
- ./context.xml:/usr/local/tomcat/conf/context.xml
jboss:
image: daggerok/jboss-eap-7.2
container_name: jboss
environment:
- PREPEND_JAVA_OPTS=-Djboss.server.default.config=standalone-full.xml
ports:
- 8080:8080
volumes:
- ./configure.cli:/tmp/configure.cli
The tool jmstool is a Spring application deployed on a Tomcat 9 to communicate over JMS with different queues. I could get it work with a standalone activeMQ.
After startup of these containers I add an application user and two queues to messaging subsystem of the running JBoss:
docker exec jboss jboss-eap-7.2/bin/add-user.sh -a -u myUser -p "myPa##word"
docker exec jboss jboss-eap-7.2/bin/jboss-cli.sh --file=/tmp/configure.cli
with content of configure.cli
connect
/subsystem=messaging-activemq/server=default/jms-queue=ImportantMessages:add(entries=[java:jboss/exported/ImportantMessages])
/subsystem=messaging-activemq/server=default/jms-queue=ImportantMessagesOut:add(entries=[java:jboss/exported/ImportantMessagesOut])
The standalone-full.xml
looks good and quite similar to [this other example][2].
<subsystem xmlns="urn:jboss:domain:messaging-activemq:4.0">
<server name="default">
<journal pool-files="10"/>
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-connector>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0">
<param name="buffer-pooling" value="false"/>
</in-vm-acceptor>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<jms-queue name="ImportantMessages" entries="java:jboss/exported/ImportantMessages"/>
<jms-queue name="ImportantMessagesOut" entries="java:jboss/exported/ImportantMessagesOut"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
</subsystem>
Now I try to configure this remote connection in the context.xml
of the Spring application. I (sadly) have to use the http-remoting
Protocol, not the connection via tcp
.
<Context>
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"/>
<Resource
name="jms/ImportantMessages"
auth="Container"
type="org.apache.activemq.command.ActiveMQQueue"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="ImportantMessages"/>
<Resource
name="jms/ImportantMessagesOut"
auth="Container"
type="org.apache.activemq.command.ActiveMQQueue"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="ImportantMessagesOut"/>
<Environment name="spring.jms.jndi-name"
value="jms/RemoteConnectionFactory"
type="java.lang.String"
override="false"/>
<Environment name="jmstool.outgoingQueues"
value="java:comp/env/jms/ImportantMessages"
type="java.lang.String"
override="false"/>
<Environment name="jmstool.incomingQueues"
value="java:comp/env/jms/ImportantMessagesOut"
type="java.lang.String"
override="false"/>
</Context>
The exception in the jmstool log does not surprise me:
ackOff{interval=5000, currentAttempts=14, maxAttempts=unlimited}. Cause: Could not create Transport. Reason: java.io.IOException: Transport scheme NOT recognized: [http-remoting]
This error still occurs when I add [jboss-remoting][3], [jboss-remoting3][4] or [activemq-optional][5] to Tomcat's lib folder.
Does anybody knows what I'm doing wrong?
EDIT: Justin's answer helped me. After adding artemis-jms-client-all.jar to tomcats lib file and reconfiguring the context.xml the connection could be established. Furthermore the client cannot lookup the queues because of following exception. Where can I configure the address property of the queues?
When I call
new JndiLocatorDelegate().lookup("java:comp/env/jms/ImportantMessages", javax.jms.Queue.class)
this exception is thrown
Caused by: java.lang.IllegalArgumentException: address cannot be null
at org.apache.activemq.artemis.jms.client.ActiveMQDestination.setSimpleAddress(ActiveMQDestination.java:414)
at org.apache.activemq.artemis.jms.client.ActiveMQDestination.setAddress(ActiveMQDestination.java:399)
at org.apache.activemq.artemis.jms.client.ActiveMQDestination.buildFromProperties(ActiveMQDestination.java:540)
at org.apache.activemq.artemis.jndi.JNDIStorable.setProperties(JNDIStorable.java:58)
at org.apache.activemq.artemis.jndi.JNDIReferenceFactory.getObjectInstance(JNDIReferenceFactory.java:65)
at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:94)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
at org.apache.naming.NamingContext.lookup(NamingContext.java:840)
... 68 more
When I set an not empty string to address="asdf"
of the queue defining Resource nodes, I get the exception
DefaultMessageListenerContainer : Could not refresh JMS Connection for destination 'java:comp/env/jms/ImportantMessagesOut' - retrying using FixedB
ackOff{interval=5000, currentAttempts=9, maxAttempts=unlimited}. Cause: Failed to create session factory; nested exception is ActiveMQConnectionTimedOutException[errorType=CONNECTION_TIMEDOUT message=AMQ219013:
Timed out waiting to receive cluster topology. Group:null]
The first thing to note is that by integrating with JBoss EAP you're not working with ActiveMQ 5.x. You're working with ActiveMQ Artemis. Therefore you need to use the integration classes from ActiveMQ Artemis, e.g.:
<Context>
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"/>
<Resource
name="jms/ImportantMessages"
auth="Container"
type="org.apache.activemq.artemis.jms.client.ActiveMQQueue"
factory="org.apache.activemq.artemis.jndi.JNDIReferenceFactory"
address="ImportantMessages"/>
<Resource
name="jms/ImportantMessagesOut"
auth="Container"
type="org.apache.activemq.artemis.jms.client.ActiveMQQueue"
factory="org.apache.activemq.artemis.jndi.JNDIReferenceFactory"
address="ImportantMessagesOut"/>
<Resource
name="jms/connectionFactory"
auth="Container"
userName="myUser"
password="myPa##word"
type="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory"
factory="org.apache.activemq.artemis.jndi.JNDIReferenceFactory"
brokerURL="tcp://jboss:8080?httpEnabled=true"/>
<Environment name="jmstool.outgoingQueues"
value="java:comp/env/jms/ImportantMessages"
type="java.lang.String"
override="false"/>
<Environment name="jmstool.incomingQueues"
value="java:comp/env/jms/ImportantMessagesOut"
type="java.lang.String"
override="false"/>
</Context>
This is discussed in the ActiveMQ Artemis documentation on Tomcat integration.
Take note of the httpEnabled=true
on the connection factory's brokerURL
. This is an important parameter which enables the client to use the http-acceptor
defined on JBoss EAP.
Also, be sure to include the artemis-jms-client-all.jar with your application.
You can potentially get an equivalent solution using the JNDI implementation from JBoss EAP (i.e. org.wildfly.naming.client.WildFlyInitialContextFactory
). Generally speaking this would be the recommended approach when integrating JMS with JBoss EAP. However, the aforementioned org.apache.activemq.artemis.jndi.JNDIReferenceFactory
provides simple, direct integration with Tomcat. Furthermore, I've not confirmed that using JBoss EAP JNDI is actually possible in this scenario, and it's almost certainly more complicated than the direct integration I outlined above.