jms-spec
  1. jms-spec
  2. JMS_SPEC-43

New API to send a message with async acknowledgement from server

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.1
    • Fix Version/s: 2.0ED, 2.0PD, 2.0
    • Labels:
      None

      Description

      This is a proposal for a new API which will send a message and return immediately without blocking until an acknowledgement has been received from the server. Instead, when the acknowledgement is received, an asynchronous callback will be invoked.

      Here is a suggested API:

      There would be a new method on javax.jms.MessageProducer:

      public void setAcknowledgeListener(AcknowledgeListener listener);
      

      This would change the behaviour of any subsequent call to any of the four send methods so that they would return without blocking until an acknowledgement has been received from the server. When the acknowledgement is received, the callback method on the AcknowledgeListener is received.

      This feature will only be available for non-transacted sessions. if setAcknowledgeListener was called on a transacted session then a javax.jms.IllegalStateException would be thrown.

       
      package javax.jms;
      import javax.jms.Message;
      
      public interface AcknowledgeListener {
      	public void onAcknowledge(Message message);
      }
      
      

        Issue Links

          Activity

          Hide
          timlfox added a comment - - edited

          Another, IMO, nicer way of doing this is to pass in some kind of CompletionHandler as an extra method in the send() method on the MessageProducer. When the message is acked, this would be called.

          This technique allows an anonymous class (or lambda in Java 8) to implement the CompletionHandler which can act as a closure around some state associated with the send, which makes programming easier for the developer.

          e.g

          for (int i = 0; i < 100; i++) {
            producer.send(message, new CompletionHandler() {
              public void onComplete() { database.delete(i); }
            });
          }
          

          or in Java 8:

          for (int i = 0; i < 100; i++) {
            producer.send(message, #{ database.delete(i) });
          }
          

          With your proposal this would be more complex - the developer would have to maintain a map of message against, whatever data was necessary to complete the request.

          This technique is also more in fitting with the new asynchronous channels used in java.nio.channels

          Show
          timlfox added a comment - - edited Another, IMO, nicer way of doing this is to pass in some kind of CompletionHandler as an extra method in the send() method on the MessageProducer. When the message is acked, this would be called. This technique allows an anonymous class (or lambda in Java 8) to implement the CompletionHandler which can act as a closure around some state associated with the send, which makes programming easier for the developer. e.g for (int i = 0; i < 100; i++) { producer.send(message, new CompletionHandler() { public void onComplete() { database.delete(i); } }); } or in Java 8: for (int i = 0; i < 100; i++) { producer.send(message, #{ database.delete(i) }); } With your proposal this would be more complex - the developer would have to maintain a map of message against, whatever data was necessary to complete the request. This technique is also more in fitting with the new asynchronous channels used in java.nio.channels
          Hide
          Nigel Deakin added a comment -

          Good idea. Thanks for this and all your other comments.

          Show
          Nigel Deakin added a comment - Good idea. Thanks for this and all your other comments.
          Hide
          Nigel Deakin added a comment - - edited

          Here is an alternative proposal based on Tim's comments above:

          This is a proposal for a new API which will send a message and return immediately without blocking until an acknowledgement has been received from the server. Instead, when the acknowledgement is received, an asynchronous callback will be invoked.

          There would be two new send methods on javax.jms.MessageProducer:

          send(Message message, 
             javax.jms.AcknowledgeListener acknowledgeListener ) 
          
          send(Message message, int deliveryMode, int priority, long timeToLive, 
             javax.jms.AcknowledgeListener acknowledgeListener) 
          

          This would have the same behaviour as the corresponding existing send methods except that that they would return without blocking until an acknowledgement has been received from the server. When the acknowledgement is received, the callback method on the supplied AcknowledgeListener is invoked.

          These methods allow a different callback object to be specified for each message that is sent. This allows applications to can pass in an anonymous class with message-specific state, which would not be possible if the same callback object were used for multiple messages.

          This feature will only be available for non-transacted sessions. if these methods are called on a transacted session then a javax.jms.IllegalStateException would be thrown.

           
          package javax.jms;
          import javax.jms.Message;
          
          public interface AcknowledgeListener {
          	public void onAcknowledge(Message message);
          }
          
          
          Show
          Nigel Deakin added a comment - - edited Here is an alternative proposal based on Tim's comments above: This is a proposal for a new API which will send a message and return immediately without blocking until an acknowledgement has been received from the server. Instead, when the acknowledgement is received, an asynchronous callback will be invoked. There would be two new send methods on javax.jms.MessageProducer : send(Message message, javax.jms.AcknowledgeListener acknowledgeListener ) send(Message message, int deliveryMode, int priority, long timeToLive, javax.jms.AcknowledgeListener acknowledgeListener) This would have the same behaviour as the corresponding existing send methods except that that they would return without blocking until an acknowledgement has been received from the server. When the acknowledgement is received, the callback method on the supplied AcknowledgeListener is invoked. These methods allow a different callback object to be specified for each message that is sent. This allows applications to can pass in an anonymous class with message-specific state, which would not be possible if the same callback object were used for multiple messages. This feature will only be available for non-transacted sessions. if these methods are called on a transacted session then a javax.jms.IllegalStateException would be thrown. package javax.jms; import javax.jms.Message; public interface AcknowledgeListener { public void onAcknowledge(Message message); }
          Hide
          Hiram Chirino added a comment -

          A send may fail so the interface AcknowledgeListener should extend ExceptionListener.

          Show
          Hiram Chirino added a comment - A send may fail so the interface AcknowledgeListener should extend ExceptionListener.
          Hide
          Hiram Chirino added a comment -

          Async acknowledgements would be handy for all potentially blocking JMS operations. I would be nice to have the same kind of support added to the commit and message.acknowledge methods.

          Show
          Hiram Chirino added a comment - Async acknowledgements would be handy for all potentially blocking JMS operations. I would be nice to have the same kind of support added to the commit and message.acknowledge methods.
          Hide
          Hiram Chirino added a comment -

          Since JMS already uses the 'Acknowledge' term for consumer acking messages, perhaps AcknowledgeListener is not the best interface name. I'd rather see it renamed CompletionHandler as Tim suggested or Callback etc.

          Show
          Hiram Chirino added a comment - Since JMS already uses the 'Acknowledge' term for consumer acking messages, perhaps AcknowledgeListener is not the best interface name. I'd rather see it renamed CompletionHandler as Tim suggested or Callback etc.
          Hide
          julienrenaut added a comment -

          Hello all.

          Some scenarios might benefit from having two different kind of callbacks. One to confirm a message has correctly arrived on the destination queue and another to confirm a message has been correctly delivered to it's recipient (picked up from destination queue).

          I propose two different callback interfaces then.

          MessageArrivalCallback.java
          package javax.jms;
          import javax.jms.Message;
          
          public interface MessageArrivalCallback {
              void onArrival(Message message);
          }
          
          MessageDeliveryCallback.java
          package javax.jms;
          import javax.jms.Message;
          
          public interface MessageDeliveryCallback {
              void onDelivery(Message message);
          }
          

          And the corresponding overloads of the send method.

          send(Message message, MessageArrivalCallback arrivalCallback);
          
          send(Message message, MessageDeliveryCallback deliveryCallback);
          
          send(Message message, MessageArrivalCallback arrivalCallback, MessageDeliveryCallback deliveryCallback);
          

          I don't know if this should be considered a different feature request or if it adds up to this one.

          Show
          julienrenaut added a comment - Hello all. Some scenarios might benefit from having two different kind of callbacks. One to confirm a message has correctly arrived on the destination queue and another to confirm a message has been correctly delivered to it's recipient (picked up from destination queue). I propose two different callback interfaces then. MessageArrivalCallback.java package javax.jms; import javax.jms.Message; public interface MessageArrivalCallback { void onArrival(Message message); } MessageDeliveryCallback.java package javax.jms; import javax.jms.Message; public interface MessageDeliveryCallback { void onDelivery(Message message); } And the corresponding overloads of the send method. send(Message message, MessageArrivalCallback arrivalCallback); send(Message message, MessageDeliveryCallback deliveryCallback); send(Message message, MessageArrivalCallback arrivalCallback, MessageDeliveryCallback deliveryCallback); I don't know if this should be considered a different feature request or if it adds up to this one.
          Hide
          Nigel Deakin added a comment - - edited

          Following the various comments, the proposed API is as follows:

          I've changed the name of the callback interface to CompletionListener. This allows us to use with other operations than sending a message. It also allows me to word this whole feature without using the word "acknowledge".

          I've worded this whole feature in terms of the send operation being performed in a separate thread, including waiting for any "confirmation" from "a JMS server", though I've also tried to state that it is up to the provider exactly how work is divided between the calling thread and the separate thread. I've also clarified that this method can be used even in cases where an ack isn't sent back from the server.

          I agree this feature might be extended to Session.commit() or Message.acknowledge() but have deferred that until we have made more progress with the initial use case.

          New methods on MessageProducer:

              void
              send(Destination destination, 
          	 Message message, 
          	 int deliveryMode, 
          	 int priority,
          	 long timeToLive) throws JMSException;
              
              /** Sends a message using the <CODE>MessageProducer</CODE>'s 
              * default delivery mode, priority, and time to live, 
              * returning immediately and notifying the specified completion listener 
              * when the operation has completed.
              * <p>
              * This method allows the JMS provider to perform the actual sending of the message,
              * and the wait for any confirmation from a JMS server, to take place in a separate thread
              * without blocking the calling thread. When the sending of the message is complete,
              * and any confirmation has been received from a JMS server, the JMS provider calls
              * the <code>onCompletion(Message)</code> method of the specified completion listener. 
              * If an exception occurs in the separate thread 
              * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
              * <p>
              * JMS does not define what operations are performed in the calling thread and what operations, if any,
              * are performed in the separate thread. In particular the use of this method does not itself specify whether
              * the separate thread should obtain confirmation from a JMS server. 
              * <p>
              * The exceptions listed below may be thrown in either thread. 
              *
              * @param message the message to send 
              * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
              *  
              * @exception JMSException if the JMS provider fails to send the message 
              *                         due to some internal error.
              * @exception MessageFormatException if an invalid message is specified.
              * @exception InvalidDestinationException if a client uses
              *                         this method with a <CODE>MessageProducer</CODE> with
              *                         an invalid destination.
              * @exception java.lang.UnsupportedOperationException if a client uses this
              *                         method with a <CODE>MessageProducer</CODE> that did
              *                         not specify a destination at creation time.
              * 
              * @see javax.jms.Session#createProducer 
              * @see javax.jms.CompletionListener 
              *
              * @since 2.0 
              */
          void send(Message message, CompletionListener completionListener) throws JMSException;
          
            
              /** Sends a message, specifying delivery mode, priority, and time to live, 
              * returning immediately and notifying the specified completion listener 
              * when the operation has completed.
              * <p>
              * This method allows the JMS provider to perform the actual sending of the message,
              * and the wait for any confirmation from a JMS server, to take place in a separate thread
              * without blocking the calling thread. When the sending of the message is complete,
              * and any confirmation has been received from a JMS server, the JMS provider calls
              * the <code>onCompletion(Message)</code> method of the specified completion listener. 
              * If an exception occurs in the separate thread 
              * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
              * <p>
              * JMS does not define what operations are performed in the calling thread and what operations, if any,
              * are performed in the separate thread. In particular the use of this method does not itself specify whether
              * the separate thread should obtain confirmation from a JMS server. 
              * <p>
              * The exceptions listed below may be thrown in either thread. 
              *
              * @param message the message to send
              * @param deliveryMode the delivery mode to use
              * @param priority the priority for this message
              * @param timeToLive the message's lifetime (in milliseconds)
              * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
              *  
              * @exception JMSException if the JMS provider fails to send the message 
              *                         due to some internal error.
              * @exception MessageFormatException if an invalid message is specified.
              * @exception InvalidDestinationException if a client uses
              *                         this method with a <CODE>MessageProducer</CODE> with
              *                         an invalid destination.
              * @exception java.lang.UnsupportedOperationException if a client uses this
              *                         method with a <CODE>MessageProducer</CODE> that did
              *                         not specify a destination at creation time.
              *
              * @see javax.jms.Session#createProducer
              * @see javax.jms.CompletionListener 
              * @since 2.0 
              */
          
            void 
            send(Message message, 
          	 int deliveryMode, 
          	 int priority,
          	 long timeToLive, CompletionListener completionListener) throws JMSException;
            
          

          New callback interface. I decided not to make it extend ExceptionListener because this requires the exception to be a JMSException, whereas when used with the methods on MessagingCOntext (see below) the exception may be a JMSRuntimeException.

          public interface CompletionListener {
          
          	/**
          	 * Notifies the application that the message has been successfully sent
          	 * 
          	 * @param message the message that was sent.
          	 */
          	void onCompletion(Message message);
          
          	/**
          	 * Notifies user that the specified exception was thrown while attempting to send the message
          	 * 
          	 * @param exception the exception
          	 */
          	void onException(Exception exception);
          }
          

          New methods on MessagingContext:

              /** Sends a message to the specified destination, using
               * the <CODE>MessagingContext</CODE>'s default delivery mode, priority,
               * and time to live,
               * returning immediately and notifying the specified completion listener 
               * when the operation has completed.
               * <p>
               * This method allows the JMS provider to perform the actual sending of the message,
               * and the wait for any confirmation from a JMS server, to take place in a separate thread
               * without blocking the calling thread. When the sending of the message is complete,
               * and any confirmation has been received from a JMS server, the JMS provider calls
               * the <code>onCompletion(Message)</code> method of the specified completion listener. 
               * If an exception occurs in the separate thread 
               * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
               * <p>
               * JMS does not define what operations are performed in the calling thread and what operations, if any,
               * are performed in the separate thread. In particular the use of this method does not itself specify whether
               * the separate thread should obtain confirmation from a JMS server. 
               * <p>
               * The exceptions listed below may be thrown in either thread. 
               *
               * @param destination the destination to send this message to
               * @param message the message to send
               * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
               *  
               * @exception JMSRuntimeException if the JMS provider fails to send the message 
               *                         due to some internal error.
               * @exception MessageFormatRuntimeException if an invalid message is specified.
               * @exception InvalidDestinationRuntimeException if a client uses
               *                         this method with an invalid destination.
               * 
               * @see javax.jms.MessagingContext#setDeliveryMode
               * @see javax.jms.MessagingContext#setPriority
               * @see javax.jms.MessagingContext#setTimeToLive
               * @see javax.jms.CompletionListener
               *
               */
               void send(Destination destination, Message message,CompletionListener completionListener);
          
              /** Sends a message to the specified destination, 
               * specifying delivery mode, priority and time to live,
               * returning immediately and notifying the specified completion listener 
               * when the operation has completed.
               * <p>
               * This method allows the JMS provider to perform the actual sending of the message,
               * and the wait for any confirmation from a JMS server, to take place in a separate thread
               * without blocking the calling thread. When the sending of the message is complete,
               * and any confirmation has been received from a JMS server, the JMS provider calls
               * the <code>onCompletion(Message)</code> method of the specified completion listener. 
               * If an exception occurs in the separate thread 
               * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener.
               * <p>
               * JMS does not define what operations are performed in the calling thread and what operations, if any,
               * are performed in the separate thread. In particular the use of this method does not itself specify whether
               * the separate thread should obtain confirmation from a JMS server. 
               * <p>
               * The exceptions listed below may be thrown in either thread. 
               * 
               * @param destination the destination to send this message to
               * @param message the message to send
               * @param deliveryMode the delivery mode to use
               * @param priority the priority for this message
               * @param timeToLive the message's lifetime (in milliseconds)
               * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed
               *  
               * @exception JMSRuntimeException if the JMS provider fails to send the message 
               *                         due to some internal error.
               * @exception MessageFormatRuntimeException if an invalid message is specified.
               * @exception InvalidDestinationRuntimeException if a client uses
               *                         this method with an invalid destination.
               *
               * @see javax.jms.CompletionListener
               */
               void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,CompletionListener completionListener);	
          
          Show
          Nigel Deakin added a comment - - edited Following the various comments, the proposed API is as follows: I've changed the name of the callback interface to CompletionListener . This allows us to use with other operations than sending a message. It also allows me to word this whole feature without using the word "acknowledge". I've worded this whole feature in terms of the send operation being performed in a separate thread, including waiting for any "confirmation" from "a JMS server", though I've also tried to state that it is up to the provider exactly how work is divided between the calling thread and the separate thread. I've also clarified that this method can be used even in cases where an ack isn't sent back from the server. I agree this feature might be extended to Session.commit() or Message.acknowledge() but have deferred that until we have made more progress with the initial use case. New methods on MessageProducer : void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException; /** Sends a message using the <CODE>MessageProducer</CODE>'s * default delivery mode, priority, and time to live, * returning immediately and notifying the specified completion listener * when the operation has completed. * <p> * This method allows the JMS provider to perform the actual sending of the message, * and the wait for any confirmation from a JMS server, to take place in a separate thread * without blocking the calling thread. When the sending of the message is complete, * and any confirmation has been received from a JMS server, the JMS provider calls * the <code>onCompletion(Message)</code> method of the specified completion listener. * If an exception occurs in the separate thread * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener. * <p> * JMS does not define what operations are performed in the calling thread and what operations, if any, * are performed in the separate thread. In particular the use of this method does not itself specify whether * the separate thread should obtain confirmation from a JMS server. * <p> * The exceptions listed below may be thrown in either thread. * * @param message the message to send * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed * * @exception JMSException if the JMS provider fails to send the message * due to some internal error. * @exception MessageFormatException if an invalid message is specified. * @exception InvalidDestinationException if a client uses * this method with a <CODE>MessageProducer</CODE> with * an invalid destination. * @exception java.lang.UnsupportedOperationException if a client uses this * method with a <CODE>MessageProducer</CODE> that did * not specify a destination at creation time. * * @see javax.jms.Session#createProducer * @see javax.jms.CompletionListener * * @since 2.0 */ void send(Message message, CompletionListener completionListener) throws JMSException; /** Sends a message, specifying delivery mode, priority, and time to live, * returning immediately and notifying the specified completion listener * when the operation has completed. * <p> * This method allows the JMS provider to perform the actual sending of the message, * and the wait for any confirmation from a JMS server, to take place in a separate thread * without blocking the calling thread. When the sending of the message is complete, * and any confirmation has been received from a JMS server, the JMS provider calls * the <code>onCompletion(Message)</code> method of the specified completion listener. * If an exception occurs in the separate thread * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener. * <p> * JMS does not define what operations are performed in the calling thread and what operations, if any, * are performed in the separate thread. In particular the use of this method does not itself specify whether * the separate thread should obtain confirmation from a JMS server. * <p> * The exceptions listed below may be thrown in either thread. * * @param message the message to send * @param deliveryMode the delivery mode to use * @param priority the priority for this message * @param timeToLive the message's lifetime (in milliseconds) * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed * * @exception JMSException if the JMS provider fails to send the message * due to some internal error. * @exception MessageFormatException if an invalid message is specified. * @exception InvalidDestinationException if a client uses * this method with a <CODE>MessageProducer</CODE> with * an invalid destination. * @exception java.lang.UnsupportedOperationException if a client uses this * method with a <CODE>MessageProducer</CODE> that did * not specify a destination at creation time. * * @see javax.jms.Session#createProducer * @see javax.jms.CompletionListener * @since 2.0 */ void send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener) throws JMSException; New callback interface. I decided not to make it extend ExceptionListener because this requires the exception to be a JMSException , whereas when used with the methods on MessagingCOntext (see below) the exception may be a JMSRuntimeException. public interface CompletionListener { /** * Notifies the application that the message has been successfully sent * * @param message the message that was sent. */ void onCompletion(Message message); /** * Notifies user that the specified exception was thrown while attempting to send the message * * @param exception the exception */ void onException(Exception exception); } New methods on MessagingContext : /** Sends a message to the specified destination, using * the <CODE>MessagingContext</CODE>'s default delivery mode, priority, * and time to live, * returning immediately and notifying the specified completion listener * when the operation has completed. * <p> * This method allows the JMS provider to perform the actual sending of the message, * and the wait for any confirmation from a JMS server, to take place in a separate thread * without blocking the calling thread. When the sending of the message is complete, * and any confirmation has been received from a JMS server, the JMS provider calls * the <code>onCompletion(Message)</code> method of the specified completion listener. * If an exception occurs in the separate thread * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener. * <p> * JMS does not define what operations are performed in the calling thread and what operations, if any, * are performed in the separate thread. In particular the use of this method does not itself specify whether * the separate thread should obtain confirmation from a JMS server. * <p> * The exceptions listed below may be thrown in either thread. * * @param destination the destination to send this message to * @param message the message to send * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed * * @exception JMSRuntimeException if the JMS provider fails to send the message * due to some internal error. * @exception MessageFormatRuntimeException if an invalid message is specified. * @exception InvalidDestinationRuntimeException if a client uses * this method with an invalid destination. * * @see javax.jms.MessagingContext#setDeliveryMode * @see javax.jms.MessagingContext#setPriority * @see javax.jms.MessagingContext#setTimeToLive * @see javax.jms.CompletionListener * */ void send(Destination destination, Message message,CompletionListener completionListener); /** Sends a message to the specified destination, * specifying delivery mode, priority and time to live, * returning immediately and notifying the specified completion listener * when the operation has completed. * <p> * This method allows the JMS provider to perform the actual sending of the message, * and the wait for any confirmation from a JMS server, to take place in a separate thread * without blocking the calling thread. When the sending of the message is complete, * and any confirmation has been received from a JMS server, the JMS provider calls * the <code>onCompletion(Message)</code> method of the specified completion listener. * If an exception occurs in the separate thread * then the JMS provider calls the <code>onException(JMSException)</code> method of the specified completion listener. * <p> * JMS does not define what operations are performed in the calling thread and what operations, if any, * are performed in the separate thread. In particular the use of this method does not itself specify whether * the separate thread should obtain confirmation from a JMS server. * <p> * The exceptions listed below may be thrown in either thread. * * @param destination the destination to send this message to * @param message the message to send * @param deliveryMode the delivery mode to use * @param priority the priority for this message * @param timeToLive the message's lifetime (in milliseconds) * @param completionListener a <code>CompletionListener</code> to be notified when the send has completed * * @exception JMSRuntimeException if the JMS provider fails to send the message * due to some internal error. * @exception MessageFormatRuntimeException if an invalid message is specified. * @exception InvalidDestinationRuntimeException if a client uses * this method with an invalid destination. * * @see javax.jms.CompletionListener */ void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive,CompletionListener completionListener);
          Hide
          Nigel Deakin added a comment -

          I've now updated the javadocs and the draft spec with details of this new feature (these changes are additive, so those docs include other changes).

          The updated Javadocs are here:
          http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar
          (See two new methods on MessageProducer, two new methods on MessagingContext, and a new interface CompletionListener)

          The updated draft spec is here:
          http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
          (all changes are highlighted clearly with changebars, but the only place I've changed is Section 4.6 "MessageProducer" and section 11.5.2. "Sending messages asynchronously", which is just a change log)

          Show
          Nigel Deakin added a comment - I've now updated the javadocs and the draft spec with details of this new feature (these changes are additive, so those docs include other changes). The updated Javadocs are here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar (See two new methods on MessageProducer, two new methods on MessagingContext, and a new interface CompletionListener) The updated draft spec is here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf (all changes are highlighted clearly with changebars, but the only place I've changed is Section 4.6 "MessageProducer" and section 11.5.2. "Sending messages asynchronously", which is just a change log)
          Hide
          Nigel Deakin added a comment - - edited

          Further changes have been made as follows.

          The updated spec is here:
          http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

          The updated javadocs are here:
          http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar
          and can be browsed online at
          http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html

          API changes

          On the CompletionListener callback interface, the onException method has an additional parameter: the message object:

          public interface CompletionListener {
          
            /**
             * Notifies the application that the message has been successfully sent
             * 
             * @param message the message that was sent.
             */
             void onCompletion(Message message);
          
            /**
             * Notifies user that the specified exception was thrown while attempting to send the specified message
             * 
             * @param message the message that was sent.
             * @param exception the exception
             * 
             */
             void onException(Message message, Exception exception);
          }
          

          Spec changes

          Section 4.6 "MessageProducer" has been expanded and divided into two: subsection 4.6.1 "Synchronous send" and subsection 4.6.2 "Asynchronous send". Here is the text in 4.6.2 "Asynchronous send":

          4.6.2 Asynchronous send

          Clients may alternatively send a message using the following methods which permit the JMS provider to perform part of the work involved in sending the message in a separate thread. JMS refers to this as an "asynchronous send".

          send(Destination destination, Message message, CompletionListener completionListener)
          send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, 
             CompletionListener completionListener)
          send(Message message,  CompletionListener completionListener)
          send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener)
          

          When the message has been successfully sent the JMS provider invokes the callback method onCompletion on an application-specified CompletionListener object. Only when that callback has been invoked can the application be sure that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed. An application which requires this degree of confidence must therefore wait for the callback to be invoked before continuing.

          The following information is intended to give an indication of how an asynchronous send would typically be implemented.

          In some JMS providers, a normal synchronous send involves sending the message to a remote JMS server and then waiting for an acknowledgement to be received before returning. It is expected that such a provider would implement an asynchronous send by sending the message to the remote JMS server and then returning without waiting for an acknowledgement. When the acknowledgement is received, the JMS provider would notify the application by invoking the onCompletion method on the application-specified CompletionListener object. If for some reason the acknowledgement is not received the JMS provider would notify the application by invoking the CompletionListener's onException method.

          In those cases where the JMS specification permits a lower level of reliability, a normal synchronous send might not wait for an acknowledgement. In that case it is expected that an asynchronous send would be similar to a synchronous send: the JMS provider would send the message to the remote JMS server and then return without waiting for an acknowledgement. However the JMS provider would still notify the application that the send had completed by invoking the onCompletion method on the application-specified CompletionListener object.

          It is up to the JMS provider to decide exactly what is performed in the calling thread and what, if anything, is performed asynchronously, so long as it satisfies the requirements given in the following sections:

          4.6.2.1. Quality of service

          After the send operation is complete, which means that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed, the JMS provider must invoke the CompletionListener. The CompletionListener must not be invoked earlier than this.

          4.6.2.2. Message order

          If the same MessageProducer or JMSContext is used to send multiple messages then JMS message ordering requirements (see section 4.4.10 "Message order") must be satisfied. This applies even if a combination of synchronous and asynchronous sends has been performed. The application is not required to wait for an asynchronous send to complete before sending the next message.

          4.6.2.3. Close, commit or rollback

          If the session is transacted (uses a local transaction) then when the commit or rollback method is called the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before performing the commit or rollback.

          If the close method is called on the MessageProducer}], {{Session}], {{Connection or JMSContext object then the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before closing the object and returning.

          4.6.2.4. Restrictions on usage in Java EE

          An asynchronous send is not permitted in a Java EE EJB or web container. If the application component violates this restriction the send method may throw a JMSException or JMSRuntimeException (depending on the method signature).

          4.6.2.5. Message headers

          JMS defines a number of message header fields and message properties which must be set by the "JMS provider on send". See section 3.4.11 "How message header values are set" and section 3.5.9 "JMS defined properties". If the send is asynchronous these fields and properties may be accessed on the sending client only after the CompletionListener has been invoked. If the CompletionListener's onException method is called then the state of these message header fields and properties is undefined. See also section 4.6.2.8 "Restrictions on the use of the Message object" below.

          4.6.2.6. Restrictions on threading

          Applications that perform an asynchronous send must confirm to the threading restrictions defined in section 4.4.6 "Conventions for using a session". This means that the session may be used by only one thread at a time.

          Setting a CompletionListener does not cause the session to be dedicated to the thread of control which calls the CompletionListener. The application thread may therefore continue to use the session after performing an asynchronous send. However the CompletionListener's callback methods must not use the session if an application thread might be using the session at the same time.

          4.6.2.7. Use of the CompletionListener by the JMS provider

          A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or JMSContext, callbacks will be performed in the same order as the corresponding calls to the asynchronous send method.

          A JMS provider must not invoke the CompletionListener from the thread that is calling the asynchronous send method.

          An application which does not need to receive notifications when the send has completed or has failed may supply a null CompletionListener. This does not remove the requirement for the close, commit or rollback methods to block until any incomplete send operations have been completed.

          4.6.2.8. Restrictions on the use of the Message object

          Applications which perform an asynchronous send must take account of the restriction that a Message object is designed to be accessed by one logical thread of control at a time and does not support concurrent use. See section 2.8 "Multi-threading".

          After the send method has returned, the application must not attempt to read the headers, properties or payload of the Message object until the CompletionListener's onCompletion or onException method has been called. This is because the JMS provider may be modifying the Message object in another thread during this time.

          A JMSException may be thrown if the application attempts to access or modify the Message object after the send method has returned and before the CompletionListener has been invoked.

          Javadoc changes

          The javadoc comments for all send methods on MessageProducer and JMSContext which perform an asynchromous send have been updated to include the above text.

          Show
          Nigel Deakin added a comment - - edited Further changes have been made as follows. The updated spec is here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf The updated javadocs are here: http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar and can be browsed online at http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html API changes On the CompletionListener callback interface, the onException method has an additional parameter: the message object: public interface CompletionListener { /** * Notifies the application that the message has been successfully sent * * @param message the message that was sent. */ void onCompletion(Message message); /** * Notifies user that the specified exception was thrown while attempting to send the specified message * * @param message the message that was sent. * @param exception the exception * */ void onException(Message message, Exception exception); } Spec changes Section 4.6 "MessageProducer" has been expanded and divided into two: subsection 4.6.1 "Synchronous send" and subsection 4.6.2 "Asynchronous send". Here is the text in 4.6.2 "Asynchronous send": 4.6.2 Asynchronous send Clients may alternatively send a message using the following methods which permit the JMS provider to perform part of the work involved in sending the message in a separate thread. JMS refers to this as an "asynchronous send". send(Destination destination, Message message, CompletionListener completionListener) send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener) send(Message message, CompletionListener completionListener) send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener) When the message has been successfully sent the JMS provider invokes the callback method onCompletion on an application-specified CompletionListener object. Only when that callback has been invoked can the application be sure that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed. An application which requires this degree of confidence must therefore wait for the callback to be invoked before continuing. The following information is intended to give an indication of how an asynchronous send would typically be implemented. In some JMS providers, a normal synchronous send involves sending the message to a remote JMS server and then waiting for an acknowledgement to be received before returning. It is expected that such a provider would implement an asynchronous send by sending the message to the remote JMS server and then returning without waiting for an acknowledgement. When the acknowledgement is received, the JMS provider would notify the application by invoking the onCompletion method on the application-specified CompletionListener object. If for some reason the acknowledgement is not received the JMS provider would notify the application by invoking the CompletionListener 's onException method. In those cases where the JMS specification permits a lower level of reliability, a normal synchronous send might not wait for an acknowledgement. In that case it is expected that an asynchronous send would be similar to a synchronous send: the JMS provider would send the message to the remote JMS server and then return without waiting for an acknowledgement. However the JMS provider would still notify the application that the send had completed by invoking the onCompletion method on the application-specified CompletionListener object. It is up to the JMS provider to decide exactly what is performed in the calling thread and what, if anything, is performed asynchronously, so long as it satisfies the requirements given in the following sections: 4.6.2.1. Quality of service After the send operation is complete, which means that the message has been successfully sent with the same degree of confidence as if a normal synchronous send had been performed, the JMS provider must invoke the CompletionListener . The CompletionListener must not be invoked earlier than this. 4.6.2.2. Message order If the same MessageProducer or JMSContext is used to send multiple messages then JMS message ordering requirements (see section 4.4.10 "Message order") must be satisfied. This applies even if a combination of synchronous and asynchronous sends has been performed. The application is not required to wait for an asynchronous send to complete before sending the next message. 4.6.2.3. Close, commit or rollback If the session is transacted (uses a local transaction) then when the commit or rollback method is called the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before performing the commit or rollback. If the close method is called on the MessageProducer}], {{Session}], {{Connection or JMSContext object then the JMS provider must block until any incomplete send operations have been completed and all callbacks have returned before closing the object and returning. 4.6.2.4. Restrictions on usage in Java EE An asynchronous send is not permitted in a Java EE EJB or web container. If the application component violates this restriction the send method may throw a JMSException or JMSRuntimeException (depending on the method signature). 4.6.2.5. Message headers JMS defines a number of message header fields and message properties which must be set by the "JMS provider on send". See section 3.4.11 "How message header values are set" and section 3.5.9 "JMS defined properties". If the send is asynchronous these fields and properties may be accessed on the sending client only after the CompletionListener has been invoked. If the CompletionListener 's onException method is called then the state of these message header fields and properties is undefined. See also section 4.6.2.8 "Restrictions on the use of the Message object" below. 4.6.2.6. Restrictions on threading Applications that perform an asynchronous send must confirm to the threading restrictions defined in section 4.4.6 "Conventions for using a session". This means that the session may be used by only one thread at a time. Setting a CompletionListener does not cause the session to be dedicated to the thread of control which calls the CompletionListener . The application thread may therefore continue to use the session after performing an asynchronous send. However the CompletionListener 's callback methods must not use the session if an application thread might be using the session at the same time. 4.6.2.7. Use of the CompletionListener by the JMS provider A session will only invoke one CompletionListener callback method at a time. For a given MessageProducer or JMSContext , callbacks will be performed in the same order as the corresponding calls to the asynchronous send method. A JMS provider must not invoke the CompletionListener from the thread that is calling the asynchronous send method. An application which does not need to receive notifications when the send has completed or has failed may supply a null CompletionListener . This does not remove the requirement for the close , commit or rollback methods to block until any incomplete send operations have been completed. 4.6.2.8. Restrictions on the use of the Message object Applications which perform an asynchronous send must take account of the restriction that a Message object is designed to be accessed by one logical thread of control at a time and does not support concurrent use. See section 2.8 "Multi-threading". After the send method has returned, the application must not attempt to read the headers, properties or payload of the Message object until the CompletionListener 's onCompletion or onException method has been called. This is because the JMS provider may be modifying the Message object in another thread during this time. A JMSException may be thrown if the application attempts to access or modify the Message object after the send method has returned and before the CompletionListener has been invoked. Javadoc changes The javadoc comments for all send methods on MessageProducer and JMSContext which perform an asynchromous send have been updated to include the above text.
          Hide
          Nigel Deakin added a comment -

          A number of clarifications have been added. For an up-to-date description of this feature, see section 4.6.2 "Asynchronous send" in the JMS 2.0 public draft.

          Show
          Nigel Deakin added a comment - A number of clarifications have been added. For an up-to-date description of this feature, see section 4.6.2 "Asynchronous send" in the JMS 2.0 public draft.

            People

            • Assignee:
              Nigel Deakin
              Reporter:
              Nigel Deakin
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: