users@jms-spec.java.net

[jms-spec users] Re: JMS 2.0 Errata: JMS_SPEC-158 (JMS 2.0 introduced incompatible changes to Connection.stop and close and Session.close)

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Thu, 27 Nov 2014 18:49:30 +0000

On 27/11/2014 15:29, Nigel Deakin wrote:

> The solution
> -------------
>
> It is proposed to amend JMS 2.0 to state that the requirement to throw an exception is OPTIONAL. JMS vendors would be
> allowed to decide whether these methods should throw an exception or return normally. This would allow vendors which
> have long allowed these methods to return normally to continue to do so, and avoid breaking existing applications.
>
> Existing JMS 2.0 implementations would not need to change.
>
> Since this would mean that some vendors would throw an exception and some would not, applications which relied on these
> methods being called from a message listener would not be portable, and the specification would need to warn of this.
>
> (In the longer term, this lack of portability could be resolved by removing the option to throw an exception. That is
> the subject of a separate issue JMS_SPEC-159 which might be considered for JMS 2.1.)

If we accept that vendors that previously allowed close and stop to be called (from a message listener on its own
connection or session) should be allowed to continue to do so, then the next question is how specific the spec should be
about what these methods should do.

My suggestion is that if these methods don't throw an IllegalStateException then they should behave exactly as stop() or
close() are required to behave anywhere else, except that the requirement to block for onMessage calls to complete is
waived in respect of the calling thread's own message listener.

To explain what I mean, here are some draft changes to the javadoc descriptions of these methods:

Changes to the javadocs for javax/jms/Connection.html#close():
--------------------------------------------------------------

Existing text:

         When this method is invoked, it should not return until message
         processing has been shut down in an orderly fashion. This means that all
         message listeners that may have been running have returned, and that all
         pending receives have returned.

Replacement text:

         When this method is invoked, it should not return until message
         processing has been shut down in an orderly fashion. This means that all
         message listeners that may have been running have returned, and that all
         pending receives have returned.

          However if the close method is called from a message listener on its own
          connection, then it will either fail and throw an <tt>IllegalStateException</tt>,
          or it will succeed and close the connection, blocking until all other
          message listeners that may have been running have returned, and all
          pending receives have returned. If close succeeds and the acknowledge mode
          of the session is set to AUTO_ACKNOWLEDGE, the current message will still
          be acknowledged automatically when the onMessage() call completes.

[Comment: I think it is clear that once you've closed the connection or session you can't call message.acknowledge() or
session.commit(), but I'm less sure whether an auto-ack message should still get acknowledged. One possibility is to
leave that undefined.]

          Since two alternative behaviors are permitted in this case, applications
          should avoid calling close from a message listener on its own
          connection because this is not portable.

Existing text:

         A message listener must not attempt to close its own connection as this
         would lead to deadlock. The JMS provider must detect this and throw a
         <tt>IllegalStateException</tt>.

Replacement text:

          [Delete this text]

Changes to the javadocs for javax/jms/Connection.html#stop():
-------------------------------------------------------------

Existing text:

         This call blocks until receives and/or message listeners in progress have
         completed.

Replacement text:

          [Delete this text]
        
Existing text:

         A call to {_at_code stop} must not return until delivery of messages
         has paused. This means that a client can rely on the fact that none of
         its message listeners will be called and that all threads of control
         waiting for {_at_code receive} calls to return will not return with a
         message until the connection is restarted. The receive timers for a
         stopped connection continue to advance, so receives may time out while
         the connection is stopped.
        
         If message listeners are running when {_at_code stop} is invoked, the
         {_at_code stop} call must wait until all of them have returned before
         it may return. While these message listeners are completing, they must
         have the full services of the connection available to them.

         A message listener must not attempt to stop its own connection as this
         would lead to deadlock. The JMS provider must detect this and throw a
         <tt>IllegalStateException</tt>.

Replacement text:

         This call blocks until receives and/or message listeners in progress have
         completed. A call to {_at_code stop} must not return until delivery of messages
         has paused. This means that a client can rely on the fact that none of
         its message listeners will be called and that all threads of control
         waiting for {_at_code receive} calls to return will not return with a
         message until the connection is restarted. The receive timers for a
         stopped connection continue to advance, so receives may time out while
         the connection is stopped.
        
         However if the stop method is called from a message listener on its own
          connection, then it will either fail and throw an <tt>IllegalStateException</tt>,
          or it will succeed and stop the connection, blocking until all other message
          listeners that may have been running have returned.

          Since two alternative behaviors are permitted in this case, applications
          should avoid calling stop from a message listener on its own
          connection because this is not portable.

Changes to the javadocs for javax/jms/Session.html#close()
----------------------------------------------------------

Existing text:

         This call will block until a {_at_code receive} call or message listener in
         progress has completed.

Replacement text:

         This call will block until a {_at_code receive} call or message listener in
         progress has completed.

          However if the close method is called from a message listener on its own
          session, then it will either fail and throw an <tt>IllegalStateException</tt>,
          or it will succeed and close the session, blocking until a {_at_code receive} call
          in progress has completed. If close succeeds and the acknowledge mode
          of the session is set to AUTO_ACKNOWLEDGE, the current message will still
          be acknowledged automatically when the onMessage() call completes.

          Since two alternative behaviors are permitted in this case, applications
          should avoid calling close from a message listener on its own
          session because this is not portable.

Existing text:

         * A <tt>MessageListener</tt> must not attempt to close its own
         * <tt>Session</tt> as this would lead to deadlock. The JMS provider must
         * detect this and throw a <tt>IllegalStateException</tt>.

Replacement text:

          [Delete this text]




Nigel