jsr368-experts@jms-spec.java.net

[jsr368-experts] JMS 2.0 errata: JMS_SPEC-125 (Define whether a JMS provider should call reset after sending a BytesMessage asynchronously)

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Tue, 09 Dec 2014 12:51:24 +0000

Here's the next proposed correction for the JMS 2.0 errata release.
https://java.net/jira/browse/JMS_SPEC-125
(Define whether a JMS provider should call reset after sending a BytesMessage asynchronously)

I'll explain the issue in some detail. The actual proposed javadoc change is quite simple, so you light want to scroll
down to the end and read that first.

You can read a more nicely-formatted version in the JIRA issue.

Problem description
-------------------

This issue concerns the behaviour of the JMS provider when it sends a BytesMessage.

The spec is not clear on what state the body of a BytesMessage is left in after it has been sent. We're talking about
the message object in the sending program, not in the receiving program.

A JMS 2.0 vendor has asked for the behaviour to be clarified for async send. However this issue will discuss the
behaviour for both async and sync send.

Possible behaviour
------------------

There are three possibilities:

1. The JMS provider leaves the body in write-only mode with the stream positioned at the end. That would allow the
application to send a message, append additional data to the message body, and send it a second time. An application
which wanted to read the message body would have to call reset.

2. The JMS provider leaves the BytesMessage in read-only with the stream positioned at the start. To achieve this the
send method would need to call reset before returning.

3. Leave the behaviour undefined.

This issue applies to both synchronous and asynchronous send. In the sync case the issue is what state the message is
left in after the call to send returns. In the async case the issue is what state the message is in when the
CompletionListener callback is performed. Let's consider these separately.

Review of options for asynchronous send
---------------------------------------

Option 1 (leave the body in write-only mode with the stream positioned at the end):

     It is not practically possible for a JMS provider to implement this correctly. This is because of the need to
support the case where the JMS provider is used to send a message whose implementation is not its own (as required by
JMS 2.0 section 3.12). In that case the JMS provider must use the public API to read the data from the "foreign"
message. After it has done so the message would be in read-only mode, with the stream positioned at the end. The only
way to change the message to write-only mode would be to call reset, but that would position the stream back at the start.

Option 2 (leave the body in read-only mode with the stream positioned at the start).

     This is the current de facto spec requirement for async send. This is because there is a JMS 2.0 TCK test which
sends a BytesMessage asynchronously and which attempts to read the body of the message object passed to the
CompletionListener. without calling reset. All existing JMS 2.0 providers will have passed this test.

     There is also a clear use case for this option, since It is expected that a CompletionListener callback method may
want to read the message in order to identify the message that was successfully sent.

Option 3 (leave the behaviour undefined).

     This is undesirable because the only things a portable application application could do would be to call reset and
read the message, or call clearBody to clear it and re-write it from scratch. If a JMS provider left the body in
write-only mode with the stream positioned at the end, and the application took advantage of this to append to the body,
then the application would not be portable.

Proposed approach for asynchronous send
---------------------------------------

It is therefore proposed to update the JMS 2.0 specification to require the behaviour described in option 2: when a
BytesMessage is sent asynchronously, the message object that was sent must be set to be read-only with the stream
positioned at the start prior to calling the CompletionListener. To achieve this the send method would need to call
reset before returning.

Review of options for synchronous send
--------------------------------------

JMS 1.1 was not specific about this and different vendors already adopt different behaviour. There are no TCK tests
which rely on a specific behaviour. It is therefore probably too late to define more specific behaviour, especially as
this has not been reported as an issue by users or vendors.

In practice I would suggest that for a synchronous send there is little reason for a sending application to want to read
a the body of a BytesMessage after it has been sent.

Nevertheless, for consistency, we should perhaps change the spec to recommend that when a message is sent synchronously,
the provider should call reset before the send() returns. But this will need to remain a recommendation since existing
JMS 1.1 providers may have interpreted this differently, making it too late to standardise this.

Proposed approach for synchronous send
--------------------------------------

It is proposed to update the JMS 2.0 specification to recommend, but not require, that the provider should call reset
before the send() returns, and to add a warning that portable applications must not make assumptions about what state
the message is in.

Proposed changes
----------------

javadoc for BytesMessage: Existing text:

    When the message is first created, and when clearBody is called, the body of
    the message is in write-only mode. After the first call to reset has been
    made, the message body is in read-only mode.

    After a message has been sent, the client that sent it can retain and modify
    it without affecting the message that has been sent. The same message object
    can be sent multiple times.

    When a message has been received, the provider has called reset so that the
    message body is in read-only mode for the client.

Replacement text: (new words marked *thus)

    When the message is first created, and when clearBody is called, the body of
    the message is in write-only mode. After the first call to reset has been
    made, the message body is in read-only mode.

    *After a message has been sent synchronously, it is recommended that the
    provider has called reset so that the message body is in read-only mode.*

    *After a message has been sent asynchronously, the provider must call reset
    prior to invoking the CompletionListener so that the message body is in
    read-only mode. This means that the message passed to the
    CompletionListener may be read without the application needing to call
    reset.*

    *In both cases,* after a message has been sent *(a synchronous send has returned
    or an asynchronous send has completed and the CompletionListener has been
    invoked)*, the client that sent it can retain and modify it without affecting
    the message that has been sent. The same message object can be sent multiple
    times.

    When a message has been received, the provider has called reset so that the
    message body is in read-only mode for the client.