Stale development discussion details

The details on the page are not reflective of current state, and were only used in initial discussion of various functionality. They are only preserved for historic reference.

JMS and AMQP behaviour for Durable Subscriptions, Shared Durable Subscriptions, and Shared Non-Durable Subscriptions

Durable Subscription (non-shared)

[Re]create Subscriber and Subscription

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createDurableConsumer(javax.jms.Topic,%20java.lang.String)

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createDurableConsumer(javax.jms.Topic,%20java.lang.String,%20java.lang.String,%20boolean)

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createDurableSubscriber(javax.jms.Topic,%20java.lang.String)

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createDurableSubscriber(javax.jms.Topic,%20java.lang.String,%20java.lang.String,%20boolean)

JMS:

Creates the consumer object, and either creates or resubscribes to the underlying named durable subscription on the given Topic.

Special cases:

Exception cases:

AMQP:

Container name is the ClientID, which MUST have been set to allow use of a non-shared durable subscription.

When closing the JMS subscriber, use Detach(close=false) to leave the subscription in place.

When opening the JMS subscriber:

1. Check locally if the connection already has an active subscriber to a shared durable subscription of the same name on this connection (which is the only connection that can do so due to ClientID enforcement), if so then throw an exception to indicate existing shared durable subscription.

2. Check locally if the connection already has an active subscriber on the non-shared durable subscription of the same name on this connection (which is the only connection that can do so due to ClientID enforcement), if so then throw an exception to indicate existing active subscriber.

3. Check if a non-shared durable subscription already exists but isn't in use by this connection currently:

Attach a receiving link, use "durable-SUBSCRIPTION" as the link name, use a null source to have the broker lookup a matching link terminus for {client container, link name, broker container} representing the subscription.

Inspect the Attach response from the broker. If there is a null Source, no durable subscription of this name existed or was created.

If there was a non-null source, verify the returned source DOES NOT have the "shared" capability, and throw an exception if it does (to indicate that a shared durable subscription with the same subscription name already exists).

4. Try to re-attach to an existing non-shared durable subscription:

If there was a non-null source in the above Attach response from the broker, inspect the details to ensure they match expectation (e.g selector and no-local filters are absent or present with values as expected, topic address matches). If they do, we are re-attached to a suitable non-shared durable subscription and are finished.

If they don't match, perform unsubscribe(subscriptionName), then proceed to establish a new subscription. If there is a null source then the subscription didnt exist and wasnt created, proceed to create a new one.

5. Create new subscription if required.

Attach a receiving link, use "durable-SUBSCRIPTION" as the link name, use the topic name as the source address, a source terminus expiry of 'never', source terminus durability of 'configuration' (or 'unsettled-state'), and filters for no-local and/or selector if specified. Ensure the attach response meets expectations.

Psuedocode

if(localActiveSharedDurableSubscriber(subscriptionName)) {
    throw new JMSException("exiting shared durable subscription with that name");
}

if(localActiveNonSharedDurableSubscriber(subscriptionName)) {
    throw new JMSException("already active subscriber on subscription");
}

if(existsSharedDurableSubscription(subscriptionName)) {
    throw new JMSException("exiting shared durable subscription with that name");
}

if(existsInactiveNonSharedDurableSubscription(subscriptionName, topic, noLocal)) {
    if(subscriptionDetailsDontMatch){
        unsubscribe(subscriptionName);
    } else {
        // Use existing subscription/subscriber
        return;
    }
}

createNewNonSharedDurableSubscription();

End Subscription

Ending the subscription is handled by the #Unsubscribe method.


Shared Durable Subscription

[Re]create Subscriber and Subscription

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createSharedDurableConsumer(javax.jms.Topic,%20java.lang.String)

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createSharedDurableConsumer(javax.jms.Topic,%20java.lang.String,%20java.lang.String)

JMS:

Creates the consumer object, and either creates or (re)subscribes to the underlying named shared durable subscription on the given Topic.

Special cases:

Exception cases:

AMQP:

When opening the JMS subscriber:

1. Check locally if there is an active shared durable subscriber which already uses the given subscription name:

If there is, verify the selector and topic details match. Throw exception if they dont match (active subscriber, cant unsubscribe). If they do match, skip to step 4.

2. Check locally that there isn't an active non-shared durable subscriber which already uses the given subscription name:

3. Check if a non-shared durable subscription already exists but isn't in use by this connection currently:

Attach a receiving link, use "durable-SUBSCRIPTION" as the link name, use a null source to have the broker lookup a matching link terminus for {client container, link name, broker container} representing the subscription.

Inspect the Attach response from the broker. If there was a non-null source and it DOES NOT contain the "shared" capability, Detach(close=false) and throw an exception to indicate presence of an existing non-shared durable subscription.

4. Try to re-attach to an existing shared durable subscription, or create a new one.

If we skipped from step 1, attach a link as in step 3, otherwise reuse the existing Attach response from above. Ensure the response details match expectation (e.g selector filter is absent or present with value as expected, source address matches expectation, "shared" source capability, expected source durability and expiry). Detach(close=false) to leave the durable subscription in place.

If there is a null source then the subscription didnt exist and wasnt created, proceed to create a new one, step 5.

If they do match, we [re-]attached to a suitable shared subscription (Note: we need to expect link-stealing here when we are not using a ClientID). Proceed to create a new subscriber link on the subscription, step 6, then Detach(close=false) to leave the durable subscription in place.

If they don't match, perform unsubscribe(subscriptionName), then if successfull proceed to establish a new subscription, step 5.

5. Create new shared subscription if required.

Attach a receiving link, use "durable-SUBSCRIPTION" as the link name, use a source with address "topic?subscription=SUBSCRIPTION" (or maybe "topic[SUBSCRIPTION]"), a source terminus expiry of 'never', source terminus durability of 'configuration' (but NOT 'unsettled-state'), filters for no-local and/or selector if specified, and the "shared" source capability. Ensure the attach response meets expectations.

If they do match, we are attached to a suitable shared subscription. Detach(close=false) to leave the durable subscription in place.

6. Create new shared subscriber.

Attach another receiving link to use for the subscriber, with a unique link name, use a source with address "topic?subscription=SUBSCRIPTION" (or maybe "topic[SUBSCRIPTION]"), a source terminus expiry of 'link-detach', source terminus durability of 'none', and filters for no-local and/or selector if specified, and the "shared" capability. Ensure the attach response meets expectations.

TODO: describe use of filter map key names to provide for 'default filter' for selector filter on new subscriber source terminus.

Psuedocode

if(localActiveSharedDurableSubscriber(subscriptionName)) {
    if(subscriptionDetailsDontMatch){
        throw new JMSException("existing shared durable subscription with that name has active subscribers and uses different topic/selector");
    }
} else {
    if(localActiveNonSharedDurableSubscriber(subscriptionName)) {
        throw new JMSException("existing non-shared durable subscription with that name");
    }

    if(existsNonSharedDurableSubscription(subscriptionName)) {
        throw new JMSException("exiting non-shared durable subscription with that name");
    }
}

if(existsInactiveSharedDurableSubscription(subscriptionName, topic)) {
    if(subscriptionDetailsDontMatch){
        unsubscribe(subscriptionName);
    } else {
        // Use existing subscription, create new subscriber
        createNewSharedDurableSubscriber();
        return;
    }
}

createNewSharedDurableSubscription();
createNewSharedDurableSubscriber();

End Subscription

Ending the subscription is handled by the #Unsubscribe method.


Unsubscribe

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#unsubscribe(java.lang.String)

JMS:

This method doubles to delete both shared and non-shared durable subscriptions, and provides no way to know in advance which type is being removed, or what Topic the subscription was made against..

Exception cases:

AMQP:

1. If the client has an existing active subscriber on the named [shared or non-shared] durable subscription on the connection attempting unsubscribe, throw an exception.

2. Attach a receiving link. Use "durable-SUBSCRIPTION" as the link name, use a null source to have the broker lookup a matching link terminus for {client container, link name, broker container} representing the subscription.

If the Attach response has a null source, interpret this to mean there was no subscription with the given name, detach and throw an exception to indicate an illegal subscription name.

3. Try to end the subscription.

Close the link using Detach(close=true) to end the subscription we have discovered. Inspect the detach reponse, ensure it matches (close=true) and contains no error. Throw exception if otherwise.

(Note: if the durable subscription is shared and there are other consumer links attached, the request to close will be denied by responding Detach(close=false) with an error).


Shared Subscription (non-durable)

[Re]create Subscriber and Subscription

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createSharedConsumer(javax.jms.Topic,%20java.lang.String)

http://docs.oracle.com/javaee/7/api/javax/jms/Session.html#createSharedConsumer(javax.jms.Topic,%20java.lang.String,%20java.lang.String)

JMS:

Creates the consumer object, and either creates or (re)subscribes to the underlying named shared subscription on the given Topic.

Exception cases:

AMQP:

When opening the JMS subscriber:

1. Check locally if there is an active non-durable shared subscriber which already uses the given subscription name:

If there is, verify the selector and topic details in use, if they dont match then throw exception due to the active subscriber using different details.

If there is and the topic+selector details do match, proceed to step 4.

If there is not an active subscriber, proceed to step 2.

2. Try to re-attach to an existing non-durable shared subscription, or create a new one.

If we know from step 1 that there is no active subscriber on this connection, we must check for an existing subscription with the given name, and create it if it doesnt exist.

Attach a receiving link, use "non-durable-SUBSCRIPTION" as the link name, use a null source to have the broker lookup a matching link terminus for {client container, link name, broker container} representing the subscription.

Inspect the Attach response from the broker:

If there is a null source then the subscription didnt exist and wasnt created, proceed tocreate a new one, step 3.

If there is a non-null source ensure the response details match expectation (e.g selector filter is absent or present with value as expected, source address matches expectation, "shared" source capability).

If they do match, we [re-]attached to a suitable non-durable shared subscription. Proceed to create a new subscriber on the subscription, step 4. Then Detach(close=false) to leave the subscription (via the psuedo-node) in place. (Note: we need to expect link-stealing here when not using a ClientID, as multiple connections could exist with the same container ID).

If they don't match, throw an exception to indicate the reason (e.g different topic or selector, no "shared" capability).

3. Create a new non-durable shared subscription if required.

Attach a receiving link, use a source with address "topic?subscription=non-durable-SUBSCRIPTION" (or maybe "topic[non-durable-SUBSCRIPTION]"), a source terminus expiry of 'never', source terminus durability of 'none', filters for no-local and/or selector if specified, the "shared" source capability, and capability TODO:"DESTROY_ON_LAST_ACTIVE_CONSUMER_DETACH" to indicate the subscription psuedo-node should self-destruct when last active subscriber link detaches (or the encompassing creating session ends without a subscriber link being attached first), as well as capability TODO:"DONT_PREVENT_SUBSCRIPTION_END" to ensure this creating link is never considered an active subscriber and thus cant prevent the subscription node removal. Ensure the attach response meets expectations. If they do match, we are attached to a suitable shared subscription. Proceed to create a new subscriber on the subscription, step 4. Then Detach(close=false) the creating link to leave the subscription in place. (Note: we need to expect link-stealing here when not using a ClientID, as multiple connections could exist with the same container ID).

4. Create new non-durable shared subscriber.

Attach another receiving link to use for the subscriber, with a unique link name, use a source with address "topic?subscription=non-durable-SUBSCRIPTION" (or maybe "topic[non-durable-SUBSCRIPTION]"), a source terminus expiry of 'link-detach', source terminus durability of 'none', filters for no-local and/or selector if specified, and the "shared" capability. Ensure the attach response meets expectations.

TODO: describe use of filter map key names to provide for 'default filter' on source of new subscriber source terminus.

Psuedocode


if(localActiveSharedNonDurableSubscriber(subscriptionName)) {
    if(subscriptionDetailsDontMatch){
        throw new JMSException("existing shared subscription with same name has active subscribers and uses different topic/selector");
    } else {
       createNewSharedNonDurableSubscriber();
       return;
    }
} else {
    if(existsSharedNonDurableSubscription(subscriptionName, topic)) {
        if(subscriptionDetailsDontMatch){
            throw new JMSException("existing shared subscription with same name has active subscribers and uses different topic/selector");
        } else {
            createNewSharedNonDurableSubscriber();
            return;
        }
    }
}

createNewSharedNonDurableSubscription();
createNewSharedNonDurableSubscriber();

End Subscription

Close all subscribers, subscription ends as it is non-durable.

JMSMapping/Subscriptions (last edited 2017-06-26 10:11:10 by gemmellr)