Search code examples
spring-bootweblogic12cspring-jmsxaatomikos

Why isn't Remote Weblogic JMS participating in XA Transaction in spring boot?


I am working on a spring-boot application where I need XA to ensure that JPA updates and JMS messages generation is either all or nothing. The problem is when a rollback happens, DB is rolling back, but not the JMS message.

I am running with embedded tomcat and JMS server is Weblogic12c.

I followed the JTA directions from the spring-boot documentation and added the dependencies for Atomikos (transactions-jms, transactions-jta, transactions-jdbc) as well as spring-boot-starter-jta-atomikos.

In the logs I can see that Atomikos is running and what appears to be the JPA queries being added to the XA transaction, but nothing for JMS.

The logs below come from code where I do JPA updates, then send JMS message using JMSTemplate, then I throw a RuntimeException:

INFO  c.a.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'dataSource': getConnection ( null )...   
INFO  c.a.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'dataSource': init...   
INFO  c.a.i.imp.CompositeTransactionImp - addParticipant ( XAResourceTransaction: 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 ) for transaction 10.30.60.173.tm0000100044   
INFO  c.a.d.xa.XAResourceTransaction - XAResource.start ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 , XAResource.TMJOIN ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98   
INFO  c.a.i.imp.CompositeTransactionImp - registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@f4a9582b ) for transaction 10.30.60.173.tm0000100044   
INFO  c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling prepareStatement(select prjct_rvsn_seq_num_seq.nextval from dual)...   
INFO  c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: isClosed()...   
INFO  c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling getWarnings...   
INFO  c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling clearWarnings...   
INFO  c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: close()...   
INFO  c.a.d.xa.XAResourceTransaction - XAResource.end ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 , XAResource.TMSUCCESS ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98   
INFO  c.c.ola.order.service.OrderService - Order saved of scope:FIRST with app ID:1127662    
INFO  c.c.o.o.s.OrderEventBroadcaster - Sending message  on queue jms/AppQueue   
DEBUG o.s.jms.core.JmsTemplate - Executing callback on JMS Session: weblogic.jms.client.WLSessionImpl@24cfb8e8   
DEBUG o.s.j.s.d.JndiDestinationResolver - Located object with JNDI name [jms/AppQueue]   
DEBUG o.s.jms.core.JmsTemplate - Sending created message: TextMessage[null, <?xml version="1.0" encoding="...]   
INFO  c.a.d.xa.XAResourceTransaction - XAResource.rollback ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98   
INFO  com.atomikos.icatch.jta.Sync2Sync - afterCompletion ( STATUS_ROLLEDBACK ) called  on Synchronization: org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization@25385341   
INFO  c.a.i.imp.CompositeTransactionImp - rollback() done of transaction 10.30.60.173.tm0000100044  

In my googling, I haven't seen much. It appears that it should just work, but it isn't where did I drop the ball?

UPDATE:

Below is how I'm creating my ConnectionFactory:

@Bean
FactoryBean<ConnectionFactory> jmsConnectionFactory(final JndiTemplate jndiTemplate) {
    final JndiObjectFactoryBean beanFactory = new JndiObjectFactoryBean();

    beanFactory.setJndiTemplate(jndiTemplate);
    beanFactory.setJndiName("jms.remoteConnectionFactory");
    beanFactory.setProxyInterface(ConnectionFactory.class);

    return (FactoryBean) beanFactory;
}

UPDATE:

Since the logs referenced weblogic.jms.client.WLSessionImpl instead of something with "XA" in the name, I investigated what weblogic was returning. The instance returned from "jms.remoteConnectionFactory" was weblogic.jms.client.JMSXAConnectionFactory which does not implement javax.jms.XAConnectionFactory which seems weird. I don't know why that is or if that is problem, but it seems like it could be.


Solution

  • My solution was to set sessionTransacted to true on the jmsTemplate.

    @Bean
    JmsTemplate cciSitesJmsTemplate(@CciSites final ConnectionFactory connectionFactory, final JndiDestinationResolver destinationResolver) {
        final JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setDestinationResolver(destinationResolver);
        // NOTE: sessionTransacted is required to join the XA transaction
        jmsTemplate.setSessionTransacted(true);
        return jmsTemplate;
    }