Kennis Blogs Configuring Camel to use HornetQ 2.2.13 in JBoss AS 7.1.1

Configuring Camel to use HornetQ 2.2.13 in JBoss AS 7.1.1

JBoss AS 7.1.1 has version 2.2.13 of the HornetQ messaging server built-in. I needed to use JMS for a Camel route from outside the container and found that configuring and using HornetQ is not really difficult. It can be confusing however, mainly because the documentation and examples I found often refer to a different version of either HornetQ or JBoss AS. In the end I got it to work; to save you the trouble of having to find it all out by yourself, I thought I'd write a walk-through of the process...

 

 

First, you will need to enable HornetQ and configure it. I used a simple configuration without clustering or HA. You will need the following additions to your JBoss configuration file:

 

In <extensions>, add:

&lt;extension module="org.jboss.as.messaging"/&gt;

In <profile>, add the messaging subsystem:

<subsystem xmlns="urn:jboss:domain:messaging:1.1">
<hornetq-server>
<clustered>false</clustered>
<persistence-enabled>true</persistence-enabled>
<security-enabled>false</security-enabled>
<shared-store>true</shared-store>
<journal-type>ASYNCIO</journal-type>
<journal-file-size>102400</journal-file-size>
<journal-min-files>2</journal-min-files>
<connectors>
<netty-connector name="netty" socket-binding="messaging"/>
<netty-connector name="netty-throughput" socket-binding="messaging-throughput">
<param key="batch-delay" value="50"/>
</netty-connector>
<in-vm-connector name="in-vm" server-id="0"/>
</connectors>
<acceptors>
<netty-acceptor name="netty" socket-binding="messaging"/>
<netty-acceptor name="netty-throughput" socket-binding="messaging-throughput">
<param key="batch-delay" value="50"/>
<param key="direct-deliver" value="false"/>
</netty-acceptor>
<in-vm-acceptor name="in-vm" server-id="0"/>
</acceptors>
<address-settings>
<address-setting match="#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-size-bytes>10485760</max-size-bytes>
<address-full-policy>BLOCK</address-full-policy>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
</address-settings>
<jms-connection-factories>
<connection-factory name="InVmConnectionFactory">
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/ConnectionFactory"/>
</entries>
</connection-factory>
<connection-factory name="RemoteConnectionFactory">
<connectors>
<connector-ref connector-name="netty"/>
</connectors>
<entries>
<entry name="RemoteConnectionFactory"/>
<entry name="java:jboss/exported/jms/RemoteConnectionFactory"/>
</entries>
</connection-factory>
<pooled-connection-factory name="hornetq-ra">
<transaction mode="xa"/>
<connectors>
<connector-ref connector-name="in-vm"/>
</connectors>
<entries>
<entry name="java:/JmsXA"/>
</entries>
</pooled-connection-factory>
</jms-connection-factories>
<jms-destinations>
<jms-queue name="someQueue">
<entry name="queue/someQueue"/>
</jms-queue>
<jms-queue name="someOtherQueue">
<entry name="queue/someOtherQueue"/>
</jms-queue>
</jms-destinations>
</hornetq-server>
</subsystem>

In the <socket-binding-group>:

<socket-binding name="messaging" port="5445"/>
<socket-binding name="messaging-throughput" port="5455"/>

 

Now, when you start JBoss, you will see some HornetQ logging as well:

 

15:18:55,511 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-4) live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=true,journalDirectory=/Applications/jboss-as-7.1.1.Final/standalone/data/messagingjournal,bindingsDirectory=/Applications/jboss-as-7.1.1.Final/standalone/data/messagingbindings,largeMessagesDirectory=/Applications/jboss-as-7.1.1.Final/standalone/data/messaginglargemessages,pagingDirectory=/Applications/jboss-as-7.1.1.Final/standalone/data/messagingpaging)
15:18:55,513 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-4) Waiting to obtain live lock
15:18:55,542 INFO  [org.hornetq.core.persistence.impl.journal.JournalStorageManager] (MSC service thread 1-4) Using NIO Journal
15:18:55,605 INFO  [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-4) Waiting to obtain live lock
15:18:55,606 INFO  [org.hornetq.core.server.impl.FileLockNodeManager] (MSC service thread 1-4) Live Server Obtained live lock
15:18:55,785 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-4) Started Netty Acceptor version 3.2.5.Final-a96d88c localhost:5445 for CORE protocol
15:18:55,786 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-4) Started Netty Acceptor version 3.2.5.Final-a96d88c localhost:5455 for CORE protocol
15:18:55,787 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-4) Server is now live
15:18:55,787 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-4) HornetQ Server version 2.2.13.Final (HQ_2_2_13_FINAL_AS7, 122) [6b03751f-0e2a-11e2-a9c7-1040f3ac1aa0]) started
15:18:55,790 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-7) trying to deploy queue jms.queue.someQueue
15:18:55,811 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-8) trying to deploy queue jms.queue.someOtherQueue
15:18:55,842 INFO  [org.hornetq.ra.HornetQResourceAdapter] (MSC service thread 1-7) HornetQ resource adaptor started

 

The next step will be to connect Camel to one of the queues. Because the JNDI lookup is secured, you need to provide a user in the ApplicationRealm. This user needs no special roles (for now). If you don't have a user for this, create one (using bin/add-user.sh).

 

Now we can add the JNDI lookup connection to our Spring application context:

 

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
<prop key="java.naming.provider.url">remote://localhost:4447</prop>
<prop key="java.naming.security.principal">[your-user]</prop>
<prop key="java.naming.security.credentials">[your-password]</prop>
</props>
</property>
</bean>

 

And the actual lookup of the JMS connection factory:

 

<bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>java:jms/RemoteConnectionFactory</value>
</property>
</bean>

 

Finally, we can create the Camel JMS component:

 

<bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
</bean>

 

Now you can access the queues directly from your Camel route builder:

 

public void configure() throws Exception {
from("jms:queue:someQueue")
...
.to("jms:queue:someOtherQueue");
}

 

Note that the "queue:" part for the endpoint is optional. Queue is the default; if you want to connect to a topic, "topic:" is required.

Also note that you must use the name of the queue (jms-queue name=), not the entry, since the latter is the JNDI location of the queue.

As you may have noted, this example runs without security on the queues, it only uses security for the JNDI lookup. Security is enabled by default, and for good reason, so let's enable and configure it now. First, enable security by changing "security-enabled" in the messaging domain to true (or you could remove the entry entirely):


&lt;security-enabled&gt;true&lt;/security-enabled&gt;

 

Next, add the security settings after the acceptors:

  ...
</acceptors>
<security-settings>
<security-setting match="#">
<permission type="send" roles="messaging"/>
<permission type="consume" roles="messaging"/>
</security-setting>
</security-settings>
<address-settings>
...

 

The match="#" attribute means these settings apply to all queues and topics. The '#'-character is the wildcard here. You could enter several security-setting elements and apply them to different sets of queues or topics by using other match strings, e.g. match="some#".

 

This settings allows users with the role "messaging" to send messages to the queues and consume messages from the queues. To still be able to send and consume messages from Camel you will have to supply credentials for a user with that role when accessing the connection factory.

 

First, you'll have to edit application-roles.properties: add the role "messaging" to the user you created earlier. Then, when obtaining a connection to the queue, you need to provide the credentials again. I used the Spring UserCredentialsConnectionFactoryAdapter to wrap the connection factory:

 

<bean id="authenticatedConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsQueueConnectionFactory"/>
<property name="username" value="[your-user]"/>
<property name="password" value="[your-password]"/>
</bean>
<bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="authenticatedConnectionFactory"/>
</bean>

 

And there you are, all ready to go!