Ok, I found the solution. Jboss includes JCA connector for any JMS factory (supports both types of transactions: XA and local). It is located in /server//deploy/jms-ra.rar. Here is how I configured it.
First, activemq-jms-ds.xml
file that goes into deploy directory next to jms-ra.rar:
<?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>
<mbean code="org.jboss.jms.jndi.JMSProviderLoader"
name="jboss.messaging:service=JMSProviderLoader,name=ActiveMQJMSProvider">
<attribute name="ProviderName">ActiveMQJMSProvider</attribute>
<attribute name="ProviderAdapterClass">org.jboss.jms.jndi.JNDIProviderAdapter</attribute>
<attribute name="FactoryRef">java:/activemq/XAConnectionFactory</attribute>
<attribute name="QueueFactoryRef">java:/activemq/XAConnectionFactory</attribute>
<attribute name="TopicFactoryRef">java:/activemq/XAConnectionFactory</attribute>
</mbean>
<tx-connection-factory>
<jndi-name>JmsXAConnectionFactory</jndi-name>
<xa-transaction/>
<rar-name>jms-ra.rar</rar-name>
<connection-definition>org.jboss.resource.adapter.jms.JmsConnectionFactory</connection-definition>
<config-property name="JmsProviderAdapterJNDI" type="java.lang.String">java:/ActiveMQJMSProvider</config-property>
</tx-connection-factory>
</connection-factories>
This tells Jboss to look into jms-ra.rar and find adapter that can provide managed connection factory for org.jboss.resource.adapter.jms.JmsConnectionFactory
. Internally jms adapter depends on JmsProviderAdapter, which is used to store JNDI names of connection factories (in my config all names are the same).
I use mbean tag to configure JMSProviderLoader (this is copied from one of internal JBoss configs). Now, all I have to do is somehow create an instance of my XA connection factory and bind it to java:/activemq/XAConnectionFactory
. There are several ways to do it (implement MBean wrapper, for example).
Since I am Jboss 5 I used microcontainer (which is likely to work in Jboss 6). I added activemq-jms-jboss-beans.xml
file into deployers
direcotry:
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<!-- Define a Jndi binding aspect/annotation that exposes beans via jndi
when they are registered with the kernel.
-->
<aop:lifecycle-configure xmlns:aop="urn:jboss:aop-beans:1.0"
name="DependencyAdvice"
class="org.jboss.aop.microcontainer.aspects.jndi.JndiLifecycleCallback"
classes="@org.jboss.aop.microcontainer.aspects.jndi.JndiBinding"
manager-bean="AspectManager"
manager-property="aspectManager">
</aop:lifecycle-configure>
<bean name="ActiveMQXAConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<annotation>@org.jboss.aop.microcontainer.aspects.jndi.JndiBinding(name="activemq/XAConnectionFactory", aliases={"java:/activemq/XAConnectionFactory"})</annotation>
<property name="brokerURL">vm://localhost</property>
</bean>
</deployment>
I create a ActiveMQXAConnectionFactory
bean. To bind it to JNDI, I annotate it with JndiBinding annotation. For this annotation to work, we need JndiLifecycleCallback. As far as I can tell, JndiLifecycleCallback is called on every bean created by microcontainer and checks for JndiBinding annotation on that bean.