glassfish
  1. glassfish
  2. GLASSFISH-7118

If JMSRA returns isSameRM=true then TM calls incorrect sequence of start() and end()

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: v2.1
    • Fix Version/s: future release
    • Component/s: jms
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      7,118
    • Status Whiteboard:
      Hide

      V2.1.1_exclude

      Show
      V2.1.1_exclude

      Description

      I have discovered that if I change the implementation of XAResource in JMSRA to
      return isSameRM()=true then the GlassFish TM does not perform the correct
      sequence of calls to start() and end().

      If I make this change, I observe the following sequence of calls when a MDB
      running in GlassFish 2.1 receives a message and sends a second message, within
      an XA transaction.

      (inboundXAResource is the XAResource for the inbound message; outboundXAResource
      is the XAResource for the outbound message)

      1. inboundXAResource.start(xid1, TMNOFLAGS)

      2. outboundXAResource.start(xid1, TMJOIN)
      3. work done using outbound resource (sending the outbound message to the broker)
      4. outboundXAResource.end(xid1, TMSUCCESS)

      5. work done using inbound resource (sending an ack back to the broker)
      6. inboundXAResource.end(xid1, TMSUCCESS)
      7. transaction is committed (details omitted)

      Step (4) is incorrect: it should not end() the transaction branch until just
      before the commit.

      Here is more information about how I came to this conclusion:

      Steps 2,3 and 4 were triggered by the MDB performing the following:

      connection = getOutboundConnectionFactory().createConnection();
      session = connection.createSession(false,
      javax.jms.Session.AUTO_ACKNOWLEDGE);
      TextMessage tm = session.createTextMessage(text);
      MessageProducer messageProducer =
      session.createProducer(getOutboundDestination());
      messageProducer.setDeliveryMode(deliveryMode);
      messageProducer.send(tm);
      session.close();
      connection.close();

      ...which is all perfectly standard and correct code.

      When createConnection() is called, this causes outboundXAResource.start(xid1,
      TMJOIN) (step 2) to be called:

      XAResourceForMC.start(Xid, int) line: 880
      TransactionState.startAssociation(XAResource, Control, int) line: 312
      TransactionImpl.enlistResource(XAResource) line: 205
      J2EETransaction.enlistResource(XAResource) line: 577

      J2EETransactionManagerOpt(J2EETransactionManagerImpl).enlistResource(Transaction, ResourceHandle)
      line: 372
      J2EETransactionManagerOpt.enlistResource(Transaction, ResourceHandle) line:
      144
      ResourceManagerImpl.registerResource(ResourceHandle) line: 144
      ResourceManagerImpl.enlistResource(ResourceHandle) line: 102
      PoolManagerImpl.getResource(ResourceSpec, ResourceAllocator,
      ClientSecurityInfo) line: 216
      ConnectionManagerImpl.internalGetConnection(...) line: 337
      ConnectionManagerImpl.allocateConnection(...) line: 235
      ConnectionManagerImpl.allocateConnection(ManagedConnectionFactory,
      ConnectionRequestInfo, String) line: 165
      ConnectionManagerImpl.allocateConnection(ManagedConnectionFactory,
      ConnectionRequestInfo) line: 158
      ConnectionFactoryAdapter._allocateConnection(String, String) line: 179
      ConnectionFactoryAdapter.createConnection(String, String) line: 166
      ConnectionFactoryAdapter.createConnection() line: 148
      MessageForwarderBean(GenericMDB).sendJMSMessageToOutboundQueue(String) line:
      71
      MessageForwarderBean(GenericMDB).onMessage(Message) line: 56

      When connection.close() is called, this causes outboundXAResource.end(xid1,
      TMSUCCESS) (step 4) to be called:

      XAResourceForMC.end(Xid, int) line: 468
      TransactionState.endAssociation(XAResource, int) line: 359
      TransactionImpl.delistResource(XAResource, int) line: 242
      J2EETransaction.delistResource(XAResource, int) line: 563

      J2EETransactionManagerOpt(J2EETransactionManagerImpl).delistResource(Transaction, ResourceHandle,
      int) line: 832
      J2EETransactionManagerOpt.delistResource(Transaction, ResourceHandle, int)
      line: 229
      ResourceManagerImpl.unregisterResource(ResourceHandle, int) line: 265
      ResourceManagerImpl.delistResource(ResourceHandle, int) line: 223
      PoolManagerImpl.resourceClosed(ResourceHandle) line: 400
      ConnectorAllocator$ConnectionListenerImpl.connectionClosed(ConnectionEvent)
      line: 72
      ConnectionEventListener.sendEvent(int, Exception, Object) line: 143
      ManagedConnection.sendEvent(int, Exception, Object) line: 676
      ConnectionAdapter.close() line: 255
      MessageForwarderBean(GenericMDB).sendJMSMessageToOutboundQueue(String) line:
      84
      MessageForwarderBean(GenericMDB).onMessage(Message) line: 56

      However we are still in onMessage() here, and so I don't think it is correct to
      call end() at this point. I think this is the root cause of the problem.

      I have performed the same test using the JMSJCA resource adaptor (which seems to
      work fine with a JOIN), and I notice that in this case the call to
      outboundXAResource.end(xid1, TMSUCCESS) is deferred until just before the commit,

      Using the debugger I have compared the code that is executed to try to find out
      why JMSJCA seems to "work" whilst JMSRA doesn't.

      The reason can be found in J2EETransactionManagerImpl (part of GlassFish)

      public boolean delistResource(Transaction tran, ResourceHandle h,
      int flag)
      throws IllegalStateException, SystemException {
      if (_logger.isLoggable(Level.FINE))
      _logger.log(Level.FINE,"TM: delistResource");
      if (!h.isShareable() || multipleEnlistDelists) {
      if (h.isTransactional() && h.isEnlisted())

      { return tran.delistResource(h.getXAResource(), flag); }

      else

      { return true; }

      }
      return true;
      }

      As can be seen, if the resource handle is "shareable" the resource is not
      delisted. In GlassFish, the JMSRA is hard-coded to be non-sharable whilst JMSJCA
      is not, which is why the two behave differently.

      As far as I can see the fact that this works at all in JMSJCA is a fluke, since
      according to Frank Kieviet a JMSJCA resource is not actually shareable, and the
      SeeBeyond integration server had it hardcoded as such. However this was never
      done in GlassFish.

      Nevertheless it seems that this shareable flag seems to be the reason why
      isSameRM() works in JMSJCA but not with JMSRA.

      However I don't think that setting shareable to false is the correct solution,
      since (as I said) the concept of connection sharing and the concept of joining
      resources in a transaction branch being different and concepts: just because
      isSameRM() returns true doesn't mean that JMSRA now support connection sharing.

      In particular, I am concerned that enabling connection sharing with JMSRA may
      have undesirable side effects since it may cause the
      application server to reuse connection objects in a way that it did not do
      before, and which might not work.

      There are numerous places in GlassFish which hard-code "shareable" to be false
      for the JMSRA resource adaptor. I don't
      personally know why this was done, but I have heard suggestions that it was done
      to pass the JMS CTS tests.

        Activity

        Hide
        marina vatkina added a comment -

        Reassigning to jms to followup.

        From Sankar's email:

        IMO, things should work once we make Resourcehandle.isShreable() return true for
        JMS Resource also (the way it is done for the JDBC Resource) and I believe, this
        is the least risk option. I don't think just because
        Resourcehandle.isShreable() is returned true (Ramesh gave a patch for the same
        some time ago), we are reusing the same inbound connection for outbound
        connection and vice versa. I would expect at least we test once the isSameRM()
        is implemented properly, using the Ramesh's patch, whether thing would work or not.

        Show
        marina vatkina added a comment - Reassigning to jms to followup. From Sankar's email: IMO, things should work once we make Resourcehandle.isShreable() return true for JMS Resource also (the way it is done for the JDBC Resource) and I believe, this is the least risk option. I don't think just because Resourcehandle.isShreable() is returned true (Ramesh gave a patch for the same some time ago), we are reusing the same inbound connection for outbound connection and vice versa. I would expect at least we test once the isSameRM() is implemented properly, using the Ramesh's patch, whether thing would work or not.
        Hide
        Nigel Deakin added a comment -

        As I feared, changing Glassfish to perform connection sharing when using JMSRA
        has undesired side-effects: See Glassfish 2.1.1 issue 8997. In short, JMSRA does
        not support connection sharing, and so simply emabling its use is not sufficient
        to resolve this issue.

        Show
        Nigel Deakin added a comment - As I feared, changing Glassfish to perform connection sharing when using JMSRA has undesired side-effects: See Glassfish 2.1.1 issue 8997. In short, JMSRA does not support connection sharing, and so simply emabling its use is not sufficient to resolve this issue.
        Hide
        jthoennes added a comment -

        Will these changes part of OpenMQ 4.4 and GF v2.1.1?

        Actually, I am looking forward to the integration of the Generic JMSRA and the
        JMSJCA into OpenMQ 4.4.

        Show
        jthoennes added a comment - Will these changes part of OpenMQ 4.4 and GF v2.1.1? Actually, I am looking forward to the integration of the Generic JMSRA and the JMSJCA into OpenMQ 4.4.
        Hide
        fkieviet added a comment -

        add fkieviet to cc

        Show
        fkieviet added a comment - add fkieviet to cc
        Hide
        kumara added a comment -

        Changing version from 9.1.1 to v2.1 to reflect new name/version.

        Show
        kumara added a comment - Changing version from 9.1.1 to v2.1 to reflect new name/version.
        Hide
        Satish Kumar added a comment -

        Reassiging the issue to Marina since this seems to be more of a TM issue than
        JMS related.

        Show
        Satish Kumar added a comment - Reassiging the issue to Marina since this seems to be more of a TM issue than JMS related.
        Hide
        jagadesh added a comment -

        Will not be fixed for V2.1.1

        Show
        jagadesh added a comment - Will not be fixed for V2.1.1
        Hide
        jagadesh added a comment -

        Will not be fixed for V2.1.1

        Show
        jagadesh added a comment - Will not be fixed for V2.1.1

          People

          • Assignee:
            marina vatkina
            Reporter:
            Nigel Deakin
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated: