Uploaded image for project: 'Application Server 3  4  5 and 6'
  1. Application Server 3 4 5 and 6
  2. JBAS-6343

JCA adapter inflow does not Roll back messages if using a non-xa connection factory in the JNDIProviderAdapter

    XMLWordPrintable

Details

    • Hide

      Throw a RuntimeException out of the onmessage to roll the tx back.

      Show
      Throw a RuntimeException out of the onmessage to roll the tx back.

    Description

      This customer is using a non-xa connection factory(IBMMQ) and is having problems with 4.2.3 rolling messages back.
      In 4.0.5, it looks like we set up an XATransactionDemarcationStrategy if the pool activation was set up for isDeliveryTransacted, but we didn't look to make sure that the resource gave us an XASession.
      if(pool.getActivation().isDeliveryTransacted())
      {
      try
      {
      return new XATransactionDemarcationStrategy();

      in 4.2.3, we fixed this and now its

      if (activation.isDeliveryTransacted() && xaSession != null)
      {
      try
      {
      current = new XATransactionDemarcationStrategy();

      This means that the customer was getting an XATransactionDemarcationStrategy, but now they are getting the LocalDemarcationStrategy. I thought to myself, wow, the XATransactionDemarcationStrategy should not work, but I see there is code in the bottom to handle it in the XATransactionDemarcationStrategy.

      // NO XASession? then manually rollback.
      // This is not so good but
      // it's the best we can do if we have no XASession.
      if (xaSession == null && pool.getActivation().isDeliveryTransacted())

      { session.rollback(); }

      Looking at the jms inflow adapter, it doesn't look like we've ever supported transaction rollbacks for non-xa connection factories, but because of a bug in 4.0.5, we were allowing nonXA connection factories to get the XATransactionDemarcationStrategy. Inside of the 4.0.5 XATransactionDemarcationStrategy, when the tx is rolled back, we look to see if we have an XA session to rollback. if we don't, then we roll back the transacted session. So returning the wrong factory actaully gave us the correct behavior. Once we fixed the bug in 4.0.5, it seems that we broke what was once working.

      What I would expect to see in the LocalDemarcationStrategy is something that would check current transaction to see if it's rolled back before calling the commit on the transacted session(similar to whats in the old StdServerSession). Here's what I see in the end for the LocalDemarcationStrategy in the inflow adapter.

      private class LocalDemarcationStrategy implements TransactionDemarcationStrategy
      {
      public void end()
      {
      final JmsActivationSpec spec = pool.getActivation().getActivationSpec();

      if (spec.isSessionTransacted())
      {
      if (session != null)
      {
      try

      { session.commit(); }

      catch (JMSException e)

      { log.error("Failed to commit session transaction", e); }
      }
      }
      }

      The code above just calls commit on the session, even if the tx has had setRollbackOnly on it inside the onMessage in an MDB. We tell customers not to throw runtime exceptions out of the onMessage because it causes the instance of the MDB to be thrown away.(which slows down performance and is discouraged by all the specs). But it looks like throwing a Runtime exception(which calls error, which calls session.rollback) is the only way to roll back a message for a non-xa ConnectionFactory(transacted session).

      Should we support a non-xa connection factory by adding the logic to look at the transaction and roll the transacted session back if the current transaction is in a rolled back state? The fix, I would imagine would be something like this in the End of the LocalDemarcationStrategy. The fix would check the current tx to see if it's rolled back and if it is, it would roll the transacted session back.

      This is somewhat of what I would expect.
      private class LocalDemarcationStrategy implements TransactionDemarcationStrategy
      {
      public void end()
      {
      final JmsActivationSpec spec = pool.getActivation().getActivationSpec();

      if (spec.isSessionTransacted())
      {
      if (session != null)
      {
      try
      {
      .....
      // Marked rollback
      if (trans.getStatus() == Status.STATUS_MARKED_ROLLBACK)
      { if (trace) log.trace("Rolling back JMS transacted session"); // actually roll it back session.rollback(); ... }
      else
      session.commit();
      }
      catch (JMSException e)
      { log.error("Failed to commit session transaction", e); }

      }
      }
      }

      Attachments

        Issue Links

          Activity

            People

              rhn-support-jhowell William Howell
              rhn-support-jhowell William Howell
              Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: