users@jms-spec.java.net

[jms-spec users] [jsr343-experts] Re: (JMS_SPEC-65) Clarify use of NoLocal arg when using createDurableSubscriber

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Wed, 23 May 2012 12:50:01 +0100

I made these proposals a week ago on Tues 15th May. I haven't received any comments so far. Can EG members please take a
look and let me know what they think?

It's simplest to read this in my comment on the JIRA issue at
http://java.net/jira/browse/JMS_SPEC-65#action_339660
You can see a summary of the proposals at the end of that comment (or at the end of this email)

Nigel


On 15/05/2012 15:27, Nigel Deakin wrote:
> On 09/01/2012 17:35, Nigel Deakin wrote:
>> I refer to this issue:
>> http://java.net/jira/browse/JMS_SPEC-65
>
> This was discussed and agreed some time ago before the early draft, but I'd like to re-open discussion of a possible
> clarification.
>
> You will remember that this issue was 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."
> (http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/Session.html#createDurableSubscriber%28javax.jms.Topic,%20java.lang.String,%20java.lang.String,%20boolean%29)
>
>
> However it has been pointed out to me that further clarification may be needed. Please read the following discussion,
> and review the proposed amendments at the end.
>
> You may find it easier to review the formatted version that I have added to the JIRA issue at
> http://java.net/jira/browse/JMS_SPEC-65#action_339660
>
> When you've had a look, please let me know what you think.
>
> Nigel
>
> ---------------------------------------------------------------------------------------------------------------------
>
> 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.
>
> Any comments? Do you agree?