*
* @param command The <code>CommandMessage</code> to process.
*/
protected Message manageSubscriptions(CommandMessage command)
{
Message replyMessage = null;
MessageDestination destination = (MessageDestination)getDestination(command);
SubscriptionManager subscriptionManager = destination.getSubscriptionManager();
Object clientId = command.getClientId();
String endpointId = (String)command.getHeader(Message.ENDPOINT_HEADER);
String subtopicString = (String) command.getHeader(AsyncMessage.SUBTOPIC_HEADER_NAME);
ServiceAdapter adapter = destination.getAdapter();
if (command.getOperation() == CommandMessage.SUBSCRIBE_OPERATION)
{
String selectorExpr = (String) command.getHeader(CommandMessage.SELECTOR_HEADER);
getMessageBroker().inspectChannel(command, destination);
// Give MessagingAdapter a chance to block the subscribe.
if ((adapter instanceof MessagingAdapter))
((MessagingAdapter)adapter).getSecurityConstraintManager().assertSubscribeAuthorization();
try
{
/*
* This allows parallel add/remove subscribe calls (protected by the
* concurrent hash table) but prevents us from doing any table mods
* when the getSubscriptionState method is active
*/
subscribeLock.readLock().lock();
if (adapter.handlesSubscriptions())
{
replyMessage = (Message) adapter.manage(command);
}
else
{
testSelector(selectorExpr, command);
}
/*
* Even if the adapter is managing the subscription, we still need to
* register this with the subscription manager so that we can match the
* endpoint with the clientId. I am not sure I like this though because
* now the subscription is registered both with the adapter and with our
* system so keeping them in sync is potentially problematic. Also, it
* seems like the adapter should have the option to manage endpoints themselves?
*/
subscriptionManager.addSubscriber(clientId, selectorExpr, subtopicString, endpointId);
}
finally
{
subscribeLock.readLock().unlock();
}
if (replyMessage == null)
replyMessage = new AcknowledgeMessage();
}
else if (command.getOperation() == CommandMessage.UNSUBSCRIBE_OPERATION)
{
// Give MessagingAdapter a chance to block the unsubscribe.
if ((adapter instanceof MessagingAdapter))
((MessagingAdapter)adapter).getSecurityConstraintManager().assertSubscribeAuthorization();
String selectorExpr = (String) command.getHeader(CommandMessage.SELECTOR_HEADER);
try
{
subscribeLock.readLock().lock();
if (adapter.handlesSubscriptions())
{
replyMessage = (Message) adapter.manage(command);
}
subscriptionManager.removeSubscriber(clientId, selectorExpr, subtopicString, endpointId);
}
finally
{
subscribeLock.readLock().unlock();
}
if (replyMessage == null)
replyMessage = new AcknowledgeMessage();
}
else if (command.getOperation() == CommandMessage.MULTI_SUBSCRIBE_OPERATION)
{
getMessageBroker().inspectChannel(command, destination);
// Give MessagingAdapter a chance to block the multi subscribe.
if ((adapter instanceof MessagingAdapter))
((MessagingAdapter)adapter).getSecurityConstraintManager().assertSubscribeAuthorization();
try
{
/*
* This allows parallel add/remove subscribe calls (protected by the
* concurrent hash table) but prevents us from doing any table mods
* when the getSubscriptionState method is active
*/
subscribeLock.readLock().lock();
if (adapter.handlesSubscriptions())
{
replyMessage = (Message) adapter.manage(command);
}
// Deals with legacy collection setting
Object[] adds = getObjectArrayFromHeader(command.getHeader(CommandMessage.ADD_SUBSCRIPTIONS));
Object[] rems = getObjectArrayFromHeader(command.getHeader(CommandMessage.REMOVE_SUBSCRIPTIONS));
if (adds != null)
{
for (int i = 0; i < adds.length; i++)
{
String ss = (String) adds[i];
int ix = ss.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
if (ix != -1)
{
String subtopic = (ix == 0 ? null : ss.substring(0, ix));
String selector = ss.substring(ix+CommandMessage.SUBTOPIC_SEPARATOR.length());
if (selector.length() == 0)
selector = null;
subscriptionManager.addSubscriber(clientId, selector, subtopic, endpointId);
}
// invalid message
}
}
if (rems != null)
{
for (int i = 0; i < rems.length; i++)
{
String ss = (String) rems[i];
int ix = ss.indexOf(CommandMessage.SUBTOPIC_SEPARATOR);
if (ix != -1)
{
String subtopic = (ix == 0 ? null : ss.substring(0, ix));
String selector = ss.substring(ix+CommandMessage.SUBTOPIC_SEPARATOR.length());
if (selector.length() == 0)
selector = null;
subscriptionManager.removeSubscriber(clientId, selector, subtopic, endpointId);
}
}
}
}
finally
{
subscribeLock.readLock().unlock();
}
if (replyMessage == null)
replyMessage = new AcknowledgeMessage();
}
else if (command.getOperation() == CommandMessage.POLL_OPERATION)
{
// This code path handles poll messages sent by Consumer.receive().
// This API should not trigger server side waits, so we invoke poll
// and if there are no queued messages for this Consumer instance we
// return an empty acknowledgement immediately.
MessageClient client = null;
try
{
client = subscriptionManager.getMessageClient(clientId, endpointId);
if (client != null)
{
if (adapter.handlesSubscriptions())
{
List missedMessages = (List)adapter.manage(command);
if (missedMessages != null && !missedMessages.isEmpty())
{
MessageBroker broker = getMessageBroker();
for (Iterator iter = missedMessages.iterator(); iter.hasNext();)
broker.routeMessageToMessageClient((Message)iter.next(), client);
}
}
FlushResult flushResult = client.getFlexClient().poll(client);
List messagesToReturn = (flushResult != null) ? flushResult.getMessages() : null;
if (messagesToReturn != null && !messagesToReturn.isEmpty())
{
replyMessage = new CommandMessage(CommandMessage.CLIENT_SYNC_OPERATION);
replyMessage.setBody(messagesToReturn.toArray());
}
else
{
replyMessage = new AcknowledgeMessage();
}