Announcement Announcement Module
Collapse
No announcement yet.
Help on JMS + XA Transaction! Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help on JMS + XA Transaction!

    I am quite new to Spring, using standalone transaction managers. I am trying a put a message on to a queue using JMSTemplate and have it participate in a XA Transaction.

    Here are my configurations:

    Active MQ Config:

    Code:
    <bean id="xaConnectionFactory"
    		class="org.apache.activemq.ActiveMQXAConnectionFactory">
    	<property name="brokerURL"
    			value="tcp://localhost:61616" />
    </bean>
    
    <bean id="queue"
    	class="org.apache.activemq.command.ActiveMQQueue">
    	<constructor-arg value="TestQ" />
    </bean>
    Transaction Manager Config:

    Code:
    <!-- Construct a TransactionManager, needed to configure Spring	-->
    <bean id="atomikosTransactionManager"
    	class="com.atomikos.icatch.jta.UserTransactionManager"
    	init-method="init" destroy-method="close">
    	<property name="forceShutdown">
    		<value>true</value>
    	</property>
    	<property name="transactionTimeout">
    		<value>600</value>
    	</property>
    </bean>
    
    <!-- Configure a UserTransaction, needed to configure Spring -->
    <bean id="atomikosUserTransaction"
    	class="com.atomikos.icatch.jta.UserTransactionImp" />
    	
    <!-- Configure the Spring framework to use JTA transactions from the JTA provider -->
    <bean id="springTransactionManager"
    	class="org.springframework.transaction.jta.JtaTransactionManager">
    	<property name="transactionManager">
    		<ref bean="atomikosTransactionManager" />
    	</property>
    	<property name="userTransaction">
    		<ref bean="atomikosUserTransaction" />
    	</property>
    </bean>
    Code:

    Code:
    utx = (UserTransactionImp) ctx.getBean("atomikosUserTransaction");
    utx.begin();
    
    // Simulate putting message on a JMS queue
    ConnectionFactory cf = (ConnectionFactory) ctx.getBean("xaConnectionFactory");
    
    JmsTemplate jmsTemplate = new JmsTemplate();
    jmsTemplate.setConnectionFactory(cf);
    
    jmsTemplate.send(new ActiveMQQueue("queue"), new MessageCreator() {
        public Message createMessage(Session session) throws JMSException {
            return session.createTextMessage("hello queue world");
        }
    });
    & Finally the exception that is thrown:

    Code:
    Caused by: javax.jms.JMSException: Session's XAResource has not been enlisted in a distributed transaction.
    	at org.apache.activemq.ActiveMQXASession.doStartTransaction(ActiveMQXASession.java:109)
    	at org.apache.activemq.ActiveMQSession.send(ActiveMQSession.java:1587)
    	at org.apache.activemq.ActiveMQMessageProducer.send(ActiveMQMessageProducer.java:226)
    	at org.apache.activemq.ActiveMQMessageProducerSupport.send(ActiveMQMessageProducerSupport.java:240)
    	at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:572)
    	at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:549)
    	at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:516)
    	at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:447)
    	... 24 more
    Any thoughts on the above problem?

  • #2
    Configure Atomikos connection factory

    Hi,

    You seem to have forgotten an Atomikos connection factory (delegating to the Active MQ XA connection factory). The Atomikos connection factory intercepts calls to the JMS and does the XA enlist to which your error refers.

    See the Atomikos samples in the download folder for examples.

    Guy

    Comment


    • #3
      Update

      Thanks for your response Guy.

      I updated the above code:

      Code:
      	<!-- Configure the JMS connector; call init to register for recovery! -->
      	<bean id="queueConnectionFactoryBean"
      		class="com.atomikos.jms.QueueConnectionFactoryBean"
      		init-method="init">
      		<property name="resourceName">
      			<value>QUEUE_BROKER</value>
      		</property>
      		<property name="xaQueueConnectionFactory">
      			<ref bean="xaConnectionFactory" />
      		</property>
      	</bean>

      Code:
      	<!-- JMS Template -->
      	<bean id="xaJmsTemplate"
      		class="org.springframework.jms.core.JmsTemplate">
      		<property name="connectionFactory"
      			ref="queueConnectionFactoryBean" />
      	</bean>
      Now, the following exception is thrown

      Code:
      javax.transaction.RollbackException: Prepare: NO vote
      	at com.atomikos.icatch.jta.TransactionImp.commit(Unknown Source)
      	at com.atomikos.icatch.jta.TransactionManagerImp.commit(Unknown Source)
      	at com.atomikos.icatch.jta.UserTransactionImp.commit(Unknown Source)
      	at com.foo.bar.xaTran.TextXA.testCommit(TestXA.java:131)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      	at java.lang.reflect.Method.invoke(Unknown Source)
      	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
      	at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
      	at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
      	at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
      	at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
      	at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
      	at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
      	at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
      	at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
      	at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
      	at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
      	at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
      	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
      	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
      Block state after rollback : CLOSED
      java.lang.IllegalStateException: This method needs a transaction for the calling thread and none exists.
      Possible causes: either you didn't start a transaction,
      it rolledback due to timeout, or it was committed already.
      ACTIONS: You can try one of the following: 
      1. Make sure you started a transaction for the thread.
      2. Make sure you didn't terminate it yet.
      3. Increase the transaction timeout to avoid automatic rollback of long transactions;
         check http://www.atomikos.org/forums/viewtopic.php?t=1259 for how to do this.
      	at com.atomikos.icatch.jta.TransactionManagerImp.raiseNoTransaction(Unknown Source)
      	at com.atomikos.icatch.jta.TransactionManagerImp.rollback(Unknown Source)
      	at com.atomikos.icatch.jta.UserTransactionImp.rollback(Unknown Source)
      	at com.foo.bar.xaTran.TextXA.testCommit(TestXA.java:141)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      	at java.lang.reflect.Method.invoke(Unknown Source)
      	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
      	at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
      	at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
      	at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
      	at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
      	at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
      	at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
      	at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
      	at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
      	at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
      	at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
      	at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
      	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
      	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
      	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
      My java code in the post above starts a user transaction, so this jms call is well within the scope of a transaction. I am not sure what is going wrong here... and why is it complaining that the commit is not within in a transaction. Any thoughts?

      Comment


      • #4
        SessionTransacted

        Please set sessionTransacted=true on the jms template.

        Guy

        Comment


        • #5
          No luck

          That gave the same error:

          Code:
          	<!-- JMS Template -->
          	<bean id="xaJmsTemplate"
          		class="org.springframework.jms.core.JmsTemplate">
          		<property name="connectionFactory"
          			ref="queueConnectionFactoryBean" />
          		<property name="sessionTransacted" value="true" />
          	</bean>

          Comment

          Working...
          X