Ok, let’s give XA a try.
0. What do we need?
[W]rap the entire processing with an XA transaction, covering the reception of the message as well as the execution of the message listener. This is only supported by
DefaultMessageListenerContainer, through specifying a “transactionManager” (typically a
JtaTransactionManager, with a corresponding XA-aware JMS
ConnectionFactorypassed in as “connectionFactory”).
Keith adds that we’ll also need a Hibernate SessionFactory bean… but we’ll leave that out for this first round.
1. The ConnectionFactory Part
For the ConnectionFactory part, we’ll use ActiveMQ’s ConnectionFactory implementation, and it will be XA-aware because we are configuring it as a JNDI datasource (do I have my terms right?) in JBoss. So, how do we do that?
1.1. Configuring the Datasource
We dropped a file named activemq-jms-ds.xml which he got from somewhere (maybe from an article on ActiveMQ’s site titled Integrating Apache ActiveMQ with JBoss) into the JBoss deploy folder*. The file starts out something like this:
PUBLIC “-//JBoss//DTD JBOSS JCA Config 1.5//EN”
<!– More stuff here… –>
Notice that this configuration file specifies XA transactions and points to an activemq-ra.rar file
*Interestingly to me, not to the config folder.
1.1.1. The thing that matters about this
This is a bunch of configuration, but what matters from the Spring bean file’s point of view is the JNDI name, because that’s how we’ll refer to it from there.
1.2. The RAR file
We had also deployed the activemq-ra.rar file to JBoss. Inside that .rar file, under a meta-inf folder, is an ra.xml file. From looking at the xsd file, other Sun documentation, and the <display-name> tag within the file, it seems that this file is a Connector Deployment Descriptor for the ActiveMQ JMS Resource Adapter. Apparently it’s not only a connector, it’s also a resource adapter. (I bet that’s why there’s an “ra” in the filename.)
At any rate, under connector -> resourceadapter -> outbound-resourceadapter, one of the <connection-definition> tags under there has these entries:
So it looks like this is how the app server knows what implementation of the javax.jms.QueueConnectionFactory interface ActiveMQ provides. (I’ve been doing a lot of guessing around — I was missing some background on JCA. ActiveMQ’s article Integrating Apache ActiveMQ with JBoss, which I didn’t see until this post was half written, helps fill in some of these gaps.)
2. Tying It All Together
There are some other things we’ll need to tie this all together:
- A bean definition for the queue connection factory to reference
- A bean definition for a JtaTransactionManager to reference
- A DefaultMessageListenerContainer bean in our Spring beans file
For the first one, we refer to the Spring manual appendix A.2.3. The jee schema; the latter two are based on the examples in section 19.4.5. Processing messages within transactions. The concept of referencing a jndi-lookup bean as if it were just a normal bean is from the Java World article, the example where it defines an appJmsDestination bean pointing to the JNDI name and then sets the JmsTemplate’s defaultDestination property to reference this bean.
So here’s the proposed Spring bean file:
<?xml version=”1.0″ encoding=”UTF-8″?>
xsi:schemaLocation=” http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
<jee:jndi-lookup id=”queueConnectionFactory” jndi-name=”activemq/QueueConnectionFactory”/>
<bean id=”transactionManager” class=”org.springframework.transaction.jta.JtaTransactionManager”/>
<bean id=”jmsContainer” class=”org.springframework.jms.listener.DefaultMessageListenerContainer”>
<property name=”connectionFactory” ref=”queueConnectionFactory“/>
<property name=”destination” ref=”destination”/>
<property name=”messageListener” ref=”messageListener”/>
<property name=”transactionManager” ref=”transactionManager“/>
3. It’s All A Bit Backwards…
Now the crazy thing is, none of this may work — I haven’t actually tried any of this. There are so many new (to me) concepts flying around that I needed to write down what I was going to try to do just to keep track of it all. (It’s like trying to keep seven concepts in your head when you can only do five at once — you keep losing focus on one of the important concepts and have to work to bring it back while hopefully not losing focus on another one.)
Next time, we’ll see if it works!