I've now drafted the necessary spec and API changes for this issue (the changes I circulated earlier were incomplete).
You can read a nicely-formatted version (and a summary of the problem and the proposed approach) at
https://java.net/jira/browse/JMS_SPEC-158
Once again these changes apply to the classic API but not to the simplified API since new methods don't have an issue
with compatibility. I'd welcome comments on whether you think it would be a good idea to extend these changes to the
simplified API as well.
Proposed changes
Changes to A.1.19 Clarification: use of stop or close from a message listener (JMS_SPEC-48)
Existing text
If a MessageListener’s onMessage method calls stop or close on its own
Connection, close on its own Session, or stop or close on its own JMSContext,
then the the JMS provider must throw a javax.jms.IllegalStateException.
Replacement text
In the simplified API, if a MessageListener’s onMessage method calls stop or
close on its own JMSContext, then the the JMS provider must throw a
javax.jms.IllegalStateException.
In the classic and domain-specific APIs, if a MessageListener’s onMessage
method calls stop or close on its own Connection or close on its own Session,
then the stop or close method will either fail and throw a
javax.jms.IllegalStateException, or it will succeed and close the connection.
Changes to Section 6.1.5 “Pausing delivery of incoming messages”
Existing text
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
javax.jms.IllegalStateException.
Replacement text
In the simplified API, if the stop method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.
In the classic and domain-specific APIs, if the stop method is called from a
message listener on its own Connection then it will either fail and throw a
javax.jms.IllegalStateException 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
using the classic and domain-specific APIs should avoid calling stop from
a message listener on its own Connection because this is not portable.
Changed to Section 6.1.8 “Closing a connection”
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
javax.jms.IllegalStateException.
Replacement text
In the simplified API, if the close method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.
In the classic and domain-specific APIs, if the close method is called from a
message listener on its own Connection then it will either fail and throw a
javax.jms.IllegalStateException or it will succeed and close the connection,
blocking until all other message listeners that may have been running have
returned, and all pending receive calls have 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
using the classic and domain-specific APIs should avoid calling close from
a message listener on its own Connection because this is not portable.
Changes to Section 6.2.15 “Closing a session”
Existing text
A message listener must not attempt to close its own session as this would
lead to deadlock. The JMS provider must detect this and throw a
javax.jms.IllegalStateException
Replacement text
In the simplified API, if the close method is called from a message listener
on its own JMSContext then it must throw a javax.jms.IllegalStateException.
In the classic and domain-specific APIs, if the close method is called from a
message listener on its own Session then it will either fail and throw a
javax.jms.IllegalStateException or it will succeed and close the Session,
blocking until any pending 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
using the classic and domain-specific APIs should avoid calling close from
a message listener on its own Session because this is not portable.
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 a
javax.jms.IllegalStateException, or it will succeed and close the connection,
blocking until all other message listeners that may have been running have
returned, and all pending receive calls have 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
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
IllegalStateException.
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 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 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 stop is invoked, the
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
IllegalStateException.
Replacement text:
This call blocks until receives and/or message listeners in progress have
completed. A call to 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 code 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 a
javax.jms.IllegalStateException, 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 receive call or message listener in
progress has completed.
Replacement text:
This call will block until a 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 a javax.jms.IllegalStateException,
or it will succeed and close the session, blocking until any pending 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 MessageListener must not attempt to close its own
Session> as this would lead to deadlock. The JMS provider must
detect this and throw a IllegalStateException.
Replacement text:
[Delete this text]