Announcement Announcement Module
Collapse
No announcement yet.
AutoProxied bean not propagating transaction rollback Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AutoProxied bean not propagating transaction rollback

    I've set up auto proxying and created a TransactionInterceptor to rollback on exceptions thrown from methods named "processMessage". It's configured with the following attribute:

    Code:
        <property name="properties">
          <props>
    	<prop key="processMessage">
    	  PROPAGATION_REQUIRED,-MessageProcException
    	</prop>
          </props>
        </property>
    My bean is an ActiveMQ container connector that is injected with an implementation of javax.jms.MessageListener.

    Code:
    <bean id="mqConnector" ...>
      ...
      <property name="messageListener">
        <ref bean="listener"/>
      </property>
    </bean>
    
    <bean id="listener" class="MyProcessor">
      <property name="destination"><value>my.Queue</value></property>
      ...
    </bean>
    Because the MessageListener interface (method 'onMessage()') doesn't throw checked exceptions, my implementation is an abstract class that includes an abstract 'processMessage()' method that does, and that is called by onMessage(). Implementations of this class for various processing needs implement processMessage():

    Code:
    abstract class my.MessageListenerImpl implements javax.jms.MessageListener &#123;
    
      public void onMessage&#40;Message m&#41; &#123;
        try &#123;
          processMessage&#40;m&#41;;
        &#125; catch &#40;Exception e&#41; &#123;
          logger.error&#40;e.getMessage&#40;&#41;&#41;;
        &#125;
    
      public abstract void processMessage&#40;Message m&#41; 
        throws MessageProcException;
    
    &#125;
    
    class MyProcessor extends MessageListenerImpl &#123;
    
      public void processMessage throws MessageProcException &#123;
        ...
      &#125;
    
    &#125;
    The onMessage() method is called by the connector when a message arrives for processing. It in turn calls processMessage(). If processMessage() throws, however, the transaction is not rolled back.

    When I add "PROPAGATION_REQUIRED,..." for "onMessage" in the interceptor's attributes and generate unchecked exceptions in onMessage(), the transaction is rolled back, but my MQ provider (ActiveMQ) doesn't seem to handle exceptions from MessageListener implementations gracefully (although I could be misinterpreting the logs.)

    I've also tried turning the two classes into two concrete classes, listener and processor, and injecting the listener with the processor but still no rollback on exception (the processor in this case still implements a processor interface). I was thinking that local method calls within a class might not execute proxy code.

    I'd love advice (no pun intended) on what to try next (or whether to just throw unchecked exceptions from MessagListener) from anyone who's configured transacted JMS message processing like this -- especially with ActiveMQ.

    thanks,

    kirt

  • #2
    Let onMessage throw MessageProcException wrapped in an unchecked exception, that's the only way to notify the transaction interceptor to rollback, apart from doing a programmatic rollback.

    Comment


    • #3
      that's the only way to notify the transaction interceptor to rollback, apart from doing a programmatic rollback
      You can specify rollback of checked exceptions declaritively as shown in the original post. See 7.4. Declarative transaction management of the reference manual.

      Comment


      • #4
        The checked exception is never thrown by the onMessage method, as illustrated in the code example.

        Comment


        • #5
          The checked exception is never thrown by the onMessage method, as illustrated in the code example.
          I see. kirt, if processMessage() is called directly by onMessage(), which it is, the proxy will never see the exception to enforce the rollback.

          Comment


          • #6
            Originally posted by katentim
            I see. kirt, if processMessage() is called directly by onMessage(), which it is, the proxy will never see the exception to enforce the rollback.
            If I change this so that onMessage() calls a processMessage() method on another bean, the proxy should then see exceptions thrown from the latter, right? So the proxy doesn't affect the inner workings of a class at all, just external calls to proxied objects?

            Thanks for your responses.

            Comment


            • #7
              Originally posted by kirt
              Originally posted by katentim
              I see. kirt, if processMessage() is called directly by onMessage(), which it is, the proxy will never see the exception to enforce the rollback.
              If I change this so that onMessage() calls a processMessage() method on another bean, the proxy should then see exceptions thrown from the latter, right? So the proxy doesn't affect the inner workings of a class at all, just external calls to proxied objects?
              Not quite. The proxy is a vehicle to decorate method calls with - in this case - an interceptor. The transactional interceptor will catch exceptions thrown by the target bean and based on its transaction attributes may do a rollback. The onMessage method catches the exception and does not rethrow so the exception will never reach the interceptor, hence no rollback will occur.

              Comment


              • #8
                Originally posted by kirt
                Originally posted by katentim
                I see. kirt, if processMessage() is called directly by onMessage(), which it is, the proxy will never see the exception to enforce the rollback.
                If I change this so that onMessage() calls a processMessage() method on another bean, the proxy should then see exceptions thrown from the latter, right? So the proxy doesn't affect the inner workings of a class at all, just external calls to proxied objects?
                Something just occured to me. The messages are processed asynchronously, so indeed, if you call a proxy instance from within the onMessage method a rollback would indeed occur.

                Comment


                • #9
                  Right -- the autoproxy mechanism would be used to proxy any bean implementation of a processMessage() method. Thanks for your help.

                  Comment

                  Working...
                  X