First, let me apologize for the length of this post, but I thought that giving detailed information was the only way anybody might be able to help me. This actually is a very simplified test case.

I'm having trouble getting proper transaction behavior using the Spring JTA transaction manager in conjunction with JOTM standalone, using XAPool's datasource, and oracle's jdbc driver on a 10g database.

As far as I understand from reading J2EE w/o EJB and the reference guide and forums, I should be able to use JOTM standalone with the JtaTransactionManager, and when using an XADataSource (XAPool) that is wired to the JtaTransactionManager, the JdbcTemplate should participate in jta-managed transactions automatically.

My logs seem fine to me, and there is every indication that synchronization is occurring correctly and the the transaction gets rolled back before the connection is closed, but the deleted rows that should have been rolled back do not get rolled back.

Here are the relevant bean definitions I'm using:

Code:
<bean id="appXaDataSource"
    class="org.enhydra.jdbc.oracle.OracleXADataSource" singleton="false" destroy-method="shutdown">
    <property name="transactionManager">
        <ref local="jotm"/>
    </property>     
</bean>
<bean id="jotm" class="org.springframework.transaction.jta.JotmFactoryBean"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="userTransaction">
        <ref local="jotm"/>
    </property>
    <property name="transactionManager">
        <ref local="jotm"/>
    </property>
</bean>
<bean id="txTestProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="target"><bean class="com.thatone.archie.transactions.TransactionTestor"/></property>
    <property name="transactionManager"><ref bean="transactionManager"/></property>
    <property name="transactionAttributes">
        <props>
            <prop key="delete*">PROPAGATION_REQUIRED,-RuntimeException</prop>
        </props>
    </property>
    <property name="proxyTargetClass"><value>true</value></property>
</bean>
The test class that throws the exception contains the following method:

Code:
    public void deleteWithFailure&#40;JdbcTemplate template, String table, String idColumnName, Object&#91;&#93; ids&#41; &#123;
        final String query = QueryUtils.createDeleteQuery&#40;table, new Object&#91;&#93; &#123;
            ids&#91;0&#93;
        &#125;, idColumnName&#41;;

        // delete only the first id, then throw an exception

        int rowsAffected = template.update&#40;query&#41;;
        System.out.println&#40;"\t\tDeleted " + rowsAffected + " rows."&#41;;
        assert rowsAffected == 1 &#58; "1 row should have been deleted, not " + rowsAffected;
        System.out.println&#40;"\t\tThrowing exception to check rollback."&#41;;
        throw new RuntimeException&#40;"Throwing exception to check rollback."&#41;;
    &#125;
The JdbcTemplate that I pass in is created using the datasource constructor, and the datasource object that is passed in is the bean above where id="appXaDataSource". I get it from the context, set its properties, then create the JdbcTemplate, which is then used for the test above.

The unittest is very simple. It just gets the transaction proxy ("txTestProxy") from the context, counts the rows in a table in 1 transaction, calls deleteWithFailure in a 2nd transaction (passing in the JdbcTemplate and other parameters), and then counts the rows in a 3rd transaction. The result is that 1 row is deleted, even though the logs show that a rollback occurred on the transaction that deleted the row.

At the risk of giving too much information, here are the log messages I see from when the transaction proxy gets the transaction object until the completion of the transaction in question:

(First line in each is the message, second line is class and method that logged the message)


Code:
Getting transaction for method 'deleteWithFailure' in class &#91;com.thatone.archie.transactions.TransactionTestor&#93;
org.springframework.transaction.interceptor.TransactionAspectSupport#getTransaction

Current.getStatus&#40;&#41;
org.objectweb.jotm.Current#getStatus

Creating new transaction
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

Beginning JTA transaction
org.springframework.transaction.jta.JtaTransactionManager#doBegin

begin transaction
org.objectweb.jotm.Current#begin

serverName=, ipAddr=0
org.objectweb.jotm.XidImpl#<init>

new Xid &#40;uuid= 403646f851002&#41;
org.objectweb.jotm.XidImpl#<init>

xid=bb14111130343033363436663835313030325f305f...0, timeout=60
org.objectweb.jotm.TransactionImpl#<init>

myXid=bb14111130343033363436663835313030325f305f...0
org.objectweb.jotm.TransactionImpl#getXid

tx=bb14111130343033363436663835313030325f305f...0
org.objectweb.jotm.Current#begin

flag=TMJOIN
org.objectweb.jotm.TransactionImpl#doAttach

number of enlisted=0
org.objectweb.jotm.TransactionImpl#doAttach

Associate tx to xid &#40;xid=bb14111130343033363436663835313030325f305f...0&#41;
org.objectweb.jotm.Current#putTxXid

myXid=bb14111130343033363436663835313030325f305f...0
org.objectweb.jotm.TransactionImpl#getXid

set timer for tx &#40;timer=org.objectweb.jotm.TimerEvent@8d5485, tx=bb14111130343033363436663835313030325f305f...0&#41;
org.objectweb.jotm.TransactionImpl#setTimer

Initializing transaction synchronization
org.springframework.transaction.support.TransactionSynchronizationManager#initSynchronization

Executing SQL update &#91;DELETE FROM order_item_details WHERE id IN &#40;'00000000000000000000000000000047'&#41;&#93;
org.springframework.jdbc.core.JdbcTemplate#update

Opening JDBC connection
org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

StandardDataSource&#58;getConnection Connection from DriverManager is returned
org.enhydra.jdbc.util.Logger#debug

Registering transaction synchronization for JDBC connection
org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

Bound value &#91;org.springframework.jdbc.datasource.ConnectionHolder@193a6a5&#93; for key &#91;&#91;driver=oracle.jdbc.OracleDriver@126f816, url=jdbc&#58;oracle&#58;thin&#58;@//localhost&#58;1521/archie, user=testDb1&#93;&#93; to thread &#91;main&#93;
org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

Retrieved value &#91;org.springframework.jdbc.datasource.ConnectionHolder@193a6a5&#93; for key &#91;&#91;driver=oracle.jdbc.OracleDriver@126f816, url=jdbc&#58;oracle&#58;thin&#58;@//localhost&#58;1521/archie, user=testDb1&#93;&#93; bound to thread &#91;main&#93;
org.springframework.transaction.support.TransactionSynchronizationManager#getResource

SQL update affected 1 rows
org.springframework.jdbc.core.JdbcTemplate$1UpdateStatementCallback#doInStatement

Retrieved value &#91;org.springframework.jdbc.datasource.ConnectionHolder@193a6a5&#93; for key &#91;&#91;driver=oracle.jdbc.OracleDriver@126f816, url=jdbc&#58;oracle&#58;thin&#58;@//localhost&#58;1521/archie, user=testDb1&#93;&#93; bound to thread &#91;main&#93;
org.springframework.transaction.support.TransactionSynchronizationManager#getResource

Applying rules to determine whether transaction should rollback on java.lang.RuntimeException&#58; Throwing exception to check rollback.
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

Winning rollback rule is&#58; RollbackRule with pattern &#91;RuntimeException&#93;
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

Invoking rollback for transaction on method 'deleteWithFailure' in class &#91;com.thatone.archie.transactions.TransactionTestor&#93; due to throwable &#91;java.lang.RuntimeException&#58; Throwing exception to check rollback.&#93;
org.springframework.transaction.interceptor.TransactionAspectSupport#doCloseTransactionAfterThrowing

Triggering beforeCompletion synchronization
org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerBeforeCompletion

Removed value &#91;org.springframework.jdbc.datasource.ConnectionHolder@193a6a5&#93; for key &#91;&#91;driver=oracle.jdbc.OracleDriver@126f816, url=jdbc&#58;oracle&#58;thin&#58;@//localhost&#58;1521/archie, user=testDb1&#93;&#93; from thread &#91;main&#93;
org.springframework.transaction.support.TransactionSynchronizationManager#unbindResource

Closing JDBC connection
org.springframework.jdbc.datasource.DataSourceUtils#doCloseConnectionIfNecessary

Initiating transaction rollback
org.springframework.transaction.support.AbstractPlatformTransactionManager#rollback

Rolling back JTA transaction
org.springframework.transaction.jta.JtaTransactionManager#doRollback

Current.rollback&#40;&#41;
org.objectweb.jotm.Current#rollback

TransactionImpl.rollback&#40;&#41;
org.objectweb.jotm.TransactionImpl#rollback

myXid=bb14111130343033363436663835313030325f305f...0
org.objectweb.jotm.TransactionImpl#getXid

unset timer for tx &#40;timer=org.objectweb.jotm.TimerEvent@8d5485, tx=bb14111130343033363436663835313030325f305f...0&#41;
org.objectweb.jotm.TransactionImpl#unsetTimer

Triggering afterCompletion synchronization
org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCompletion

Clearing transaction synchronization
org.springframework.transaction.support.TransactionSynchronizationManager#clearSynchronization
I'm hoping somebody who has worked with JOTM/JTA and Spring (best of all would be Oracle too) could sanity check my setup above and see if anything obvious is wrong.

Thanks very much for any pointers.

-calvin