Why we’d want at least version 1.3.1

Bitronix Transaction Manager has been helpful for our integration tests, which can then run outside the app server and have a JTA transaction manager and enough of a JNDI provider to get by.

We have been using version 1.3, since that’s the version that first had the JNDI server.  But we had to specify disableJmx=true in the Configuration object so that the java: prefix could work.

This limitation has been removed as of BTM 1.3.1.  I’m BTM-enabling another module — maybe now’s the time to update to the current version of BTM…

We’ll want to JNDI-lookup the queue, too…

In our system we have proved out looking up the JMS connection factory from JNDI, but up to this point we have declared the Queue bean using an <amq:queue> element in the application bean files.  This ties our application code to the ActiveMQ broker, which we don’t want.  We want to move toward looking up the connection factory and the queue from JNDI.  That way the application bean file only needs to know the JNDI name, and we can configure the queue in the connection factory datasource configuration file on the app server (e.g., activemq-jms-ds.xml), probably as an mbean element in there:


   <mbean code="org.jboss.resource.deployment.AdminObject" name="activemq.queue:name=TheMBeanNameYouSeeInTheJMXConsole">
      <attribute name="JNDIName">this/is/the/jndi/name/the/bean/files/will/use</attribute>
      <depends optional-attribute-name="RARName">jboss.jca:service=RARDeployment,name='activemq-rar-5.1.0.rar'</depends>
      <attribute name="Type">javax.jms.Queue</attribute>
      <attribute name="Properties">PhysicalName=theQueueName.YouWillSee.In.ActiveMQ</attribute>
   </mbean>

But Who Will Care for the Babies?

This will be fine for a production environment — but what about our integration tests?  Right now we use Bitronix Transaction Manager 1.3’s JNDI server facilities to provide JNDI lookup of the JDBC datasource for our integration tests.  I thought we’d also use BTM to look up the JMS connection factory… but BTM does not support JNDI-looking-up queues as well.  Ludovic says:

If you really need a complete JNDI server, you can use Tomcat’s which is quite easy to reuse. This is what I recommended using before BTM 1.3, there is an example here: http://docs.codehaus.org/display/BTM/Hibernate

That’s probably what we’ll need to look into when the time comes…

Why it wasn’t blowing up when it should have been

I’m preparing to commit a change that will switch our code over from datasource beans defined within the .war project to datasources that are looked up via JNDI from the app server.  I have to make this change carefully, placing the datasource configuration file on the app servers and setting up the properties files beforehand so that my commit doesn’t break the build.

As part of my testing, I made the changes to my local JBoss.  Everything seemed to work.  Then I removed the no-longer-used properties that had been needed when we defined the bean locally.  Everything still worked.  Then, to make sure I wasn’t getting false positives, I removed the JNDI-name property that should be relied on by the new code…

Everything still worked.

The deployment failed when I deleted the properties file altogether, but it was satisfied even with a completely empty file.  What was going on?

What was going on

I had forgotten about some logic in our code that is responsible for loading the bean files — we don’t load the persistence beans file if the project doesn’t need them.  And currently all the persistence stuff is mocked out, so it doesn’t need them.  Since the beans file is not loaded, the project doesn’t care about those properties in the properties file.

Mystery solved.  Thanks to Detective Keith for his help!

java: Dropping the prefix

(Usually it’s good to drop one’s pretensions, but since all we have handy is a prefix we’ll just drop that instead…)

We are (for the moment, anyway) going to need to change our JBoss JDBC datasources so that the datasource resides in the global JNDI namespace, to be looked up under jndi-name Blah rather than java:Blah.  The reason we need to make this change is that Bitronix doesn’t currently support the java: prefix.

I seem to remember seeing a tag that you could put in your datasource configuration file that would tell JBoss to make the datasource available from the global JNDI namespace instead of from the JVM-specific java: one.

Ah yes, the JBoss 4 Application Server Guide and the DTD both document the use-java-context element.  Set that to false and it goes in the global JNDI namespace.  Using the java: namespace would be preferred; The JBoss 4 Application Server Guide also says,

DataSource wrappers are not usable outside of the server VM, so they are normally bound under the java:/, which isn’t shared outside the local VM.

That’s what we’ll need to set in our production datasources so that Bitronix Transaction Manager can exactly replicate the JNDI functionality at integration test time.

Why we wanted a JNDI server for integration testing

Why is having a JNDI server for our integration testing environment so helpful?  Well, just for our minimal XA integration test example, there were (at one point) fourteen Spring beans:

If we had to use a non-JNDI strategy for integration testing outside the app server, seven of these beans would have to be swapped out for test-only doubles — but we want our configuration for integration testing to match as closely as possible our production configuration so that we’re testing the same thing we’re deploying!

A minor simplification: the JtaTransactionManager bean

In a previous episode, I replaced a JTA transaction manager bean resembling this:


    <tx:jta-transaction-manager />

with a bean resembling this:


    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
    </bean>

That’s kind of ok, but having to change out that transaction manager bean makes the configuration more complicated.

As it turns out though, my testing shows that we can keep the


    <tx:jta-transaction-manager />

version and it finds the BTM UserTransaction and TransactionManager fine.

XA, JNDI and Bitronix, part 4: dancing on the happy path

In part 3, we tried our first JMS message send; but even after we wrapped the message send in a transaction using AOP, BTM still reported that “resource ‘activemq/QueueConnectionFactory’ cannot be used outside XA transaction scope.”  Today we’ll work to resolve that issue.

Both Sends and Receives Need Transactions

Ludovic’s helpful comment on yesterday’s post confirms that we need to make sure both sends and receives are in transactions.  As of yesterday, we were only wrapping the message sends, but not receives, in a transaction — at least that was what we were trying to do!  As it turns out, the transaction-wrappage of the sends was unsuccessful, while on the other hand we were accidentally successfully wrapping the receives!  Here’s how it happened:

Wrapping Sends: If It Ain’t A Bean…

As you may recall from yesterday, the pointcut I had defined for applying transaction advice to message sends was as follows:

        <aop:pointcut id="messageReceiveOperation" expression="execution(void com.example.dmn.JndiBitronixTest.transactedSendMessage(..))" />

But as Keith points out, since my JndiBitronixTest class is not defined as a bean in my Spring beans files, the transaction advice will not be applied to the transactedSendMessage method execution.  Oops!  I didn’t realize that Spring AOP advice applied only to beans!  Fixing that is easy enough: the transactedSendMessage method calls one layer down into the MessageSender class, which is defined as a bean.  We can just start the transaction there instead:

        <aop:pointcut id="messageSendOperation" expression="execution(void com.example.dmn.MessageSender.sendMessage(..))" />

Wrapping Receives: Forgotten Advice

I was looking in the main beans file to verify that MessageSender was defined as a bean when I saw a surprising thing:  I already had transactional advice on the message receives, including the following pointcut:

        <aop:pointcut id="messageReceiveOperation" expression="execution(void com.example.dmn.MessageProcessor.processIt(..))" />

This advice came along when I brought this code over from my original XA example manual test that runs only on an app server.  I consolidated this advice with the send advice into the spring-beans-bitronix.xml file to yield this advice:

    
        
            
        
    

    
        <aop:pointcut id="messageSendOperation" expression="execution(void com.example.dmn.MessageSender.sendMessage(..))" />
        
    

    
        <aop:pointcut id="messageReceiveOperation" expression="execution(void com.example.dmn.MessageProcessor.processIt(..))" />
        
    

And this time both pointcuts point to classes that are Spring beans.  :)

Happy Path Seems to Work

Now our integration test can send a JMS message and the listener picks it up from the queue and writes it to the database, without exceptions or stack traces.  Furthermore, when I bump the log level to DEBUG for Bitronix classes, in my log4j.properties file:

log4j.logger.bitronix.tm=DEBUG

Then I see encouraging looking XA-type messages like the following:

DEBUG bitronix.tm.BitronixTransaction  - committing, 2 enlisted resource(s)
DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to PREPARING
DEBUG bitronix.tm.journal.TransactionLogAppender  - between 19089 and 19193, writing a Bitronix TransactionLogRecord with status=PREPARING, recordLength=96, headerLength=28, time=1219154728262, sequenceNumber=11, crc32=-1825120209, gtrid=737072696E672D62746D0000011BDB48D3FF00000000, uniqueNames=XAOracleDS,activemq/QueueConnectionFactory
DEBUG bitronix.tm.journal.TransactionLogAppender  - disk journal appender now at position 19193
DEBUG bitronix.tm.twopc.AbstractPhaseEngine  - executing phase on 2 resource(s) enlisted in 1 position(s) in natural position order

...

DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to PREPARED
...

DEBUG bitronix.tm.twopc.Preparer  - successfully prepared 2 resource(s)
DEBUG bitronix.tm.BitronixTransaction  - 2 interested resource(s)
DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to COMMITTING (forced)
...

DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to COMMITTED

There’s Also a One-Phase Commit In There (and that’s good)

Before I found that two-phase commit sequence in the log, I found another sequence farther up


DEBUG bitronix.tm.BitronixTransaction  - committing, 1 enlisted resource(s)
DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to PREPARING
DEBUG bitronix.tm.journal.TransactionLogAppender  - between 18721 and 18813, writing a Bitronix TransactionLogRecord with status=PREPARING, recordLength=84, headerLength=28, time=1219154728200, sequenceNumber=7, crc32=-667556454, gtrid=737072696E672D62746D0000011BDB48D4AA00000003, uniqueNames=activemq/QueueConnectionFactory
DEBUG bitronix.tm.journal.TransactionLogAppender  - disk journal appender now at position 18813
DEBUG bitronix.tm.twopc.Preparer  - 1 resource enlisted, no prepare needed (1PC)
DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to PREPARED
DEBUG bitronix.tm.journal.TransactionLogAppender  - between 18813 and 18905, writing a Bitronix TransactionLogRecord with status=PREPARED, recordLength=84, headerLength=28, time=1219154728200, sequenceNumber=8, crc32=-2001767057, gtrid=737072696E672D62746D0000011BDB48D4AA00000003, uniqueNames=activemq/QueueConnectionFactory
DEBUG bitronix.tm.journal.TransactionLogAppender  - disk journal appender now at position 18905
DEBUG bitronix.tm.BitronixTransaction  - 1 interested resource(s)
DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to COMMITTING
DEBUG bitronix.tm.journal.TransactionLogAppender  - between 18905 and 18997, writing a Bitronix TransactionLogRecord with status=COMMITTING, recordLength=84, headerLength=28, time=1219154728200, sequenceNumber=9, crc32=236131807, gtrid=737072696E672D62746D0000011BDB48D4AA00000003, uniqueNames=activemq/QueueConnectionFactory
...

DEBUG bitronix.tm.BitronixTransaction  - changing transaction status to COMMITTED

I worried about line 8 where it said that only one resource was enlisted and so only a one-phase commit (1PC) was needed — “What happened to the database resource?” I wondered.  But then I remembered that this must be the message send (I tend to forget that that’s being transacted too), and the send does not involve the database resource.

Next Steps

I’d still like to have my integration test query the database to verify that the record really made it in there.

XA, JNDI and Bitronix, part 3: first send

In part two, we got the rest of the Spring beans connected up, and now we’re ready to try sending messages.

First Send

After initializing the application context, we’ll add this:


        MessageSender messageSender = (MessageSender) startupService.getContext().getBean("messageSender");
        messageSender.sendMessage("hello there");

We get this error:

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: error enlisting a MessageProducerWrapper of a DualSessionWrapper in state ACCESSIBLE of a JmsPooledConnection of pool activemq/QueueConnectionFactory in state ACCESSIBLE with underlying connection ActiveMQConnection {id=ID:blahblah-1409-1219089747392-2:1,clientId=ID:blahblah-1409-1219089747392-3:1,started=false} with 1 opened session(s)

Caused by: bitronix.tm.internal.BitronixSystemException: resource ‘activemq/QueueConnectionFactory’ cannot be used outside XA transaction scope. Set allowLocalTransactions to true if you want to allow this and you know your resource supports this.

Local Transactions Not Enough Help

We can set the allowLocalTransactions property on our bitronix.tm.resource.jms.PoolingConnectionFactory bean:

But we still get an error, though a new one:

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: Session’s XAResource has not been enlisted in a distributed transaction.

I’ll take out the allowLocalTransactions setting since it didn’t help.

The Stack Trace is Right

Come to think of it, that stack trace has a point — we’re not in a transaction.  My original tied-to-an-app-server XA example used AOP to start a transaction at the service layer entry point, but I removed all that when I stripped off the service layer for this integration test.  Let’s add in the AOP transactional stuff to the Bitronix spring beans file:

   
       
           
       

   

   
       
       
   

We still get:

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: error enlisting a MessageProducerWrapper of a DualSessionWrapper in state ACCESSIBLE of a JmsPooledConnection of pool activemq/QueueConnectionFactory in state ACCESSIBLE with underlying connection ActiveMQConnection {id=ID:blahblah-1759-1219092563720-2:1,clientId=ID:blahblah-1759-1219092563720-3:1,started=false} with 1 opened session(s)

Caused by: bitronix.tm.internal.BitronixSystemException: resource ‘activemq/QueueConnectionFactory’ cannot be used outside XA transaction scope. Set allowLocalTransactions to true if you want to allow this and you know your resource supports this.

Why aren’t we in an XA transaction?

Debug Statements

Let’s put some debug statements in there to


    @Test
    public void TestBitronix() {
        System.err.println("***Before transactedSendMessage");
        transactedSendMessage("hello there");
    }

    private void transactedSendMessage(String text) {
        MessageSender messageSender = (MessageSender) startupSvc.getContext().getBean("messageSender");
        System.err.println("***Before sendMessage");
        messageSender.sendMessage(text);
        System.err.println("***After sendMessage");
    }

When we run this, a curious thing happens: in the console output we see:

***Before transactedSendMessage
***Before sendMessage

But we should have seen a transaction start between those, shouldn’t we?

And on that unanswered question we must close for today!

(We’ll pick up next time.)

XA, JNDI and Bitronix, part 2: JDBC

In our last episode, we worked to get the JMS connection factory able to be looked up via JNDI using the Bitronix Transaction Manager… and after fixing several things, God helping us, we succeeded.  Today we want to re-enable the rest of the Spring beans in our project (Hibernate beans, default message listener container, etc.) and see them all working with Bitronix.

Updating to BTM 1.3

Over the weekend, Bitronix Transaction Manager version 1.3 final was released.  I wanted to update to that from version 1.3-RC2, so I updated the <version> tag of the btm artifact in my project’s pom file and removed the <repository> section that had been pointing to the codehaus-snapshots repository (the full 1.3 release is now on the regular Maven 2 central repository, so I no longer need to reference the early releases repository).

I re-ran my integration test and it still does the JNDI lookup fine.  That was easy!

Bringing In the Beans

Our goal is to not have to modify production Spring bean files for integration testing… but this project will help us determine how to set up the production bean files to make this possible.  So this time around, I’m going to have to modify my mock-production bean files to work in the non-app-server environment

First, let’s get rid of the JTA transaction manager bean ( <tx:jta-transaction-manager /> ) from our main bean file.  The definition of the transactionManager bean needs to be different in a production environment than with Bitronix, so that bean doesn’t belong in a production beans file.  Along with this, we need to rename our transaction manager bean from JtaTransactionManager to transactionManager, since that’s what the jta-transaction-manager bean provided and the Hibernate sessionFactory is expecting.

We also need to remove the “java:” from the jndi-name our queueConnectionFactory expects to look up: <jee:jndi-lookup id="queueConnectionFactory" jndi-name="java:activemq/QueueConnectionFactory" />

…and similar with the Oracle datasource in spring-beans-hibernate-SimplePersonDAO.xml:     <jee:jndi-lookup id="myDataSource" jndi-name="java:XAOracleDS" />

Can’t Find the Database Datasource

Now when we run our integration test, Spring complains that nothing named XAOracleDS is available from JNDI.  Ah, yes — we need to give Bitronix the details of what’s needed so it can make a datasource available under that name.

So, combining step 2 of the Spring procedure with some hints from the JDBC pools setup documentation, I cobbled together this bean:


    <bean id="oracleDataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource" init-method="init" destroy-method="close">
<property name="className" value="oracle.jdbc.xa.client.OracleXADataSource" />
<property name="uniqueName" value="XAOracleDS" />
<property name="maxPoolSize" value="5" />
<property name="driverProperties">
<props>
<prop key="user">myUser</prop>
<prop key="password">myPassword</prop>
<prop key="URL">jdbc:oracle:thin:@localhost:1521:XE</prop>
            </props>
        </property>
    </bean>

I don’t expect this to work right off, because I don’t think I have the Oracle XE library listed in my pom file.  But — vaguely TDD-style — let’s try it first and verify that we do get an error.  Sure enough:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘oracleDataSource’ defined in class path resource [spring-beans-bitronix.xml]: Invocation of init method failed; nested exception is bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named XAOracleDS

And way down toward the end of the stack trace is this:

Caused by: java.lang.ClassNotFoundException: oracle.jdbc.xa.client.OracleXADataSource

Let’s add the Oracle jdbc driver dependency to our pom file:


        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc5</artifactId>
            <version>11.1.0.6.0</version>
        </dependency>

Bitronix Transaction Manager Refuses to Start?

After Maven Eclipsing to update my project with the new dependency, I now get this:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘BitronixTransactionManager’ defined in class path resource [spring-beans-bitronix.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public static synchronized bitronix.tm.BitronixTransactionManager bitronix.tm.TransactionManagerServices.getTransactionManager()] threw exception; nested exception is bitronix.tm.utils.InitializationException: recovery failed, cannot safely start the transaction manager

Why can BTM not safely start?  Is it trying to force me to come along with its view of how much risk is acceptable in a system’s configuration?  …But wait, let’s look at some of those Caused-bys farther down in the stack trace:

Caused by: bitronix.tm.recovery.RecoveryException: error running recovery on resource XAOracleDS

And farther down:

Caused by: java.sql.SQLException: Io exception: The Network Adapter could not establish the connection

Aha — I forgot to fire up my local Oracle XE instance.  Oops!

Thank You for Watching the Caused-By Show

(Remember The Cosby Show? :)

After starting up Oracle and re-running my test… I get the same error again, but — now I’m getting some XA verbiage showing up in the Caused-Bys:

Caused by: bitronix.tm.recovery.RecoveryException: error running recovery on resource XAOracleDS (XAER_RMERR)

and

Caused by: javax.transaction.xa.XAException

I wonder if that means we’re getting close?

After messing around a while, I searched the BTM forum and found that the Oracle user under which I’m performing the integration test needs to have certain additional database privileges:

grant select on sys.dba_pending_transactions to myUser;
grant select on sys.pending_trans$ to myUser;
grant select on sys.dba_2pc_pending to myUser;
grant execute on sys.dbms_system to myUser;

[First, drop to Oracle SQL command line and do connect / as sysdba]

Hey, now the integration test passes!  (Granted, it’s only instantiating all the beans so far, but that means the Oracle JDBC JNDI lookup must have succeeded…!)

Guess allowLocalTransactions needs to stay

Following one of the examples, I had put the following two settings in my Oracle data source bean definition:

<property name="allowLocalTransactions" value="true" />
<property name="testQuery" value="SELECT 1 FROM DUAL" />

Do we really need these settings?  Let’s try removing them.

We get an error:

java.sql.SQLException: error enlisting a JdbcConnectionHandle of a JdbcPooledConnection from datasource XAOracleDS in state ACCESSIBLE wrapping oracle.jdbc.driver.T4CXAConnection@948069 on oracle.jdbc.driver.LogicalConnection@17a7706

…with this Caused-By:

Caused by: bitronix.tm.internal.BitronixSystemException: resource ‘XAOracleDS’ cannot be used outside XA transaction scope. Set allowLocalTransactions to true if you want to allow this and you know your resource supports this.

Removing the testQuery property setting doesn’t seem to have any similarly bad effect, but maybe I’ll just leave both of these settings in for the moment.

Where We Are

We now have all our beans instantiated, including the big three (JDBC datasource, JMS connection factory, and XA transaction manager), and the only changes we had to make to the “production” bean files were to remove the java: namespace from the jndi-names and get rid of the jta-transaction-manager bean declaration.

In our next installment, we’ll try sending a message and see what happens.

Getting everything right

There are sometimes a bunch of things that you have to get right, and getting any one of them wrong keeps you from being where you need to be.   (I guess it’s a lot worse for space shuttle engineers!)

Things I Had Wrong

Here are six issues, mostly from today, that all needed to be corrected for my project to work:

  1. I didn’t have a jndi.properties file with a java.naming.factory.initial setting pointing to the bitronix.tm.jndi.BitronixInitialContextFactory.  This was causing a NoInitialContextException.
  2. I didn’t realize that Bitronix Transaction Manager supports (at least) two types of config file: the transaction manager config file and the resource loader config file.  I was putting settings in the transaction manager config file (defaults to bitronix-default-config.properties) that belong in the release loader config file.  This caused those settings to be ignored by BTM (if my bitronix-default-config.properties file is being read at all, which I’m not sure of).
  3. The bitronix.tm.resource.configuration property by which you can specify a resource loader config file expects a path relative to the folder in which you started the virtual machine, not relative to the classpath, so my resource loader configuration was never being found (that’s also why I got a NullPointerException when I tried to set the resourceConfigurationFilename property on the btmConfig bean).
  4. The uniqueName I was using for the JMS ConnectionFactory was java:activemq/QueueConnectionFactory, but BTM’s JNDI implementation doesn’t support the colon-ized namespace (i.e., I needed to remove the “java:” from the JNDI-name).  [Update 8/26/2008: It turns out you can use the java:-prefixed with BTM if you do it right]
  5. I neglected to set the init-method and destroy-method on my PoolingConnectionFactory bean, so the my org.apache.activemq.ActiveMQXAConnectionFactory underlying my bitronix.tm.resource.jms.PoolingConnectionFactory never got initialized (causing the uniqueName to never be registered with the JNDI server).
  6. I misspelled the name of the underlying class for my connection factory bean — as  org.activemq.ActiveMQXAConnectionFactory, when it’s actually org.apache.activemq.ActiveMQXAConnectionFactory — so I got a “ResourceConfigurationException: cannot create JMS connection factory named QueueConnectionFactory” error that had as its cause farther down a “java.lang.ClassNotFoundException: org.activemq.ActiveMQXAConnectionFactory”

Honorable Mention

I had also specified the wrong implementation of the slf4j-api (slf4j-jdk14 instead of slf4j-log4j12) in my pom file, which meant I didn’t see all of BTM’s messages when I set the logging level to DEBUG in log4j.properties.  This didn’t directly keep my project from doing what it oughta, but it might have slowed the problem analysis.

Unnecessary Changes

These are things that at one time or another I suspected I needed to change, but that ended up not being part of the problem:

  • Adding a jndiEnvironment section to the JndiObjectFactoryBean definition for the queueConnectionFactory.  This would have resulted in a queueConnectionFactory bean definition like this:
    <bean id="queueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:activemq/QueueConnectionFactory" />
    <property name="jndiEnvironment">
    <props>
    <prop key="java.naming.factory.initial">bitronix.tm.jndi.BitronixInitialContextFactory</prop>
        </props>
      </property>
    </bean>

    This was taken care of by having this setting in the jndi.properties file.

  • Adding a depends-on attribute to the BitronixTransactionManager bean and/or queueConnectionFactory JndiObjectFactoryBean explicitly telling Spring which other beans needed to be instantiated before these beans.  Seems to work fine without that.
  • Adding bitronix.tm.resource.bind = true to a bitronix-default-config.properties in the root of the classpath.  The JNDI lookup seems to be doing fine without explicitly setting this property.

Analysis

Two quick points:

  • Experience will be a great help here, as inexperience with JNDI and BTM were a big part of why I took all these wrong turns; and
  • Hallelujah that it’s Friday!  :)

Where We Are Now

I have JNDI lookup working on both a JTA transaction manager and a JMS connection factory, kicked off from a JUnit-based integration test.

Next Steps

I need to get my JDBC datasource hooked up similarly, on the way to getting my whole XA example working as a JUnit test — sending a message to the JMS queue, receiving it and writing to the database, demonstrating both the commit and a rollback situations.