INT-2449 Fix PubSub Subscriber Accounting

PubSub channel subscriber accounting was incorrect; the counter
was not decremented when unsubscribing.

The handler count, reflecting the current number of subscriptions,
was maintained in the AbstractSubscribableChannel. The count really
belongs in the dispatcher and calls should be delegated to it, particularly
for a custom ASC, which might have a custom AbstractDispatcher.

However, it is possible (although perhaps rare) that someone
could implement a custom channel with a custom dispatcher that
is *not* a subclass of AbstractDispatcher.

Therefore, we now delegate to the dispatcher if we can, and
revert to a counter in the channel if we can't.

Also, the asymmetric accounting in this case is resolved; the
counter is decremented when a subscriber unsubscribes.

Polishing - factor out common code.
This commit is contained in:
Gary Russell
2012-02-22 17:16:20 -05:00
parent c5e3bcf245
commit b6b4e25efc
3 changed files with 92 additions and 22 deletions

View File

@@ -24,8 +24,8 @@ import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageDispatchingException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.dispatcher.AbstractDispatcher;
import org.springframework.integration.dispatcher.MessageDispatcher;
import org.springframework.integration.dispatcher.UnicastingDispatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -44,20 +44,31 @@ public abstract class AbstractSubscribableChannel extends AbstractMessageChannel
public boolean subscribe(MessageHandler handler) {
MessageDispatcher dispatcher = this.getRequiredDispatcher();
boolean added = dispatcher.addHandler(handler);
if (added) {
int counter = handlerCounter.incrementAndGet();
if (logger.isInfoEnabled()) {
logger.info("Channel '" + this.getComponentName() + "' has " + counter + " subscriber(s).");
}
}
this.adjustCounterIfNecessary(dispatcher, added ? 1 : 0);
return added;
}
public boolean unsubscribe(MessageHandler handle) {
if (this.getRequiredDispatcher() instanceof UnicastingDispatcher){
handlerCounter.getAndDecrement();
MessageDispatcher dispatcher = this.getRequiredDispatcher();
boolean removed = dispatcher.removeHandler(handle);
this.adjustCounterIfNecessary(dispatcher, removed ? -1 : 0);
return removed;
}
private void adjustCounterIfNecessary(MessageDispatcher dispatcher, int delta) {
if (delta != 0) {
int counter = 0;
if (dispatcher instanceof AbstractDispatcher) {
counter = ((AbstractDispatcher) dispatcher).getHandlerCount();
}
else {
// some other dispatcher - hand-roll the counter
counter = handlerCounter.addAndGet(delta);
}
if (logger.isInfoEnabled()) {
logger.info("Channel '" + this.getComponentName() + "' has " + counter + " subscriber(s).");
}
}
return this.getRequiredDispatcher().removeHandler(handle);
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @author Iwein Fuld
* @author Oleg Zhurakousky
* @author Gary Russell
*/
public abstract class AbstractDispatcher implements MessageDispatcher {
@@ -79,4 +80,11 @@ public abstract class AbstractDispatcher implements MessageDispatcher {
public String toString() {
return this.getClass().getSimpleName() + " with handlers: " + this.handlers.toString();
}
/**
* @return The current number of handlers
*/
public int getHandlerCount() {
return this.handlers.size();
}
}