Camel
  1. Camel
  2. CAMEL-5055

Offer a way to not set a transaction manager in camel-jms

    Details

    • Estimated Complexity:
      Unknown

      Description

      The following sample Spring config sets up a camel-activemq component

      <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> 
           <property name="configuration" ref="jmsConfigAmq" />
        </bean>
        
        <bean id="jmsConfigAmq" class="org.apache.activemq.camel.component.ActiveMQConfiguration" >
            <property name="connectionFactory" ref="jmsPooledConnectionFactory" /> 
            <property name="transacted" value="true"/> 
            <!--  <property name="transactionManager" ref="jmsTransactionManager" />  -->
            <property name="cacheLevelName" value="CACHE_CONSUMER"/>
        </bean>
        
        <bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
          <property name="connectionFactory" ref="jmsPooledConnectionFactory" />
        </bean>           
           
        <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
          <property name="brokerURL" value="tcp://localhost:61617" /> 
          <property name="watchTopicAdvisories" value="false" />
        </bean>
      	    
         <bean id="jmsPooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" >
            <property name="maxConnections" value="1"/>
            <property name="connectionFactory" ref="jmsConnectionFactory"/>
         </bean>
      

      The ActiveMQConfiguration sets transacted=true and configures for a JmsTransactionManager. Also, a PooledConnectionFactory is used.
      The config for a camel-jms component would be similar.

      The Spring JMS javadoc on AbstractPollingMessageListenerContainer.setTransactionManager states:

      Note: Consider the use of local JMS transactions instead. Simply switch the "sessionTransacted" flag to "true" in order to use a locally transacted JMS Session for the entire receive processing, including any Session operations performed by a SessionAwareMessageListener (e.g. sending a response message).

      It basically advises to only set transacted=true and don't specify a TX manager. The benefit of doing so is that the cacheLevel setting will be honored when using local transactions without a configured TX manager. When a TX manager is configured, no caching happens at DMLC level and its necessary to rely on a pooled connection factory. This is discussed here.

      However right now its not possible to configure the cameljms or camel-activemq component to not use an external TX manager when transacted=true is set.
      Even when setting lazyCreateTransactionManager=false.
      In case of camel-activemq, it still creates a default JmsTransactionManager:

      ActiveMQConfiguration.java
      public PlatformTransactionManager getTransactionManager() {
        PlatformTransactionManager answer = super.getTransactionManager();
        if (isTransacted() && answer == null) {
          // lets auto-default the transaction manager if its not specified
          answer = createTransactionManager();
          setTransactionManager(answer);
          answer = getTransactionManager();
        }
        return answer;
      }
      

      In case of camel-jms it throws an exception:

      JmsConfiguration.java
      PlatformTransactionManager tm = getTransactionManager();
      if (tm != null) {
        container.setTransactionManager(tm);
      } else if (transacted) {
        throw new IllegalArgumentException("Property transacted is enabled but a transactionManager was not injected!");
      }
      

      We should allow for using transactions in camel-jms and camel-activemq without setting an external TX manager.

        Issue Links

          Activity

          Hide
          Babak Vahdat added a comment -

          No I don't think so, as what this JIRA ticket resolved was only to change the behaviour in the case where transacted was true but there was no transactionManager to be injected.

          That's the change is instead of throwing IllegalArgumentException like:

          PlatformTransactionManager tm = getTransactionManager();
          if (tm != null) {
            container.setTransactionManager(tm);
          } else if (transacted) {
            throw new IllegalArgumentException("Property transacted is enabled but a transactionManager was not injected!");
          }
          

          We do now:

          PlatformTransactionManager tm = getTransactionManager();
          if (tm != null) {
            container.setTransactionManager(tm);
          } else if (transactionManager == null && transacted && !lazyCreateTransactionManager) {
            container.setSessionTransacted(true);
          }
          

          And that's it!

          Maybe verify/check other potential changes you may have done in your config, code and whatnot. And please use the User-Forum for any further Questions you may have where you could still reference this ticket.

          Show
          Babak Vahdat added a comment - No I don't think so, as what this JIRA ticket resolved was only to change the behaviour in the case where transacted was true but there was no transactionManager to be injected. That's the change is instead of throwing IllegalArgumentException like: PlatformTransactionManager tm = getTransactionManager(); if (tm != null ) { container.setTransactionManager(tm); } else if (transacted) { throw new IllegalArgumentException( "Property transacted is enabled but a transactionManager was not injected!" ); } We do now: PlatformTransactionManager tm = getTransactionManager(); if (tm != null ) { container.setTransactionManager(tm); } else if (transactionManager == null && transacted && !lazyCreateTransactionManager) { container.setSessionTransacted( true ); } And that's it! Maybe verify/check other potential changes you may have done in your config, code and whatnot. And please use the User-Forum for any further Questions you may have where you could still reference this ticket.
          Hide
          Marco Zapletal added a comment -

          Thanks. Since some days, I also notice that approx. 5% of my messages get redelivered

          Example log entry: Transaction commit (0x26b5f36e) redelivered(true) for (MessageId: ID:MYSERVER-51520-1338396250920-0:4:2:1:30 on ExchangeId: ID-4711)) [Camel (myserver) thread #8 - JmsConsumer[MyJMSQueue]] [o.a.c.s.s.TransactionErrorHandler]

          Could it be the case that the patch provokes this, since I haven't had these redeliveries before.

          Show
          Marco Zapletal added a comment - Thanks. Since some days, I also notice that approx. 5% of my messages get redelivered Example log entry: Transaction commit (0x26b5f36e) redelivered(true) for (MessageId: ID:MYSERVER-51520-1338396250920-0:4:2:1:30 on ExchangeId: ID-4711)) [Camel (myserver) thread #8 - JmsConsumer [MyJMSQueue] ] [o.a.c.s.s.TransactionErrorHandler] Could it be the case that the patch provokes this, since I haven't had these redeliveries before.
          Hide
          Babak Vahdat added a comment -

          Thanks for the hint. I did a mistake where I unintentionally removed one existing line:

          container.setSessionTransacted(transacted); 
          

          I did revert this which now makes your test pass again.

          Show
          Babak Vahdat added a comment - Thanks for the hint. I did a mistake where I unintentionally removed one existing line: container.setSessionTransacted(transacted); I did revert this which now makes your test pass again.
          Hide
          Marco Zapletal added a comment -

          With this change, a config like the one mentioned in the description does not work any longer by failing with 'javax.jms.JMSException: acknowledgeMode SESSION_TRANSACTED cannot be used for an non-transacted Session."

          Please find attached a test case showing the exception (or did I miss anything in the config?)

          Show
          Marco Zapletal added a comment - With this change, a config like the one mentioned in the description does not work any longer by failing with 'javax.jms.JMSException: acknowledgeMode SESSION_TRANSACTED cannot be used for an non-transacted Session." Please find attached a test case showing the exception (or did I miss anything in the config?)
          Hide
          Babak Vahdat added a comment - - edited

          I opened AMQ-3861 to track this on AMQ side as well.

          Show
          Babak Vahdat added a comment - - edited I opened AMQ-3861 to track this on AMQ side as well.
          Hide
          Babak Vahdat added a comment -

          Now you can reach the behaviour using:

          transacted=true
          lazyCreateTransactionManager=false
          
          Show
          Babak Vahdat added a comment - Now you can reach the behaviour using: transacted= true lazyCreateTransactionManager= false
          Hide
          Torsten Mielke added a comment -

          I am not working on this bug right now (due to missing time). So feel free to implement a solution.
          Many thx.
          Torsten

          Show
          Torsten Mielke added a comment - I am not working on this bug right now (due to missing time). So feel free to implement a solution. Many thx. Torsten
          Hide
          Babak Vahdat added a comment -

          Torsten, do you already work on a patch or am I allowed to take over this?

          Show
          Babak Vahdat added a comment - Torsten, do you already work on a patch or am I allowed to take over this?
          Hide
          Claus Ibsen added a comment -

          Torsten, you are welcome to work on a patch.

          Show
          Claus Ibsen added a comment - Torsten, you are welcome to work on a patch.

            People

            • Assignee:
              Babak Vahdat
              Reporter:
              Torsten Mielke
            • Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development