(selectorString == null ? "" : ", selector '" + selectorString + "'") +
(subscriptionName == null ? "" : ", subscription '" + subscriptionName + "'") +
(noLocal ? ", noLocal" : ""));
}
ManagedDestination mDest = dm.getDestination(jmsDestination.getName(), jmsDestination.isQueue());
if (mDest == null)
{
throw new InvalidDestinationException("No such destination: " + jmsDestination + " has it been deployed?");
}
if (jmsDestination.isTemporary())
{
// Can only create a consumer for a temporary destination on the same connection
// that created it
if (!connectionEndpoint.hasTemporaryDestination(jmsDestination))
{
String msg = "Cannot create a message consumer on a different connection " +
"to that which created the temporary destination";
throw new IllegalStateException(msg);
}
}
String consumerID = GUIDGenerator.generateGUID();
// Always validate the selector first
Selector selector = null;
if (selectorString != null)
{
selector = new Selector(selectorString);
}
Queue queue;
if (jmsDestination.isTopic())
{
if (subscriptionName == null)
{
// non-durable subscription
if (log.isTraceEnabled()) { log.trace(this + " creating new non-durable subscription on " + jmsDestination); }
// Create the non durable sub
queue = new MessagingQueue(nodeId, GUIDGenerator.generateGUID(),
idm.getID(), ms, pm, false,
mDest.getMaxSize(), selector,
mDest.getFullSize(),
mDest.getPageSize(),
mDest.getDownCacheSize(),
mDest.isClustered(),
sp.getRecoverDeliveriesTimeout());
JMSCondition topicCond = new JMSCondition(false, jmsDestination.getName());
postOffice.addBinding(new Binding(topicCond, queue, false), false);
queue.activate();
String counterName = TopicService.SUBSCRIPTION_MESSAGECOUNTER_PREFIX + queue.getName();
int dayLimitToUse = mDest.getMessageCounterHistoryDayLimit();
if (dayLimitToUse == -1)
{
//Use override on server peer
dayLimitToUse = sp.getDefaultMessageCounterHistoryDayLimit();
}
//We don't create message counters on temp topics
if (!mDest.isTemporary())
{
MessageCounter counter = new MessageCounter(counterName, null, queue, true, false, dayLimitToUse);
sp.getMessageCounterManager().registerMessageCounter(counterName, counter);
}
}
else
{
if (jmsDestination.isTemporary())
{
throw new InvalidDestinationException("Cannot create a durable subscription on a temporary topic");
}
// We have a durable subscription, look it up
String clientID = connectionEndpoint.getClientID();
if (clientID == null)
{
throw new JMSException("Cannot create durable subscriber without a valid client ID");
}
// See if there any bindings with the same client_id.subscription_name name
String name = MessageQueueNameHelper.createSubscriptionName(clientID, subscriptionName);
Binding binding = postOffice.getBindingForQueueName(name);
if (binding == null)
{
// Does not already exist
if (trace) { log.trace(this + " creating new durable subscription on " + jmsDestination); }
queue = new MessagingQueue(nodeId, name, idm.getID(),
ms, pm, true,
mDest.getMaxSize(), selector,
mDest.getFullSize(),
mDest.getPageSize(),
mDest.getDownCacheSize(),
mDest.isClustered(),
sp.getRecoverDeliveriesTimeout());
// Durable subs must be bound on ALL nodes of the cluster (if clustered)
postOffice.addBinding(new Binding(new JMSCondition(false, jmsDestination.getName()), queue, true),
postOffice.isClustered() && mDest.isClustered());
queue.activate();
//We don't create message counters on temp topics
if (!mDest.isTemporary())
{
String counterName = TopicService.SUBSCRIPTION_MESSAGECOUNTER_PREFIX + queue.getName();
MessageCounter counter =
new MessageCounter(counterName, subscriptionName, queue, true, true,
mDest.getMessageCounterHistoryDayLimit());
sp.getMessageCounterManager().registerMessageCounter(counterName, counter);
}
}
else
{
//Durable sub already exists
queue = binding.queue;
if (trace) { log.trace(this + " subscription " + subscriptionName + " already exists"); }
//Check if it is already has a subscriber
//We can't have more than one subscriber at a time on the durable sub unless it is clustered
//we need this for clustered since otherwise we wouldn't be able to fail over subcribers for the same durable
//sub onto a node which already has one
if (queue.getLocalDistributor().getNumberOfReceivers() > 0 && !mDest.isClustered())
{
throw new IllegalStateException("Cannot create a subscriber on the durable subscription since it already has subscriber(s)");
}
// If the durable sub exists because it is clustered and was created on this node due to a bind on another node
// then it will have no message counter
String counterName = TopicService.SUBSCRIPTION_MESSAGECOUNTER_PREFIX + queue.getName();
boolean createCounter = false;
if (sp.getMessageCounterManager().getMessageCounter(counterName) == null)
{
createCounter = true;
}
// From javax.jms.Session Javadoc (and also JMS 1.1 6.11.1):
// 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.
String filterString = queue.getFilter() != null ? queue.getFilter().getFilterString() : null;
boolean selectorChanged =
(selectorString == null && filterString != null) ||
(filterString == null && selectorString != null) ||
(filterString != null && selectorString != null &&
!filterString.equals(selectorString));
if (trace) { log.trace("selector " + (selectorChanged ? "has" : "has NOT") + " changed"); }
String oldTopicName = ((JMSCondition)binding.condition).getName();
boolean topicChanged = !oldTopicName.equals(jmsDestination.getName());
if (log.isTraceEnabled()) { log.trace("topic " + (topicChanged ? "has" : "has NOT") + " changed"); }
if (selectorChanged || topicChanged)
{
if (trace) { log.trace("topic or selector changed so deleting old subscription"); }
// Unbind the durable subscription
// Durable subs must be unbound on ALL nodes of the cluster
postOffice.removeBinding(queue.getName(), postOffice.isClustered() && mDest.isClustered());
// create a fresh new subscription
queue = new MessagingQueue(nodeId, name, idm.getID(), ms, pm, true,
mDest.getMaxSize(), selector,
mDest.getFullSize(),
mDest.getPageSize(),
mDest.getDownCacheSize(),
mDest.isClustered(),
sp.getRecoverDeliveriesTimeout());
// Durable subs must be bound on ALL nodes of the cluster
postOffice.addBinding(new Binding(new JMSCondition(false, jmsDestination.getName()), queue, true),
postOffice.isClustered() && mDest.isClustered());
queue.activate();
if (!mDest.isTemporary())
{
createCounter = true;
}
}
if (createCounter)
{
MessageCounter counter =
new MessageCounter(counterName, subscriptionName, queue, true, true,
mDest.getMessageCounterHistoryDayLimit());
sp.getMessageCounterManager().registerMessageCounter(counterName, counter);
}
}
}
}
else
{
// Consumer on a jms queue
// Let's find the queue
queue = postOffice.getBindingForQueueName(jmsDestination.getName()).queue;
if (queue == null)
{
throw new IllegalStateException("Cannot find queue: " + jmsDestination.getName());
}
}
int prefetchSize = connectionEndpoint.getPrefetchSize();
Queue dlqToUse = mDest.getDLQ() == null ? defaultDLQ : mDest.getDLQ();
Queue expiryQueueToUse = mDest.getExpiryQueue() == null ? defaultExpiryQueue : mDest.getExpiryQueue();
int maxDeliveryAttemptsToUse = mDest.getMaxDeliveryAttempts() == -1 ? defaultMaxDeliveryAttempts : mDest.getMaxDeliveryAttempts();
long redeliveryDelayToUse = mDest.getRedeliveryDelay() == -1 ? defaultRedeliveryDelay : mDest.getRedeliveryDelay();
//Is the consumer going to have its session state replicated onto a backup node?
boolean replicating = supportsFailover && queue.isClustered() && !(jmsDestination.isTopic() && !queue.isRecoverable());