[JMS_SPEC-33] Improving the JMS API with API simplifications, annotations and CDI Created: 21/Jul/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-64 Define simplified JMS API Resolved
depends on JMS_SPEC-70 Define annotations for injecting Mess... Resolved
Tags: ed20-added

 Description   

We should provide a modern, easier-to-use API, probably using annotations and CDI. There seemed to be a variety of ideas of how we might do this, and we will need to explore these in detail. Whilst I think we mostly see this as a feature for Java EE containers, there seems to be interest in offering features to those using a Java SE environment as well.

(This issue is a placeholder for discussion on the JSR 343 EG. More information will be added later)



 Comments   
Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-30] Define mandatory activation config properties clientId and subscriptionName Created: 14/Jul/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on EJB_SPEC-41 Define mandatory activation config pr... Resolved
blocks MQ-251 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-54 Define a standard way to configure th... Resolved
Tags: jms20-jsr345, pd20-added

 Description   

This is a request for the JMS and/or EJB specifications to define additional mandatory activation config properties for JMS MDBs. Although MDBs are specified in the EJB specification, this request should be considered first by the JMS 2.0 expert group who may then want to raise it with the EJB 3.2 expert group.

The EJB 3.1 spec is distinctly vague about how a MDB is defined. The relevant sections are 5.4.15, 5.4.16 and 5.4.17.1. The only activation config properties defined are acknowledgeMode (only used when transactions are bean-managed, and which must be either Auto-acknowledge or Dups-ok-acknowledge), messageSelector, destinationType (which must be must be either javax.jms.Queue or javax.jms.Topic) and subscriptionDurability (which must be either Durable or NonDurable). But it doesn't specify how the destination is defined or, when subscriptionDurability is Durable, how the subscription name and client identifier are defined.

The JCA 1.6 spec has some additional guidance, at least for MDBs that use a resource adapter. Section B2 states that providers are "strongly encouraged" to provide the properties mentioned above and also destination, subscriptionName and clientId, with destination and destinationType as "required" properties.

Whatever else we do, there seems to be a clear need to make these mandatory for JMS MDBs, whether or not they use JCA.

The JMS 2.0 and EJB 3.2 expert groups should also decide whether the EJB spec is the best place to list such JMS-specific details. Although MDBs (which are not just for JMS) should remain in the EJB spec, perhaps any additional specification for JMS MDBs should be in the JMS spec.



 Comments   
Comment by Nigel Deakin [ 15/Sep/11 ]

Following discussions, it is proposed that changes are sought to the EJB 3.2 spec to add additional activation configuration properties clientId and subscriptionName for JMS message-driven beans as follows:

Section 5.4 of the EJB 3.1 spec currently defines the the following activation configuration properties for JMS message-driven beans:
acknowledgeMode (optional, default is AUTO_ACKNOWLEDGE)
messageSelector (default is an empty String)
destinationType (optional, no default)
subscriptionDurability (default is NonDurable)

This should be extended to define the following additional activation configuration properties:

clientId
subscriptionName

These property names match those recommended in JCA 1.6.

If set, clientId would be used to set clientId for the connection used by the MDB, and must be unique in accordance with JMS 1.1. There would be no default value. JMS 1.1 states that clientId must be set if a durable subscription is being used. However in JMS 2.0 JMS_SPEC-39 proposes that this requirement would be removed and clientId would always be optional.

If a durable subscription is being used, then JMS requires that subscriptionName be set. In the case of a MDB the subscriptionName is normally given a name unique to the MDB, to distinguish it from other MDBs and other applications subscribed to the same topic. It is therefore proposed that the EJB specification state that if the subscription is durable and subscriptionName is not set then the container will automatically set subscriptionName to the name of the MDB.

As with the existing activation configuration properties for JMS message-driven beans defined in the EJB specification, clientId and subscriptionName could be specified either using the MessageDriven annotation

@MessageDriven(activationConfig =  {
    @ActivationConfigProperty(propertyName = "subscriptionDurability.", propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "clientId", propertyValue = "MyMDB"),
    @ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "MySub")
})

or in ejb-jar.xml:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>test.MyMDB</ejb-name>
      <activation-config>
         <activation-config-property>
            <activation-config-property-name>subscriptionDurability</activation-config-property-name>
            <activation-config-property-value>Durable</activation-config-property-value>
         </activation-config-property>
         <activation-config-property>
            <activation-config-property-name>clientId</activation-config-property-name>
            <activation-config-property-value>MyMDB</activation-config-property-value>
         </activation-config-property>
         <activation-config-property>
            <activation-config-property-name>subscriptionName</activation-config-property-name>
            <activation-config-property-value>MySub</activation-config-property-value>
         </activation-config-property>                  
      </activation-config>
    </message-driven>
  </enterprise-beans>
</ejb-jar>

Note: The issue of how to define the destination on which a JMS message-driven bean listens for messages will be considered separately, as this is a more complex topic.

Comment by Nigel Deakin [ 07/Nov/11 ]

Added tag jsr345 to identify that this issue requires changes to the EJB spec, not the JMS spec

Comment by Nigel Deakin [ 05/Dec/12 ]

Renaming issue to reflect the fact that this issue covers the activation config properties clientId and subscriptionName only.

Comment by Nigel Deakin [ 07/Feb/13 ]

The activation properties clientId and subscriptionName are now defined in the JMS 2.0 specification, section 13.1 "MDB activation properties" as follows:

Activation property Description
clientId This property may be used to specify the client identifier that will be used when connecting to the JMS provider from which the endpoint (message-driven bean) is to receive messages.

Setting this property is always optional.
subscriptionName This property only applies to endpoints (message-driven beans) that receive messages published to a topic. It may be used to specify the name of the durable or non-durable subscription.

The EJB 3.2 specification has also been updated with a consistent definition.

Now that this feature has been added to the JMS 2.0 and EJB 3.2 specifications, this issue can be marked as resolved.





[JMS_SPEC-27] Clarify the relationship between the JMS and other Java EE specifications Created: 06/Jul/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: ed20-added

 Description   

Summary

We need to clarify the relationship between the JMS and other Java EE specifications. This is mainly a documentation exercise, especially for those methods which are forbidden or modified in a EJB or Web container, but there are some ambiguities, especially when the transaction context is undefined.

More detail

If you want use the JMS API in a Java EE application such as a EJB or servlet you soon discover that much of the JMS spec (including the JMS javadocs) does not apply, at least in the EJB and web containers. For example, you aren't allowed to create message listeners, you need to defined MDBs instead. You aren't allowed to create local transactions, you need to use CMT or BMT transactions instead. You aren't allowed to set clientID on a connection. You aren't allowed to perform client acknowledgement. Essentially, in a Java EE container, the JMS API is simply different. However this is not explained in the JMS spec but is described in other specs, notably the EJB and Java EE platform specs.

Some of this information of necessity in other specs, but the absence of any mention of it in the JMS spec or javadocs is confusing to users.

I would like the JMS expert group to review what it says about JMS in other specs and consider whether this material should be moved to the JMS spec, duplicated in the JMS spec, or cross-referenced from the JMS spec. In addition the javadocs need to be clarified to mention that some API is not allowed, or has a different effect, in a Java EE web or EJB container.

I see this mainly as a documentation exercise. However this analysis will inevitably identify that some areas of behaviour are not well defined. For example, the EJB spec states explicitly that in an "undefined transactional context" it is not defined how the JMS provider should handle transactions. This means that vendors may behave differently which reduces the portability of application. If possible this should be resolved.



 Comments   
Comment by Nigel Deakin [ 26/Jan/12 ]

I've now updated the API, javadocs and the draft spec.
The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

I've written a completely new section to add to the new chapter 12 "Use of JMS API in Java EE applications" which was added for JMS_SPEC-45. This is intended to simply restate what is already defined in the EJB 3.1 and Java EE 6 platform specs, though I have extended it to cover the simplified API. here it is:

12.2. Restrictions on the use of JMS API in the Java EE web or EJB container

JMS applications which run in the Java EE web or EJB container are subject to a number of restrictions in the way the JMS API may be used. These restrictions are necessary for the following reasons:

  • In a Java EE web or EJB container, a JMS provider operates as a transactional resource manager which must participate in JTA transactions as defined in the Java EE platform specification. This overrides the behaviour of JMS sessions as defined elsewhere in the JMS specification. For more details see section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container".
  • The Java EE web or EJB containers need to be able to manage the threads used to run applications.
  • The Java EE web and EJB containers perform connection management which may include the pooling of JMS connections.

The restrictions described in this section do not apply to the Java EE application client container.
Applications running in the Java EE web and EJB containers must not attempt to create more than one active (not closed) Session object per connection.

  • If an application attempts to use the Connection object’s createSession method when an active Session object exists for that connection then a JMSException should be thrown.
  • If an application attempts to use the MessagingContext object's createMessagingContext method then a JMS{{RuntimeException}} should be thrown, since the first messaging context already contains a connection and session and this method would create a second session on the same connection.

The following methods are intended for use by the application server and their use by applications running in the Java EE web or EJB container may interfere with the container's ability to properly manage the threads used in the runtime environment. They must therefore not be called by applications running in the Java EE web or EJB container:

  • javax.jms.Session method setMessageListener
  • javax.jms.Session method getMessageListener
  • javax.jms.Session method setBatchMessageListener
  • javax.jms.Session method getBatchMessageListener
  • javax.jms.Session method run
  • javax.jms.Connection method createConnectionConsumer
  • javax.jms.Connection method createDurableConnectionConsumer

The following methods may interfere with the container's ability to properly manage the threads used in the runtime environment and must not be used by applications running in the Java EE web or EJB container:

  • javax.jms.MessageConsumer method setMessageListener
  • javax.jms.MessageConsumer method getMessageListener
  • javax.jms.MessageConsumer method setBatchMessageListener
  • javax.jms.MessageConsumer method getBatchMessageListener
  • javax.jms.MessagingContext method setMessageListener
  • javax.jms.MessagingContext method getMessageListener
  • javax.jms.MessagingContext method setBatchMessageListener
  • javax.jms.MessagingContext method getBatchMessageListener

This restriction means that applications running in the Java EE web or EJB container which need to receive messages asynchronously may only do so using message-driven beans.

The following methods may interfere with the container's management of connections and must not be used by applications running in the Java EE web or EJB container:

  • javax.jms.Connection method setClientID
  • javax.jms.Connection method stop
  • javax.jms.Connection method setExceptionListener
  • javax.jms.MessagingContext method setClientID
  • javax.jms.MessagingContext method stop
  • javax.jms.MessagingContext method setExceptionListener

Applications which need to use a specific client identifier must set it on the connection factory, as described in section 4.3.2 "Client Identifier"

All the methods listed in this section may throw a javax.jms.JMSException (if allowed by the method) or a javax.jms.JMSRuntimeException (if not) when called by an application running in the Java EE web or EJB container. This is recommended but not required.

Comment by Nigel Deakin [ 26/Jan/12 ]

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The javadocs for all the methods listed above which are not permitted in a Java EE web or Java EE container now include the following statement:

* This method must not be used in a Java EE web or EJB application. 
* Doing so may cause a <code>JMSException</code> to be thrown though this is not guaranteed.

In addition, the list of exceptions for these methods now states that they may throw a JMSException (or JMSRuntimeException if called in a Java EE web or EJB container, together with the caveat that "it is not guaranteed that an exception is thrown in this case"

The three Connection methods createSession now include the statement:

* Applications running in the Java EE web and EJB containers must not attempt 
* to create more than one active (not closed) <code>Session</code> object per connection. 
* If this method is called in a Java EE web or EJB container when an active
* <code>Session</code> object already exists for this connection 
* then a <code>JMSException</code> will be thrown.

The list of exceptions for these methods states that they will (must) throw a JMSException if "this method is being called in a Java EE web or EJB application and an active session already exists for this connection."

The MessageConsumer method createMessagingContext now includes the statement:

* This method is for use in a Java SE environment or in the Java EE application client container only. 
* It may not be used in a Java EE environment because this would violate
* the Java EE restriction that a connection may have only one session.

The list of exceptions for this method now states that it will (must) throw an exception if "this method is being called in a Java EE web or EJB application"

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-63] Introduce concept of platform default JMS connection factory in Java EE Created: 04/Dec/11  Updated: 20/Mar/13  Resolved: 23/Aug/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0

Type: Improvement Priority: Major
Reporter: arjan tijms Assignee: Unassigned
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JAVAEE_SPEC-2 Define platform default JMS connectio... Resolved
Tags: jms20-jsr342-added

 Description   

In a Java EE environment a JMS provider is mandatory present and can be used without the user having to configure or setup anything.

Some implementations (e.g. JBoss AS), provide by default a JMS connection factory for this platform provided JMS provider (java:/ConnectionFactory and java:JmsXA), yet in other implementations (e.g. GlassFish) users have to create a connection factory themselves.

I would like to propose to formally introduce the concept of a platform default JMS connection factory and make this available under some portable JNDI name (e.g. java:/JmsConnectionFactory). The exact configuration of this factory should be an implementation detail, but the spirit of the specification should be that it must not be purposely crippled and should be principally intended for production use.

Besides shielding users from having to create a connection factory, an additional benefit might be that other platform JMS facilities that otherwise would need an explicit reference to a connection factory, could default to this standard connection factory.

E.g. from http://java.net/downloads/jms-spec/JMS2.0Devoxx2011.pdf slide 23:

@Inject 
@JMSConnection(lookup="jms/connFactory") 
@JMSDestination(lookup="jms/inboundQueue") 
MessageProducer producer;

could become:

@Inject 
@JMSDestination(lookup="jms/inboundQueue") 
MessageProducer producer; // defaults to java:/JmsConnectionFactory

etc.



 Comments   
Comment by Nigel Deakin [ 08/Dec/11 ]

I think this is a good idea, which I'll raise with the JSR 343 expert group. This might need to be defined in the Java EE platform spec rather than the JMS spec. I'll investigate.

Comment by Nigel Deakin [ 19/Jan/12 ]

I have logged this in the Java EE issue tracker as JAVAEE_SPEC-2

Comment by Nigel Deakin [ 23/Aug/12 ]

This has now been included in the Java EE 7 specification. A new section EE 5.19 "Default JMS COnnection Factory" states:

The Java EE Platform requires that a Java EE Product Provider provide a JMS provider in the operational environment (see Section EE.2.7.8, "Java™ Message Service (JMS)") . The Java EE Product Provider must also provide a preconfigured, JMS ConnectionFactory for use by the application in accessing this JMS provider.

The Java EE Product Provider must make the default JMS connection factory accessible to the application under the JNDI name java:comp/defaultJMSConnectionFactory.

The Application Component Provider or Deployer may explicitly bind a JMS ConnectionFactory resource reference to the default connection factory using the lookup element of the Resource annotation or the lookup-name element of the resource-ref deployment descriptor element. For example,

@Resource(name="myJMSCF", lookup="java:comp/defaultJMSConnectionFactory") 
ConnectionFactory myJMScf;

In the absence of such a binding for a JMS connection factory resource reference, the reference will map to a JMS connection factory for the product's JMS provider.

For example, the following will map to a preconfigured connection factory for the product's default JMS provider:

@Resource(name="myJMSCF")
ConnectionFactory myJMScf;




[JMS_SPEC-62] Define standard way to create JMS Destination objects from within a Java EE application Created: 23/Nov/11  Updated: 24/Feb/12  Resolved: 24/Feb/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: arjan tijms Assignee: Unassigned
Resolution: Invalid Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: destination, javaee

 Description   

The JMS 1.1 spec states in section 2.3 that JMS Destinations (Queue and Topic) are administered objects for the following reason:

It is also expected there will be major differences in how a provider's system is installed and administered. If JMS clients are to be portable, they must be isolated from these proprietary aspects of a provider.

In practice however, there is often only very little information needed to create a basic Destination that is suitable for a lot of use-cases and there aren't really any major differences there. Especially if such Destinations are completely used internally in the application, they don't necessarily need to be administered objects. Many Java EE servers do make it possible to define Destinations from within the application, but every implementation has a different way to do this. This hurts portability.

For instance;

JBoss AS 6.x

*-hornetq-jms.xml
<configuration xmlns="urn:hornetq"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"
>    
    <queue name="myQueue">
        <entry name="/queue/myQueue" />
    </queue>
</configuration>

Glassfish 3.1.x

META-INF/glassfish-resources.xml
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
    "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <admin-object-resource res-adapter="jmsra" res-type="javax.jms.Queue" jndi-name="java:app/myQueue" >        
        <property name="Name" value="myQueue"/>
    </admin-object-resource>
</resources>

As can be seen in these two examples, all that the user needs to declare is a name and whether a queue or topic is required.

I would like to propose to define a standard way to define Destinations from within a Java EE application, analogous to how JDBC datasources can be defined via a DataSourceDefinition annotation and a corresponding <data-source> element in application.xml.



 Comments   
Comment by arjan tijms [ 04/Dec/11 ]

Slide 29 of http://java.net/downloads/jms-spec/JMS2.0Devoxx2011.pdf mentions exactly this:

JSR 342 (Java EE 7) will define new annotations:

@JMSConnectionFactoryDefinition( 
    name="java:app/MyJMSFactory", 
    resourceType="javax.jms.QueueConnectionFactory", 
    clientId="foo",
    resourceAdapter="jmsra", 
    initialPoolSize=5, 
    maxPoolSize=15
)
@JMSDestinationDefinition( 
    name="java:app/orderQueue", 
    resourceType="javax.jms.Queue", 
    resourceAdapter="jmsra", 
    destinationName="orderQueue"
)
Comment by Nigel Deakin [ 08/Dec/11 ]

As mentioned in those Devoxx slides, the Java EE 7 platform expert group is planning to include a feature similar to this. Please contact the Java EE 7 expert group for more information. http://javaee-spec.java.net

This is a platform issue and won't be addressed in the JMS spec.

Comment by Nigel Deakin [ 24/Feb/12 ]

Please see section EE.5.17.5 "JMS Destination Definition" of the proposed Java EE 7 specification (available via http://javaee-spec.java.net). This states

An application may define a JMS Destination resource. A JMS Destination resource is a JMS Queue or Topic.

The JMS {{Destination}}resource may be defined in any of the JNDI namespaces described in Section EE.5.2.2, “Application Component Environment Namespaces”.

A JMS Destination resource may be defined in a web module, EJB module, application client module, or application deployment descriptor using the jms-destination element.

For example:

<jms-destination>
    <description>Sample JMS Destination definition</description>
    <name>java:app/MyJMSDestination</name>
    <class-name>javax.jms.Queue</class-name>
    <resource-adapter-name>myJMSRA</resource-adapter-name>
    <resource-name>myQueue1</resource-name>
    <property>
      <name>Property1</name>
      <value>10</value>
    </property>
    <property>
      <name>Property2</name>
      <value>20</value>
    </property>
    </jms-destination>

A JMS Destination resource may also be defined using the JMSDestinationDefinition annotation on a container-managed class, such as a servlet or enterprise bean class.

For example:

@JMSDestinationDefinition(
    name="java:app/MyJMSQueue",
    className="javax.jms.Queue",
    resourceName="myQueue1")

The JMSDestinationDefinition annotation can be overridden by a deployment descriptor when the application is deployed.)

Once defined, a JMS Destination resource may be referenced by a component using the resource-ref deployment descriptor element or the Resource annotation. For example, the above Destination could be referenced as follows:

@Stateless
public class MySessionBean {
    @Resource(lookup = "java:app/MyJMSQueue")
    Queue myQueue;
    ...
}

The following JMSDestinationDefinition annotation elements (and corresponding XML deployment descriptor elements) are considered to specify an address for a JMS Destination resource: resourceAdapterName, resourceName.

Comment by Nigel Deakin [ 24/Feb/12 ]

I've marked this as resolved, with a resolution of "invalid". This doesn't mean the suggestion was invalid, of course, but that the request applied to a different specification. Comments and feedback remain welcome.





[JMS_SPEC-54] Define a standard way to configure the destination on which a JMS MDB consumes messages Created: 21/Oct/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on CONNECTOR_SPEC-4 Clarify whether the ResourceAdapter.e... Resolved
blocks MQ-250 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-30 Define mandatory activation config pr... Resolved
is related to JMS_SPEC-55 Define a standard way to configure th... Resolved
Tags: eg, jms20-jsr345, pd20-added

 Description   

This is a request for the JMS and/or EJB specifications to improve the way in which specify how an application or deployer may specify the destination from which a JMS message-driven bean to receive messages. There are several significant omissions from the specification which need to be rectified.

Although MDBs are specified in the EJB specification, this request should be considered first by the JMS 2.0 expert group who may then want to raise it with the EJB 3.2 expert group.

Review of existing specification (EJB 3.1)

In the EJB 3.1 specification, Section 16.9 "Message Destination References" states that the destination used by a JMS message-driven bean can be specified using the <message-destination-link> element of the <message-driven> element in ejb-jar.xml:

<message-driven>
   <ejb-name>ExpenseProcessing</ejb-name>
   <ejb-class>com.wombat.empl.ExpenseProcessingBean</ejb-class>
   <messaging-type>javax.jms.MessageListener</messaging-type>
   ...
   <message-destination-type>javax.jms.Queue</message-destination-type>
   <message-destination-link>ExpenseProcessingQueue</message-destination-link>
   ...
</message-driven>

Issues with the existing specification

This raises the following questions:

1. What is <message-destination-link>?

The <message-destination-link> element defines the destination from which the MDB consumes messages in terms of a "message destination reference".

The purpose of "message destination references" is to allow an application which sends messages to a particular destination and also consumes from the same destination to inform the deployer of this fact without having to actually specify the name (or JNDI name) of the destination.

As stated above, a MDB can specify the "message destination reference" of the destination from which it consumes messages using a <message-destination-link> element under the <message-driven> element. Another component (e.g. a session bean or another MDB) can specify the destination to which it sends messages using a <message-destination-link> element under a <message-destination-ref> element. If these two elements contain the same string then the deployer knows they refer to the same queue or topic.

A message destination reference is not the JNDI name of the queue or topic. It is just a logical name. It can be mapped to an actual JNDI name using the <assembly-descriptor> element in ejb-jar.xml as follows:

Here's how ejb-jar.xml could be used to define a MDB as consuming messages from a "message destination reference" called MsgBeanInQueue which was mapped to a JNDI name jms/inboundQueue:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <display-name>MDB1</display-name>
      <ejb-name>MessageBean</ejb-name>
      <messaging-type>javax.jms.MessageListener</messaging-type>
      <transaction-type>Container</transaction-type>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <message-destination-link>MsgBeanInQueue</message-destination-link>
    </message-driven>
  </enterprise-beans>
  <assembly-descriptor>
    <message-destination>
      <lookup-name>jms/inboundQueue</lookup-name>   <!---
      <message-destination-name>MsgBeanInQueue</message-destination-name>
    </message-destination>
  </assembly-descriptor>
</ejb-jar> 

A message destination reference can typically also be mapped to an actual JNDI name using the application-server-specific deployment descriptor, though by definition this is beyond the scope of the EJB specification.

2. Is that the only way you can define the destination on which a MDB consumes messages in ejb-jar.xml? Can you define its JNDI name directly without bothering with references?

No, the EJB specification doesn't mention any way to define the destination in ejb-jar.xml apart from using the <message-destination-link> element of ejb-jar.xml. In particular it doesn't define any way to define its JNDI name directly, analogous to using either the JNDI API or a @Resource(lookup="jms/foo") declaration for managed connections.

3. Can I define the message destination reference for a MDB using annotation?

No, there is equivalent to <message-destination-link> using annotation.

4. Can I define the JNDI name of the destination on which a MDB consumes messages directly using annotation?

No, there is no way to define this using annotation, analogous to using a @Resource(lookup="jms/foo") declaration when using the JMS API directly.

So, what seems to be missing?

A. As explained in (2) and (4) above, there isn't a standard way for MDB applications to short-circuit the use of message destination references and define the JNDI name of the destination from which a JMS message-driven bean consumes messages, either using ejb-jar.xml or annotations. This contrasts with EJBs which send messages, where the JNDI name of the destination can be specified in the MDB code using the JNDI API or a @Resource(lookup="jms/foo") declaration.

B. As explained in (3) above, there is no standard way for the application to define using annotation the "message destination reference" on which the JMS message-driven bean is consuming messages.

Proposals:

A. It is proposed that the <message-driven> element in ejb-jar.xml be extended to define an additional sub-element which can be used to specify the JNDI name of the destination from which a JMS message-driven mean consumes messages. A suggested element name is <message-destination-jndi-name>:

<ejb-jar>
  <display-name>Ejb1</display-name>
  <enterprise-beans>
    <message-driven>
      <display-name>MDB1</display-name>
      <ejb-name>MessageBean</ejb-name>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <message-destination-jndi-name>jms/inboundQueue<message-destination-jndi-name>
      ...

It might be asked why this needs to be defined by a new subelement of <message-driven> rather than, say, a new standard activation configuration property. The answer is that the way that the JNDI name is defined needs to be consistent with the way that the message destination reference is defined, which is by the <message-destination-link> subelement of <message-driven>

B. It is proposed that the equivalent annotation be a new attribute of the @MessageDriven annotation, called messageDestinationJndiName. For example:

@MessageDriven(messageDestinationJndiName="jms/inboundQueue")
public class MyMDB implements MessageListener {
....

C. It is proposed that the @MessageDriven annotation be extended to allow applications to define the "message destination reference" on which the JMS message-driven bean is consuming messages, using a new attribute messageDestinationLink"

@MessageDriven(messageDestinationLink="ExpenseProcessingQueue")
public class MyMDB implements MessageListener {
....


 Comments   
Comment by rdohna [ 25/Oct/11 ]

Linked these two issues

Comment by Nigel Deakin [ 25/Oct/11 ]

Corrected names of annotation attributes

Comment by Nigel Deakin [ 07/Nov/11 ]

Added tag jsr345 to identify that this issue requires changes to the EJB spec, not the JMS spec

Comment by Nigel Deakin [ 05/Dec/12 ]

The current proposal is to define a standard activation property destinationLookup.

However this is only possible if the connector spec can guarantee that the resource adapter will be able to perform the lookup in the endpointActivation call. I have logged CONNECTOR_SPEC-4 to request clarification .

Comment by Nigel Deakin [ 07/Feb/13 ]

Note that CONNECTOR_SPEC-4 is now resolved.

Comment by Nigel Deakin [ 07/Feb/13 ]

The JMS 2.0 and EJB 3.2 specifications now define a activation property destinationLookup. This is defined as follows (JMS 2.0 section 13.1 "MDB activation properties"):

Activation property Description
destinationLookup This property may be used to specify the lookup name of an administratively-defined javax.jms.Queue or javax.jms.Topic object which defines the JMS queue or topic from which the endpoint (message-driven bean) is to receive messages.

This issue can now be marked as resolved.





[JMS_SPEC-64] Define simplified JMS API Created: 08/Dec/11  Updated: 20/Mar/13  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-176 Implement simplified API for JMS 2.0 Closed
blocks JMS_SPEC-33 Improving the JMS API with API simpli... Resolved
blocks JMS_SPEC-70 Define annotations for injecting Mess... Resolved
Tags: pd20-added

 Description   

This is a request for a simplified JMS API. This would achieve the following goals:

  • To reduce the number of objects needed to send and receive messages, and in particular to combine the JMS 1.1 Connection, Session, MessageProducer and MessageConsumer objects as much as possible.
  • To take advantage of the fact that this is a new API to simplify method signatures and make other simplifications which cannot be made to the old API because it would break backwards compatibility.
  • To maintain a consistent style with the existing API where possible so that users of the old API feel it to be an evolution which that can learn quickly.
  • To support, and offer benefits to, both Java EE and Java SE applications.
  • To allow resource injection to be exploited in those environment which support it, whilst still offering significant improvements for those environments which do not.
  • To provide the option to send and receive message payloads to be sent and received directly without the need to use javax.jms.Message objects.
  • To remove as much as possible the need to catch JMSException on method calls
  • To be functionally complete. The old API will remain to provide backwards compatibility. However the new API is intended to be functionally as complete as the old JMS 1.1 API. Users should not need to switch back to the old API to perform an operation that is unavailable in the new API.


 Comments   
Comment by Nigel Deakin [ 08/Dec/11 ]

A proposed API is described in JMS20SimplifiedAPIv1.pdf with javadocs in jms-2.0-javadoc.jar

Comment by Nigel Deakin [ 03/Feb/12 ]

I've now updated the API, javadocs and the draft spec in accordance with the proposals made above.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

See particularly the new interfaces javax.jms.MessagingContext, javax.jms.SyncMessageConsumer and the new factory methods on javax.jms.Connection.createMessagigingContext

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

See particularly the new chapter 13 "Simplified JMS API" and the change log in section 11.5.16.

Note that these changes cover the simplified API only. They do not include any proposals for injection of JMS objects (which will be handled in a separate JIRA issue).

Comment by Nigel Deakin [ 17/Feb/12 ]

I've updated the API, javadocs and the draft spec in accordance with the following changes.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

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

Added new methods on MessagingContext to send the Map and byte[] payloads directly as MapMessage and BytesMessage.

Extended existing methods on SyncMessagingContext that receive message payloads directly to support MapMessage and BytesMessage

Added new method methods on MessagingContext: setAutoStart() and getAutoStart(). These allow the autostart behaviour (where the connection is automatically started when a consumer is created) to be disabled.

The spec has been clarified to define when MessagingContext.setClientID may be called and when it may not. The JMS 1.1 spec says that Connection.setClientID may only be called immediately after the conneciton is created and prior to doing anything else with the connection. Since the factory method to create a MessagingContext creates a connection and then uses it to create a session this means that calling MessagingContext.setClientID after this would never be valid. The spec has therefore been clarified to state that this is indeed valid.

Comment by Nigel Deakin [ 21/Mar/12 ]

Following discussions, I have changed the API for consuming messages asynchronously to require the use of a separate consumer. This means that applications cannot set a message listener directly on the MessagingContext. Instead they need to create a consumer object and set the message listener on that.

The new combined consumer object (for sync and async delivery) is called JMSConsumer
For reasons of consistency, MessagingContext has been renamed JMSContext

I've updated the API, javadocs and the draft spec with these changes

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

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

API and Javadoc changes

Changes to SyncMessageConsumer

  • Renamed to JMSConsumer
  • New method getMessageListener added
  • New method setmessageListener added
  • New method getBatchMessageListener added
  • New method setBatchMessageListener added

Changes to MessagingContext

  • Renamed to JMSContext
  • Existing method createSyncConsumer (3 methods) renamed to createConsumer
  • Existing method createSyncDurableConsumer (2 methods) renamed to createDurableConsumer
  • Existing method setmessageListener (5 methods) deleted
  • Existing method setBatchMessageListener (5 methods) deleted
  • Existing method createMessagingContext renamed to createContext

Changes to ConnectionFactory

  • Existing method {{createMessagingContext (4 methods) renamed to createContext

Spec changes

Section 11.2.4 "Consuming messages asynchronously" has been completely deleted.

Section 11.2.5 "Consuming messages synchronously" has been renamed 11.2.4 "Consuming messages" and updated to cover async message delivery as well.

Following the deletion of the section mentioned above, sections 11.2.6, 11.2.7, 11.2.8 and 11.2.9 become 11.2.5, 11.2.6, 11.2.7 and 11.2.8.

In section A.2 "Unresolved issues in the JMS 2.0 Early Draft", subsection A.2.1 "Simplified JMS API: Support for multiple consumers on a session" has been deleted since this issue has now been resolved.

References to MessagingContext have been changed to JMSContext throughout
References to SyncMessageConsumer have been changed to JMSConsumer throughout

Section 11.4. "Examples using the simplified API" has been updated to reflect these API changes.

Note that the spec does not attempt to record the changes between the Early Draft and this version, since this would be too complicated.

Comment by Nigel Deakin [ 21/Sep/12 ]

The API for sending messages has been completely revised to introduce a new interface JMSProducer. For a full description see section 11.2.4 "Sending messages" in the JMS 2.0 public draft.





[JMS_SPEC-55] Define a standard way to configure the connection factory used by a JMS MDB to consume messages Created: 07/Nov/11  Updated: 20/Mar/13  Resolved: 07/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on CONNECTOR_SPEC-4 Clarify whether the ResourceAdapter.e... Resolved
blocks MQ-250 Implement JMSRA activation properties... Closed
Related
is related to JMS_SPEC-54 Define a standard way to configure th... Resolved
Tags: jms20-jsr345, pd20-added

 Description   

This is a request for the EJB specification to define a standard way to configure the connection factory used by a MDB to consume messages.

Currently there is no standard way to do this, and vendors differ in the way in which connection information is specified in a MDB. Some vendors support an activation property connectionFactoryJndiName but this is not defined in the EJB 3.1 (or the JCA 1.6) specifications and support for it is not universal. In fact some vendors expect connection information to be specified directly using non-standard activation properties rather than via a connection factory.

This limits the portability of applications between different JMS providers, resource adapters and application servers. It will also hinder the automatic provisioning of JMS resources in a PaaS environment which is a goal of Java EE 7.

Two alternatives are proposed:

1. Define a mandatory activation property connectionFactoryJndiName

This would make it mandatory for application servers to support the activation property connectionFactoryJndiName. This would essentially standardise what some vendors support already.

This could be specified in ejb-jar.xml as follows:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>MyMDB</ejb-name>
      <activation-config>          
         <activation-config-property>
            <activation-config-property-name>connectionFactoryJndiName</activation-config-property-name>
            <activation-config-property-value>jms/connectionFactory</activation-config-property-value>
         </activation-config-property>
      <activation-config>   
      ...

...or using annotation as follows:

@MessageDriven(
    activationConfig = {
        @ActivationConfigProperty(
            propertyName="connectionFactoryJndiName", propertyValue="jms/connectionFactory")
    })
public class MyMDB implements MessageListener {
....

2. Define a new element under the <message-driven> element and a corresponding annotation

This option would propose that the <message-driven> element in ejb-jar.xml be extended to define an addition sub-element which can be used to specify the JNDI name of the connection factory used by a JMS message-driven bean to consume messages. A suggested element name is <connection-factory-jndi-name>:

<ejb-jar>
  <enterprise-beans>
    <message-driven>
      <ejb-name>MessageBean</ejb-name>
      <message-destination-type>javax.jms.Queue</message-destination-type>
      <connection-factory-jndi-name>jms/connectionFactory<connection-factory-jndi-name>
      ...

To provide an equivalent annotation, a new attribute would need to be added to the @MessageDriven annotation. A suggested name is connectionFactoryJndiName:

@MessageDriven(connectionFactoryJndiName="jms/connectionFactory")
public class MyMDB implements MessageListener {
....

It might be asked why this needs to be defined by a new subelement of <message-driven> and a new attribute of @MessageDriven rather than by a new standard activation configuration property. Possible answers are:

  • this is needed for consistency with the existing <message-destination-link> and the proposed <message-destination-jndi-name> subelements of <message-driven>. (See JMS_SPEC-54).
  • the connection factory is such an important property of a JMS MDB that it deserves explicit support in the ejb-jar.xml schema and by the compiler, rather than being relegated to being just an activation property.

Options

In brief, the options are:

1) New mandatory activation property connectionFactoryJndiName
2) New element <connection-factory-jndi-name> and corresponding annotation @MessageDriven(connectionFactoryJndiName=...
3) Both 1) and 2)
4) Neither



 Comments   
Comment by Nigel Deakin [ 05/Dec/12 ]

The current proposal is to define a standard activation property connectionFactoryLookup.

However this is only possible if the connector spec can guarantee that the resource adapter will be able to perform the lookup in the endpointActivation call. I have logged CONNECTOR_SPEC-4 to request clarification .

Comment by Nigel Deakin [ 07/Feb/13 ]

The JMS 2.0 and EJB 3.2 specifications now define a activation property connectionFactoryLookup. This is defined as follows (JMS 2.0 section 13.1 "MDB activation properties"):

Activation property Description
connectionFactoryLookup This property may be used to specify the lookup name of an administratively-defined javax.jms.ConnectionFactory, javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory object that will be used to connect to the JMS provider from which the endpoint (message-driven bean) is to receive messages.

This issue is now incorporated in the JMS 2.0 spec and can be marked as resolved.





[JMS_SPEC-65] Clarify use of NoLocal arg when using createDurableSubscriber Created: 22/Dec/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-168 Implement clarified behaviour of noLo... Closed
Tags: ed20-added

 Description   

This issue relates to the following method on javax.jms.Session:

TopicSubscriber createDurableSubscriber(Topic topic,
                                        java.lang.String name,
                                        java.lang.String messageSelector,
                                        boolean noLocal)
                                        throws JMSException

What does noLocal mean in this context? The javadoc states that this method "Creates a durable subscriber to the specified topic, using a message selector and specifying whether messages published by its own connection should be delivered to it". However it is ambiguous whether "it" refers to the durable subscription in the JMS provider or the TopicSubscriber object.

Does noLocal mean
(1) that messages published by this connection should not be added to the durable subscription, or that
(2) messages published by this connection should not be delivered to this particular TopicSubscriber? These do not mean the same thing, since in the latter case the messages might be saved in the subscription and delivered at some later stage.

This should be clarified.



 Comments   
Comment by Nigel Deakin [ 22/Dec/11 ]

The suggested interpretation is that it means (1): that messages published by its own connection should not be added to the durable subscription.

Comment by Hiram Chirino [ 22/Dec/11 ]

Agree it should be (1). Otherwise you will get an inconsistent behavior once a consumer reconnects, and lets face it folks hate inconsistencies.

Comment by Nigel Deakin [ 09/Jan/12 ]

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

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

Section 6.11 "TopicSubscriber" has been reworded to state that "When a non-durable subscription is created on a topic, the noLocal argument may be used to specify that the subscriber must not receive messages published to the topic by its own connection."

Section 6.11.1 "Durable TopicSubscriber" has been reworded to state that "When a durable subscription is created on a topic, the noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the durable subscription."

These changes are also listed in the change log, section 11.5.13.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

I've clarified the javadocs for the existing methods on Session that create both durable and non-durable subscribers:

Change to javadoc comment for Session.createConsumer(destination, messageSelector, NoLocal), which returns a MessageConsumer. This is used for non-durable topic subscriptions and for queues.

Old comment:

     /** Creates <CODE>MessageConsumer</CODE> for the specified destination, using a
      * message selector. This method can specify whether messages published by
      * its own connection should be delivered to it, if the destination is a
      * topic.

      . . .

      * <P>In some cases, a connection may both publish and subscribe to a
      * topic. The consumer <CODE>NoLocal</CODE> attribute allows a consumer
      * to inhibit the delivery of messages published by its own connection.
      * The default value for this attribute is False. The <CODE>noLocal</CODE>
      * value must be supported by destinations that are topics.

      . . .

      * @param NoLocal  - if true, and the destination is a topic,
      *                   inhibits the delivery of messages published
      *                   by its own connection.  The behavior for
      *                   <CODE>NoLocal</CODE> is
      *                   not specified if the destination is a queue.

New comment:

     /** Creates <CODE>MessageConsumer</CODE> for the specified destination, using a
      * message selector. This method can specify whether messages published by
      * its own connection should be delivered to it, if the destination is a
      * topic.

      . . .

      * <P>The <code>NoLocal</code> argument is for use when the
      * destination is a topic and the session's connection
      * is also being used to publish messages to that topic.
      * If <code>NoLocal</code> is set to true then the
      * <code>MessageConsumer</code> will not receive messages published
      * to the topic by its own connection. The default value of this
      * argument is false. If the destination is a queue
      * then the effect of setting <code>NoLocal</code>
      * to true is not specified.

      . . .

      * @param NoLocal  - if true, and the destination is a topic,
      *                   then the <code>MessageConsumer</code> will
      *                   not receive messages published to the topic
      *                   by its own connection.

Change to javadoc comment for Session.createDurableSubscriber(topic, name, messageSelector, noLocal), which returns a TopicSubscriber. This is used for durable topic subscriptions.

Old comment:

   /** Creates a durable subscriber to the specified topic,
        using a message selector and specifying whether messages
        published by its own connection should be delivered to it.

       . . .

     * @param noLocal if set, inhibits the delivery of messages published
     * by its own connection

New comment:

    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>TopicSubscriber</code>
     * on that durable subscription, specifying a message
     * selector and whether messages published by its
     * own connection should be added to the durable subscription.

     . . .

     * <P>The <code>NoLocal</code> argument is for use when the session's
     * connection is also being used to publish messages to the topic.
     * If <code>NoLocal</code> is set to true then messages published
     * to the topic by its own connection will not be added to the
     * durable subscription. The default value of this
     * argument is false.

     . . .

     * @param noLocal if true, messages published by its own connection
     * will not be added to the durable subscription.

I've also updated the javadoc comment for Session.createDurableConsumer(topic, name, messageSelector, noLocal), which returns a MessageConsumer. This is proposed to satisfy JMS_SPEC-51 and is further modified here:

     /** Creates a durable subscription with the specified name on the
      * specified topic, and creates a <code>MessageConsumer</code>
      * on that durable subscription, specifying a message
      * selector and whether messages published by its
      * own connection should be added to the durable subscription.

      . . .

     * <P>The <code>NoLocal</code> argument is for use when the session's
     * connection is also being used to publish messages to the topic.
     * If <code>NoLocal</code> is set to true then messages published
     * to the topic by its own connection will not be added to the
     * durable subscription. The default value of this
     * argument is false.
      . . .

      * @param noLocal if true, messages published by its own connection
      * will not be added to the durable subscription.

In addition, I've updated all the relevant methods on the JMSContext interface proposed in http://java.net/jira/browse/JMS_SPEC64:

Updated javadoc comment for JMSContext.createConsumer(destination, messageSelector, NoLocal), which returns a JMSConsumer. This is proposed to satisfy JMS_SPEC-64 and is further modified here.

/**
 * Creates a <CODE>JMSConsumer</CODE> for the specified destination, using
 * a message selector. This method can specify whether messages published by
 * its own connection should be delivered to it, if the destination is a
 * topic.

 . . .

 * The <code>noLocal</code> argument is for use when the
 * destination is a topic and the JMSContext's connection
 * is also being used to publish messages to that topic.
 * If <code>noLocal</code> is set to true then the
 * <code>JMSConsumer</code> will not receive messages published
 * to the topic by its own connection. The default value of this
 * argument is false. If the destination is a queue
 * then the effect of setting <code>noLocal</code>
 * to true is not specified.
  
 . . .

 * @param noLocal  if true, and the destination is a topic,
 *                 then the <code>JMSConsumer</code> will
 *                 not receive messages published to the topic
 *                 by its own connection
 * 

Updated javadoc comment for JMSContext.createDurableConsumer(topic, name, messageSelector, noLocal), which returns a JMSConsumer.

/** Creates a durable subscription with the specified name on the
 * specified topic, and creates a <code>JMSConsumer</code> 
 * on that durable subscription, specifying a message selector and 
 * whether messages published by its own connection should be added to 
 * the durable subscription.  

   . . .

 * The <code>noLocal</code> argument is for use when the JMSContext's 
 * connection is also being used to publish messages to the topic. 
 * If <code>noLocal</code> is set to true then messages published
 * to the topic by its own connection will not be added to the
 * durable subscription. The default value of this 
 * argument is false. 

   . . .

 * @param noLocal if true, messages published by its own connection
 * will not be added to the durable subscription.

Updated 15 May 2012 to reflect the rename of MessagingContext to JMSContext and other changes to that interface.

Comment by Nigel Deakin [ 15/May/12 ]

This issue was discussed and agreed some time ago before the early draft, but I'd like to re-open it for discussion of a possible clarification.

You will remember that this issue is about the purpose of the noLocal parameter when creating a durable subscription.

The JMS 1.1 javadocs simply states that this flag "inhibits the delivery of messages published by its own connection".
(http://docs.oracle.com/javaee/6/api/javax/jms/Session.html#createDurableSubscriber%28javax.jms.Topic,%20java.lang.String,%20java.lang.String,%20boolean%29)

For JMS 2.0 we have already agreed to clarify this to state that if this flag is set "messages published by its own connection will not be added to the durable subscription."
(See comments above or at http://java.net/jira/browse/JMS_SPEC-65#action_328549)

However it has been pointed out to me that further clarification may be needed.

Let's review this in stages.

Case 1

Consider the simplest case. A client creates a connection and calls createDurableSubscriber with noLocal=true. This returns a TopicSubscriber. It then uses the same connection to create a MessageProducer and uses it to send a message to the topic. The client then uses the TopicSubscriber to try to receive the message.

String clientID = "foo";
String subscriptionName = "bar";
boolean noLocal=true;
String messageSelector=null;
ConnectionFactory connectionFactory = ... // lookup connection factory
Topic topic = ...                         // lookup topic
Connection connection = connectionFactory.createConnection();
connection.setClientID(clientID);
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.send(session.createTextMessage("Hello"));
			
connection.start();
Message message = subscriber.receive(1000));
// is a message received or not?
connection.close();

What happens? JMS 1.1 states that the noLocal flag "inhibits the delivery of messages published by its own connection". We're using the same connection to send and receive messages, so clearly no message is received.

Case 2

After the previous case is run, the client now creates a second connection with the same clientID as before and calls createDurableSubscriber with identical arguments as before. This returns a second TopicSubscriber. The client then uses the second TopicSubscriber to try to receive the message.

Here's the complete case:

String clientID = "foo";
String subscriptionName = "bar";
boolean noLocal=true;
String messageSelector=null;
ConnectionFactory connectionFactory = ... // lookup connection factory
Topic topic = ...                         // lookup topic

// Step 1
Connection connection = connectionFactory.createConnection();
connection.setClientID(clientID);
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.send(session.createTextMessage("Hello"));
			
connection.start();
Message message = subscriber.receive(1000));
// message is null
connection.close();


// Step 2
Connection connection2 = connectionFactory.createConnection();
connection2.setClientID(clientID);
Session session2 = connection2.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber2 = session2.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
connection2.start();
Message message2 = subscriber2.receive(1000));
// is a message received or not?
connection2.close();

What happens? JMS 1.1 simply states that the noLocal flag "inhibits the delivery of messages published by its own connection". But in this case the message was published by a different connection. Should it be delivered?

However we've already taken the decision in JMS 2.0 to clarify the effect of the noLocal flag to state that "messages published by its own connection will not be added to the durable subscription." In this case, the message was published using the same connection as was used to create the durable subscription. So in accordance with this new wording, the message is not added to the durable subscription and so will never be delivered, even to a subsequent consumer that uses a different connection.

Case 3

So far so good. But now let's consider a third case: what if this second connection is also used to send a second message to the topic? Is it added to the durable subscription or not?

Here's the complete case:

String clientID = "foo";
String subscriptionName = "bar";
boolean noLocal=true;
String messageSelector=null;
ConnectionFactory connectionFactory = ... // lookup connection factory
Topic topic = ...                        // lookup topic

// Step 1
Connection connection = connectionFactory.createConnection();
connection.setClientID(clientID);
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.send(session.createTextMessage("Hello"));
			
connection.start();
Message message = subscriber.receive(1000));
// message is null
connection.close();


// Step 2
Connection connection2 = connectionFactory.createConnection();
connection2.setClientID(clientID);
Session session2 = connection2.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber2 = session2.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
connection2.start();
Message message2 = subscriber2.receive(1000));
// message is null

MessageProducer messageProducer2 = session2.createProducer(session2.createTopic(topicName));
messageProducer2.send(session2.createTextMessage("Hello"));

connection2.close();

// Step 3
Connection connection3 = connectionFactory.createConnection();
connection3.setClientID(clientID);
Session session3 = connection3.createSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber3 = session3.createDurableSubscriber(topic, subscriptionName, messageSelector, noLocal);
			
connection3.start();
Message message3 = subscriber3.receive(1000));
// is a message received or not?
connection3.close();

The message sent using the first connection was not added to the durable subscription. Similarly, I think that the message sent using the second connection should not be added to the durable subscription. Anything else would be inconsistent and not very useful.

Just to reiterate this: the effect of setting noLocal shouldn't be restricted to messages sent using the very first connection, the one used to create the durable subscription. It should apply throughout the life of the durable subscription.

However this leads to one further question. In case 3, step 2 above, does it matter whether the producer was created, and the message sent, before or after the durable subscription was activated? At what point does connection2 become "tainted" and unable to send messages to the durable subscription?

I think the simplest answer to that is to say that it doesn't matter at what point connection2 activates the durable subscription. It has the same clientID as was associated with the durable subscription, and so any messages it sends to the topic will never be added to the durable subscription. This is the only definition of noLocal which gives consistent behaviour throughout the life of the subscription.

However for JMS 2.0 we have made clientID optional when creating a durable subscription. This means we need to define what noLocal means when clientID is not set. The simplest approach would be to define that setting noLocal on a durable subscription has no effect unless clientID is set.

In summary

In summary, it is proposed to further clarify the meaning of the noLocal parameter in the method Session.createDurableConsumer as follows:

/** Creates a durable subscription with the specified name on the
 * specified topic, and creates a <code>MessageConsumer</code>
 * on that durable subscription, specifying a message
 * selector and the noLocal argument.

   . . .

 * <P>If <code>noLocal</code> is set to true, 
 * and the client identifier is set, then any messages published 
 * using this connection or any other with the same client identifier 
 * will not be added to the durable subscription. 
 * If the client identifier is unset then 
 * setting <code>noLocal</code> to true has no effect.
 * The default value of <code>noLocal</code> is false.


   . . .

 * @param noLocal if true, and the client identifier is set, 
 * then any messages published using this connection 
 * or any other with the same client identifier 
 * will not be added to the durable subscription. 

Similar changes will be made to Session.createDurableSubscriber and JMSContext.createDurableConsumer, and to the JMS specification itself.

Comment by Nigel Deakin [ 30/May/12 ]

I've now updated the draft spec and javadocs in accordance with the changes proposed in the previous comment.

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

Section 6.11.1 "Durable TopicSubscriber" has been reworded to define the effect of setting noLocal as follows:

When a durable subscription is created on a topic, the noLocal argument may be used to specify that messages published to the topic by its own connection or any other with the same client identifier will not be added to the durable subscription. If the client identifier is unset then setting noLocal to true has no effect.

In addition, the effect of supplying a different value of noLocal when creating a consumer on an existing durable subscription has been clarified as follows:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal argument, then the durable subscription will be deleted and a new one created.

However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal argument, then a JMSException or JMSRuntimeException will be thrown.

Note that changing noLocal only has an effect if the client identifier is set.

These changes are also listed in the change log, section B.5.16.

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

I've clarified the javadocs for all the existing methods on Session and JMSContext that create durable subscribers. The methods affected are the Session methods createDurableSubscriber and createDurableConsumer and the JMSContext methods createDurableConsumer. These all now have javadoc comments similar to the following example:

* Creates a durable subscription with the specified name on the specified
* topic (if one does not already exist), specifying a message selector and
* the <code>noLocal</code> parameter, and creates a
* <code>TopicSubscriber</code> on that durable subscription.


* If there are no active consumers on the durable subscription (and no
* consumed messages from that subscription are still part of a pending
* transaction or are not yet acknowledged in the session), and this method
* is used to create a new consumer on that durable subscription, specifying
* the same name and client identifier (if set) but a different topic or
* message selector, or, if the client identifier is set, a different
* noLocal argument, then the durable subscription will be deleted and a new
* one created. 
*
* However if there is an active consumer on the durable
* subscription (or a consumed message from that subscription is still part
* of a pending transaction or is not yet acknowledged in the session), and
* an attempt is made to create an additional consumer, specifying the same
* name and client identifier (if set) but a different topic or message
* selector, or, if the client identifier is set, a different noLocal
* argument, then a <code>JMSException</code> will be thrown.
*
* If <code>noLocal</code> is set to true, and the client identifier is set,
* then any messages published to the topic using this session's connection,
* or any other connection or <code>JMSContext</code> with the same client
* identifier, will not be added to the durable subscription. If the client
* identifier is unset then setting <code>noLocal</code> to true has no
* effect. The default value of <code>noLocal</code> is false.

. . .

* @param noLocal
*            if true, and the client identifier is set, then any messages
*            published to the topic using this session's connection, or any
*            other connection or <code>JMSContext</code> with the same
*            client identifier, will not be added to the durable
*            subscription.
Comment by Nigel Deakin [ 13/Sep/12 ]

I've added a further change:

If the client identifier is unset then setting noLocal to true will cause an IllegalStateException or IllegalStateRuntimeException (depending on the method signature) to be thrown.

Comment by clebertsuconic [ 13/Sep/12 ]

I agree.. clientID is non set, calling createDurableSubscription with noLocal=true should throw an exception, otherwise there's no way to replay durable subscriptions.

However.... if you set clientID==null on a non-durable subscription, it would be possible to filter out with some sort of UUID at the implementation. However the usage semantics would get complicated.. so I would vote to just keep it simple.. i.e.:

clientID==null && noLocal==true => throw SomeException

Comment by chris.barrow [ 13/Sep/12 ]

Are you suggesting the createConsumer method should follow the same logic? I would have to urge against that because clientID has nothing whatsoever to do with non-durables, so it would be confusing to suddenly relate the two. Moreover it would be an incompatible change from 1.1 (which currently allows createConsumer with noLocal=true whether or not there is a clientID set on the connection).

Comment by Nigel Deakin [ 13/Sep/12 ]

This change (and this whole issue) concerns durable subscriptions only, and was intended to clarify what the existing JMS 1.1 behaviour should be.

The definition of noLocal for non-durable, non-shared subscriptions is unchanged from JMS 1.1. In that case client identifier may be either set or unset when noLocal is true. If a message is sent by the same Connection object which created the subscription then the message will not be added to the subscription. No need to rely on UUID, since when the connection that created the subscription is closed, the subscription will be deleted.

The introduction of shared durable and non-durable subscriptions in JMS 2.0 does introduce the issue of what noLocal means in that case. I will raise this as part of issue JMS_SPEC-40 which covers shared durable and non-durable subscriptions.

Comment by clebertsuconic [ 13/Sep/12 ]

My bad .. this is is certainly only about durable subscription

I'm happy with what you propose then.. but as I told you in a private email I prefer some exception as opposed to just ignore it.

Comment by chris.barrow [ 13/Sep/12 ]

Sorry to eat my words here, but in light of the discussion about non-durables I would now recommend changing the behavior for createDurableSubscription with noLocal=true to make it independent of clientID and consistent with non-durable shared consumers. See my recent comment in JMS_SPEC_40.

Comment by clebertsuconic [ 13/Sep/12 ]

@chriss: you need some sort of client-id to replay the queues and do the correct association.

Most implementations I know will use an internal filter on the queue with message.originatingID != currentID.

how would you replay the queue on these circunstances? what about previous sent messages?

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-34] Calling setJMSDeliveryMode or setJMSPriority on a javax.jms.Message before it is sent don't have any effect Created: 25/Jul/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-60 Obscurity setting special JMSHeaders Closed
Tags: ed20-added

 Description   

This issue relates to the following methods on javax.jms.Message:

setJMSPriority
setJMSDeliveryMode

Many novice developers think these methods can be used to set the priority and delivery mode of a message before it is sent. In fact these methods have no effect: the only way to set priority and delivery mode is by using methods on javax.jms.MessageProducer.

This a common cause of confusion to developers. Can we either deprecate these methods or else change them so that actually do something?



 Comments   
Comment by Nigel Deakin [ 25/Jul/11 ]

The same issue applies to the following methods on javax.jms.Message as well:

setJMSDeliveryMode
setJMSExpiration
setJMSPriority
setJMSMessageID
setJMSTimestamp
setJMSRedelivered
setJMSDeliveryTime (proposed in JMS_SPEC-44)

If any of these methods are called on a message before it is sent they have no effect. The javadoc comment on each of these methods states "This method can be used to change the value for a message that has been received.", despite it being far from obvious why an application might want to do this.

Comment by Nigel Deakin [ 22/Nov/11 ]

These methods are needed because a JMS provider is required to be capable of sending messages whose implementation is not its own. This would typically occur if an application received a message from provider 1 and then sent the same message using provider 2.

When this happens, provider 2 is responsible for setting the JMSDestination, JMSDeliveryMode, JMSExpiration, JMSPriority, JMSMessageID and JMSTimestamp header field values on the message. The only way that provider 2 can set these values on a message implemented by provider 1 is using these public setter methods.

Here's an example: if the application sends a message with a priority of 3 then it does this either by setting the priority on the MessageProducer by calling its setPriority method prior to sending the message, or by setting the priority on the individual message send by calling the MessageProducer method send(destination, message, deliveryMode, priority, timeToLive). The provider is responsible for ensuring that, after the message has been sent, the message's JMSPriority header holds the appropriate priority so that the line of code following the call to send could obtain this value. (See section 3.4.10 of the JMS 1.1 spec).

// message1 was obtained from provider 1
// we're sending it using provider 2
messageConsumer.setPriority(3);
messageConsumer.send(message1);
int priority = message1.getJMSPriority(); // should return 3

In the above example, provider 2's send method needs to be able to set the JMSPriority header on message1, which was implemented by provider 1, so it needs a standard, public API to do this.

We therefore cannot remove these methods. It would, however, be possible to clarify the javadoc comments to make it clear that these methods cannot be used by the sending application to control the message priority, delivery mode. We will improve the wording in JMS 2.0.

I suspect that some people who fall into the trap of misunderstanding these methods simply guess the method name, see that it gets accepted by their IDE, and use it. There's not much we can do about this (though since most IDEs can display javadoc comments clarifying the javadoc may help).

Comment by koen.serneels [ 23/Nov/11 ]

My opinion is still that it should always be the goal of a good API to minimize the percentage of obscurity.
By offering methods in a public API that do nothing, you are creating confusion from the start.

Can't there be a Message SPI or some other way that the provider can set the priority before sending? Imho this is just bad design which leads to errornous code and time consuming debegugging to find out "why this setter method doesn't work" ?.

Comment by Nigel Deakin [ 23/Nov/11 ]

@koen.serneels: You're perfectly right, the existence of these methods is misleading and with hindsight the people who designed this API should have done something different. But removing them would be a non-compatible change so I think we're stuck with them.

Comment by Nigel Deakin [ 22/Dec/11 ]

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

The javadoc comments for the following methods on Message have been updated:

setJMSDeliveryMode
setJMSExpiration
setJMSPriority
setJMSMessageID
setJMSTimestamp
setJMSRedelivered
setJMSDeliveryTime (proposed in JMS_SPEC-44)

Currently the javadoc comments for these methods simply states:

    /** Sets the message's [name of property] value
      *  
      * <P>JMS providers set this field when a message is sent. This method
      * can be used to change the value for a message that has been received.

These have been changed as follows:

   /** Sets the message's [name of property] value.
     *
     * <P>This method is for use by JMS providers only to set this field 
     * when a message is sent. This message cannot be used by clients 
     * to configure the [describe feature] of the message. This method is public
     * to allow one JMS provider to set this field when sending a message
     * whose implementation is not its own.

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. The changes for this issue are as follows:

Section 3.4.1 "How Message Header Values Are Set" has been updated.

Section 11.5.8. "Clarification: message headers that are intended to be set by the JMS provder" is the change log for this issue.

Comment by Nigel Deakin [ 23/Feb/12 ]

Clarified the explanation in the second comment .





[JMS_SPEC-31] change javadoc on session.createQueue and createTopic to make clearer the provider may create a physical destination Created: 15/Jul/11  Updated: 20/Mar/13  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: clebertsuconic Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

Most users have been asking us to add a flag to just create the server's side queue with some default values.

If I add the flag the configuration won't be spec compliant in some people's interpretation as the javadoc says the createQueue / createTopic is not for the physical creation itself.

I'm not sure what to make on the javadoc, the current version says this:

"Note that this method is not for creating the physical queue. The physical creation of queues is an administrative task and is not to be initiated by the JMS API. The one exception is the creation of temporary queues, which is accomplished with the createTemporaryQueue method."

My proposal is to change it to something permissive where the provider may or not create the physical queue. That would be a design choice.



 Comments   
Comment by clebertsuconic [ 15/Jul/11 ]

This is a simple change. We should simply remove the text about physical creation of the queues. I believe most experts will agree this is already currently allowed on the spec.

Comment by rdohna [ 18/Jul/11 ]

+1

But I think that it must be configurable to either throw an exception or to create a new destination. If you have hundreds of queues, I'd rather have an exception than go search around who created this strange new queue. So IMHO at least this behaviour should be required by the spec. Automatically generating destinations should be mentioned as one legal alternative, when so configured... even if it's the default.

Comment by Nigel Deakin [ 09/Mar/12 ]

This issue will be considered by the expert group for inclusion in the JMS 2.0 public draft. Tagging accordingly.

Comment by Nigel Deakin [ 23/Apr/12 ]

My feeling is that we should keep this method as it was originally intended, which is as a way to convert a provider-specific queue name to a javax.jms.Queue object which can be used in the JMS API, and not as a mechanism for creating the physical queue in the server.

However I do think we need to clarify that this method is NOT expected to throw a JMSException if the physical queue does not exist. I think this is pretty clear already but should be clarified: the 1.1 javadoc refers to "if the session fails to create a queue". Given that the javadoc states that this method does not create the physical queue then this error can only mean "fails to create a Queue object".

I know that some JMS providers (Apache ActiveMQ and Oracle GlassFish MQ) allow the queue to be created automatically in the server when the first message is sent to it (or perhaps when a producer or consumer is created). However they don't create the queue when createQueue is called, and do don't violate the statement "this method is not for creating the physical queue".

Here is the existing javadoc description for the createQueue method on Session:

      /** Creates a queue identity given a <CODE>Queue</CODE> name.
      *
      * <P>This facility is provided for the rare cases where clients need to
      * dynamically manipulate queue identity. It allows the creation of a
      * queue identity with a provider-specific name. Clients that depend
      * on this ability are not portable.
      *
      * <P>Note that this method is not for creating the physical queue.
      * The physical creation of queues is an administrative task and is not
      * to be initiated by the JMS API. The one exception is the
      * creation of temporary queues, which is accomplished with the
      * <CODE>createTemporaryQueue</CODE> method.
      *
      * @param queueName the name of this <CODE>Queue</CODE>
      *
      * @return a <CODE>Queue</CODE> with the given name
      *
      * @exception JMSException if the session fails to create a queue
      *                         due to some internal error.
      * @since 1.1
      */

    Queue createQueue(String queueName) throws JMSException;

I think this is basically correct, though the phrase "queue identity" is a bit mysterious. I've now reworded it as follows:

	/**
	 * Creates a <code>Queue</code> object which encapsulates a specified
	 * provider-specific queue name.
	 * <p>
	 * The use of provider-specific queue names in an application may render the
	 * application non-portable. Portable applications are recommended to not
	 * use this method but instead look up an administratively-defined
	 * <code>Queue</code> object using JNDI.
	 * <p>
	 * Note that this method simply creates an object that encapsulates the name
	 * of a queue. It does not create the physical queue in the JMS provider.
	 * JMS does not provide a method to create the physical queue, since this
	 * would be specific to a given JMS provider. Creating a physical queue is
	 * provider-specific and is typically an administrative task performed by an
	 * administrator, though some providers may create them automatically when
	 * needed. The one exception to this is the creation of a temporary queue,
	 * which is done using the <code>createTemporaryQueue</code> method.
	 * 
	 * @param queueName
	 *            A provider-specific queue name
	 * @return a Queue object which encapsulates the specified name
	 * 
	 * @throws JMSException
	 *             if a Queue object cannot be created due to some internal
	 *             error
	 */
	Queue createQueue(String queueName) throws JMSException;

I've made this change to the createQueue method on Session and, mutatis mutandis, to the createTopic method on Session and the createQueue and createTopic methods on JMSContext.

The new javadocs may be browsed here

I've also updated the change list in the draft spec to refer to this change. See section B.5.18 "Clarification: Session methods createQueue and createTopic".

The draft spec may be downloaded here (you need to log in to java.net first)

Comment by Nigel Deakin [ 21/Sep/12 ]

For the final wording see the API docs to accompany the JMS 2.0 public draft.





[JMS_SPEC-51] New methods to replace Session.createDurableSubscriber() and return a MessageConsumer Created: 16/Sep/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-171 New methods to replace Session.create... Closed
Tags: ed20-added

 Description   

In JMS 1.1 the following two methods on Session return a TopicSubscriber.

TopicSubscriber createDurableSubscriber(Topic topic)

TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

These are the only "domain-independent" methods in the whole JMS 1.1 API which depend on a "domain-specific" interface. This dependency prevents the "domain-specific" interfaces being removed from JMS as proposed in JMS_SPEC-47.

It is therefore proposed to modify these methods to return a MessageConsumer. Since this is a supertype of TopicSubscriber it should not break existing applications.



 Comments   
Comment by Nigel Deakin [ 20/Sep/11 ]

It has been pointed out that the above proposal would require existing applications would need to cast the MessageConsumer that is returned down to a TopicSubscriber.

This suggests that we need to provide new versions of this method which return a MessageConsumer. This would allow us to mark the old methods as deprecated and propose them for removal.

We can't simply add new methods with the same name which return a MessageConsumer since the compiler would consider these duplicate methods.

Two options have been proposed:

Option 1

We could define new methods named createConsumer:

MessageConsumer createConsumer(Topic topic, java.lang.String name)

MessageConsumer createConsumer(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

However there's potential confusion between the first of those methods and the existing method to create an ordinary consumer with a message selector:

MessageConsumer createConsumer(Destination destination, java.lang.String messageSelector)

The compiler would allow it, but if the user tried to create a durable subscription using a variable which was really a Topic but which was declared as Destination then the wrong method would be called.

It could also be argued that removing the word "durable" from the method name would be confusing for users.

We could either live with these drawbacks, or we could use:

Option 2

We could define new methods named createDurableConsumer:

MessageConsumer createDurableConsumer(Topic topic, java.lang.String name)

MessageConsumer createDurableConsumer(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)

Comment by Nigel Deakin [ 03/Jan/12 ]

Following a discussion within the JSR 343 expert group I've selected option 2 above.

I've now updated the javadocs and the draft spec accordingly (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
(Two createDurableConsumer methods have been added to Session. See below for javadocs).

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 6.11.1 "Durable TopicSubscriber" and 11.5.9 "createDurableConsumer" which is the change log).

Here are the two new methods:

    /** Creates a durable subscription with the specified name on the
      * specified topic, and creates a <code>MessageConsumer</code> 
      * on that durable subscription.
      * <P>
      * If the durable subscription already exists then this method
      * creates a <code>MessageConsumer</code> on the existing durable
      * subscription.
      * <p>
      * A durable subscription is used by a client which needs to receive
      * all the messages published on a topic, including the ones published 
      * when there is no <code>MessageConsumer</code> or <code>TopicSubscriber</code> associated with it. 
      * The JMS provider retains a record of this durable subscription 
      * and ensures that all messages from the topic's publishers are retained 
      * until they are delivered to, and acknowledged by,
      * a <code>MessageConsumer</code> or <code>TopicSubscriber</code> on this durable subscription
      * or until they have expired.
      * <p>
      * A durable subscription will continue to accumulate messages 
      * until it is deleted using the <code>unsubscribe</code> method. 
      * <p>
      * A durable subscription which has a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being active. 
      * A durable subscription which has no <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being inactive. 
      * <p>
      * Only one session at a time can have a
      * <code>MessageConsumer</code> or <code>TopicSubscriber</code> for a particular durable subscription.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was first created then a client which 
      * subsequently wishes to create a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * on that durable subscription must use the same client identifier.
      * <p>
      * A client can change an existing durable subscription by calling
      * <code>createDurableConsumer</code> 
      * with the same name and client identifier (if used),
      * and a new topic and/or message selector. 
      * Changing a durable subscriber is equivalent to 
      * unsubscribing (deleting) the old one and creating a new one.
      *
      * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
      * @param name the name used to identify this subscription
      *  
      * @exception JMSException if the session fails to create the durable subscription 
      *            and <code>MessageConsumer</code> due to some internal error.
      * @exception InvalidDestinationException if an invalid topic is specified.
      *
      * @since 2.0
      */ 
     MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException;
     /** Creates a durable subscription with the specified name on the
      * specified topic, and creates a <code>MessageConsumer</code> 
      * on that durable subscription, specifying a message 
      * selector and whether messages published by its
      * own connection should be delivered to it.
      * <P>
      * If the durable subscription already exists then this method
      * creates a <code>MessageConsumer</code> on the existing durable
      * subscription.
      * <p>
      * A durable subscription is used by a client which needs to receive
      * all the messages published on a topic, including the ones published 
      * when there is no <code>MessageConsumer</code> or <code>TopicSubscriber</code> associated with it. 
      * The JMS provider retains a record of this durable subscription 
      * and ensures that all messages from the topic's publishers are retained 
      * until they are delivered to, and acknowledged by,
      * a <code>MessageConsumer</code> or <code>TopicSubscriber</code> on this durable subscription
      * or until they have expired.
      * <p>
      * A durable subscription will continue to accumulate messages 
      * until it is deleted using the <code>unsubscribe</code> method. 
      * <p>
      * A durable subscription which has a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being active. 
      * A durable subscription which has no <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * associated with it is described as being inactive. 
      * <p>
      * Only one session at a time can have a
      * <code>MessageConsumer</code> or <code>TopicSubscriber</code> for a particular durable subscription.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was first created then a client which 
      * subsequently wishes to create a <code>MessageConsumer</code> or <code>TopicSubscriber</code>
      * on that durable subscription must use the same client identifier.
      * <p>
      * A client can change an existing durable subscription by calling
      * <code>createDurableConsumer</code> 
      * with the same name and client identifier (if used),
      * and a new topic and/or message selector. 
      * Changing a durable subscriber is equivalent to 
      * unsubscribing (deleting) the old one and creating a new one.
      *
      * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
      * @param name the name used to identify this subscription
      * @param messageSelector only messages with properties matching the
      * message selector expression are delivered.  A value of null or
      * an empty string indicates that there is no message selector 
      * for the message consumer.
      * @param noLocal if set, inhibits the delivery of messages published
      * by its own connection
      *  
      * @exception JMSException if the session fails to create the durable subscription 
      *                         and <code>MessageConsumer</code> due to some internal error.
      * @exception InvalidDestinationException if an invalid topic is specified.
      * @exception InvalidSelectorException if the message selector is invalid.
      *
      * @since 2.0
      */ 
      MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;   
Comment by Nigel Deakin [ 03/Jan/12 ]

I've changed the summary line for this issue from
Change Session.createDurableSubscriber() to return a MessageConsumer
to
New methods to replace Session.createDurableSubscriber() and return a MessageConsumer.

This reflects the decision not to change the existing methods (to preserve backwards compatibility) but to add new methods.





[JMS_SPEC-49] Improve specification of ExceptionListener Created: 16/Aug/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: ed20-added

 Description   

The use of a ExceptionListener is described in the JMS 1.1 specification in section 4.3.8 "ExceptionListener":

If a JMS provider detects a problem with a connection, it will inform the connection's ExceptionListener, if one has been registered. To retrieve an ExceptionListener, the JMS provider calls the connection's getExceptionListerer()
method. This method returns the ExceptionListener for the connection. If no ExceptionListener is registered, the value null is returned. The connection can then use the listener by calling the listener 's onException() method, passing it a JMSException describing the problem.

This allows a client to be asynchronously notified of a problem. Some connections only consume messages, so they would have no other way to learn their connection has failed.

A Connection serializes execution of its ExceptionListener.

A JMS provider should attempt to resolve connection problems itself prior to notifying the client of them.

The exceptions delivered to ExceptionListener are those that have no other place to be reported. If an exception is thrown on a JMS call it, by definition, must not be delivered to an ExceptionListener (in other words, ExceptionListener is not for the purpose of monitoring all exceptions thrown by a connection).

Despite this, there have been a number of questions about the use of an ExceptionListener. These questions are listed below, together with proposed answers. It is proposed that the answers to these questions be incorporated into the specification.

Question 1: When Connection.stop() or Connection.close() is called, must these methods wait until any active calls to ExceptionListeners for that connection have returned, in the same way that they must wait until any active call to MessageListeners have returned?

Proposed answer: No.

Question 2: Is there any restriction on the use of Connection.stop() or Connection.close() from an ExceptionListener?

Proposed answer: No.

Question 3: What does "a Connection serializes execution of its ExceptionListener" mean?

Proposed answer: This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage() from one thread at a time. Note however that if the same ExceptionListener is registered with different connections then it is undefined whether these connections could call onMessage() from different threads simultaneously.

Question 4: What is the effect of ExceptionListener.onException() being slow or blocking?

Proposed answer: This is undefined. There is no requirement that any other operation need block until ExceptionListener.onException() has return, apart from other calls to ExceptionListener.onException() for the same connection.



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

I've now written the following draft text:

Changes to section 4.3.8 "ExceptionListener":

After:

A Connection serializes execution of its ExceptionListener.

Insert:

This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage() from one thread at a time. Note however that if the same ExceptionListener is registered with multiple connections then it is undefined whether these connections could call onMessage() from different threads simultaneously.

At the end, insert:

There is no restriction on the use of the JMS API by the listener's onException method. However since that method will only be called when there is a serious problem with the connection, any attempt to use that connection may fail and cause exceptions.

New text in the javadoc for ExceptionListener:

There is no restriction on the use of the JMS API by the listener's onException method. However since that method will only be called when there is a serious problem with the connection, any attempt to use that connection may fail and cause exceptions.

A Connection serializes execution of its ExceptionListener. This means that if a connection encounters multiple problems and therefore needs to call its ExceptionListener multiple times, then it will only invoke onMessage from one thread at a time. Note however that if the same ExceptionListener is registered with multiple connections then it is undefined whether these connections could call onMessage from different threads simultaneously.

New text in the javadoc for Connection.stop():

For the avoidance of doubt, if an exception listener for this connection is running when stop is invoked, there is no requirement for the exception listener to return before the stop method returns.

New text in the javadoc for Connection.close():

For the avoidance of doubt, if an exception listener for this connection is running when stop is invoked, there is no requirement for the exception listener to return before the stop method returns.

Comment by Nigel Deakin [ 03/Jan/12 ]

I've now updated the javadocs and the draft spec with these clarifications (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 updated javadocs for Connection.stop, Connection.close, Session.close, MessagingContext.stop, MessagingContext.close)

  • The javadoc comments for the stop and close methods on the Connection interface have been amended to clarify that, if an exception listener for the connection is running when stop or close are invoked, there is no requirement for the stop or close call to wait until the exception listener has returned before it may return.
  • Similarly, the javadoc comment for the close method on the Session interface has been amended to clarify that, if an exception listener for the session's connection is running when close is invoked, there is no requirement for the close call to wait until the exception listener has returned before it may return.
  • The javadoc comments for the stop and close methods on the MessagingContext interface have been amended to clarify that, if an exception listener for the MessagingContext's connection is running when stop or close are invoked, there is no requirement for the stop or close call to wait until the exception listener has returned before it may return.

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.

The changes for this issue are to section 4.3.8 "Exception Listener":

  • The existing text which states that a connection "serializes execution of its ExceptionListener" has been extended to explain what this means.
  • A note has been added to state that there are no restrictions on the use of the JMS API by the listener's onException method.

In addition a new section 11.5.11 has been added which is the change log for this issue.





[JMS_SPEC-48] Specify that connection.stop() or close() may not be called from a MessageListener Created: 16/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: ed20-added

 Description   

Possible deadlock when calling connection.stop()

If the javax.jms.MessageListener method onMessage calls Connection.stop() then, according to the JMS 1.1 specification, deadlock may result.

Section 4.3.4 "Pausing Delivery of Incoming Messages" states:

If MessageListeners are running when stop is invoked, stop must wait until all of them have returned before it may return. While these MessageListeners are completing, they must have the full services of the connection available to them.

This means that if a MessageListener calls Connection.stop() then the call to stop() will block forever, waiting for the onMessage() method which is calling it to return.

To avoid the possibility of applications causing deadlock, the JMS specification needs to be clarified to state that a MessageListener must not call connection.stop().

The section above states that a MessageListener must have "the full services of the connection" available to it. The meaning of the term "full services" is not defined, but it needs to be made clear that this does not include the ability to call Connection.stop().

Possible deadlock when calling connection.close()

A similar issue exists for Connection.close(). If the javax.jms.MessageListener method onMessage calls Connection.close() then, according to the JMS 1.1 specification, deadlock may result.

Section 4.3.5 "Closing a connection" states:

If one or more of the connection's session's message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

When connection close 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.

Again, this means that if a MessageListener calls Connection.close() then the call to close() will block forever, waiting for the onMessage() method which is calling it to return.

To avoid the possibility of applications causing deadlock, the JMS specification needs similarly to be clarified to state that a MessageListener must not call connection.close().

The section above states that a MessageListener must have "all the facilities of the connection" available to it. The meaning of the term "all the facilities" is again not defined, but it needs to be made clear that those does not include the ability to call Connection.close().

Enforcement

JMS provider should be required to throw a javax.jms.IllegalStateException if Connection.stop() or Connection.close() is called from the onMessage method of a javax.jms.MessageListener.



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

I've now drafted the spec changes as follows:

Section 4.3.4 "Pausing Delivery of Incoming Messages"

After:

If MessageListeners are running when stop is invoked, stop must wait until all of them have returned before it may return. While these MessageListeners are completing, they must have the full services of the connection available to
them.

Append:

However a MessageListeners must not call the connection's stop() method as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.stop() is called from the onMessage method of a javax.jms.MessageListener.

Section 4.3.5 "Closing a Connection"

After:

If one or more of the connection’s session’s message listeners is processing a message at the point when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

Append:

However a message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.close() is called from the onMessage method of a javax.jms.MessageListener.

Section 4.4.1 "Closing a Session"

After:

When session close is invoked, it should not return until its message processing has been shut down in an orderly fashion. This means that none of its message listeners are running, and that if there is a pending receive, it has
returned with either null or a message.

Append:

A message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Session.stop() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Connection.stop()

After:

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.

Insert:

However a message listener must not call the connection's stop() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.stop() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Connection.close()

After:

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. A close terminates all pending message receives on the connection's sessions' consumers. The receives may return with a message or with null, depending on whether there was a message available at the time of the close. If one or more of the connection's sessions' message listeners is processing a message at the time when connection close is invoked, all the facilities of the connection and its sessions must remain available to those listeners until they return control to the JMS provider.

Append:

However a message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Connection.close() is called from the onMessage method of a javax.jms.MessageListener.

Javadoc for Session.close()

After:

This call will block until a receive call or message listener in progress has completed. A blocked message consumer receive call returns null when this session is closed.

Append:

A message listener must not call the connection's close() method, or the session's close() method, as this would lead to deadlock. The JMS provider must throw a javax.jms.IllegalStateException if Session.close() is called from the onMessage method of a javax.jms.MessageListener.

Comment by Nigel Deakin [ 04/Jan/12 ]

I've now updated the javadocs and the draft spec
(these changes are additive, so those docs include other changes).

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)

Section 4.3.4 "Pausing Delivery of Incoming Messages"

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.

Section 4.3.5 "Closing a Connection"

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.

Section 4.4.1 "Closing a Session"

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.

Section 11.5.12 "Clarification of use of stop or close from a message listener (JMS_SPEC-48)"

This is the change log for this issue.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

New javadoc comment on Connection.stop():

      * 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.

New javadoc comment on Connection.close():

      * 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.

New javadoc comment on Session.close():

      * 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.

New javadoc comment on MessagingContext.stop():

     * A message listener must not attempt to stop its own MessagingContext as this 
     * would lead to deadlock. The JMS provider must detect this and throw a 
     * javax.jms.IllegalStateRuntimeException.

New javadoc comment on MessagingContext.close():

     * A message listener must not attempt to close its own MessagingContext as this 
     * would lead to deadlock. The JMS provider must detect this and throw a 
     * javax.jms.IllegalStateRuntimeException.
Comment by Nigel Deakin [ 05/Dec/12 ]

I'd like to reopen this issue. Since the changes described above was added to the spec it has been pointed out that a similar issue applies with the close() methods on MessageConsumer and JMSConsumer.

I would therefore like to propose that we amend the definition of MessageConsumer.close() and JMSConsumer.close() to match the other methods listed here.

Comment by Nigel Deakin [ 05/Dec/12 ]

I've now drafted the necessary API changes:

New javadoc comment on MessageConsumer.close():

	 * This call blocks until a {@code receive} or message listener in progress
	 * has completed. A blocked message consumer {@code receive} call returns
	 * null when this message consumer is closed.
	 * <p>
	 * A {@code MessageListener} must not attempt to close its own
	 * {@code MessageConsumer} as this would lead to deadlock. The JMS provider
	 * must detect this and throw a {@code IllegalStateException}.
	 * 
	 * @exception IllegalStateException
	 *                this method has been called by a {@code MessageListener}
	 *                on its own {@code MessageConsumer}

Note that the words "this call blocks until a... message listener in progress has completed" are not new and were in JMS 1.1.

New javadoc comment on JMSConsumer.close()

	 * This call blocks until a {@code receive} or message listener in progress has completed.
	 * A blocked {@code receive} call returns null when
	 * this {@code JMSConsumer} is closed.
	 * <p>
	 * A {@code MessageListener} must not attempt to close its own
	 * {@code JMSConsumer} as this would lead to deadlock. The JMS provider
	 * must detect this and throw a {@code IllegalStateRuntimeException}.
	 * 
 	 * @exception IllegalStateRuntimeException
	 *                this method has been called by a {@code MessageListener}
	 *                on its own {@code JMSConsumer}

In addition I've added a new section 4.5.3 "Closing a MessageConsumer"

When the MessageConsumer's close method is invoked it should not return until its message processing has been shut down in an orderly fashion. This means that none of its message listeners are running, and that if there is a pending receive, it has returned with either null or a message.

A message listener must not attempt to close its own MessageConsumer as this would lead to deadlock. The JMS provider must detect this and throw a javax.jms.IllegalStateException.

Comment by Nigel Deakin [ 12/Feb/13 ]

The JMS EG has agreed to revise the behaviour of consumer close to:

  • Allow consumer.close to be called from within a message listener
  • Allowing a consumer to be closed from any thread, even if it isn't the thread of control

The main changes are listed below.

New Javadoc for MessageConsumer.close

/**
 * Closes the message consumer.
 * <p>
 * Since a provider may allocate some resources on behalf of a
 * {@code MessageConsumer} outside the Java virtual machine, clients should
 * close them when they are not needed. Relying on garbage collection to
 * eventually reclaim these resources may not be timely enough.
 * <P>
 * This call will block until a {@code receive} call in progress on this
 * consumer has completed. A blocked {@code receive} call returns null when
 * this message consumer is closed.
 * <p>
 * If this method is called whilst a message listener is in progress in
 * another thread then it will block until the message listener has
 * completed.
 * <p>
 * This method may be called from a message listener's {@code onMessage}
 * method on its own consumer. After this method returns the
 * {@code onMessage} method will be allowed to complete normally. 
 * <p>
 * This method is the only {@code MessageConsumer} method that can be called
 * concurrently.
 * 
 * @exception JMSException
 *                if the JMS provider fails to close the consumer due to
 *                some internal error.
 */

Spec changes: new section 8.8. Closing a consumer

8.8. Closing a consumer

The close methods on MessageConsumer, JMSConsumer, QueueReceiver and TopicSubscriber allow a consumer to be closed separately from the session or connection used to create it.

Closing a consumer terminates the delivery of messages to the consumer.

close is the only method on a consumer that may be invoked from a thread of control separate from the one which is currently controlling the session.

If close is called in one thread whilst another thread is calling receive on the same consumer then the call to close must block until the receive call has completed. A blocked receive call returns null when the consumer is closed.

If close is called in one thread whilst a message listener for this consumer is in progress in another thread then the call to close must block until the message listener has completed.

If close is called from a message listener's onMessage method on its own consumer then after this method returns the onMessage method must be allowed to complete normally.

Closing a consumer has no effect on the acknowledgement of messages delivered to the application, or on any transaction in progress. This is because message acknowledgement and transactions are functions of the session, not the consumer.

  • If the session mode is AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE then any messages delivered to the application will be automatically acknowledged as normal.
  • If the session mode is CLIENT_ACKNOWLEDGE then any messages delivered to the application may be acknowledged by calling acknowledge in the normal way. It makes no difference whether this occurs before or after the consumer is closed.
  • If the session is transacted then the application may commit or rollback the transaction as normal. It makes no difference whether this occurs before or after the consumer is closed.
Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-45] Clarify and improve Connection.createSession Created: 09/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-172 Implement two new Connection.createS... Closed
Tags: ed20-added

 Description   

In the JMS 1.1 specification, the following method on a javax.jms.Connection is used to create a javax.jms.Session:

Session createSession(boolean transacted, int acknowledgeMode) throws JMSException

where transacted may be set to true or false and
acknowledgeMode may be set to Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE

(There are similar methods on javax.jms.QueueConnection and javax.jms.TopicConnection: this whole issue applies to all three.)

This is a rather confusing method for several reasons:

  • It uses two arguments to define a single aspect of the session
  • In a Java EE transaction, both arguments are ignored anyway
  • In a Java EE unspecified transaction context, the meaning of the arguments is undefined and unclear

It uses two arguments to define the same thing

This method uses two arguments to define what is in practice a single aspect of the session with four possibilities: if transacted is set to false then the session is non-transacted and the acknowledgeMode argument defines which of three kinds of acknowledgement are used when receiving messages. If transacted is set to true then the acknowledgeMode argument is ignored.

This is inconsistent with the method Session.getAcknowledgeMode() which returns one of four values: Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, or Session.DUPS_OK_ACKNOWLEDGE if the session is not transacted and Session.SESSION_TRANSACTED if the session is transacted.

This also leads to code which is potentially misleading, since if transacted is false the user still has to set acknowledgeMode to some value even if it is ignored, which leads to code such as

Session session = connection.createSession(true,Session.AUTO_ACKNOWLEDGE);

Some developers like to use

Session session = connection.createSession(true,Session.SESSION_TRANSACTED);

though this is still misleading since since if transacted was set to true then the second argument is ignored anyway, and if transacted is false then setting acknowledgeMode to Session.SESSION_TRANSACTED would be an error.

In a Java EE transaction, both arguments are ignored anyway

In a Java EE transaction none of the four options listed above are permitted. Instead, both arguments to connection.createSession are ignored and a global transaction is used.

The EJB 3.1 Specification, section 13.3.5 "use of JMS APIs in Transactions" states that, in a container-managed or bean-managed transaction,

Because the container manages the transactional enlistment of JMS sessions on behalf of a bean, the parameters of the createSession(boolean transacted, int acknowledgeMode) method createQueueSession... are ignored.

This also applies to web applications. The Java EE platform spec, Section EE.6.7 "Java Message Service (JMS) 1.1 Requirements" specifies that

The behavior of a JMS provider should be the same in both the EJB container and the web container." It continues "The EJB specification describes restrictions on the use of JMS in an EJB container, as well as the interaction of JMS with transactions in an EJB container. Applications running in the web container should follow the same restrictions.

Instead, the receiving and sending of messages must be part of the container-managed or bean-managed transaction, and the transaction will be committed or rolled back in the way that container-managed or bean-managed transactions are committed or rolled back.

  • Container-managed transactions are either committed when the appropriate business method completes or are rolled back using EJBContext.setRollbackOnly.
  • Bean-managed transactions are either committed using UserTransaction.commit or rolled back using UserTransaction.rollback.

How explicit is the EJB specification about all this? In addition to specifying that in a transactional context the arguments to Connection.createSession are ignored, it also states the following:

  • Section 13.3.5 states that "within a transaction" the bean should not use the acknowledge method. This therefore covers both container-managed and bean-managed transactions.
  • Section 13.3.3 states that in the case of bean-managed transactions, the bean must not invoke the commit or rollback methods on the javax.jms.Session interface.
  • Section 13.3.4 states that in the case of container-managed transactions, the bean must not "use any resource-managed specific transaction management methods that would interfere with the container's demarcation of transaction boundaries" and again must not invoke the commit or rollback methods on the javax.jms.Session interface.
  • Section 13.1.1 states that in the case of bean-managed transactions, "all resource manager accesses between the UserTransaction.begin and UserTransaction.commit calls are part of a transaction", thereby apparently ruling out the use of non-transacted sessions using auto-acknowledgement and dups-ok-acknowledgement as well as those using client-acknowledgement.
  • Section 13.1.1 also states in a container-managed transaction the transaction demarcation depends on the transaction attributes of the bean method. It doesn't explicitly state that all resource manager accesses should be part of this transaction, but this is implied.

In a Java EE unspecified transaction context, the meaning of the arguments undefined and unclear

The previous section only relates to the use of the JMS API "in transactions". It does not cover how the JMS API should behave when there is no current container-managed or bean-managed transaction. That is, when there is an unspecified transaction context.

The EJB 3.1 Specification, section 13.6.5 "Handling of Methods that run with an unspecified transaction context" defines an "unspecified transaction context" as covering "the cases in which the EJB architecture does not fully define the transaction semantics of an enterprise bean method execution".

Section 13.6.5 goes on to give a list of examples of when an "unspecified transaction context" may arise. All the cases given are for container-managed transactions, leaving an ambiguity about what an "unspecified transaction context" means when using bean-managed transactions. An obvious interpretation is that that if a bean is configured to use bean-managed transactions, then business methods or onMessage() code executed before a call to userTransaction.begin(), or after a call to UserTransaction.commit or UserTransaction.rollback, is executed in an unspecified transaction context, as is any code executed in the four bean lifecycle callback methods listed in 13.6.5 (PostConstruct,PreDestroy, PostActivate, or PrePassivate). However this is not explicitly stated in the EJB spec.

So, what does the EJB spec say should happen in an "unspecified transaction context"?

Section 13.6.5 is written with all resource managers (not just JMS) in mind, and states that

"The EJB specification does not prescribe how the container should manage the execution of a method with an unspecified transaction context—the transaction semantics are left to the container implementation.

It goes on to give some options, which include treating "each call... to a resource manager as a single transaction", merging multiple calls into a single transaction, or accessing the resource manager "without a transaction context".

Now in the case of JMS the application has a way to give the container a hint as to what behaviour they desire: the arguments to {[createSession}}. So it would seem reasonable to follow these.

However the EJB 3.1 specification, section 13.3.5 does explicitly state that "The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container.

It is curious that although Session.acknowledge is prohibited in a unspecified transaction context, Session.commit is not, even though both perform message acknowledgement. If the former is invalid, then the latter must be as well.

This means that within an unspecified transaction context:

  • a non-transacted session using client acknowledgement is explicitly prohibited
  • a (local) transacted session is implicitly prohibited
  • a non-transacted session is permitted, with both client-acknowledgement and dups-ok-acknowledgement (which is an optimised version of auto-acknowledgement) allowed.

Summary

So in Connection.createSession (and QueueConnection.createQueueSession and TopicConnection.createTopicSession we have a method which offers different options depending on the context in which it is used:

  • In a Java EE transaction there are no options: the session is part of a transaction managed by the container and the application has no choice on the matter.
  • In a Java EE unspecified transaction context there are two options:
    • non-transacted session with auto-acknowledgement
    • non-transacted session with dups-ok-acknowledgement
  • In a Java SE environment there are four options:
    • non-transacted session with auto-acknowledgement
    • non-transacted session with dups-ok-acknowledgement
    • non-transacted session with client-acknowledgement
    • transacted session

So, in the light of all this, what are the problems?

  • the special behaviour of this method in a Java EE transaction is not mentioned anywhere in the JMS specification or in the javadocs, which means that users are surprised when they discover that the arguments to createSession are ignored. Fortunately, however, the required behaviour is clearly defined in the EJB specification.
  • the special behaviour in a Java EE unspecified transaction context is also not mentioned anywhere in the JMS specification or in the javadocs. Unfortunately, the required behaviour is not explicitly described in the EJB specification but has to be pieced together from various different sections, as in the analysis above. This needs to be confirmed and stated explicitly.
  • the actual API for createSession, with its two arguments, not only does not reflect the four options available in the normal Java SE case, it does not reflect the zero options available in the Java EE transaction case or the two options available in the Java EE unspecified transaction context case. However when compared the the two preceding issues this is perhaps not such a major issue.

Proposals

It is proposed that

  • The JMS specification and javadocs be updated to describe how createSession behaves in a Java EE applicaiton, both in a transaction and in an unspecified transaction context. The former case will be a restatement of the existing EJB spec, the latter case will be intended to remove any ambiguities in the EJB spec along the lines of the analysis above.
  • A new method be provided in a javax.jms.Connection
Session createSession(int sessionMode) throws JMSException

In a normal Java SE environment sessionMode may be set to 
Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE 
or Session.TRANSACTED

In a Java EE transaction, sessionMode is ignored.

In a Java EE undefined transaction context, sessionMode may be set to 
Session.AUTO_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE only.
  • A further new method be provided in a javax.jms.Connection
Session createSession() throws JMSException

This method is  particularly intended for use in a Java EE environment,
though it may also be used in a normal Java SE environment.

In a normal Java SE environmentm this is equivalent to calling createSession(Session.AUTO_ACKNOWLEDGE)

In a Java EE transaction, the session will be part of a transaction managed by the container. 

In a Java EE undefined transaction context, the session will have a sessionMode of Session.AUTO_ACKNOWLEDGE.
  • The existing method createSession(boolean transacted,int acknowledgeMode will remain with a note added to encourage applications to use the other two methods. In accordance with Java EE policy it will remain in the API indefinitely, and will not be formally marked as @Deprecated.


 Comments   
Comment by Nigel Deakin [ 23/Sep/11 ]

Description updated to propose new method Session createSession() with no arguments for use in a Java EE environment.

Comment by Nigel Deakin [ 30/Sep/11 ]

Updated to propose that the existing method createSession(boolean transacted,int acknowledgeMode will be formally marked as @Deprecated

Comment by Nigel Deakin [ 18/Oct/11 ]

Do we need a new method getSessionMode()?

There is already a method getAcknowledgeMode() which Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, Session.DUPS_OK_ACKNOWLEDGE or Session.TRANSACTED as appropriate. It therefore already returns the session mode though the name is misleading.

We have lived with this mis-named method for a long time so I don't think it is necessary to create a new method getSessionMode() which is functionally identical but more appropriately named. We could never remove the old method, so this would simply clutter up the API whilst confusing the user.

We should therefore stick with getAcknowledgeMode and change the javadoc documentation to clarify that what it returns is the same as the session mode.

Comment by Nigel Deakin [ 13/Jan/12 ]

Before we finalise the above proposals I'd like to explore in more detail exactly how createSession (and other methods in the JMS API) are required to behave in a Java EE environment. Before we can clarify the use of this method we need to be able to answer the following questions.

(I've already suggested answers to some, but not all, of these questions in my proposals above. However I think it's very important to get this right and it's work revisiting them. In addition, there are several additional issues which need to be answered before users can unambiguously know how this method is required to behave.)

1. JMS resources which do not support JTA transactions

In the EJB 3.1 specification, section 13.3.5 "use of JMS APIs in Transactions" states that:

Because the container manages the transactional enlistment of JMS sessions on behalf of a bean, the parameters of the createSession(boolean transacted, int acknowledgeMode) method createQueueSession... are ignored."

The reference to "transaction enlistment" appears to be a reference to JTA transactions managed by the application server, which may be "bean-managed" (using the UserTransaction API to begin and commit the transaction) or, for EJBs, "container-managed".

Q1.1: Does the sentence quoted above mean that the JMS session must participate in the transaction, or is it permitted to create a session which does not participate in the transaction.

There have been suggestions that connections which are "non-managed" or "non-JCA" connections are not required to participate in the transaction. However there is no mention of such cases in the EJB spec.

Q1.2: Is this permitted?

Q1.3: Are such cases also exempt from the requirement that the arguments to createSession be ignored?

2. When there isn't a container-managed or bean-managed transaction.

I'd also like to explore the case where there isn't a container-managed or bean-managed transaction. The EJB 3.1 Specification, section 13.6.5 "Handling of Methods that run with an unspecified transaction context" contains some guidance about the transaction semantics in such a case.

Q2.1: What is an "unspecified transaction context"? Does this mean any case where there is not an active JTA transaction, such as where the transaction attribute is set to "Never"? Does it include the BMT case before userTransaction.begin() or after userTransaction.commit()? Does it include all of the EJB callback methods?

3. The ban on calling acknowledge()

Section 13.3.5 of the EJB spec, "Use of JMS APIs in Transactions", states that "The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container."

Q3.1: What is the reason for this restriction? Is it necessary?

Q3.2: If acknowledge is called in a Java EE environment, what should happen? Should an exception be thrown?

Q3.3: Do these restrictions on explicit message acknowledgement also apply to local transactions, given that calling session.commit has the effect of acknowledging all messages received in the local transaction?

4. Bean-managed transactions

In a application that uses bean-managed transactions, what happens if the session is created before the transaction is started? Consider the following:

Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(destination);
producer.send(message1);
userTransaction.begin();
producer.send(message2);
. . .
userTransaction.commit();

Q4.1: Is this valid?

Q4.2: Is message1 sent immediately or is it committed as part of the user transaction?

Q4.3: Is message2 sent immediately or is it committed as part of the user transaction?

Comment by Nigel Deakin [ 24/Jan/12 ]

I've now updated the API, javadocs and the draft spec in accordance with the proposals made above.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

  • New methods Connection.createSession(int sessionMode) and Connection.createSession() which create a Session.
  • New javadoc comment for the existing method Connection.createSession(boolean transacted, int acknowledgeMode) which creates a Session.
  • New javadoc comments for the various methods on ConnectionFactory and MessagingContext which create a MessagingContext

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

  • Updated section 1.4.7 "Java Platform, Enterprise Edition (Java EE)"
  • Deleted section 1.4.8 "Integration of JMS with the EJB Components"
  • New chapter 12 "Use of JMS API in Java EE applications"
  • New section 12.2 "Use of JMS API in Java EE applications"
  • New sections 11.5.14 & 11.5.15 which are the change log for these changes

(I'll come back later and formally answer the questions I made in the previous comment)

Comment by Nigel Deakin [ 24/Jan/12 ]

I have updated the description above to remove the statement that the existing method createSession(boolean transacted,int acknowledgeMode will be marked as @Deprecated and that the javadocs will warn that this method may be removed in the future.

The Java EE Backwards Compatibility Requirements do not allow us to use @Deprecated, not do they allow us to remove existing methods from the API.

Instead the javadoc comment for this method will simply have a note which encourages applications to use the other two createSession methods instead.

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-44] New API to specify delivery delay Created: 08/Aug/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-166 Implement Delivery Delay Closed
blocks MQ-184 Topic subscription matching time/Queu... Closed
Tags: ed20-added

 Description   

This issue was raised by members of the JSR 343 Expert Group and is logged here to allow the issue to be discussed and tracked.

This is a proposal to allow a JMS client to specify a delivery delay when sending a message. If a delivery delay has been specified for a message then the message will not be delivered to any consumers until after the delivery delay has expired.

This feature has also been referred to as "delivery time", "timed messages" or "future messages".

The API for delivery delay is intended to be similar to that for the existing timeToLive property of a MessageProducer and the corresponding JMSExpiration header field of a Message.

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

 
public void setDeliveryDelay(long deliveryDelay) throws javax.jms.JMSException;

This sets the minimum length of time in milliseconds from its dispatch time 
that a produced message should be retained by the messaging system before 
delivery to a consumer. 

If the delivery delay is greater then the time to live then the message 
will always be expired before delivery.
public long getDeliveryDelay()

Returns the minimum length of time in milliseconds from its dispatch time 
that a produced message should be retained by the messaging system before delivery to a consumer. 

There would be new methods on javax.jms.Message:

public long getJMSDeliveryTime() throws JMSException

Returns the message's delivery time. 

When a message is sent, the JMSDeliveryTime header field is left unassigned. 
After completion of the send or publish method, it holds the minimum delivery time time 
of the message. This is the sum of the delivery delay value specified by the client and 
the GMT at the time of the send or publish. 

When the delivery delay is specified as zero, JMSDeliveryTime is set to zero to indicate
that there is no delivery delay.

A provider must not deliver a message before the defined delivery time has been reached.
public void setJMSDeliveryTime(long deliveryTime) throws JMSException

Sets the message's delivery time.

JMS providers set this field when a message is sent. 
This method can be used to change the value for a message that has been received. 

Note that this public method is not intended for use by clients but is needed to allow providers to set this value on a message implemented by a different provider. There is a separate issue to clarify this behaviour: JMS_SPEC-34



 Comments   
Comment by Nigel Deakin [ 19/Dec/11 ]

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

New methods on MessageProducer

    /** Sets the default minimum length of time in milliseconds from its dispatch time
     * before a produced message becomes visible on the target destination and available
     * for delivery to consumers.  
     *
     * <P>deliveryDelay is set to zero by default.
     *
     * @param deliveryDelay the delivery delay in milliseconds.
     *
     * @exception JMSException if the JMS provider fails to set the delivery
     *                         delay due to some internal error.
     *
     * @see javax.jms.MessageProducer#getDeliveryDelay
     * @see javax.jms.Message#DEFAULT_DELIVERY_DELAY
     * 
     * @since 2.0
     */
  
   void setDeliveryDelay(long deliveryDelay) throws JMSException;      
   
   /** Gets the default minimum length of time in milliseconds from its dispatch time
    * before a produced message becomes visible on the target destination and available
    * for delivery to consumers.  
    *
    * @return the delivery delay in milliseconds.
    *
    * @exception JMSException if the JMS provider fails to get the delivery 
    *                         delay due to some internal error.
    *
    * @see javax.jms.MessageProducer#setDeliveryDelay
    * 
    * @since 2.0
    */ 

  long getDeliveryDelay() throws JMSException;   

New methods on MessagingContext:

/** Sets the default minimum length of time in milliseconds from its dispatch time
 * before a produced message becomes visible on the target destination and available
 * for delivery to consumers.  
 *
 * <P>deliveryDelay is set to zero by default.
 *
 * @param deliveryDelay the delivery delay in milliseconds.
 *
 * @exception JMSRuntimeException if the JMS provider fails to set the delivery
 *                         delay due to some internal error.
 *
 * @see javax.jms.MessagingContext#getDeliveryDelay
 * @see javax.jms.Message#DEFAULT_DELIVERY_DELAY
 */

void setDeliveryDelay(long deliveryDelay);      

/** Gets the default minimum length of time in milliseconds from its dispatch time
* before a produced message becomes visible on the target destination and available
* for delivery to consumers.  
*
* @return the delivery delay in milliseconds.
*
* @exception JMSRuntimeException if the JMS provider fails to get the delivery 
*                         delay due to some internal error.
*
* @see javax.jms.MessagingContext#setDeliveryDelay
*/ 

long getDeliveryDelay();   

New methods on Message:

    /** Gets the message's delivery time value.
     *  
     * <P>When a message is sent, the <CODE>JMSDeliveryTime</CODE> header field 
     * is left unassigned. After completion of the <CODE>send</CODE> or 
     * <CODE>publish</CODE> method, it holds the delivery time of the
     * message. This is the sum of the deliveryDelay value specified by the
     * client and the GMT at the time of the <CODE>send</CODE> or 
     * <CODE>publish</CODE>.
     *
     * <P>A message's delivery time is the earliest time when a provider may
     * make the message visible on the target destination and available for
     * delivery to consumers. 
     *
     * <P>Clients must not receive messages before the delivery time has been reached.
     * 
     * @return the message's delivery time, which is the sum of the deliveryDelay 
     * value specified by the client and the GMT at the time of the <CODE>send</CODE> or 
     * <CODE>publish</CODE>.
     *  
     * @exception JMSException if the JMS provider fails to get the message 
     *                         expiration due to some internal error.
     *
     * @see javax.jms.Message#setJMSDeliveryTime(long)
     * 
     * @since 2.0
     */ 
   long getJMSDeliveryTime() throws JMSException;


   /** Sets the message's delivery time value.
     *
     * <P>This method is for use by JMS providers only to set this field 
     * when a message is sent. This message cannot be used by clients 
     * to configure the delivery time of the message. This method is public
     * to allow one JMS provider to set this field when sending a message
     * whose implementation is not its own.
     *  
     * @param expiration the message's delivery time value
     *  
     * @exception JMSException if the JMS provider fails to set the delivery 
     *                         time due to some internal error.
     *
     * @see javax.jms.Message#getJMSDeliveryTime() 
     * 
     * @since 2.0
     */ 
   void setJMSDeliveryTime(long deliveryTime) throws JMSException;    

A new static constant on Message:

    /** The message producer's default delivery delay is zero.
     * @since 2.0
     */
    static final long DEFAULT_DELIVERY_DELAY = 0;  
Comment by Nigel Deakin [ 19/Dec/11 ]

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 two new methods and a static constant on Message.

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. The changes for this issue are as follows:

A new section 3.4.13 "JMSDeliveryTime" which states:

When a message is sent, its delivery time is calculated as the sum of the delivery delay value specified on the send method and the current GMT value. On return from the send method, the message’s JMSDeliveryTime header field contains this value. When a message is received its JMSDeliveryTime header field contains this same value.

A message's delivery time is the earliest time when a provider may make the message visible on the target destination and available for delivery to consumers.

Clients must not receive messages before the delivery time has been reached.

A new section 4.13 "Delivery delay" which states:

A client can specify a delivery delay value in milliseconds for each message it sends. This value defines a message delivery time which is the sum of the message’s delivery delay and the GMT it is sent (for transacted sends, this is the time the client sends the message, not the time the transaction is committed).

A message's delivery time is the earliest time when a JMS provider may make the message visible on the target destination and available for delivery to consumers. The provider must not deliver messages before the delivery time has been reached.

For more information on message delivery delay, see Section 3.4.13 "JMSDeliveryTime".

Section 4.4.10.2 "Order of message sends" has been updated to state that messages with a later delivery time may be delivered after messages with an earlier delivery time.

Section 4.4.11 "Message Acknowledgement" has been updated to state that when a session's recover method is called the messages it now delivers may be different from those that were originally delivered due to the delivery of messages which could not previously be delivered as they had not reached their specified delivery time.

Section 4.6 "Message Producer" has been updated to mention that a client may now define a default delivery delay for messages sent by a producer.

Section 11.5.4 "Delivery delay" is the change log for this feature.

A deliberate decision was made to leave section 3.4.12 "Overriding message header fields" unchanged. This means that the spec will not permit an administrator to configure JMS to override the client specified values for JMSDeliveryTime.

Comment by Nigel Deakin [ 21/Sep/12 ]

Further updates have been made. For an up-to-date description of this feature, see section 4.12 "Delivery delay" of the JMS 2.0 public draft.

Just one issue remains: this is described in section A.3.1 in the JMS 2.0 early draft.





[JMS_SPEC-43] New API to send a message with async acknowledgement from server Created: 05/Aug/11  Updated: 26/Nov/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-174 Implement new API to send a message w... Closed
Duplicate
is duplicated by JMS_SPEC-12 Message producer confirms aka async m... Resolved
Tags: ed20-added

 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);
}



 Comments   
Comment by timlfox [ 05/Aug/11 ]

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

Comment by Nigel Deakin [ 05/Aug/11 ]

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

Comment by Nigel Deakin [ 20/Sep/11 ]

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);
}

Comment by Hiram Chirino [ 13/Dec/11 ]

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

Comment by Hiram Chirino [ 13/Dec/11 ]

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.

Comment by Hiram Chirino [ 13/Dec/11 ]

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.

Comment by julienrenaut [ 14/Dec/11 ]

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.

Comment by Nigel Deakin [ 15/Dec/11 ]

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);	
Comment by Nigel Deakin [ 15/Dec/11 ]

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)

Comment by Nigel Deakin [ 18/Jul/12 ]

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.

Comment by Nigel Deakin [ 21/Sep/12 ]

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.





[JMS_SPEC-42] Make support for JMSXDeliveryCount mandatory Created: 05/Aug/11  Updated: 02/Nov/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-173 Implement JMSXDeliveryCount Closed
blocks MQ-236 Broker support JMS2.0 mandatory JMSXD... Closed
Tags: ed20-added

 Description   

This issue was raised by a member of the JSR 343 Expert Group and is logged here to allow the issue to be discussed and tracked.

It is proposed that support for the JMS defined message property JMSXDeliveryCount be made mandatory.

The JMS 1.1 specification currently defines an optional JMS defined message property JMSXDeliveryCount. When used, this is set by the JMS provider when a message is received, and is set to the number of times this message has been delivered (including the first time). The first time is 1, the second time 2, etc.

Support for this property would allow arbitrary containers and applications to improve the way they handle "poisonous" messages - messages which cannot be consumed for some reason and need to be redelivered. For example, it would allow applications to detect when a message has been redelivered more than a specified number of times and perform some special handling such as redirecting it to some other destination.

This property wouldn't need to be perfectly accurate every time. For example, it wouldn't be necessary to persist this value in the server. A "best efforts" implementation would probably be adequately.



 Comments   
Comment by Nigel Deakin [ 20/Dec/11 ]

I've now updated the javadocs and the draft spec with this change (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

The only change is to Message. This wording is very generic and doesn't mention individual properties. All I've done is to mention that some properties may be mandatory, some may be optional. I've also added a clarification to state that the effect of setting a message selector on a property (such as JMSXDeliveryCount) which is set by the provider on receive is undefined.

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. The changes for this issue are as follows:

Section 3.5.9 "JMS Defined Properties" has been updated to state that the property JMSXDeliveryCount is now mandatory with a reference to 3.5.11 "JMSXDeliveryCount" for a definition.

Some of the wording in this section has been rearranged to reflect the fact that some properties are optional but that one (JMSXDeliveryCount) is now mandatory. A clarification has been added to state that the effect of setting a message selector on a property (such as JMSXDeliveryCount) which is set by the provider on receive is undefined.

Section 3.4.7 "JMSRedelivered" has been updated to say "The JMS-defined message property JMSXDeliveryCount will be set to the number of times a particular message has been delivered. See section 3.5.11 "JMSXDeliveryCount".

A new section 3.5.11 "JMSXDeliveryCount" has been added. This states:

When a client receives a message the mandatory JMS-defined message property JMSXDeliveryCount will be set to the number of times the message has been delivered. The first time a message is received it will be set to 1, so a value of 2 or more means the message has been redelivered.

If the JMSRedelivered value is set then the {{JMSXDeliveryCount}}property must always be 2 or more.

The purpose of the JMSXDeliveryCount property is to allow consuming applications to identify whether a particular message is being repeatedly redelivered and take appropriate action.

The value of the JMSXDeliveryCount property is not guaranteed to be exactly correct. The JMS provider is not expected to persist this value to ensure that its value is not lost in the event of a failure.

4.4.11 Message Acknowledgement: The sentence "a session must set the JMSRedelivered flag of messages it redelivers due to a recovery" has been amended to state that it should also increment the JMSXDeliveryCount property as well.

4.4.12 "Duplicate Delivery of Messages": The sentence "The JMSRedelivered message header field will be set for a message redelivered under these circumstances" has been amended to the JMSXDeliveryCount property should be incremented as well.

4.5.2 "Asynchronous delivery": This states that if a message listener throws an exception in AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE mode the message will be immediately redelivered and the JMSRedelivered message header field will be set. This has been amended to state that the JMSXDeliveryCount message property will be incremented as well.

4.10. "Reliability": This states "Unacknowledged messages redelivered due to system failure must have the JMSRedelivered message header field set by the JMS provider.". This has been amended to state "Unacknowledged messages redelivered due to system failure must have the JMSRedelivered message header field set, and the JMSXDeliveryCount incremented, by the JMS provider, as described in sections 3.4.7 "JMSRedelivered" and 3.5.11 "JMSXDeliveryCount"

11.5.6 "JMSXDeliveryCount" is the change log for this change.





[JMS_SPEC-53] Make Connection and other interfaces implement AutoCloseable Created: 29/Sep/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-169 Make Connection and other interfaces ... Closed
Tags: ed20-added

 Description   

This is a proposal to change all the JMS interfaces that currently implement a close() method to implement the java.lang.AutoCloseable interface?

This would affect Connection, Session, MessageConsumer, MessageProducer, QueueBrowser.

This is a new feature of Java SE 7 which makes it easier to write code which closes a resource after use.

There's a nice explanation here:
http://www.javacodegeeks.com/2011/07/java-7-try-with-resources-explained.html]

Briefly, it allows you to write code such as:

try { 
   Connection conn = connectionFactory.createConnection();
   Session sess = conn.createSession(false,Session.AUTO_ACKNOWLEDGE;
   MessageProducer producer = seession.createProducer(dest);
}{
   Message mess = sess.createTextMessage("hello");
   producer.send(mess);
} catch(JMSException e){
  // exception handling
}

When this code is executed, the close() methods on the connection, session and producer are always called after use.

  • There's no need to call close() on any of the objects that are created.
  • There's no need to provide a finally block containing the calls to close().
  • Objects are closed in the reverse order in which they were created.
  • There's no need to guard against calling close() on a null value.
  • There's no need to use a nested try/catch block within the finally block to catch exceptions thrown by close()
  • If the try() block throws an exception, and a subsequent call to close() throws a second exception as a consequence, then it is the first exception, not the second exception, that is passed to the catch block. So you only see the exception that really matters. Any suppressed exceptions can still be accessed from the thrown exception if needed.

This change would be of benefit to both Java SE and Java EE applications. The only drawback I can think of is that it would introduce a dependency on Java SE 7. This isn't an issue for Java EE 7 applications since these are already dependent on Java SE 7. But it would force Java SE applications to use Java SE 7. However by the time JMS 2.0 is released, in a year from now, Java 7 will be pretty widespread so this might not be a problem.



 Comments   
Comment by Nigel Deakin [ 16/Dec/11 ]

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
(One-line changes to Connection, Session, MessageProducer, MessageConsumer and QueueBrowser)

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 4.3.5 "Closing a Connection", 4.4.1 "Closing a Session", the example in section 9.1.3. Creating a Connection", and, in the changelog, section 11.5.3 "Automatically closing a connection or session")

I've now made Connection, Session, MessageProducer, MessageConsumer and QueueBrowser all extend AutoCloseable. (Note that MessagingContext, part of the proposed simplified API, already extends AutoCloseable)

(This updates the previous version of this comment which only referred to changes to Connection).

Comment by Nigel Deakin [ 05/Feb/12 ]

I've also changed javax.jms.SyncMessageConsumer to extend AutoCloseable, for consistency with MessageConsumer. API and javadocs updated.





[JMS_SPEC-52] Clarify that a message may be sent using a different session from that used to create the message Created: 21/Sep/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-170 Implement clarified behaviour of meth... Open
Tags: ed20-added

 Description   

The JMS 1.1 API defines how a JMS message object is created using one of the following methods on a Session:

Message 	createMessage() 
BytesMessage 	createBytesMessage() 
MapMessage 	createMapMessage() 
ObjectMessage 	createObjectMessage() 
ObjectMessage 	createObjectMessage(java.io.Serializable object) 
StreamMessage 	createStreamMessage() 
TextMessage 	createTextMessage() 
TextMessage 	createTextMessage(java.lang.String text) 

The following question has been raised:

Can a message be sent using a MessageProducer that was created from a different Session than was used to create the message?

This is not stated explicitly in the specification, and discussions within the JSR 343 Expert group show that different individuals have come to different conclusions on this issue.

My own interpretation is that a MessageProducer must be able to send a javax.JMS.Message irrespective of how it was created. It might have been created using Session.createMessage(), or it may have been received by a MessageConsumer.

Section 4.4.5 "Optimized message implementations" of the JMS 1.1 specification states:

A session provides message create methods that use provider-optimized implementations. This allows a provider to minimize its overhead for handling messages.
Sessions must be capable of sending all JMS messages regardless of how they may be implemented.

Furthermore, Section 3.12 of the JMS 1.1 specification states explicitly that a MessageProducer must be able to send a message that was created using a different JMS provider, and which would therefore have used a different session:

A provider must be prepared to accept, from a client, a message whose implementation is not one of its own. A message with a 'foreign' implementation may not be handled as efficiently as a provider's own implementation; however, it must be handled.

Despite this, there is a widespread view within the JMS community that for messages created within the same JVM by the same JMS provider, the session used to create the message must be the same as that used to send it.

It is therefore proposed that the JMS specification be clarified that there is no such restriction, and that a MessageProducer can be used to send any message object

  • irrespective of which session or connection was used to create it,
  • irrespective of whether the message was created within this JVM or received from a JMS destination, and
  • irrespective of whether the MessageProducer and message are implemented by the same or different JMS providers.


 Comments   
Comment by Nigel Deakin [ 22/Sep/11 ]

Edited description to clarify that a MessageProducer can be used to send any message object
irrespective of what connection (as well as session) was used to create it.

Comment by Nigel Deakin [ 19/Dec/11 ]

I've now updated the javadocs and the draft spec to clarify this issue (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

The six message-creation methods on Session have been modified to include the following additional javadoc comments:

* The message object returned may be sent using any session or messaging context. 
* It is not restricted to being sent using the session used to create it.
* <p>
* The message object returned may be optimised for use with the JMS provider
* used to create it. However it can be sent using any JMS provider, not just the 
* JMS provider used to create it.

The second sentence above has been included because it would be confusing and inconsistent to mention that a message may be sent using a different session and not also mention the even more significant fact that a message may be sent using a different JMS provider.

The six message-creation methods on the proposed new MessagingContext interface have been modified to include the following additional javadoc comments:

* The message object returned may be sent using any session or messaging context. 
* It is not restricted to being sent using the messaging context used to create it.
* <p>
* The message object returned may be optimised for use with the JMS provider
* used to create it. However it can be sent using any JMS provider, not just the 
* JMS provider used to create it.

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. The changes for this issue are as follows:

Section 4.4.5. "Optimized Message Implementations" has been updated to state:

A session provides the following methods to create messages: createMessage, createBytesMessage, createMapMessage, createObjectMessage, createStreamMessage and createTextMessage.

These methods allow the JMS provider to create message implementations which are optimized for that particular provider and allow the provider to minimize its overhead for handling messages.

A session provides message create methods that use provider-optimized implementations. This allows a provider to minimize its overhead for handling messagesHowever .the fact that these methods are provided on a session does not mean that messages must be sent using a message producer created from the same session. Messages may be sent using any session, not just the session used to create the message.

Furthermore, Sessions must be capable of sending all JMS messages regardless of how they may be implemented. See section 3.12 "Provider Implementations of JMS Message Interfaces".

Section 11.5.5 "Clarification: message may be sent using any session" is the change log for this clarification.





[JMS_SPEC-39] Make clientId optional when creating a durable subscription Created: 05/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: ed20-added

 Description   

(There was a change of mind on this issue. Initially this feature was added for both JMS 1.1 unshared subscriptions as well as JMS 2.0 shared subscriptions but we changed our mind and in the end it was added for JMS 2.0 shared subscriptions only. This note was added retrospectively to make this issue easier to understand when reading it.)

This is a proposal to make clientId optional when creating a durable subscription

In JMS 1.1, a durable subscription is defined by the combination of clientId and subscriptionName. Section 6.11.1 of the Specification states:

Sessions with durable subscribers must always provide the same client
identifier. In addition, each client must specify a name that uniquely identifies
(within client identifier) each durable subscription it creates.

Whilst it is clear that a durable subscription needs to have a name to allow it to be identified, it is less clear why it needs to be identified by clientId. This is the only place in the JMS API where a connection must have clientId set.

This requirement to have clientId set causes complication for applications, especially in a Java EE application, where clientId must be set on the connection factory. This means that the connection factory can only be used to create a single instance, and if a connection pool is used it must be constrained to allow only a single instance.

It is therefore proposed that the use of clientId be made optional when creating a durable subscription. In this case, the subscription will be defined by the name of the subscription alone.

This change is not intended to change the existing restrictions stated in Section 6.11.1:

Only one session at a time can have a TopicSubscriber for a particular durable subscription.



 Comments   
Comment by timlfox [ 05/Aug/11 ]

I don't understand how client id can be optional. The unique id of a durable subscription is effectively defined by a tuple (client_id, subscription_name).

This means there can be many different durable subscriptions with the same value of subscription_name but different values of client_id.

Client id normally maps to some kind of notion of user, so this allows each user to maintain their own namespace within which they don't have to worry about naming of durable subscriptions.

Removing client id would mean there is effectively one "global" namespace of durable subscriptions. This is not desirable IMHO.

Comment by Nigel Deakin [ 05/Aug/11 ]

If clientID was set then it would still be used (to maintain backwards compatibility). However this change would allow a durable subscription to be created for which its identifying "tuple" was (null,subscription_name).

Comment by Nigel Deakin [ 21/Dec/11 ]

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The only changes are to comments, not to the API. The updated comments as follows:

On the Session interface the javadocs for the two createDurableSubscriber methods and the unsubscribe method have been rewritten as follows:

    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>TopicSubscriber</code>
     * on that durable subscription.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no <code>TopicSubscriber</code> associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a <code>TopicSubscriber</code> on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A durable subscription which has a <code>TopicSubscriber</code>
     * associated with it is described as being active.
     * A durable subscription which has no <code>TopicSubscriber</code>
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * <CODE>TopicSubscriber</CODE> for a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     *
     * @exception JMSException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationException if an invalid topic is specified.
     *
     * @since 2.0
     */
    TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException;
    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>TopicSubscriber</code>
     * on that durable subscription, specifying a message
     * selector and whether messages published by its
     * own connection should be delivered to it.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no <code>TopicSubscriber</code> associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a <code>TopicSubscriber</code> on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A durable subscription which has a <code>TopicSubscriber</code>
     * associated with it is described as being active.
     * A durable subscription which has no <code>TopicSubscriber</code>
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * <CODE>TopicSubscriber</CODE> for a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     * @param messageSelector only messages with properties matching the
     * message selector expression are delivered. A value of null or
     * an empty string indicates that there is no message selector
     * for the message consumer.
     * @param noLocal if set, inhibits the delivery of messages published
     * by its own connection
     *
     * @exception JMSException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationException if an invalid topic is specified.
     * @exception InvalidSelectorException if the message selector is invalid.
     *
     * @since 2.0
     */
     TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;
    /** Unsubscribes a durable subscription that has been created by a client.
      *
      * <P>This method deletes the state being maintained on behalf of the
      * subscriber by its provider.
      * <p>
      * A durable subscription is identified by a name specified by the client
      * and by the client identifier if set. If the client identifier was set
      * when the durable subscription was created then a client which
      * subsequently wishes to use this method to
      * delete a durable subscription must use the same client identifier.
      *
      * <P>It is erroneous for a client to delete a durable subscription
      * while there is an active <CODE>MessageConsumer</CODE>
      * or <CODE>TopicSubscriber</CODE> for the
      * subscription, or while a consumed message is part of a pending
      * transaction or has not been acknowledged in the session.
      *
      * @param name the name used to identify this subscription
      *
      * @exception JMSException if the session fails to unsubscribe to the
      * durable subscription due to some internal error.
      * @exception InvalidDestinationException if an invalid subscription name
      * is specified.
      *
      * @since 1.1
      */
    void unsubscribe(String name) throws JMSException;
Comment by Nigel Deakin [ 21/Dec/11 ]

On the proposed MessagingContext interface the javadocs for the two createSyncDurableSubscriber methods, the two setMessageListener methods used to create durable subscriptions, the two setBatchMessageListener methods used to create durable subscriptions and the unsubscribe method have been rewritten as follows:

    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>SyncMessageConsumer</code>
     * on that durable subscription.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>SyncMessageConsumer</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>SyncMessageConsumer</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createSyncDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     *
     * @exception JMSRuntimeException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid topic is specified.
     *
     */
    SyncMessageConsumer createSyncDurableSubscriber(Topic topic, String name);
    /** Creates a durable subscription with the specified name on the
     * specified topic, and creates a <code>SyncMessageConsumer</code>
     * on that durable subscription, specifying a message selector and
     * whether messages published by its own connection should be delivered to it.
     * <P>
     * If the durable subscription already exists then this method
     * creates a <code>SyncMessageConsumer</code> on the existing durable
     * subscription.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a <code>SyncMessageConsumer</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createSyncDurableSubscriber</code>
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     *
     * @param topic the non-temporary <CODE>Topic</CODE> to subscribe to
     * @param name the name used to identify this subscription
     * @param messageSelector only messages with properties matching the
     * message selector expression are delivered. A value of null or
     * an empty string indicates that there is no message selector
     * for the message consumer.
     * @param noLocal if set, inhibits the delivery of messages published
     * by its own connection
     *
     * @exception JMSRuntimeException if the session fails to create a subscriber
     * due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid topic is specified.
     * @exception InvalidSelectorRuntimeException if the message selector is invalid.
     *
     */
    SyncMessageConsumer createSyncDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param listener - The listener to which the messages are to be delivered
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     */
void setMessageListener (Topic topic, String subscriptionName, MessageListener listener);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>,
     * specifying a message selector and whether messages published by its
     * own connection should be delivered to it.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param messageSelector - Only messages with properties matching the message selector
     * expression are delivered. A value of null or an empty string
     * indicates that there is no message selector for the message
     * consumer.
     * @param NoLocal - If true, inhibit* subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param messageSelector - Only messages with properties matching the message selector
     * expression are delivered. A value of null or an empty string
     * indicates that there is no message selector for the message
     * consumer.
     * @param NoLocal - If true, inhibits the delivery of messages published by its own connection.
     * @param listener - The listener to which the messages are to be delivered
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     * @throws InvalidSelectorRuntimeException - If the message selector is invalid.
     */
    void setMessageListener(Topic topic, String subscriptionName, String messageSelector, boolean NoLocal, MessageListener listener);
   /**
     * Creates a durable subscription with the specified name on the specified topic,
     * and creates a consumer on that durable subscription
     * that will deliver messages in batches to the specified <code>BatchMessageListener</code>
     * with the specified maximum batch size and timeout.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     * <p>
     * Messages will be delivered to the specified <code>BatchMessageListener</code>
     * in batches whose size is no greater than the specified maximum batch size.
     * The JMS provider may defer message
     * delivery until the specified batch timeout has expired in order to
     * assemble a batch of messages that is as large as possible but no greater
     * than the batch size.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param listener - The listener to which the messages are to be delivered
     * @param maxBatchSize - The maximum batch size that should be used. Must be greater than zero.
     * @param batchTimeout - The batch timeout in milliseconds. A value of zero means no
     * timeout is required The JMS provider may override the
     * specified timeout with a shorter value.
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     */
    void setBatchMessageListener(Topic topic, String subscriptionName, BatchMessageListener listener, int maxBatchSize, long batchTimeout);
    /**
     * Creates a durable subscription with the specified name on the specified topic,
     * using the specified message message selector,
     * and creates a consumer on that durable subscription
     * that will deliver messages in batches to the specified <code>BatchMessageListener</code>
     * with the specified maximum batch size and timeout.
     * This method can specify whether messages published by its own connection
     * should be delivered to the specified listener.
     * <p>
     * If the durable subscription already exists then this method creates a consumer on the existing durable subscription
     * that will deliver messages to the specified <code>MessageListener</code>.
     * <p>
     * A durable subscription is used by a client which needs to receive
     * all the messages published on a topic, including the ones published
     * when there is no active consumer associated with it.
     * The JMS provider retains a record of this durable subscription
     * and ensures that all messages from the topic's publishers are retained
     * until they are delivered to, and acknowledged by,
     * a consumer on this durable subscription
     * or until they have expired.
     * <p>
     * A durable subscription will continue to accumulate messages
     * until it is deleted using the <code>unsubscribe</code> method.
     * <p>
     * A consumer may be created on a durable subscription using the
     * <code>createSyncDurableSubscriber</code> methods on <code>MessagingContext</code>,
     * the appropriate <code>setMessageListener</code> methods on <code>MessagingContext</code>
     * or the <code>createDurableSubscriber</code> methods on <code>Session</code> or <code>TopicSession</code>
     * A durable subscription which has a consumer
     * associated with it is described as being active.
     * A durable subscription which has no consumer
     * associated with it is described as being inactive.
     * <p>
     * Only one session or messaging context at a time can have a
     * active consumer on a particular durable subscription.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which
     * subsequently wishes to create a consumer
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * this or any of the other methods listed above
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector.
     * Changing a durable subscriber is equivalent to
     * unsubscribing (deleting) the old one and creating a new one.
     * <p>
     * Messages will be delivered to the specified <code>BatchMessageListener</code>
     * in batches whose size is no greater than the specified maximum batch size.
     * The JMS provider may defer message
     * delivery until the specified batch timeout has expired in order to
     * assemble a batch of messages that is as large as possible but no greater
     * than the batch size.
     * <p>
     * If the specified listener is null then this method does nothing.
     *
     * @param topic - The topic from which messages are to be consumed
     * @param subscriptionName - The name used to identify the durable subscription
     * @param messageSelector - Only messages with properties matching the message selector
     * expression are delivered. A value of null or an empty string
     * indicates that there is no message selector for the message
     * consumer.
     * @param NoLocal - If true, inhibits the delivery of messages published by its own connection.
     * @param listener - The listener to which the messages are to be delivered
     * @param maxBatchSize - The maximum batch size that should be used. Must be greater than zero.
     * @param batchTimeout - The batch timeout in milliseconds. A value of zero means no
     * timeout is required The JMS provider may override the
     * specified timeout with a shorter value.
     * @throws JMSRuntimeException - If the operation fails due to some internal error.
     * @throws InvalidDestinationRuntimeException - If an invalid topic is specified.
     * @throws InvalidSelectorRuntimeException - If the message selector is invalid.
     */
    void setBatchMessageListener(Topic topic, String subscriptionName, String messageSelector, boolean NoLocal,
BatchMessageListener listener, int maxBatchSize, long batchTimeout);
    /** Unsubscribes a durable subscription that has been created by a client.
     *
     * <P>This method deletes the state being maintained on behalf of the
     * subscriber by its provider.
     * <p>
     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was created then a client which
     * subsequently wishes to use this method to
     * delete a durable subscription must use the same client identifier.
     *
     * <P>It is erroneous for a client to delete a durable subscription
     * while there is an active consumer on that subscription,
     * or while a consumed message is part of a pending
     * transaction or has not been acknowledged in the session.
     * <P>
     * If the active consumer is represented by a <CODE>SyncMessageConsumer</CODE> then calling
     * <CODE>close</CODE> on either that object or the <CODE>MessagingContext</CODE> used to create it
     * will render the consumer inactive and allow the subscription to be deleted.
     * <P>
     * If the active consumer was created by calling <code>setMessageListener</code> on the <CODE>MessagingContext</CODE>
     * then calling <CODE>close</CODE> on the <CODE>MessagingContext</CODE>
     * will render the consumer inactive and allow the subscription to be deleted.
     * <p>
     * If the active consumer is represented by a <code>MessageConsumer</code> or <code>TopicSubscriber</code> then calling
     * <code>close</code> on that object or on the <code>Session</code> or <code>Connection</code> used to create it
     * will render the consumer inactive and allow the subscription to be deleted.
     *
     * @param name the name used to identify this subscription
     *
     * @exception JMSRuntimeException if the session fails to unsubscribe to the
     * durable subscription due to some internal error.
     * @exception InvalidDestinationRuntimeException if an invalid subscription name
     * is specified.
     */
    void unsubscribe(String name);
Comment by Nigel Deakin [ 21/Dec/11 ]

The updated draft spec is here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf
All changes are hightlighted. The changes made for this issue are as follows:

In JMS 2.0 it is no longer mandatory for the client identifier to be set when creating or activating a durable subscription. The following changes have been updated to reflect this change:

Section 4.3.2 "Client Identifier" has been changed to state that its use in identifying a durable subscription is optional.

Section 6.3 "Durable Subscription" has been amended by adding a cross-reference to Section 6.11.1 "Durable TopicSubscriber" at the end.

Section 6.11.1 "Durable TopicSubscriber" has been completely rewritten. This section was essentially a copy of the javadoc comment on the createDurableSubscriber methods and since those javadoc comments have been rewritten to make them clearer this section has been rewritten as well.

The only substantive change is to state that the use of client identifier in identifying a durable subscription is optional. Cross-references to Section 6.3 "Durable Subscription" and Section 4.3.2 "Client Identifier" have been added at the end.

Section 11.5.7. Durable subscriptions has been added, which is a change log.

Comment by Nigel Deakin [ 18/Jan/12 ]

Additional changes have been made to the javadoc comments for the following methods to clarify the case where the durable subscription already exists:

  • Session.createDurableSubscriber (2 methods)
  • Session.createDurableConsumer (2 methods, added for JMS_SPEC-51)
  • MessagingContext.createSyncDurableConsumer (2 methods)
  • MessagingContext.setMessageListener (only the 2 methods for durable subscriptions)
  • MessagingContext.setBatchMessageListener (only the 2 methods for durable subscriptions

Here's an example for Session.createDurableSubscriber:

This is the old comment:

     * If the durable subscription already exists then this method
     * creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.

This is the new comment:

     * If a durable subscription already exists with the same name 
     * and client identifier (if set) and the same topic and message selector 
     * then this method creates a <code>TopicSubscriber</code> on the existing durable
     * subscription.

Note that the javadoc comment for these methods already states the following:

     * A durable subscription is identified by a name specified by the client
     * and by the client identifier if set. If the client identifier was set
     * when the durable subscription was first created then a client which 
     * subsequently wishes to create a <code>TopicSunscriber</code>
     * on that durable subscription must use the same client identifier.
     * <p>
     * A client can change an existing durable subscription by calling
     * <code>createDurableSubscriber</code> 
     * with the same name and client identifier (if used),
     * and a new topic and/or message selector. 
     * Changing a durable subscriber is equivalent to 
     * unsubscribing (deleting) the old one and creating a new one.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

Comment by Nigel Deakin [ 26/Nov/12 ]

It has now been decided that changing the Session method createDurableSubscriber to make clientId optional for durable subscriptions breaks the http://java.net/projects/javaee-spec/pages/CompatibilityRequirements Backwards Compatibility Requirements for Java EE Specifications.

It will therefore remain mandatory to set clientId when creating a non-shared durable subscription using the following existing or new methods:

Methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) (JMS 1.1)
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 1.1)
  • MessageConsumer createDurableConsumer(Topic topic, String name) (JMS 2.0)
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 2.0)

Methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name)
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will only allow a single consumer on a durable subscription
  • clientId MUST be set

However setting clientId will be optional when creating a shared durable subscriptions using any of the following new methods:

Methods on Session:

  • MessageConsumer createSharedDurableConsumer(Topic topic, String name)
  • MessageConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

Methods on JMSContext:

  • JMSConsumer createSharedDurableConsumer(Topic topic, String name)
  • JMSConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will allow multiple consumers on a durable subscription
  • clientId may or may not be set
Comment by Nigel Deakin [ 20/Mar/13 ]

Marking this issue as "resolved", with a resolution of "Won't fix"





[JMS_SPEC-40] Allow multiple consumers to be created on the same topic subscription Created: 05/Aug/11  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-93 Does changing the noLocal flag when c... Resolved
blocks MQ-175 support optional clientId when creati... Closed
blocks MQ-178 Implement new API to allow multiple c... Closed
blocks MQ-229 Implementing noLocal behavior for sha... Closed
Duplicate
is duplicated by JMS_SPEC-23 Allow and specify clustered durable s... Closed
Tags: pd20-added

 Description   

This proposal would allow multiple message consumers to be used to consume messages from the same durable or non-durable topic subscription. This would increase scalability by allowing messages from a topic to be processed by multiple consumers in a Java SE environment. Note that the existing JMS 1.1 API already allows this to be achieved for messages from a queue.

The multiple consumers might be in the same or different JVMs. Within the same JVM, the multiple consumers might use the same or different sessions and connection. Note, however, that the normal restrictions on the use of a session by multiple threads would continue to apply.

Durable subscriptions

For durable subscriptions, there would be no need to change the existing API. Applications would simply be allowed to create multiple consumers on the same durable subscription:

This affects the following JMS existing JMS 2.1 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession):

createDurableSubscriber(Topic topic, String name)
createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) 

It also affects the following JMS new JMS 2.0 methods on Session (and its subtypes QueueSession, TopicSession, XASession, XAQueueSession and XATopicSession) (added in JIRA issue 51 ):

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

And in the new JMS 2.0 simplified API, it also affects the following method on JMSContext:

createDurableConsumer(Topic topic, String name)
createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

All these methods currently have a restriction "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". This restriction would be removed.

No change is proposed to the existing JMS requirement that only one connection may have a given clientID. This is defined in JMS 1.1 Section 4.4.3.2 "Client identifier", which states:

By definition, the client state identified by a client identifier can be 'in use' by only one client at a time. A JMS provider must prevent concurrently executing clients from using it.

This means that if a durable subscription is created by a connection with clientId set then it will not be possible to create a second consumer on it using a different connection.

However in JMS 2.0, clientId will become optional when creating a durable subscription (see JIRA issue 39). If a durable subscription is created by a connection with clientId unset then other connections may freely create further consumers on the same durable subscription.

This means that for two message consumers on different connections to share a durable subscription, clientId would need to be left unset.

In addition, the effect of using a different topic or message selector than was used when the subscription was first created needs to be amended. Currently this states (from the javadoc for Session.createDurableSubscriber):

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.

This behaviour will continue, but only if there are no other active consumers on the durable subscription. If there is an active consumer on the durable subscription, and an attempt is made to create an additional consumer with a different topic or message selector, then a JMSException will be thrown (in the case of JMSContext a JMSRuntimeException will be thrown).

The semantics for the unsubscribe methods on Session and JMSContext would remain unchanged. The javadocs state that "It is erroneous for a client to delete a durable subscription while there is an active MessageConsumer or TopicSubscriber for the subscription". This will continue to be the case.

Non-durable subscriptions

For non-durable subscriptions, the JMS 1.1 specification specifies that if two non-durable TopicSubscribers are created on the same topic then two independent subscriptions are created: a copy of each message is sent to every consumer on that topic (with an appropriate message selector).

To allow two consumers to share the same subscription, so that they can share the load of processing messages from that subscription, then new API is required. To allow the consumers to specify that they wish to use the same non-durable subscription, they will need to specify the same sharedSubscriptionName.

The following new methods on Session (and its subtypes) are proposed:

MessageConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName);
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector)
MessageConsumer createSharedConsumer(
   Destination destination, String sharedSubscriptionName, String messageSelector, boolean NoLocal)

Note that if these methods were called simply createConsumer there would be a clash with the existing method createConsumer(Destination destination, String messageSelector). Note that these methods take a Topic, not a Destination.

In the new simplified API, the following new methods on JMSContext are proposed:

JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector)
JMSConsumer createSharedConsumer(
   Topic topic, String sharedSubscriptionName, String messageSelector, boolean noLocal)

Note that a given shared subscription does not exist if there are no consumers using it.



 Comments   
Comment by Nigel Deakin [ 19/Aug/11 ]

It should be noted that the JMS 1.1 specification currently states that this feature is not currently available.

4.4.15 Concurrent Message Delivery

...

Note that JMS itself does not provide the facilities for concurrently processing a topic’s message set (the messages delivered to a single consumer). A client could use a single consumer and implement all the multithreading logic needed to concurrently process the messages; however, it is not possible to do
this reliably, because JMS does not have the transaction facilities needed to handle the concurrent transactions this would require.

Comment by Nigel Deakin [ 30/Mar/12 ]

Description completely updated.

Comment by Nigel Deakin [ 30/Mar/12 ]

Added a dependency on JMS_SPEC-93, which concerns the effect of changing noLocal when activating a durable subscription.

Comment by Nigel Deakin [ 10/Apr/12 ]

Added clarification that the semantics of the unsubscribe methods on Session and JMSContext would remain unchanged.

Comment by Nigel Deakin [ 13/Apr/12 ]

Javadoc and spec updates (for durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

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

Changes to Javadocs

I've made the following changes to the javadoc for all the following methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException;
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException;
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException;

and for the following methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name);
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal);

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

Changes to spec

Section 6.11.1 "Durable subscriptions", which contains similar text to the javadoc comments of the above methods, has been similarly changed:

I've deleted

Only one session at a time can have a consumer for a particular durable subscription.

and replaced it with:

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

I've deleted

A client can change an existing durable subscription by calling [this method] with the same name and client identifier (if used), and a new topic and/or message selector. Changing a durable subscription is equivalent to unsubscribing (deleting) the old one and creating a new one.

and replaced it with:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, then the durable subscription will be deleted and a new one created. However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, then a JMSException will be thrown.

A new section has been added to Appendix B "Change history" to describe this change.

Comment by Nigel Deakin [ 17/Apr/12 ]

Javadoc and spec updates (for non-durable subscriptions)

I've now updated the javadocs and the draft spec to incorporate these changes.

The updated Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

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

Changes to Javadocs

I've added the following new methods on Session

  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector) throws JMSException;
  • MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal) throws JMSException;

and the following new methods on JMSContext

  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector);
  • JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal);

Here's an example of the javadoc for one of the methods on Session:

	/**
	 * Creates a shared non-durable subscription with the specified name on the
	 * specified topic, and creates a <code>MessageConsumer</code> on that
	 * subscription, specifying a message selector and whether messages
	 * published by its own connection should be added to the subscription.
	 * <p>
	 * If a shared non-durable subscription already exists with the same name
	 * and the same topic and message selector then this method creates a
	 * <code>MessageConsumer</code> on the existing subscription.
	 * <p>
	 * A non-durable shared subscription is used by a client which needs to be
	 * able to share the work of receiving messages from a topic subscription
	 * amongst multiple consumers. A non-durable shared subscription may
	 * therefore have more than one consumer. Each message from the subscription
	 * will be delivered to only one of the consumers on that subscription. Such
	 * a subscription is not persisted and will be deleted (together with any 
	 * undelivered messages associated with it) when there are no consumers on it.
	 * <p>
	 * A consumer may be created on a non-durable shared subscription using the
	 * <code>createSharedConsumer</code> methods on <code>JMSContext</code>,
	 * <code>Session</code> or <code>TopicSession</code>.
	 * <p>
	 * If there is an active consumer on the non-durable shared subscription (or
	 * a consumed message from that subscription is still part of a pending
	 * transaction or is not yet acknowledged in the session), and an attempt is
	 * made to create an additional consumer, specifying the same name but a
	 * different topic or message selector, then a <code>JMSException</code>
	 * will be thrown.
	 * <p>
	 * The <code>noLocal</code> argument is for use when the session's connection is also
	 * being used to publish messages to the topic. If noLocal is set to true
	 * then messages published to the topic by its own connection will not be
	 * added to the non-durable shared subscription. The default value of this
	 * argument is false.
	 * <p>
	 * There is no restriction to prevent a shared non-durable subscription and
	 * a durable subscription having the same name. Such subscriptions would be
	 * completely separate.
	 * 
	 * @param topic
	 *            the <code>Topic</code> to subscribe to
	 * @param sharedSubscriptionName
	 *            the name used to identify the shared non-durable subscription
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are added to the non-durable subscription. A value
	 *            of null or an empty string indicates that there is no message
	 *            selector for the non-durable subscription.
	 * @param noLocal
	 *            if true, messages published by its own connection will not be
	 *            added to the non-durable subscription.
	 * 
	 * @throws JMSException
	 *             if the session fails to create the non-durable subscription
	 *             and <code>MessageConsumer</code> due to some internal error.
	 * @throws InvalidDestinationException
	 *             if an invalid topic is specified.
	 * @throws InvalidSelectorException
	 *             if the message selector is invalid.
	 */
	MessageConsumer createSharedConsumer(
           Topic topic, String sharedSubscriptionName, 
           java.lang.String messageSelector, boolean noLocal) 
           throws JMSException;   

Changes to draft spec:

The existing section 6.11 "TopicSubscriber" has been extended to cover shared non-durable subscriptions:

Updated introductory section 6.11 "TopicSubscriber":

A client consumes messages from a topic by creating a subscription on that topic, and creating a MessageConsumer or TopicSubscriber on that subscription.

In general, a subscription will receive a copy of every message sent to the topic. However if a message selector is specified then only those messages whose properties match the message selector will be added to the subscription.

In addition, if the noLocal flag was specified when a MessageConsumer or {{TopicSubscriber}}was created, then any messages sent using the same connection will not be added to the subscription.

Each copy of the message is treated as a completely separate message. Work done on one copy has no effect on any other; acknowledging one does not acknowledge any other; one message may be delivered immediately, while another waits for its consumer to process messages ahead of it.

Subscriptions may be durable or non-durable.

A non-durable subscription exists only so long as a MessageConsumer or TopicSubscriber object exists to consume messages from it. A non-durable subscription may be either unshared or shared.

An unshared non-durable subscription does not have a name and may have only a single MessageConsumer or TopicSubscriber object associated with it. It is created automatically when the MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when it is closed. See section 6.11.1 "Unshared non-durable subscriptions" below.

A shared non-durable subscription is identified by name, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. It is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is not persisted and is deleted automatically when the last MessageConsumer or TopicSubscriber object is closed. See section 6.11.2 "Shared non-durable subscriptions" below.

A durable subscription is identified by a name and an optional client identifier, which may be used to associate several MessageConsumer or TopicSubscriber objects with it. A durable subscription is created automatically when the first MessageConsumer or TopicSubscriber object is created. It is persisted and continues to exist until explicitly deleted, even if there are no MessageConsumer or TopicSubscriber objects consuming messages from it. See section 6.11.3 "Durable subscriptions" below.

New section 6.11.1. "Unshared non-durable subscriptions":

An unshared non-durable subscription is the simplest way to consume messages from a topic.

An unshared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the createConsumer methods on Session, JMSContext or TopicSession.

Alternatively an unshared non-durable subscription is created, and a TopicSubscription created on that subscription, using one of the createSubscriber methods on TopicSession.

An unshared non-durable subscription does not have a name. Each call to createConsumer or createSubscriber creates a new subscription.

An unshared non-durable subscription only exists for as long as the MessageConsumer or TopicSubscriber exists. This means that any messages sent to the topic will only be added to the subscription whilst the MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the consumer is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

Each unshared non-durable subscription has a single consumer. If the application needs to create multiple consumers on the same subscription then a shared non-durable subscription should be used instead. See section 6.11.2 "Shared non-durable subscriptions".

If the application needs to be able to receive messages that were sent to the topic even when there was no active consumer on it then a durable subscription should be used instead. See section 6.11.3 "Durable subscriptions".

New section 6.11.2. "Shared non-durable subscriptions":

A non-durable shared subscription is used by a client which needs to be able to share the work of receiving messages from a topic subscription amongst multiple consumers. A non-durable shared subscription may therefore have more than one consumer. Each message from the subscription will be delivered to only one of the consumers on that subscription.

A shared non-durable subscription is created, and a MessageConsumer created on that subscription, using one of the {[createSharedConsumer}} methods on Session, JMSContext or TopicSession. The same methods may be used to create a MessageConsumer on an existing shared non-durable subscription.

A shared non-durable subscription is identified by a name specified by the client.

A shared non-durable subscription only exists for as long as a MessageConsumer or TopicSubscriber exists on the subscription. This means that any messages sent to the topic will only be added to the subscription whilst a MessageConsumer or TopicSubscriber is active. The subscription is not persisted and will be deleted (together with any undelivered messages associated with it) when the last consumer on the subscription is closed.

If a message selector is specified then only messages with properties matching the message selector expression will be added to the subscription.

The noLocal argument may be used to specify that messages published to the topic by its own connection must not be added to the subscription.

If there is an active consumer on the non-durable shared subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name but a different topic or message selector, then a JMSException will be thrown.

There is no restriction to prevent a shared non-durable subscription and a durable subscription having the same name. Such subscriptions would be completely separate.

Comment by Nigel Deakin [ 13/Sep/12 ]

What does the noLocal mean when the subscription is shared? This question applies to both durable and non-durable subscriptions.

In very broad terms noLocal is a way of designating that if a connection creates a consumer on a subscription, then messages sent by that connection will not be added to the subscription.

For JMS 1.1 non-durable subscriptions this is easy to define, since you can only have one consumer on a subscription, and the moment its connection is closed, the subscription will be deleted.

For JMS 1.1 durable subscriptions this is slightly harder to define, since the connection that created the durable subscription could close and "come back later" to reactivate the same durable subscription. In that case, we define that any messages sent by a connection with the same client identifier as the connection which created the subscription will not be added to the subscription.

In JMS 2.0 we introduce three new features to topic subscriptions:

  • We allow a durable subscription to have multiple consumers (see this issue)
  • We allow the creation of named non-durable subscriptions which may have multiple consumers (see this issue)
  • We allow client identifier to be unset when creating a durable subscription (see JMS_SPEC-39)

What does this mean for noLocal? We need to consider the following cases:

1. Unshared durable subscription with client identifier set
2. Unshared durable subscription with client identifier unset
3. Shared durable subscription with client identifier set
4. Shared durable subscription with client identifier unset
5. Shared non-durable subscription with client identifier set
6. Shared durable non-subscription with client identifier unset

1. Unshared durable subscription with client identifier set

This case is already allowed in JMS 1.1 and the meaning of noLocal has been clarified in JMS_SPEC-65.

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

2. Unshared durable subscription with client identifier unset

This case is new in JMS 2.0 and the meaning of noLocal has already been defined in JMS_SPEC-65: this will not be allowed and will throw an exception.

3. Shared durable subscription with client identifier set

This case is new in JMS 2.0. Since two connections cannot have the same client identifier all consumers on the durable subscription must use the same connection. We can simply apply the rule given in (1).

Any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

4. Shared durable subscription with client identifier unset

This case is new in JMS 2.0. We can simply apply the rule given in (2) and not allow this.

5. Shared non-durable subscription with client identifier set

This case is new in JMS 2.0 and we don't have a rule yet which covers it.

We could simply apply the same rule as for durable subscriptions, given in (1) above. However it should be noted that unlike for durable subscriptions, the client identifier will not be part of the subscription name and so we may have multiple consumers with different client identifier. In that case why should we assign a special status to the client identifier that originally created the subscription?

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

6. Shared durable non-subscription with client identifier unset

If we adopted the same rule as for durable subscriptions we would simply not allow this. However if we adopted the alternative given in (5) above we could also apply it in this case.

Summary

For shared non-durable subscriptions we have two alternatives:

A. Adopt a rule similar to that for durable subscriptions, based on client id

If noLocal is set to true, and the client identifier is set, then any messages published to the topic using the connection that created the durable subscription, or any other connection with the same client identifier, will not be added to the durable subscription.

If the client identifier is unset then setting noLocal to true will cause a IllegalStateException to be thrown.

B. Adopt a rule based on whether a connection has created a consumer on the shared subscription

Any messages published by a connection which has created a consumer on the shared non-durable subscription will not be added to the subscription.

Comment by chris.barrow [ 13/Sep/12 ]

I would strongly urge against clientID having any bearing on non-durables.
I would vote for the alternative in 5 (i.e. B), except there is one little wrinkle that needs to be addressed: the part highlighted in the copy below:

An alternative is to adopt a rule based not on client identifier but on whether the connection has created a consumer on the subscription. In that case, once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This would then give equal status to all consumers. However it would be inconsistent with durable subscriptions.

Does the highlighted part means that if I send messages on the connection then shared consumers on the same subscription on the same or different connections would not receive them? I think that is the desirable behavior. My understanding of the intention of the noLocal parameter is that if you are sending a message then you already know about it (and have dealt with it) so you don't need to receive it. And in this case the receiving "you" should include all of the shared message consumers, since presumably they are cooperating to process the messages.

The only unfortunate thing about this is there is an ambiguity if a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one "wins"? If the intention is that noLocal=true implies a message sent on the same connection will not be received by any of the sharedConsumers (on the same or different connections), then noLocal=true would have to "win", effectively changing the behavior of the first consumer on-the-fly.

If we consider that the behavior for the above corner case is too unexpected, then there is another option (which we could perhaps call alternative "C"). This would be to apply strictly the same behavior as for createConsumer. That is, when a message is sent on a connection, it would be delivered to any one of the shared consumers on the subscription except ones created on that same connection with noLocal=false. But (as well as being potentially harder to implement) I think this is actually less useful behavior, for the reasons pointed out above (cooperating consumers). So my vote is still for B, provided we clearly define the behavior for this corner case.

BTW, it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription.

Comment by clebertsuconic [ 13/Sep/12 ]

Two things: I may be late on that, but why do we need a createSharedConsumer? If you let specify createDurableSubscription without clientID you are basically creating or reattaching the subscription that already existed. You are just using a global parameter. (i.e. no clientID)

In regard to noLocal, I simply believe we should rule out noLocal & clientID=null, that will make things simpler and clearer. I can't foresee any usecase with clientID=null and noLocal=true anyways. (anything other than that would be an anti-pattern IMO)

Comment by chris.barrow [ 13/Sep/12 ]

There is a fundamental difference between durable and non-durable subscriptions, even in the shared consumer case: durables live for ever (until they are explicitly deleted) and they store messages even when there are no active consumers (rather like queues). Non-durables only survive as long as there is at least one active consumer, so there is no persistent message store.

Since clientID has no impact on the identity of a non-durable subscription, I strongly think it should have no influence on their behavior. The issue I pointed out above when two shared non-durable consumers are created on the same connection with different noLocal values would still remain even if we do insist that clientID be set for noLocal=true.

I guess you are worried about the inconsistency between the durable and non-durable cases. I do think you have a point there. Maybe we should reconsider the durable noLocal behavior to make it agnostic about clientID as well? The rule suggested for nondurables ("once a connection has created a consumer on the subscription its messages would no longer be added to the subscription.a") could perfectly well be applied to durables as well. There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription.

Comment by Nigel Deakin [ 17/Sep/12 ]

To answer Clebert: createSharedConsumer is for non-durable subscriptions. We need a new method because the existing createConsumer method doesn't have a subscriptionName parameter.

For durable subscriptions, I have accepted your suggestion that if the client identifier is not set and noLocal is true then an IllegalStateException should be thrown.

Comment by Nigel Deakin [ 17/Sep/12 ]

To Answer Chris's comment of 13/Sep/12 07:13 PM:

1. My option B was that if noLocal was true then once a connection has created a consumer on the subscription its messages would no longer be added to the subscription. This means they would not be delivered to any consumers. I think that was what you were asking for. As you say, if you have multiple consumers on the same subscription they are cooperating to process the messages so they should behave the same way.

2. You ask what would happen if "a shared consumer is created with noLocal=false, then a second is created on the same connection with noLocal=true (or vice versa). Which one wins?"

If the first session still had a consumer on the shared non-durable subscription, then if a second connection or session tried to create a consumer on the same subscription with a different topic, message selector or noLocal value then they are trying to change the nature of the subscription, so it should throw an exception.

Obviously if the first connection was closed before the second connection created the consumer then this would not be a problem, as the subscription would have been deleted when the first consumer was closed.

3. Your option (C) shouldn't then be needed

4. You suggest "it would be worth pointing out (for any of the options) that the message still gets sent to the destination (topic) even if it doesn't get delivered to the subscription."

Yes, definitely. More accurately, even if a message doesn't get added to one particular subscription on the topic, it will still be added to all other elegible subscriptions on the same topic.

To answer Chris's comment of 13/Sep/12 09:51 PM:

5. You write "There's no good reason I can see why the noLocal behavior should outlive the consumer (and the connection) in the durables case. After all, it is the subscription that is durable, not the consumer. And it is the consumer that has noLocal=true, not the subscription."

That's quite an important point. However one could argue that the noLocal flag is really just another kind of message selector on the subscription (based on the client id that sent the message), and so continues to exist irrespective of whether there were any consumers active.

However I think we ultimately have a slightly arbitrary decision here. noLocal is a distinctly obscure feature: it would be interested to know how much it gets used.

We should also consider an option D, which is when the new createSharedConsumer method is used to create a shared non-durable subscription (which is a new feature of JMS 2.0), there is no noLocal option at all.

Comment by Nigel Deakin [ 05/Nov/12 ]

Because shared non-durable subscriptions are so similar in concept to durable subscriptions I think we should aim to make the definition of noLocal for the two types of subscription as similar as possible. This means:

1. Changing the definition of a shared non-durable subscription so that the client identifier, if set, forms part of the name of the shared non-durable subscription (as is already the case with durable subscriptions).

2. Defining noLocal in exactly the same way for shared non-durable subscriptions as for durable subscriptions:

When a durable or shared non-durable subscription is created on a topic, the noLocal argument may be used to specify that messages published to the topic by its own connection or any other with the same client identifier will not be added to the durable subscription. If the client identifier is unset then setting noLocal to true will cause an exception to be thrown.

Since only one connection may have a given client identifier at a time, this means that the noLocal flag may only be used when there is a single connection consuming from a subscription. I believe this is a benefit as it it gives us a clear, simple definition, it maintains consistency with JMS 1.1, and avoiding the need to contrive complex and entirely hypothetical use cases in which noLocal is used in conjunction with multiple consumers.

Following consultation with the expert group and user alias I have now added this definition to the draft specification.

To see the new text in the spec, please download the latest draft here (log in to java.net first) and read section 6.11.2. "Shared non-durable subscriptions"

You can find the updated API documentation for Session.createSharedConsumer here and for JMSContext.createSharedConsumer here

I have added a special note to section A.3. "Unresolved issues in the JMS 2.0 Public Draft" to state that this is an issue which we aren't completely sure about, and that when this specification goes to public review we're particularly welcome comments on it.

Comment by Nigel Deakin [ 14/Nov/12 ]

Reopening this issue as this feature changes the behaviour of Session.createDurableSubscription in an incompatible way

Incompatibility 1.

According to JMS 1.1 section 6.11.1: "Only one session at a time can have a TopicSubscriber for a particular durable subscription.". The spec and API docs do not explicitly state that an attempt to create two {{TopicSubscriber}}s on the same durable subscription should throw an exception, but I think this is implied, at least for the case where different sessions are used.

In JMS 2.0 we are proposing to remove this restriction and allow multiple {{TopicSubscriber}}s(and {{MessageConsumer}}s) to be created on the same durable subscription.

Incompatibility 2.

According to JMS 1.1 section 6.11.1: "Sessions with durable subscribers must always provide the same client
identifier." The spec and API docs do not explicitly state that clientId must be set when calling createDurableSubscription, and that an exception must be thrown if it is not set, but again I think this is is implied.

In JMS 2.0 we are proposing to remove this restriction and allow clientId to be either set or unset when Session.createDurableSubscription is called. If clientId is set then the combination of clientId and subscription name will be used to identify the durable subscription. If clientId is not set then the subscription name will be used to identify the durable subscription.

Comment by Nigel Deakin [ 21/Nov/12 ]

I have updated the API for creating durable subscriptions to retain backwards compatibility with JMS 1.1 as follows:

The following methods have been reverted to the JMS 1.1 behaviour:

Methods on Session:

  • TopicSubscriber createDurableSubscriber(Topic topic, String name) (JMS 1.1)
  • TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 1.1)
  • MessageConsumer createDurableConsumer(Topic topic, String name) (JMS 2.0)
  • MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) (JMS 2.0)

Methods on JMSContext:

  • JMSConsumer createDurableConsumer(Topic topic, String name)
  • JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will only allow a single consumer on a durable subscription
  • clientId MUST be set

I have also added the following new methods to support shared durable subscriptions:

Methods on Session:

  • MessageConsumer createSharedDurableConsumer(Topic topic, String name)
  • MessageConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

Methods on JMSContext:

  • JMSConsumer createSharedDurableConsumer(Topic topic, String name)
  • JMSConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

These methods:

  • Will allow multiple consumers on a durable subscription
  • clientId may or may not be set

You can see the updated API docs here:
http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/index.html

I have also updated the spec to incorporate these changes:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/specification/word/JMS20.pdf

Comment by Nigel Deakin [ 12/Feb/13 ]

The JMS 2.0 expert group has agreed that the noLocal parameter serves no useful purpose for shared subscriptions (both durable and non-durable) and should be removed.

Changes to Session:

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)

Changes to JMSContext

Removed:

  • createSharedConsumer(Topic topic, String sharedSubscriptionName, java.lang.String messageSelector, boolean noLocal)

Changed:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal)

To:

  • createSharedDurableConsumer(Topic topic, String name, String messageSelector)




[JMS_SPEC-50] Clarify that JMS providers must implement both P2P and Pub-Sub Created: 19/Aug/11  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0ED, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: ed20-added

 Description   

In the JMS Specification 1.1, Chapter 1.3 "What Is Required by JMS" says:

Providers of JMS point-to-point functionality are not required to provide publish/subscribe functionality and vice versa.

However Java EE 6 in Section EE.2.7.8 "Java™ Message Service (JMS)" says

The Java Message Service is a standard API for messaging that supports reliable point-to-point messaging as well as the publish-subscribe model. This specification requires a JMS provider that implements both point-to-point messaging as well as publish-subscribe messaging.

It is proposed to change the JMS specification to bring it in to line with Java EE, and make it mandatory for a standalone JMS provider to implement both point-to-point messaging (Queues) and publish-subscribe messaging (Topics).



 Comments   
Comment by Nigel Deakin [ 16/Sep/11 ]

This has been agreed in principle by the JSR 343 Expert group and will be in the JMS 2.0 Early Draft.

Comment by Nigel Deakin [ 03/Jan/12 ]

I've now updated the draft spec to reflect this decision (these changes are additive, so those docs include other changes).

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. The only sections affected are section 1.3 "What Is Required by JMS" and section 11.5.10 which is the change log for this issue.)





[JMS_SPEC-69] Clarify that QueueRequestor and TopicRequestor only work in a non-transacted session with auto or dups-ok ack Created: 30/Jan/12  Updated: 20/Mar/13  Resolved: 11/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fd20-doc-added

 Description   

The javadocs for QueueRequestor and TopicRequestor state that "This implementation assumes the session parameter to be non-transacted, with a delivery mode of either AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE".

  • There is no mention of this in the spec in section 5.10 "QueueRequestor" or 6.14 "TopicRequestor". This should be clarified.
  • In addition, the class comment should also mention this restriction.

There is no reason why a user could not implement a modified version of this class which uses client-ack. However there is a more general issue regarding the use of transactions with request-reply messaging:

  • It would also be worth mentioning the general point that if an application implements request/reply messaging, the request message must not be sent within the same transaction as the reply is received.
  • It would also be worth mentioning that this means that a QueueRequestor and TopicRequestor cannot be used in a Java EE web or EJB container when there is an active JTA transaction.
  • The following text copied from the EJB spec might be worth including in a modified form somewhere in the spec (in the 2.0 Early Draft it has been added to Section 12.3 "Behaviour of JMS sessions in the Java EE web or EJB container" but since this isn't specific to Java EE it should be moved somewhere more appropriate)

The Bean Provider should not make use of the JMS request/reply paradigm (sending of a JMS message, followed by the synchronous receipt of a reply to that message) within a single transaction. Because a JMS message is typically not delivered to its final destination until the transaction commits, the receipt of the reply within the same transaction will not take place.



 Comments   
Comment by Nigel Deakin [ 11/Feb/13 ]

The JMS 2.0 proposed final draft has been amended to say:

4.1.6 QueueRequestor

The legacy domain-specific API for point-to-point messaging provides a QueueRequestor helper class to simplify making service requests.

The QueueRequestor constructor is given a non-transacted QueueSession and a destination queue. It creates a TemporaryQueue for the responses and provides a request method that sends the request message and waits for its reply.

This is a very basic request/reply abstraction which assumes the session is non-transacted with a delivery mode of either AUTO_ACKNOWLEDGE}] or {{DUPS_OK_ACKNOWLEDGE. It is expected that most applications will create less basic implementations.

There is no equivalent to this class for the classic or simplified APIs. Applications using these APIs are expected to create their own implementations.

The Javadoc for QueueRequestor has been modified to say the same thing:

/** The {@code QueueRequestor} helper class simplifies
  * making service requests.
  *
  * <P>The {@code QueueRequestor} constructor is given a non-transacted 
  * {@code QueueSession} and a destination {@code Queue}. It creates a
  * {@code TemporaryQueue} for the responses and provides a 
  * {@code request} method that sends the request message and waits 
  * for its reply.
  * <p>
  * This is a very basic request/reply abstraction which assumes the session 
  * is non-transacted with a delivery mode of either AUTO_ACKNOWLEDGE or 
  * DUPS_OK_ACKNOWLEDGE. It is expected that most applications will create 
  * less basic implementations.
  *
  * @version 2.0
  * @since 1.0
  * @see javax.jms.TopicRequestor
  */

4.2.10 TopicRequestor

The legacy domain-specific API for pub/sub messaging provides a TopicRequestor helper class to simplify making service requests.

The TopicRequestor constructor is given a non-transacted TopicSession and a destination topic. It creates a TemporaryTopic for the responses and provides a request method that sends the request message and waits for its reply.

This is a very basic request/reply abstraction which assumes the session is non-transacted with a delivery mode of either AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE. It is expected that most applications will create less basic implementations.

There is no equivalent to this class for the classic or simplified APIs. Applications using these APIs are expected to create their own implementations.

The Javadoc for TopicRequestor has been modified to say the same thing:

/** The {@code TopicRequestor} helper class simplifies
  * making service requests.
  *
  * <P>The {@code TopicRequestor} constructor is given a non-transacted 
  * {@code TopicSession} and a destination {@code Topic}. It creates a 
  * {@code TemporaryTopic} for the responses and provides a 
  * {@code request} method that sends the request message and waits 
  * for its reply.
  * <p>
  * This is a very basic request/reply abstraction which assumes the session 
  * is non-transacted with a delivery mode of either AUTO_ACKNOWLEDGE or 
  * DUPS_OK_ACKNOWLEDGE. It is expected that most applications will create 
  * less basic implementations.
  *
  * @version 2.0
  * @since 1.0
  * @see javax.jms.QueueRequestor
  */
Comment by Nigel Deakin [ 11/Feb/13 ]

Resolved in the JMS 2.0 final draft.





[JMS_SPEC-81] Remove Change History for previous versions from the specification Created: 21/Feb/12  Updated: 20/Mar/13  Resolved: 14/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fd20-doc-added

 Description   

The JMS 1.1 specification contains in chapter 11 a detailed list of changes that were introduced in version 1.0.1, 1.0.2, 1.0.2b and 1.1. These all relate to changes made a decade ago. They are of interest only to historians of JMS, and have no value in the JMS 2.0 specification other than to clutter up the spec. They should be removed.

This information will remain in the JMS 1.1 specification for the benefit of future historians.

(For the avoidance of doubt, the JMS 2.0 spec should of course contain a list of changes made between 1.1 and 2.0)



 Comments   
Comment by Nigel Deakin [ 14/Feb/13 ]

Now done in the JMS 2.0 proposed final draft.





[JMS_SPEC-80] Error in example 9.3.3.2 "Reconnect to a topic using a durable subscription" Created: 21/Feb/12  Updated: 21/Sep/12  Resolved: 21/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

Section 9.3.3.2 "Reconnect to a topic using a durable subscription" of the JMS 1.1 specification gives an example of how a client can reconnect to an existing durable subscription. It says:

there are some important restrictions to be aware of:

  • The client must be attached to the same Connection.
  • The Destination and subscription name must be the same.
  • If a message selector was specified, it must also be the same.
    If these conditions are not met, then the durable subscription is deleted, and a new subscription is created.

The first of these points is incorrect. The Connection need not be the same. However the client identifier must be the same as was used when creating the durable subscription originally.



 Comments   
Comment by Nigel Deakin [ 14/May/12 ]

In the JMS 1.1 specification, the whole of this section is

9.3.3.2. Reconnecting to a topic using a durable subscription

To re-connect to a topic that has an existing durable subscription, the client program can simply call session.CreateDurableSubscriber again, using the same parameters that it previously used. A client program may be intermittently connected. Using durable subscriptions allows messages to still be available to a client program that consumes from a topic, even though the client program was not continuously connected.

/* Reconnect to a durable subscription */
session.createDurableSubscriber(newsFeedTopic,"mySubscription");

This reconnects the client program to the topic, and any messages that arrived while the client was disconnected are delivered.

However, there are some important restrictions to be aware of:

• The client must be attached to the same Connection.
• The Destination and subscription name must be the same.
• If a message selector was specified, it must also be the same.

If these conditions are not met, then the durable subscription is deleted, and a new subscription is created.

Comment by Nigel Deakin [ 14/May/12 ]

I've now updated the draft spec with the following updated text, which corrects this error and also updates it to reflect the fact that a durable subscription may have more than one consumer, and to make a more accurate distinction between topic, durable subscription and consumer.

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

Here is the new text:

9.3.3.2. Creating a consumer on an existing durable subscription

Once a durable subscription has been created it will continue to accumulate messages until the subscription is deleted using the Session method unsubscribe, even if the original consumer is closed leaving no consumer on the durable subscription.

A client application may create a consumer on an existing durable subscription by calling one of the Session methods createDurableConsumer or createDurableSubscriber, supplying the same parameters that were specified when the durable subscription was first created.

/* Create a consumer on an existing durable subscription */
session.createDurableConsumer(newsFeedTopic, "mySubscription");

If there were no consumers on the durable subscription prior to calling this method then any messages which were added to the subscription whilst it had no consumers will be delivered.

A durable subscription may have more than one active consumer (this was not permitted prior to JMS 2.0). Each message from the subscription will be delivered to only one of the consumers on that subscription.

When creating a consumer on an existing durable subscription there are some important restrictions to be aware of:

• The Destination and subscription name must be the same as when the durable subscription was first created.

• If the connection's client identifier was set when the durable subscription was first created then the same client identifier must be set when subsequently creating a consumer on it.

• If a message selector was specified when the durable subscription was first created then the same message selector must be specified when subsequently creating a consumer on it.

The change log has been updated to add the following new section:

B.5.19 Correction: Reconnecting to a durable subscription (JMS_SPEC-80)

In the JMS 1.1 specification, section 9.3.3.2 "Reconnect to a topic using a durable subscription" stated that "the client must be attached to the same Connection". This was incorrect and has been corrected to state that the client must use a connection with the same client identifier.

In addition this section has been renamed 9.3.3.2 "Creating a consumer on an existing durable subscription" and rewritten to make it clearer.





[JMS_SPEC-78] JMS implementation of QueueRequestor and TopicRequestor doesn't throw correct exception when destination is null Created: 16/Feb/12  Updated: 20/Mar/13  Resolved: 04/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-197 JMS TCK test queueRequestorExceptionT... Closed
Tags: pd20-added

 Description   

The javadocs for the constructor methods QueueRequestor(session,queue) and TopicRequestor(session,topic) state that a InvalidDestinationException should be thrown if an invalid queue/topic is specified.

http://docs.oracle.com/javaee/6/api/javax/jms/QueueRequestor.html
http://docs.oracle.com/javaee/6/api/javax/jms/TopicRequestor.html

However if a value of null is supplied no exception is thrown, despite this not being valid.

These classes are supplied with JMS rather than by implementations, which is why this is being logged here rather than with any particular JMS provider.

If you look at the implementation:

    public
    QueueRequestor(QueueSession session, Queue queue) throws JMSException {
        this.session = session;
        this.queue   = queue;
        tempQueue    = session.createTemporaryQueue();
        sender       = session.createSender(queue);
        receiver     = session.createReceiver(tempQueue);
    }

you can see why it doesn't throw an exception. Calling createQueue(null) is valid as it creates an anonymous producer. However although this is valid in general it isn't valid here. An explicit check for null needs to be added which should cause a InvalidDestinationException to be thrown.



 Comments   
Comment by Nigel Deakin [ 04/Sep/12 ]

Now fixed.

Note that the implementation of these classes is actually part of the RI.





[JMS_SPEC-70] Define annotations for injecting MessagingContext objects Created: 03/Feb/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
depends on JMS_SPEC-64 Define simplified JMS API Resolved
blocks MQ-177 Implement injection of JMSContext obj... Closed
blocks JMS_SPEC-33 Improving the JMS API with API simpli... Resolved
Tags: pd20-added

 Description   

The simplified API (JMS_SPEC-64) defines a single object, javax.jms.MessagingContext, which provides methods for sending and receiving messages.

It is proposed that the JMS API define some standard annotations that can be used to inject MessagingContext objects into application code.

  • The injection point should allow the application define the two parameters needed to create a MessagingContext: JNDI name (of the connection factory) and sessionMode. Both should be optional with suitable defaults.
  • The implementation should ideally be implemented using CDI and have behaviour consistent with it. However this is not essential.
  • It must be possible to use injection in Java EE applications. It is desirable but not essential to be able to use injection in Java SE applications.
  • Injected MessagingContexts must have an appropriate scope and must be automatically closed when they fall out of scope.


 Comments   
Comment by Nigel Deakin [ 08/Feb/12 ]

Here is the proposed text to be added to the JMS spec:

This section relates to application classes which run in the Java EE web, EJB or application client containers and which support injection. Section EE.5 of the Java EE specification lists the application classes that support injection.

Applications may declare a field of type javax.jms.MessagingContext and annotate it with the javax.inject.Inject annotation:

@Inject
private MessagingContext context;

The container will inject a MessagingContext. It will have request scope and will be automatically closed when the request ends. However, unlike a normal CDI request-scoped object, a separate MessagingContext instance will be injected for every injection point.

The annotation javax.jms.JMSConnectionFactory may be used to specify the JNDI lookup name of the ConnectionFactory used to create the messaging context. For example:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
private MessagingContext context;

If no lookup name is specified or the JMSConnectionFactory annotation is omitted then the platform default JMS connection factory will be used.

The annotation javax.jms.JMSSessionMode may be used to specify the session mode of the messaging context:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSSessionMode(MessagingContext.AUTO_ACKNOWLEDGE)
private MessagingContext context;

The meaning and possible values of session mode are the same as for the ConnectionFactory method createMessagingContext(int sessionMode):

  • In the Java EE application client container, session mode may be set to any of MessagingContext.SESSION_TRANSACTED, MessagingContext.CLIENT_ACKNOWLEDGE, MessagingContext.AUTO_ACKNOWLEDGE or MessagingContext.DUPS_OK_ACKNOWLEDGE. If no session mode is specified or the JMSSessionMode annotation is omitted a session mode of MessagingContext.AUTO_ACKNOWLEDGE will be used.
  • In a Java EE web or EJB container, when there is an active JTA transaction in progress, session mode is ignored and the JMSSessionMode annotation is unnecessary.
  • In a Java EE web or EJB container, when there is no active JTA transaction in progress, session mode may be set to either of MessagingContext.AUTO_ACKNOWLEDGE or MessagingContext.DUPS_OK_ACKNOWLEDGE. If no session mode is specified or the JMSSessionMode annotation is omitted a session mode of MessagingContext.AUTO_ACKNOWLEDGE will be used.

For more information about the use of session mode when creating a messaging context, see section 10.3 of the JMS 2.0 Early Draft, "Behaviour of JMS sessions in the Java EE web or EJB container" and the API documentation for the ConnectionFactory method createMessagingContext(int sessionMode).

Comment by Nigel Deakin [ 08/Feb/12 ]

The proposed new annotations are as follows:

New annotation javax.jms.JMSConnectionFactory:

package javax.jms;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * This optional annotation may be used to specify the JNDI lookup name of a <code>javax.jms.ConnectionFactory</code>
 * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
 */
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface JMSConnectionFactory {
    /**
     * (Optional) Specifies the JNDI lookup name of a <code>javax.jms.ConnectionFactory</code>
     * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
     */
    String value() default "";
}

New annotation javax.jms.JMSSession:

package javax.jms;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * This optional annotation may be used to specify the session mode
 * to be used when injecting a <code>javax.jms.MessagingContext</code> object.
 * The meaning and possible values of session mode are the same as for the 
 * <code>ConnectionFactory</code> method <code>createMessagingContext(int sessionMode)</code>.
 * 
 * @see javax.jms.MessagingContext#createMessagingContext(int) 
 */
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface JMSSessionMode {
    /**
     * (Optional) Specifies the session mode used when injecting a <code>javax.jms.MessagingContext</code> object.
     */
    int value() default MessagingContext.AUTO_ACKNOWLEDGE;
}
Comment by Nigel Deakin [ 10/Feb/12 ]

I've now updated the API, javadocs and the draft spec in accordance with the proposals made above.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

The only changes are the two annotations javax.jms.JMSConnectionFactory and javax.jms.JMSSession.

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

See particularly the new section 13.3 "Injection of MessagingContext objects" and a full set of examples in section 11.4 "Examples using the simplified API". The change log for the simplified API, section B.5.12 has also been updated.

Comment by Nigel Deakin [ 17/Feb/12 ]

I've updated the API, javadocs and the draft spec in accordance with the following changes.

The updated API and Javadocs are here:
http://java.net/projects/jms-spec/sources/repository/content/jms2.0/target/jms-2.0-javadoc.jar

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

A new annotation has been added to allow the application to specify the user and password to be used when injecting a MessagingContext:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSPasswordCredential(userName="admin",password="mypassword")
private MessagingContext context;

A new annotation has been added to allow the application to configure whether the connection is automatically started when a consumer is created:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
@JMSSessionMode(MessagingContext.AUTO_ACKNOWLEDGE)
@JMSAutoStart(false)
private MessagingContext context;
Comment by Nigel Deakin [ 21/Sep/12 ]

This feature has been further revised: an up-to-date description may be found in section 11.3 "Injection of JMSContext objects" in the JMS 2.0 public draft.

11.3. Injection of JMSContext objects

Comment by Nigel Deakin [ 26/Oct/12 ]

This issue is now closed as a full definition of how JMSContext objects may be injected will be included in the JMS 2.0 public draft.





[JMS_SPEC-93] Does changing the noLocal flag when connecting to a durable subscription cause the durable subscription to be deleted? Created: 30/Mar/12  Updated: 21/Sep/12  Resolved: 17/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks JMS_SPEC-40 Allow multiple consumers to be create... Resolved
Tags: pd20-added

 Description   

The JMS 1.1 specification, section 6.11.1 "Durable TopicSubscriber" states:

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector, or NoLocal attribute. Changing a durable subscription is equivalent to deleting and recreating it.

However the javadoc here for the Session method createDurableSubscriber(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal) states that

A client can change an existing durable subscription by creating a durable TopicSubscriber with the same name and a new topic and/or message selector. Changing a durable subscriber is equivalent to unsubscribing (deleting) the old one and creating a new one.

The latter text uses an almost identical sentence but does not mention the effect of creating a durable subscriber with a different value of the noLocal flag.

This is contradictory and needs to be clarified. What is the effect if creating a durable subscriber with a different value of the noLocal flag than was used when the durable subscription was created?

I propose that we should interpret the javadoc as being correct and change the spec to match. The NoLocal flag determines whether messages sent using the connection that created the durable subscription should be added to it. Its significance ceases when the connection is closed. If the second call to createDurableSubscription uses a different connection then the value of noLocal that it specifies is completely independent of the previous value and does not render the durable subscription invalid. It is therefore not necessary to delete the durable subscription and create a new one.



 Comments   
Comment by Nigel Deakin [ 15/May/12 ]

When I logged this issue I think I was misunderstanding the meaning of the noLocal parameter. A clarified definition of this parameter is proposed in http://java.net/jira/browse/JMS_SPEC-65#action_339660 . This proposes we interpret noLocal as meaning "If noLocal is set to true, and the client identifier is set, then any messages published using this connection or any other with the same client identifier will not be added to the durable subscription."

In this case the value of noLocal remains a part of the definition of the durable subscription for the whole of its lifetime. This means that an attempt to activate the durable subscription using a different value of noLocal will invalidate the subscription, and so should cause the subscription to be deleted and recreated.

If the proposals in http://java.net/jira/browse/JMS_SPEC-65#action_339660 are approved then I propose that we resolve this issue by doing the opposite of what I first proposed, and to change the javadoc to match the specification.

Comment by Nigel Deakin [ 17/Sep/12 ]

Following the changes for JMS_SPEC-65, the API docs and spec have been clarified as follows:

If there are no active consumers on the durable subscription (and no consumed messages from that subscription are still part of a pending transaction or are not yet acknowledged in the session), and this method is used to create a new consumer on that durable subscription, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal value, then the durable subscription will be deleted and a new one created.

However if there is an active consumer on the durable subscription (or a consumed message from that subscription is still part of a pending transaction or is not yet acknowledged in the session), and an attempt is made to create an additional consumer, specifying the same name and client identifier (if set) but a different topic or message selector, or, if the client identifier is set, a different noLocal value, then a JMSException or JMSRuntimeException will be thrown.





[JMS_SPEC-87] Section 2.5 "Interfaces" needs updating to introduce the simplified API Created: 12/Mar/12  Updated: 20/Mar/13  Resolved: 14/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fd20-doc-added

 Description   

Section 2.5 "Interfaces" needs updating to introduce the simplified API alongside the "standard" API and to explain how they interrelate.

As part of this work it may be helpful to modify Figure 2.2 "Overview of JMS object relationships" to show the cardinality of the inter-object relationships, for both the standard and simplified API and for Java SE and for the Java EE web or EJB container.



 Comments   
Comment by Nigel Deakin [ 14/Feb/13 ]

The structure of the JMS 1.1 specification reflected the domain-specific APIs introduced in JMS 1.0, with section titles such as "QueueConnection" and "TopicSubscriber". This was an inappropriate structure even in JMS 1.1 since these interfaces had been superseded in JMS 1.1 by the "unified" API. The addition of the simplified API in JMS 2.0 makes that structure even more inappropriate.

The JMS 2.0 specification has now been completely restructured along functional lines, with chapter headings such as "connecting to a JMS provider" and "receiving messages". These describe each area of functionality in generic terms followed by a description of how it is implemented in the various APIs. In general these chapters contain the same text as in the previous version.

In particular a new section 2.5. "JMS APIs" introduces the various APIs introduced in each version of JMS. A new section 2.7. "Classic API interfaces" contains a diagram of the objects used in the "classic" (formerly "standard") API, and section 2.8. "Simplified API interfaces" contains a diagram of the objects used in the simplified API.





[JMS_SPEC-86] Chapter 1 "Introduction" is a little dated and requires rewriting Created: 12/Mar/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fr20-doc-added

 Description   

Chapter 1 "Introduction" of the JMS 1.1 specification (and the JMS 2.0 Early Draft) is a little dated (as would be expected given that it was written almost ten years ago). This would probably merit from rewriting.



 Comments   
Comment by Nigel Deakin [ 20/Mar/13 ]

Chapter 1 of the JMS 2.0 specification has been updated accordingly in time for the JMS 2.0 final release. The changes are summarised in this expert group email





[JMS_SPEC-97] Define Java EE JMS Connection Factory Definition annotation and descriptor elements Created: 23/Jul/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The Java EE 7 Early Draft specifies that an application may define a JMS ConnectionFactory resource using either a JMSConnectionFactoryDefinition annotation on an application class or a <jms-connection-factory> element in the deployment descriptor.

Although this feature is specified in the Java EE platform spec, the JMS spec needs to define the following:

  • The list of standard properties that may be specified
  • The actual javax.jms.JMSConnectionFactoryDefinition annotation as part of the JMS API


 Comments   
Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-96] Define Java EE JMS Destination Definition annotation and descriptor elements Created: 23/Jul/12  Updated: 22/Mar/13  Resolved: 22/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The Java EE 7 Early Draft specifies that an application may define a JMS Destination resource using either a JMSDestinationDefinition annotation on an application class or a <jms-destination> element in the deployment descriptor.

Although this feature is specified in the Java EE platform spec, the JMS spec needs to define the following:

  • The list of standard properties that may be specified
  • The actual javax.jms.JMSDestinationDefinition annotation as part of the JMS API





[JMS_SPEC-107] Extend connection consumer API to support shared durable and non-durable subscriptions Created: 06/Dec/12  Updated: 20/Mar/13  Resolved: 10/Dec/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-253 Extend connection consumer API to sup... Closed
Tags: pd20-added

 Description   

Now that JMS_SPEC-40 has added shared-durable and non-durable subscriptions to JMS, the connection consumer API needs to be extended to support them.

So in addition to the existing methods on Connection:

ConnectionConsumer createConnectionConsumer(
   Destination destination, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Queues or unshared non-durable topic subscriptions, clientId optional)

ConnectionConsumer createDurableConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Unshared durable topic subscriptions, clientId required)

we also need

ConnectionConsumer createSharedConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Shared non-durable topic subscriptions, clientId optional)

ConnectionConsumer createSharedDurableConnectionConsumer(
   Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, 
   int maxMessages)

(Shared durable topic subscriptions, clientId optional)



 Comments   
Comment by Nigel Deakin [ 06/Dec/12 ]

Here are the proposed new methods on Connection:

	/**
	 * Creates a connection consumer for this connection (optional operation)
	 * on the specific topic using a shared non-durable subscription with
	 * the specified name.
	 * <p>
	 * This is an expert facility not used by ordinary JMS clients.
	 * <p>
	 * This method must not be used in a Java EE web or EJB application. Doing
	 * so may cause a {@code JMSException} to be thrown though this is not
	 * guaranteed.
	 * 
	 * @param topic
	 *            the topic to access
	 * @param subscriptionName
	 *            the name used to identify the shared non-durable subscription
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are delivered. A value of null or an empty string
	 *            indicates that there is no message selector for the message
	 *            consumer.
	 * @param sessionPool
	 *            the server session pool to associate with this connection
	 *            consumer
	 * @param maxMessages
	 *            the maximum number of messages that can be assigned to a
	 *            server session at one time
	 * 
	 * @return the connection consumer
	 * 
	 * @exception InvalidDestinationException
	 *                if an invalid destination is specified.
	 * @exception InvalidSelectorException
	 *                if the message selector is invalid.
	 * @exception JMSException
	 *                if the {@code Connection} object fails to create a
	 *                connection consumer for one of the following reasons:
	 *                <ul>
	 *                <li>an internal error has occurred 
	 *                <li>invalid arguments for {@code sessionPool} and 
	 *                {@code messageSelector} or 
	 *                <li>this method has been called in a Java EE web or EJB
	 *                application (though it is not guaranteed that an exception
	 *                is thrown in this case)
	 *                </ul>
	 * 
	 * @since 2.0
	 * @see javax.jms.ConnectionConsumer
	 */
	ConnectionConsumer createSharedConnectionConsumer(Topic topic,
			String subscriptionName,
			String messageSelector, ServerSessionPool sessionPool,
			int maxMessages) throws JMSException;
	/**
	 * Creates a connection consumer for this connection (optional operation)
	 * on the specific topic using a shared durable subscription with
	 * the specified name.
	 * <p>
	 * This is an expert facility not used by ordinary JMS clients.
	 * <p>
	 * This method must not be used in a Java EE web or EJB application. Doing
	 * so may cause a {@code JMSException} to be thrown though this is not
	 * guaranteed.
	 * 
	 * @param topic
	 *            topic to access
	 * @param subscriptionName
	 *            the name used to identify the shared durable subscription 
	 * @param messageSelector
	 *            only messages with properties matching the message selector
	 *            expression are delivered. A value of null or an empty string
	 *            indicates that there is no message selector for the message
	 *            consumer.
	 * @param sessionPool
	 *            the server session pool to associate with this durable
	 *            connection consumer
	 * @param maxMessages
	 *            the maximum number of messages that can be assigned to a
	 *            server session at one time
	 * 
	 * @return the durable connection consumer
	 * 
	 * @exception InvalidDestinationException
	 *                if an invalid destination is specified.
	 * @exception InvalidSelectorException
	 *                if the message selector is invalid.
	 * @exception JMSException
	 *                if the {@code Connection} object fails to create a
	 *                connection consumer for one of the following reasons:
	 *                <ul>
	 *                <li>an internal error has occurred 
	 *                <li>invalid arguments
	 *                for {@code sessionPool} and {@code messageSelector} or 
	 *                <li>this method has been called in a Java EE web or EJB
	 *                application (though it is not guaranteed that an exception
	 *                is thrown in this case)
	 *                </ul>
	 * @since 2.0
	 * @see javax.jms.ConnectionConsumer
	 */
	ConnectionConsumer createSharedDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector,
			ServerSessionPool sessionPool, int maxMessages) throws JMSException;




[JMS_SPEC-98] Fix findbugs warnings in JMSException, JMSRuntimeException, QueueRequestor, TopicRequestor Created: 14/Aug/12  Updated: 20/Mar/13  Resolved: 04/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The following JMS 1.1 classes give the following findbugs warnings:

javax/jms/JMSException.java:86: UG_SYNC_SET_UNSYNC_GET: 
javax.jms.JMSException.getLinkedException() is unsynchronized, 
javax.jms.JMSException.setLinkedException(Exception) is synchronized

javax/jms/QueueRequestor.java:62: URF_UNREAD_FIELD:
Unread field: javax.jms.QueueRequestor.queue

java/javax/jms/TopicRequestor.java:61: URF_UNREAD_FIELD: Unread field:
javax.jms.TopicRequestor.topic

It should be possible for fix all these without breaking backwards compatibility.

Also, the following new JMS 2.0 class givs the following findbugs warnings:

javax/jms/JMSRuntimeException.java:118: UG_SYNC_SET_UNSYNC_GET:
javax.jms.JMSRuntimeException.getLinkedException() is unsynchronized,
javax.jms.JMSRuntimeException.setLinkedException(Exception) is synchronized

This should be fixed.



 Comments   
Comment by Nigel Deakin [ 04/Sep/12 ]

Now fixed.





[JMS_SPEC-94] Define what characters are valid in a durable (or shared subscription) name Created: 17/Apr/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-added

 Description   

The JMS 1.1 specification does not specify what characters are valid in a durable subscription name.

It is proposed that the JMS 2.0 specification defines a minimum set of characters which are valid in a durable or non-durable subscription name.

This is needed to allow portable applications to be created. It is also needed because EJB_SPEC-41 states that if a MDB is defined with subscriptionDurability set to Durable but subscriptionName is not set then the container will automatically set subscriptionName to a suitably unique global name of the MDB, and the container vendor needs to be sure that the name it generates will always be a legal subscription name.



 Comments   
Comment by Nigel Deakin [ 31/May/12 ]

In addition, the JMS 2.0 should specify the minimum length of durable subscription name that a JMS provider should support.

Comment by chris.barrow [ 06/Dec/12 ]

Issue JMS_SPEC-90 "Provide simpler mechanism to refer to queues and topics in a portable way" is related. Could we deal with that issue at the same time? It could easily be resolved by stipulating the same rules for queue and topic names as those proposed for durable subscription name (minimum set of characters and length that must be supported), as noted in a comment I added to that issue.

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-20] New "Not Before" Header Created: 24/May/11  Updated: 07/Nov/11  Resolved: 07/Nov/11

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: fribeiro Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

It would be nice to be able to filter out messages that shouldn't be consumed before a timestamp provided in a standard "not before" header.

I've heard before that at least one implementation provides a custom header for this use case, but can't find the reference now.



 Comments   
Comment by clebertsuconic [ 24/May/11 ]

+1 Most providers have scheduled delivery as part of their implementation. I even thought this was part of the API already.

There should be a standard way IMO through the API.

Comment by Nigel Deakin [ 07/Nov/11 ]

The JSR 343 Expert group has proposed JMS_SPEC-44 which is effectively a duplicate of this issue. I will therefore mark this issue as resolved with a resolution of "Duplicate.

Please look at JMS_SPEC-44 and add any comments you feel appropriate.





[JMS_SPEC-15] Queue Depth Created: 24/May/11  Updated: 09/Mar/12  Resolved: 09/Mar/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: colincrist Assignee: Unassigned
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-18 Standard set of server JMX MBeans Open
duplicates JMS_SPEC-59 Basic metadata/management via JMS Open

 Description   

As a client I would like to get the current queue depth on a queue. All existing providers give this information via a custom API or JMX at present.



 Comments   
Comment by fribeiro [ 24/May/11 ]

Maybe we should revise whether the spec specifies the notifications that must be supported by implementations – this one should definitely be there.

Comment by rdohna [ 09/Dec/11 ]

JMS_SPEC-15 is a special case of JMS_SPEC-59

Comment by Nigel Deakin [ 09/Mar/12 ]

@fribeiro: I'm not sure what you mean by notifications here and how it relates to obtaining the queue depth (and I don't want to guess). Can you please log your proposal as a new JIRA issue?

Comment by Nigel Deakin [ 09/Mar/12 ]

I'm merging this proposal with two more general proposals:

JMS_SPEC-59 - which covers general non-JMX metadata queries
JMS_SPEC-18 - which covers general JMX facilities

I'm going to close this issue as a duplicate of those. Feel free to contribute comments to those issues.





[JMS_SPEC-12] Message producer confirms aka async message production. Created: 23/May/11  Updated: 05/Mar/12  Resolved: 05/Mar/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0

Type: New Feature Priority: Major
Reporter: colincrist Assignee: Nigel Deakin
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-43 New API to send a message with async ... Resolved

 Description   

The synchronous 1.1 JMS API has an impact on how a single thread can produce messages with a session. There is too much waiting around for a reply from the server.

As a JMS client I would like to send a message on a non-transacted session with persistent delivery and receive asynchronous confirmation that it is stable via a callback. The session can then interact with the server in a more efficient manner.

RabbitMQ has a good write up of the functionality http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms.
29West and Tervela have similar capability.
No doubt some JMS implementations have similar capabilities using non-JMS APIs.



 Comments   
Comment by timlfox [ 08/Jun/11 ]

+1 on this feature.

HornetQ was a pioneer with this - it's definitely a must for high throughput reliable message sending.

http://docs.jboss.org/hornetq/2.2.2.Final/user-manual/en/html/send-guarantees.html#asynchronous-send-acknowledgements

Comment by bsnyder [ 10/Jun/11 ]

Agreed, this is one area where there is a hole in the JMS 1.x spec.

Comment by rdohna [ 14/Jun/11 ]

I can see that there are some very-high-throughput use cases for this feature, but you'd need to implement your own two-phase commit, wouldn't you? It's a lot of code every client would have to re-implement... and it's easy to get it wrong and extremely difficult to test. It's quite a chimaera between transactional and non-transactional, isn't it?

I think we should either find a solution that's easier to work with, or choose to leave it out of the standard; it may have to be optimised for every JMS implementation anyway.

Comment by colincrist [ 15/Jun/11 ]

Persistent messaging does not imply container managed transactions. In the classic J2EE world the way to do persistent messaging and database co-ordination is via XA. This is fine for many use cases but I have found JMS used a great deal without a J2EE container and XA is not the only way to avoid data loss although it does require a bit of coding to co-ordinate

If say on some thread(s) messages are sent whilst on another the stability confirms are received sometime later then the application can update its store that the message (say an order) has indeed been sent successfully and can also do this in batch, keeping the disk I/O under control. This approach leads to a flurry of application generated duplicate messages on recovery as the application has to send messages it has not seen stability confirms for but this is the price you pay for scalability. On the plus side there is far less waiting around to co-ordinate disk writes via XA so you get a hugh increase in throughput, 10s-100s of times faster is not uncommon.

The implementation of this part of the API is up to the provider and its performance would be another differentiator between products.

Comment by rdohna [ 16/Jun/11 ]

NON_PERSISTENT means at-most-once message delivery. PERSISTENT currently (as of JMS 1.1) means once-and-only-once message delivery. I understand that this issue requests something else, as it doesn't want to pay the price for the transaction overhead, but still wants guaranteed delivery.

This means that you'd have to mark the reason for the message as "in progress" before you send the message. When you receive an ack, you'd mark that status as "done". This as a manual two-phase commit, isn't it?

Now whenever the sender or the receiver fails, there are two options: If the receiver is idempotent, you can resend all "in progress" messages... that's a new at-least-once message delivery and not yet supported by JMS... there may be use cases for this.

But if you still require full once-and-only-once guarantee, there has to be some resolution mechanism to re-sync the status of the sender and the receiver. Distributed transactions have such mechanisms, but that's expensive... and I can see no way around that.

If JMS 2.0 defines a at-least-once delivery guarantee, I'd prefer not to have every client to repeat that code, but to hide it somehow at a lower layer. But I don't have any good ideas, yet.

Comment by abien [ 18/Jun/11 ]

+1 for callback. But why just with persistent messages? Could be also interesting for transient messages.

Comment by Nigel Deakin [ 05/Mar/12 ]

This requirement appears to have been satisfied by JMS_SPEC-43, which was included in the JMS 2.0 Early Draft. Please review that draft and provide any comments.

That other issue appears to be a duplicate of this one. Given that the other issue contains details of the proposed changes I will close this issue as being a duplicate. Feel free to make comments on the other issue, or directly to users@jms-spec.java.net.





[JMS_SPEC-115] Remove the statement that portable applications should only have one consumer per queue Created: 19/Feb/13  Updated: 20/Mar/13  Resolved: 25/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fd20-doc-added

 Description   

The JMS 1.1 specification, in section 4.4.9 "Multiple Sessions" states that

For PTP, JMS does not specify the semantics of concurrent QueueReceivers for
the same Queue; however, JMS does not prohibit a provider from supporting
this. Therefore, message delivery to multiple QueueReceivers will depend on the
JMS provider's implementation. Applications that depend on delivery to
multiple QueueReceivers are not portable

This means that a JMS provider is not required to support multiple consumers on the same queue, and that although JMS providers are allowed to do so, any application which depends on this is not portable.

I think that statement is obsolete now that all modern JMS providers allow multiple consumers on a queue. It is also anomalous now that JMS 2.0 requires shared subscriptions to allow multiple consumers.

It is therefore proposed that the section above be reworded to state that a queue may have multiple consumers, but that JMS does not define how messages from a queue are distributed amongst multiple consumers (i.e. there is no requirement for load-balancing etc).

Although JMS does not define how many concurrent consumers on a queue or shared subscription must be supported, providers are expected to support more than one consumer.



 Comments   
Comment by Nigel Deakin [ 25/Feb/13 ]

In the JMS 2.0 final draft, a new section 4.1.2 "Queue semantics" has been added. Significant text in bold:

When point-to-point messaging is being used, an application sends messages to a queue.

An application may consume messages from the queue by creating a consumer (a MessageConsumer, JMSConsumer or QueueReceiver object) on that queue. A consumer may be used to consume messages either synchronously or asynchronously.

A queue may have more than one consumer. Each message in the queue is delivered to only one consumer.

A consumer may be configured to use a message selector. In this case only messages whose properties match the message selector will be delivered to the consumer. Messages which are not selected remain on the queue or are delivered to another consumer.

The order in which an individual consumer receives messages is described in section 6.2.9 “Message order” below.
By definition, if a consumer uses a message selector, or there are other consumers on the same queue, then a consumer may not receive all the messages on the queue. However those messages that are delivered to the consumer will be delivered in the order defined in section 6.2.9.

Apart from the requirements of any message selectors, JMS does not define how messages are distributed between multiple consumers on the same queue.

A corresponding new section 4.2.2 "Topic semantics" has been added. Significant text in bold:

When pub/sub messaging is being used, an application sends messages to a topic.

An application consumes messages from a topic by creating a subscription on that topic, and creating a consumer (a MessageConsumer, JMSConsumer or TopicSubscriber object) on that subscription.

A subscription may be thought of as an entity within the JMS provider itself whereas a consumer is a JMS object within the application.

A subscription will receive a copy of every message that is sent to the topic after the subscription is created, except if a message selector is specified. If a message selector is specified then only those messages whose properties match the message selector will be added to the subscription.

Each copy of the message is treated as a completely separate message. Work done on one copy has no effect on any other; acknowledging one does not acknowledge any other; one message may be delivered immediately, while another waits for its consumer to process messages ahead of it.

Some subscriptions are restricted to a single consumer. In this case all the messages in the subscription are delivered to that consumer. Some subscriptions allow multiple consumers. In this case each message in the subscription is delivered to only one consumer. JMS does not define how messages are distributed between multiple consumers on the same subscription.

The order in which messages are delivered to a consumer is described in section 6.2.10 “Message order” below. By definition, if a subscription uses a message selector, or there are other consumers on the same subscription, then a consumer may not receive all the messages sent to the topic. However those messages that are delivered to the consumer will be delivered in the order defined in section 6.2.10.





[JMS_SPEC-114] Clarify javadoc descriptions of XAQueueConnection#createSession and XATopicSession#createSession Created: 14/Feb/13  Updated: 20/Mar/13  Resolved: 14/Feb/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0FD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: jms20-fd20-doc-added

 Description   

In JMS 1.1 the javadoc description of Connection#createSession is "Creates an Session object...Returns: a Session object"
http://docs.oracle.com/javaee/6/api/javax/jms/XAConnection.html#createSession%28boolean,%20int%29

However the javadoc description of XAQueueConnection.html#createQueueSession is "Creates an XAQueueSession object...Returns: a newly created XAQueueSession"
http://docs.oracle.com/javaee/6/api/javax/jms/XAQueueConnection.html#createQueueSession%28boolean,%20int%29

and the javadoc description of XATopicConnection#createTopicSession is "Creates an XATopicSession object...Returns: a newly created XA topic session"
http://docs.oracle.com/javaee/6/api/javax/jms/XATopicConnection.html#createTopicSession%28boolean,%20int%29

The latter two descriptions are inconsistent with the return type. The fact that the first description is consistent with the return type confirms that this is a typo. They should be changed to be consistent with the return type declared in the method signature.

XAQueueConnection.html#createQueueSession should "return a QueueSession" and

XATopicConnection#createTopicSession should "return a TopicSession"



 Comments   
Comment by Nigel Deakin [ 14/Feb/13 ]

Now corrected at

http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/XAQueueConnection.html#createQueueSession%28boolean,%20int%29

http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/XATopicConnection.html#createTopicSession%28boolean,%20int%29





[JMS_SPEC-106] Methods on JMSContext that are disallowed if the context is injected should throw a IllegalStateException not a JMSException Created: 07/Nov/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-240 Implement modified exceptions on JMSC... Closed
Tags: pd20-added

 Description   

Section 11.3.5. "Restrictions on use of injected JMSContext objects" of the draft JMS 2.0 specification lists some methods which may not be used if the JMSContext is injected (container-managed). It specifies that these methods must throw a JMSRuntimeException if the JMSContext is injected.

A better exception to throw would be an IllegalStateRuntimeException since the error is caused by the JMSContext being "in the wrong state" (container-managed).



 Comments   
Comment by Nigel Deakin [ 14/Nov/12 ]

API docs and spec now updated.





[JMS_SPEC-105] Provide API to allow an app server or resource adapter to obtain a XAResource from a JMSContext Created: 30/Oct/12  Updated: 20/Mar/13  Resolved: 20/Mar/13

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 2.0PD
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-233 Implement API to allow an app server ... Closed
Tags: pd20-added

 Description   

JMS 1.1 defined an optional API to allow an application server or resource adapter to obtain a XAResource object corresponding to a Session object. This is the "chapter 8" API, which defines the optional interfaces XAConnectionFactory, XAConnection, XASession and the method XASession#getXAResource().

However there is currently no equivalent API to allow an application server or resource adapter to obtain a XAResource object corresponding to a JMSContext object.

This means that an application server which uses the "chapter 8" API to integrate with a JMS provider (rather than using a resource adapter) cannot support JMSContext properly. The same applies for a generic resource adapter which uses the "chapter 8" API to integrate with any JMS provider.

There are two alternatives:

Option 1

This option follows the same approach as the existing "chapter 8" API

  • Add four new new createXAContext methods to XAConnectionFactory. These are similar to the four existing createContext methods on ConnectionFactory except that they return a XAJMSContext rather than a JMSContext
  • Define a new interface XAJMSContext. This is a subtype of JMSContext with one additional method, getXAResource, which returns a XAResource.

Option 2

  • Simply add a new method getXAResource to the JMSContext

In both cases implementation of the new interfaces and methods would be optional just like the rest of the existing "chapter 8" API is.

It is proposed that option 1 be adopted, but option 2 is mentioned as a possible alternative.

Note that even though the chapter 8 API is optional, and JMS 2.0 encourages the use of a the JCA API rather than the chapter 8 API for integration of a JMS provider and an application server, the chapter 8 API continues to be part of JMS and is valued by some vendors. If we did not implement this change then we would effectively be breaking this API by making it unusable with JMSContext objects.



 Comments   
Comment by clebertsuconic [ 30/Oct/12 ]

Another issue I constantly face over Transactions is... Most Transaction Managers will offer a recovery option, and currently there's no way to register the XAResource to be recovered. There's no public API that would allow that. it would be nice if we could address that. But I think this will probably go beyond the scope of JMS.

Comment by Nigel Deakin [ 30/Oct/12 ]

@clebert: Do you mean there is no standard way for a transaction manager performing recovery to obtain all the XAResource objects it needs to use for recovery? If so then this is more than a JMS issue.

Comment by nwright [ 12/Nov/12 ]

If I understand, it looks like we'd need a hook on the transaction manager API to actively tell it that we (a JMS resource) are a candidate for XA recovery. In which case this does go beyond the scope of JMS, who can we talk to from the JTA spec about this?

I may have the wrong end of the stick however

Comment by Nigel Deakin [ 20/Mar/13 ]

This issue is resolved in the JMS 2.0 final release. Marking issue as resolved with a "fix version" of 2.0





[JMS_SPEC-101] New methods Message.getBody(Class<T> c) and isBodyAssignableTo(Class c) Created: 23/Oct/12  Updated: 20/Mar/13  Resolved: 08/Nov/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: New Feature Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Dependency
blocks MQ-226 Implement new method Message.getBody ... Closed
blocks JMS_SPEC-102 Make JMSConsumer.receivePayload metho... Closed
Tags: pd20-added

 Description   

This is a proposal to add a new method to javax.jms.Message which allows the message payload to be obtained without the need to cast the object to the appropriate subtype first. This can slightly simplify the code of a MessageListener's, onMessage method, where the object passed in is always declared to be a javax.jms.Message.

Here is the proposed API:

	/**
	 * Returns the messages's payload, which must be of the specified type. If
	 * the message has no payload then null is returned. This method may be used
	 * to obtain the payload of any type of message except for
	 * <tt>StreamMessage</tt>.
	 * 
	 * @param c
	 *            The class of the payload.<br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code>.<br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code>. <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>.<br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>.<br/>
	 *            If the message payload is not of the specified type a
	 *            <code>MessageFormatException</code> will be thrown
	 * 
	 * @return the messages's payload
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the payload due to some
	 *                internal error.
	 * @exception MessageFormatException
	 *                if the payload is not of the specified type or, if the
	 *                message is an ObjectMessage, if object deserialization
	 *                fails.
	 * @Exception MessageNotReadableException - if the message is a BytesMessage
	 *                and the message is in write-only mode.
	 */
	<T> T getPayload(Class<T> c) throws JMSException;

This means that instead of something like:

    public void onMessage(Message message) {
        String payload = ((TextMessage) message).getText();

we could have

    public void onMessage(Message message) {
        String payload2 = message.getPayload(String.class); 


 Comments   
Comment by Nigel Deakin [ 23/Oct/12 ]

Here's an updated proposal:

	/**
	 * Returns the messages's payload, which must be assignable to the specified
	 * type. If the message has no payload then null is returned. This method
	 * may be used to obtain the payload of any type of message except for
	 * <tt>StreamMessage</tt>.
	 * 
	 * @param c
	 *            The class of the payload.
	 *            <br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code> or any other class to
	 *            which a String is assignable.
	 *            <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code> or
	 *            any other class to which the payload is assignable.
	 *            <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>.
	 *            <br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>.
	 * 
	 * @return the messages's payload
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the payload due to some
	 *                internal error.
	 * @exception MessageFormatException
	 *                if the message is a <code>StreamMessage</code>, or the
	 *                payload cannot be assigned to the specified type, or the
	 *                message is an <code>ObjectMessage</code> and object deserialization
	 *                fails.
	 * @exception MessageNotReadableException - if the message is a <code>BytesMessage</code>
	 *                and the message is in write-only mode.
	 */
	<T> T getPayload(Class<T> c) throws JMSException;
Comment by Nigel Deakin [ 26/Oct/12 ]

Following discussion on the expert group the name of this proposed method is changed from getPayload to getBody (for consistency with established JMS 1.1 terminology). Minor changes have also been made to the wording. Here's the latest draft API:

	/**
	 * Returns the message body as an object of the specified type. The message
	 * body must be capable of being assigned to the specified type. This means
	 * that the specified class or interface must be either the same as, or a
	 * superclass or superinterface of, the class of the message body. This
	 * method may be used to obtain the body of any type of message except for
	 * <tt>StreamMessage</tt>. If the message has no body then null is returned.
	 * 
	 * @param c
	 *            The type to which the message body should be assigned. <br/>
	 *            If the message is a <code>TextMessage</code> then this should
	 *            be set to <code>String.class</code> or another class to which
	 *            a String is assignable. <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            should be set to <code>java.io.Serializable.class</code> or
	 *            another class to which the payload is assignable. <br/>
	 *            If the message is a <code>MapMessage</code> then this should
	 *            be set to <code>java.util.Map.class</code>. <br/>
	 *            If the message is a <code>BytesMessage</code> then this should
	 *            be set to <code>byte[].class</code>. The
	 *            <code>BytesMessage</code> must not be in write-only mode.
	 * 
	 * @return the message body
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to get the message body due to
	 *                some internal error.
	 * @exception MessageFormatException
	 *                if the message is a <code>StreamMessage</code>, or the
	 *                message body cannot be assigned to the specified type, or
	 *                the message is an <code>ObjectMessage</code> and object
	 *                deserialization fails.
	 * @exception MessageNotReadableException
	 *                if the message is a <code>BytesMessage</code> and the
	 *                message is in write-only mode.
	 */
	<T> T getBody(Class<T> c) throws JMSException;

In addition, there has been a proposal to provide an additional method isBodyAssignableTo which can be used to find out whether a subsequent call to getBody would throw a MessageFormatException. Here it is:

	/**
	 * Returns whether the message body is capable of being assigned to the
	 * specified type. If this method returns true then a subsequent call to the
	 * method <code>getBody</code> with the same type argument would not throw a
	 * MessageFormatException.
	 * <p>
	 * If the message is a <code>StreamMessage</code> then false is returned. If
	 * the message is a <code>ObjectMessage</code> and object deserialization
	 * fails then false is returned. If the message has no body then true is
	 * returned.
	 * 
	 * @param c
	 *            The specified type <br/>
	 *            If the message is a <code>TextMessage</code> then method will
	 *            only return true if this parameter is set to
	 *            <code>String.class</code> or another class to which a String
	 *            is assignable. <br/>
	 *            If the message is a <code>ObjectMessage</code> then this
	 *            method will only return true if this parameter is set to
	 *            <code>java.io.Serializable.class</code> or another class to
	 *            which the payload is assignable. <br/>
	 *            If the message is a <code>MapMessage</code> then this method
	 *            will only return true if this parameter is set to
	 *            <code>java.util.Map.class</code>. <br/>
	 *            If the message is a <code>BytesMessage</code> then this this
	 *            method will only return true if this parameter is set to
	 *            <code>byte[].class</code>.
	 * 
	 * @return whether the message body is capable of being assigned to the
	 *         specified type
	 * 
	 * @exception JMSException
	 *                if the JMS provider fails to return a value due to some
	 *                internal error.
	 * @exception MessageNotReadableException
	 *                if the message is a <code>BytesMessage</code> and the
	 *                message is in write-only mode.
	 */
	boolean isBodyAssignableTo(Class c) throws JMSException;
Comment by Nigel Deakin [ 26/Oct/12 ]

Change issue summary to refer to getBody instead of getPayload.

Comment by Nigel Deakin [ 08/Nov/12 ]

This is now approved and added to the public draft.





[JMS_SPEC-82] Clarify definition of JMSExpiration, replacing GMT with UTC Created: 28/Feb/12  Updated: 21/Sep/12  Resolved: 19/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1, 2.0
Fix Version/s: 2.0PD, 2.0

Type: Improvement Priority: Minor
Reporter: mickhayes Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

N/A


Tags: pd20-added

 Description   

1.1 and the draft 2.0 make multiple references to (Greenwich Mean Time) GMT.
It would be an improvement to remove all reference to GMT in this standard, and replace with UTC instead.



 Comments   
Comment by mickhayes [ 28/Feb/12 ]

I should add that there is some overlap with JMS_SPEC-44, in that it covers GMT-mentioning parts.
Regards,
Mick Hayes.

Comment by Nigel Deakin [ 28/Feb/12 ]

Yes, the reference to GMT is somewhat anachronistic, though I note that the Java SE 7 javadocs are not very consistent in this matter (e.g. the method getTime() on java.util.Date refers to GMT, whereas the method currentTimeMillis() on java.lang.System refers to UTC). However I agree UTC is the way to go.

Adding tag for consideration for the public release.

It is worth adding that although the JMS 1.1 spec refers to "the GMT at the time of the send or publish" it doesn't specify how the time is represented as a long. I would expect implementation will use System.currentTimeMillis() )(which is the number of ms since a certain time in 1970) but there's nothing in the spec that requires this.

Comment by Nigel Deakin [ 19/Sep/12 ]

All references have now been changed from GMT to UTC. In addition the definition of the JMSExpiration message header field has been clarified.

In the JMS 1.1 specification, section 3.4.9 "JMSExpiration", a message's expiration time was defined as "the sum of the time-to-live value specified on the send method and the current GMT value".

However the JMSExpiration header field is a long value and the specification does not define how the expiration time is converted to a long.

This has now been clarified to state that it is "the difference, measured in milliseconds, between the expiration time and midnight, January 1, 1970 UTC." This definition is chosen to be consistent with the java.lang.System method currentTimeMillis.

The updated text can be seen in the JMS 2.0 public draft, section 3.4.9 "JMSExpiration" and in the API docs for the Message method getJMSExpiration.

Comment by Nigel Deakin [ 19/Sep/12 ]

Title changed from "Replace GMT with UTC" to "Clarify definition of JMSExpiration, replacing GMT with UTC"

Comment by Nigel Deakin [ 19/Sep/12 ]

This issue is now resolved in the JMS 2.0 public draft. Marking issue as resolved.





[JMS_SPEC-77] MapMessage.setBytes API discrepancy found in the javadocs Created: 16/Feb/12  Updated: 21/Sep/12  Resolved: 03/Sep/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: 2.0PD, 2.0

Type: Bug Priority: Minor
Reporter: adf59 Assignee: Nigel Deakin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

N/A


Tags: pd20-added

 Description   

MapMessage API source question.

We notice a discrepancy between setBytes method when passing in empty string or null for name. Why does one method throw NullPointerException and why does the other throw IllegalArgumentException?. By the way the original JMS TCK 1.1 test code for this checks for IllegalArgumentException in both cases. This should be corrected in the JavaDoc.

Below is from the source of the latest javadocs.

MapMessage.java (snippet of code)

    /** Sets a byte array value with the specified name into the Map.
      *
      * @param name the name of the byte array
      * @param value the byte array value to set in the Map; the array
      *              is copied so that the value for <CODE>name</CODE> will
      *              not be altered by future modifications
      *
      * @exception JMSException if the JMS provider fails to write the message
      *                         due to some internal error.
      * @exception NullPointerException if the name is null, or if the name is
      *                          an empty string.
      * @exception MessageNotWriteableException if the message is in read-only
      *                                         mode.
      */

    void
    setBytes(String name, byte[] value)
                        throws JMSException;


    /** Sets a portion of the byte array value with the specified name into the
      * Map.
      *
      * @param name the name of the byte array
      * @param value the byte array value to set in the Map
      * @param offset the initial offset within the byte array
      * @param length the number of bytes to use
      *
      * @exception JMSException if the JMS provider fails to write the message
      *                         due to some internal error.
      * @exception IllegalArgumentException if the name is null or if the name is
      *                          an empty string.
      * @exception MessageNotWriteableException if the message is in read-only
      *                                         mode.
      */

    void
    setBytes(String name, byte[] value,
                 int offset, int length)
                        throws JMSException;


 Comments   
Comment by Nigel Deakin [ 22/Feb/12 ]

Tidied up formatting.

Comment by Nigel Deakin [ 22/Feb/12 ]

In JMS 1.1 there are twelve methods on MapMessage of the form setSomething(name, value).

Eleven of them specify that a IllegalArgumentException is thrown "if the name is null or if the name is an empty string."

One of them, setBytes(name, value), specifies that a java.lang.NullPointerException is thrown "if the name is null, or if the name is an empty string."

This looks like an error in the javadocs, and is confirmed by the TCK tests which (you report) expect a IllegalArgumentException in this latter case.

I'll recommend to the expert group that this be fixed in the Public Draft.

Comment by Nigel Deakin [ 03/Sep/12 ]

Now fixed in JMS 2.0 Public Draft





[JMS_SPEC-13] New JMS header type: a Set Created: 23/May/11  Updated: 07/Mar/12  Resolved: 07/Mar/12

Status: Resolved
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: New Feature Priority: Minor
Reporter: colincrist Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates JMS_SPEC-5 Multi-Value Support in Properties Open

 Description   

As a JMS client I would like to populate a set in the message header and have it take part in selectors. The set would be generic somehow and the filter expressions available would "contains" and "not contains"

I cannot come up with a good looking API change to the Message interface to allow this set to be manipulated cleanly other than getStringHeaderSet, getDoubleHeaderSet etc. There must be a better way, perhaps via a builder pattern.

What I really would find useful is the selector:

"MyProperty contains 'AAA' or MyProperty contains 'BBB'"

Use Case:

Consider a multi national orgianisation with many offices (legal entities) and therefore many back office systems and they are all connected via messaging. A single "deal" can span many offices and many clients. When the deal has been agreed a notification would be sent with a "header set" containing all the offices involved in the deal with each back office subscribing to deals where it is a participant and therefore its identifier is in the header set.

Topics and wild carding do not work in this scenario as the number of participating offices is variable.



 Comments   
Comment by colincrist [ 23/May/11 ]

Just seen JMS_SPEC-5 - I think I have just dupe'd it.

Comment by fribeiro [ 24/May/11 ]

It is allright, do you mind voting for it instead?

Comment by Nigel Deakin [ 07/Mar/12 ]

This will be considered as part of JMS_SPEC-5. Closing this issue as a duplicate.





Generated at Mon Aug 31 18:36:17 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.