2 Replies Latest reply on Mar 26, 2009 5:05 AM by timfox

    JMSMessage.ack call is equivalent to JMSSession.commit()

    clebert.suconic


      Say.. you have a JMS Session, transacted...

       Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
       MessageConsumer consumer = consumerSess.createConsumer(queue1);
       conn.start();
      



      Say, an user now being aware of what he is doing calls message.acknowledge();

      int count = 0;
       while (true)
       {
       Message m = consumer.receive(200);
       if (m == null)
       {
       break;
       }
       m.acknowledge(); // This is invalid, but I guess we should just ignore this call
       count++;
       }
      



      ATM, a subsequent call to rollback is useless, as m.acknowledge already fired a transaction commit.

      Message javadoc states we should ignore the call to ack:

      "Calls to acknowledge are ignored for both transacted sessions and sessions specified to use implicit acknowledgement modes. "

      so.. what should we do on this case?

        • 1. Re: JMSMessage.ack call is equivalent to JMSSession.commit()
          clebert.suconic


          It should be a simple fix, but to fix that I would need access to JBossSession from JBossMessage, or the ACKMode as a property on JBossMessage.


          This is the complete test:

          class AcknowledgementTest
          ....
          
          
           public void testTransactionalAcknowledgementClientCallingACK() throws Exception
           {
           Connection conn = null;
          
           try
           {
           conn = cf.createConnection();
          
           Session producerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
           MessageProducer producer = producerSess.createProducer(queue1);
          
           Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED);
           MessageConsumer consumer = consumerSess.createConsumer(queue1);
           conn.start();
          
           final int NUM_MESSAGES = 20;
          
           // Send some messages
           for (int i = 0; i < NUM_MESSAGES; i++)
           {
           Message m = producerSess.createMessage();
           //m.acknowledge(); // This is invalid but this call should be ignored accordingly to the javadoc
           producer.send(m);
           }
          
           assertRemainingMessages(0);
          
           producerSess.rollback();
          
           // Send some messages
           for (int i = 0; i < NUM_MESSAGES; i++)
           {
           Message m = producerSess.createMessage();
           producer.send(m);
           }
           assertRemainingMessages(0);
          
           producerSess.commit();
          
           assertRemainingMessages(NUM_MESSAGES);
          
          
           int count = 0;
           while (true)
           {
           Message m = consumer.receive(200);
           if (m == null)
           {
           break;
           }
           m.acknowledge();
           count++;
           }
          
           assertRemainingMessages(NUM_MESSAGES);
          
           assertEquals(count, NUM_MESSAGES);
          
           consumerSess.rollback();
          
           assertRemainingMessages(NUM_MESSAGES);
          
           int i = 0;
           for (; i < NUM_MESSAGES; i++)
           {
           consumer.receive();
           }
          
           assertRemainingMessages(NUM_MESSAGES);
          
           // if I don't receive enough messages, the test will timeout
          
           consumerSess.commit();
          
           assertRemainingMessages(0);
          
           checkEmpty(queue1);
           }
           finally
           {
           if (conn != null)
           {
           conn.close();
           }
           }
           }
          
          
          


          • 2. Re: JMSMessage.ack call is equivalent to JMSSession.commit()
            timfox

            Actually I think the fix is even simpler.

            The JBossMessage only needs the session reference if it is CLIENT_ACK. So when we create the JBossMessage we pass in the session if it is CLIENT_ACK otherwise we pass in null.

            I have fixed this locally.