|
|
|
@ -44,6 +44,7 @@ import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.util.MultiValueMap; |
|
|
|
import org.springframework.util.MultiValueMap; |
|
|
|
import org.springframework.util.PathMatcher; |
|
|
|
import org.springframework.util.PathMatcher; |
|
|
|
|
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Implementation of {@link SubscriptionRegistry} that stores subscriptions |
|
|
|
* Implementation of {@link SubscriptionRegistry} that stores subscriptions |
|
|
|
@ -73,6 +74,7 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry { |
|
|
|
|
|
|
|
|
|
|
|
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; |
|
|
|
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
private String selectorHeaderName = "selector"; |
|
|
|
private String selectorHeaderName = "selector"; |
|
|
|
|
|
|
|
|
|
|
|
private volatile boolean selectorHeaderInUse = false; |
|
|
|
private volatile boolean selectorHeaderInUse = false; |
|
|
|
@ -114,26 +116,28 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Configure the name of a selector header that a subscription message can |
|
|
|
* Configure the name of a header that a subscription message can have for |
|
|
|
* have in order to filter messages based on their headers. The value of the |
|
|
|
* the purpose of filtering messages matched to the subscription. The header |
|
|
|
* header can use Spring EL expressions against message headers. |
|
|
|
* value is expected to be a Spring EL boolean expression to be applied to |
|
|
|
* <p>For example the following expression expects a header called "foo" to |
|
|
|
* the headers of messages matched to the subscription. |
|
|
|
* have the value "bar": |
|
|
|
* <p>For example: |
|
|
|
* <pre> |
|
|
|
* <pre> |
|
|
|
* headers.foo == 'bar' |
|
|
|
* headers.foo == 'bar' |
|
|
|
* </pre> |
|
|
|
* </pre> |
|
|
|
* <p>By default this is set to "selector". |
|
|
|
* <p>By default this is set to "selector". You can set it to a different |
|
|
|
|
|
|
|
* name, or to {@code null} to turn off support for a selector header. |
|
|
|
|
|
|
|
* @param selectorHeaderName the name to use for a selector header |
|
|
|
* @since 4.2 |
|
|
|
* @since 4.2 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void setSelectorHeaderName(String selectorHeaderName) { |
|
|
|
public void setSelectorHeaderName(@Nullable String selectorHeaderName) { |
|
|
|
Assert.notNull(selectorHeaderName, "'selectorHeaderName' must not be null"); |
|
|
|
this.selectorHeaderName = StringUtils.hasText(selectorHeaderName) ? selectorHeaderName : null; |
|
|
|
this.selectorHeaderName = selectorHeaderName; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the name for the selector header. |
|
|
|
* Return the name for the selector header name. |
|
|
|
* @since 4.2 |
|
|
|
* @since 4.2 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
@Nullable |
|
|
|
public String getSelectorHeaderName() { |
|
|
|
public String getSelectorHeaderName() { |
|
|
|
return this.selectorHeaderName; |
|
|
|
return this.selectorHeaderName; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -143,25 +147,32 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry { |
|
|
|
protected void addSubscriptionInternal( |
|
|
|
protected void addSubscriptionInternal( |
|
|
|
String sessionId, String subsId, String destination, Message<?> message) { |
|
|
|
String sessionId, String subsId, String destination, Message<?> message) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expression expression = getSelectorExpression(message.getHeaders()); |
|
|
|
|
|
|
|
this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression); |
|
|
|
|
|
|
|
this.destinationCache.updateAfterNewSubscription(destination, sessionId, subsId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
|
|
|
private Expression getSelectorExpression(MessageHeaders headers) { |
|
|
|
Expression expression = null; |
|
|
|
Expression expression = null; |
|
|
|
MessageHeaders headers = message.getHeaders(); |
|
|
|
if (getSelectorHeaderName() != null) { |
|
|
|
String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(getSelectorHeaderName(), headers); |
|
|
|
String selector = SimpMessageHeaderAccessor.getFirstNativeHeader(getSelectorHeaderName(), headers); |
|
|
|
if (selector != null) { |
|
|
|
if (selector != null) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
expression = this.expressionParser.parseExpression(selector); |
|
|
|
expression = this.expressionParser.parseExpression(selector); |
|
|
|
this.selectorHeaderInUse = true; |
|
|
|
this.selectorHeaderInUse = true; |
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
logger.trace("Subscription selector: [" + selector + "]"); |
|
|
|
logger.trace("Subscription selector: [" + selector + "]"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Throwable ex) { |
|
|
|
catch (Throwable ex) { |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
logger.debug("Failed to parse selector: " + selector, ex); |
|
|
|
logger.debug("Failed to parse selector: " + selector, ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
this.subscriptionRegistry.addSubscription(sessionId, subsId, destination, expression); |
|
|
|
return expression; |
|
|
|
this.destinationCache.updateAfterNewSubscription(destination, sessionId, subsId); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
|