Allow to customize separator for messaging destinations
In order to be able to use separators like "." (used by default by most broker relays) instead of "/" for destination patterns handling, the PathMatcher used in spring-messaging can now be customized easily thanks to XML websocket namespace or JavaConfig. AntPathMatcher has been updated in order to use the configured path separator instead of an hardcoded "/" for path concatenation. Extension handling is now disabled when the "." separator is configured. Issue: SPR-11660
This commit is contained in:
committed by
Rossen Stoyanchev
parent
b676c41805
commit
928a466b5d
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -55,21 +55,35 @@ public final class DestinationPatternsMessageCondition
|
||||
* @param patterns 0 or more URL patterns; if 0 the condition will match to every request.
|
||||
*/
|
||||
public DestinationPatternsMessageCondition(String... patterns) {
|
||||
this(patterns, null);
|
||||
this(patterns, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional constructor with flags for using suffix pattern (.*) and
|
||||
* trailing slash matches.
|
||||
* Additional constructor with a customized path matcher.
|
||||
* @param patterns the URL patterns to use; if 0, the condition will match to every request.
|
||||
* @param pathMatcher for path matching with patterns
|
||||
* @param pathMatcher the customized path matcher to use with patterns
|
||||
*/
|
||||
public DestinationPatternsMessageCondition(String[] patterns,PathMatcher pathMatcher) {
|
||||
this(asList(patterns), pathMatcher);
|
||||
public DestinationPatternsMessageCondition(String[] patterns, PathMatcher pathMatcher) {
|
||||
this(asList(patterns), pathMatcher, true);
|
||||
}
|
||||
|
||||
private DestinationPatternsMessageCondition(Collection<String> patterns, PathMatcher pathMatcher) {
|
||||
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
|
||||
/**
|
||||
* Additional constructor with a customized path matcher and a flag specifying if
|
||||
* the destination patterns should be prepended with "/".
|
||||
* @param patterns the URL patterns to use; if 0, the condition will match to every request.
|
||||
* @param pathMatcher the customized path matcher to use with patterns
|
||||
* @param prependLeadingSlash to specify whether each pattern that is not empty and does not
|
||||
* start with "/" will be prepended with "/" or not
|
||||
* @since 4.1
|
||||
*/
|
||||
public DestinationPatternsMessageCondition(String[] patterns, PathMatcher pathMatcher,
|
||||
boolean prependLeadingSlash) {
|
||||
this(asList(patterns), pathMatcher, prependLeadingSlash);
|
||||
}
|
||||
|
||||
private DestinationPatternsMessageCondition(Collection<String> patterns,
|
||||
PathMatcher pathMatcher, boolean prependLeadingSlash) {
|
||||
this.patterns = Collections.unmodifiableSet(initializePatterns(patterns, prependLeadingSlash));
|
||||
this.pathMatcher = (pathMatcher != null) ? pathMatcher : new AntPathMatcher();
|
||||
}
|
||||
|
||||
@@ -77,13 +91,14 @@ public final class DestinationPatternsMessageCondition
|
||||
return patterns != null ? Arrays.asList(patterns) : Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
private static Set<String> initializePatterns(Collection<String> patterns,
|
||||
boolean prependLeadingSlash) {
|
||||
if (patterns == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<String>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/") && prependLeadingSlash) {
|
||||
pattern = "/" + pattern;
|
||||
}
|
||||
result.add(pattern);
|
||||
@@ -134,7 +149,7 @@ public final class DestinationPatternsMessageCondition
|
||||
else {
|
||||
result.add("");
|
||||
}
|
||||
return new DestinationPatternsMessageCondition(result, this.pathMatcher);
|
||||
return new DestinationPatternsMessageCondition(result, this.pathMatcher, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +184,7 @@ public final class DestinationPatternsMessageCondition
|
||||
}
|
||||
|
||||
Collections.sort(matches, this.pathMatcher.getPatternComparator(destination));
|
||||
return new DestinationPatternsMessageCondition(matches, this.pathMatcher);
|
||||
return new DestinationPatternsMessageCondition(matches, this.pathMatcher, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,7 +52,6 @@ import org.springframework.messaging.handler.invocation.AbstractExceptionHandler
|
||||
import org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.messaging.simp.SimpAttributes;
|
||||
import org.springframework.messaging.simp.SimpAttributesContextHolder;
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageMappingInfo;
|
||||
@@ -94,7 +93,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
|
||||
private ConversionService conversionService = new DefaultFormattingConversionService();
|
||||
|
||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||
private PathMatcher pathMatcher;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
@@ -113,7 +112,22 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
* @param brokerTemplate a messaging template to send application messages to the broker
|
||||
*/
|
||||
public SimpAnnotationMethodMessageHandler(SubscribableChannel clientInboundChannel,
|
||||
MessageChannel clientOutboundChannel, SimpMessageSendingOperations brokerTemplate) {
|
||||
MessageChannel clientOutboundChannel, SimpMessageSendingOperations brokerTemplate) {
|
||||
this(clientInboundChannel, clientOutboundChannel, brokerTemplate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of SimpAnnotationMethodMessageHandler with the given
|
||||
* message channels and broker messaging template.
|
||||
* @param clientInboundChannel the channel for receiving messages from clients (e.g. WebSocket clients)
|
||||
* @param clientOutboundChannel the channel for messages to clients (e.g. WebSocket clients)
|
||||
* @param brokerTemplate a messaging template to send application messages to the broker
|
||||
* @param pathSeparator the path separator to use with the destination patterns
|
||||
* @since 4.1
|
||||
*/
|
||||
public SimpAnnotationMethodMessageHandler(SubscribableChannel clientInboundChannel,
|
||||
MessageChannel clientOutboundChannel, SimpMessageSendingOperations brokerTemplate,
|
||||
String pathSeparator) {
|
||||
|
||||
Assert.notNull(clientInboundChannel, "clientInboundChannel must not be null");
|
||||
Assert.notNull(clientOutboundChannel, "clientOutboundChannel must not be null");
|
||||
@@ -122,6 +136,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
this.clientInboundChannel = clientInboundChannel;
|
||||
this.clientMessagingTemplate = new SimpMessagingTemplate(clientOutboundChannel);
|
||||
this.brokerTemplate = brokerTemplate;
|
||||
this.pathMatcher = new AntPathMatcher(pathSeparator);
|
||||
|
||||
Collection<MessageConverter> converters = new ArrayList<MessageConverter>();
|
||||
converters.add(new StringMessageConverter());
|
||||
@@ -318,31 +333,31 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
MessageMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping messageAnnot = AnnotationUtils.findAnnotation(method, MessageMapping.class);
|
||||
if (messageAnnot != null) {
|
||||
SimpMessageMappingInfo result = createMessageMappingCondition(messageAnnot);
|
||||
SimpMessageMappingInfo result = createMessageMappingCondition(messageAnnot, typeAnnotation == null);
|
||||
if (typeAnnotation != null) {
|
||||
result = createMessageMappingCondition(typeAnnotation).combine(result);
|
||||
result = createMessageMappingCondition(typeAnnotation, false).combine(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
SubscribeMapping subsribeAnnotation = AnnotationUtils.findAnnotation(method, SubscribeMapping.class);
|
||||
if (subsribeAnnotation != null) {
|
||||
SimpMessageMappingInfo result = createSubscribeCondition(subsribeAnnotation);
|
||||
SimpMessageMappingInfo result = createSubscribeCondition(subsribeAnnotation, typeAnnotation == null);
|
||||
if (typeAnnotation != null) {
|
||||
result = createMessageMappingCondition(typeAnnotation).combine(result);
|
||||
result = createMessageMappingCondition(typeAnnotation, false).combine(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SimpMessageMappingInfo createMessageMappingCondition(MessageMapping annotation) {
|
||||
private SimpMessageMappingInfo createMessageMappingCondition(MessageMapping annotation, boolean prependLeadingSlash) {
|
||||
return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.MESSAGE,
|
||||
new DestinationPatternsMessageCondition(annotation.value()));
|
||||
new DestinationPatternsMessageCondition(annotation.value(), this.pathMatcher, prependLeadingSlash));
|
||||
}
|
||||
|
||||
private SimpMessageMappingInfo createSubscribeCondition(SubscribeMapping annotation) {
|
||||
private SimpMessageMappingInfo createSubscribeCondition(SubscribeMapping annotation, boolean prependLeadingSlash) {
|
||||
return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.SUBSCRIBE,
|
||||
new DestinationPatternsMessageCondition(annotation.value()));
|
||||
new DestinationPatternsMessageCondition(annotation.value(), this.pathMatcher, prependLeadingSlash));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.messaging.support.MessageHeaderInitializer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
/**
|
||||
* A "simple" message broker that recognizes the message types defined in
|
||||
@@ -48,7 +49,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler {
|
||||
|
||||
private final SubscribableChannel brokerChannel;
|
||||
|
||||
private SubscriptionRegistry subscriptionRegistry = new DefaultSubscriptionRegistry();
|
||||
private SubscriptionRegistry subscriptionRegistry;
|
||||
|
||||
private MessageHeaderInitializer headerInitializer;
|
||||
|
||||
@@ -63,6 +64,20 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler {
|
||||
*/
|
||||
public SimpleBrokerMessageHandler(SubscribableChannel clientInboundChannel, MessageChannel clientOutboundChannel,
|
||||
SubscribableChannel brokerChannel, Collection<String> destinationPrefixes) {
|
||||
this(clientInboundChannel, clientOutboundChannel, brokerChannel, destinationPrefixes, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional constructor with a customized path matcher.
|
||||
*
|
||||
* @param clientInboundChannel the channel for receiving messages from clients (e.g. WebSocket clients)
|
||||
* @param clientOutboundChannel the channel for sending messages to clients (e.g. WebSocket clients)
|
||||
* @param brokerChannel the channel for the application to send messages to the broker
|
||||
* @param pathMatcher the path matcher to use
|
||||
* @since 4.1
|
||||
*/
|
||||
public SimpleBrokerMessageHandler(SubscribableChannel clientInboundChannel, MessageChannel clientOutboundChannel,
|
||||
SubscribableChannel brokerChannel, Collection<String> destinationPrefixes, PathMatcher pathMatcher) {
|
||||
|
||||
super(destinationPrefixes);
|
||||
Assert.notNull(clientInboundChannel, "'clientInboundChannel' must not be null");
|
||||
@@ -71,6 +86,11 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler {
|
||||
this.clientInboundChannel = clientInboundChannel;
|
||||
this.clientOutboundChannel = clientOutboundChannel;
|
||||
this.brokerChannel = brokerChannel;
|
||||
DefaultSubscriptionRegistry subscriptionRegistry = new DefaultSubscriptionRegistry();
|
||||
if(pathMatcher != null) {
|
||||
subscriptionRegistry.setPathMatcher(pathMatcher);
|
||||
}
|
||||
this.subscriptionRegistry = subscriptionRegistry;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -23,7 +23,6 @@ import java.util.List;
|
||||
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -67,6 +66,4 @@ public abstract class AbstractBrokerRegistration {
|
||||
return this.destinationPrefixes;
|
||||
}
|
||||
|
||||
protected abstract AbstractBrokerMessageHandler getMessageHandler(SubscribableChannel brokerChannel);
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.springframework.messaging.simp.user.UserSessionRegistry;
|
||||
import org.springframework.messaging.support.AbstractSubscribableChannel;
|
||||
import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
@@ -206,12 +207,16 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
||||
@Bean
|
||||
public SimpAnnotationMethodMessageHandler simpAnnotationMethodMessageHandler() {
|
||||
|
||||
String defaultSeparator = this.getBrokerRegistry().getDefaultSeparator();
|
||||
SimpAnnotationMethodMessageHandler handler = new SimpAnnotationMethodMessageHandler(
|
||||
clientInboundChannel(), clientOutboundChannel(), brokerMessagingTemplate());
|
||||
clientInboundChannel(), clientOutboundChannel(), brokerMessagingTemplate(), defaultSeparator);
|
||||
|
||||
handler.setDestinationPrefixes(getBrokerRegistry().getApplicationDestinationPrefixes());
|
||||
handler.setMessageConverter(brokerMessageConverter());
|
||||
handler.setValidator(simpValidator());
|
||||
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher(defaultSeparator);
|
||||
handler.setPathMatcher(pathMatcher);
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,14 @@ import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
|
||||
import org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A registry for configuring message broker options.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
*/
|
||||
public class MessageBrokerRegistry {
|
||||
@@ -47,6 +49,7 @@ public class MessageBrokerRegistry {
|
||||
|
||||
private ChannelRegistration brokerChannelRegistration = new ChannelRegistration();
|
||||
|
||||
private String defaultSeparator;
|
||||
|
||||
public MessageBrokerRegistry(SubscribableChannel clientInboundChannel, MessageChannel clientOutboundChannel) {
|
||||
Assert.notNull(clientInboundChannel);
|
||||
@@ -119,12 +122,24 @@ public class MessageBrokerRegistry {
|
||||
return this.brokerChannelRegistration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the default separator used for destination patterns matching/combining.
|
||||
* It can be used to configure "." as the default separator, since it is used in most
|
||||
* STOMP broker relay, enabling destination patterns like "/topic/PRICE.STOCK.**".
|
||||
* <p>The default separator is "/".
|
||||
*/
|
||||
public MessageBrokerRegistry defaultSeparator(String defaultSeparator) {
|
||||
this.defaultSeparator = defaultSeparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected SimpleBrokerMessageHandler getSimpleBroker(SubscribableChannel brokerChannel) {
|
||||
if ((this.simpleBrokerRegistration == null) && (this.brokerRelayRegistration == null)) {
|
||||
enableSimpleBroker();
|
||||
}
|
||||
if (this.simpleBrokerRegistration != null) {
|
||||
return this.simpleBrokerRegistration.getMessageHandler(brokerChannel);
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher(this.defaultSeparator);
|
||||
return this.simpleBrokerRegistration.getMessageHandler(brokerChannel, pathMatcher);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -148,4 +163,9 @@ public class MessageBrokerRegistry {
|
||||
protected ChannelRegistration getBrokerChannelRegistration() {
|
||||
return this.brokerChannelRegistration;
|
||||
}
|
||||
|
||||
protected String getDefaultSeparator() {
|
||||
return this.defaultSeparator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -19,11 +19,13 @@ package org.springframework.messaging.simp.config;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
/**
|
||||
* Registration class for configuring a {@link SimpleBrokerMessageHandler}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SimpleBrokerRegistration extends AbstractBrokerRegistration {
|
||||
@@ -36,10 +38,9 @@ public class SimpleBrokerRegistration extends AbstractBrokerRegistration {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected SimpleBrokerMessageHandler getMessageHandler(SubscribableChannel brokerChannel) {
|
||||
protected SimpleBrokerMessageHandler getMessageHandler(SubscribableChannel brokerChannel, PathMatcher pathMatcher) {
|
||||
return new SimpleBrokerMessageHandler(getClientInboundChannel(),
|
||||
getClientOutboundChannel(), brokerChannel, getDestinationPrefixes());
|
||||
getClientOutboundChannel(), brokerChannel, getDestinationPrefixes(), pathMatcher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -18,18 +18,36 @@ package org.springframework.messaging.handler;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DestinationPatternsMessageCondition}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class DestinationPatternsMessageConditionTests {
|
||||
|
||||
@Parameter(0)
|
||||
public String pathSeparator;
|
||||
|
||||
@Parameters
|
||||
public static Iterable<Object[]> arguments() {
|
||||
return Arrays.asList(new Object[][]{{"/"}, {"."}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prependSlash() {
|
||||
DestinationPatternsMessageCondition c = condition("foo");
|
||||
@@ -47,20 +65,21 @@ public class DestinationPatternsMessageConditionTests {
|
||||
@Test
|
||||
public void combineEmptySets() {
|
||||
DestinationPatternsMessageCondition c1 = condition();
|
||||
DestinationPatternsMessageCondition c2 = condition();
|
||||
DestinationPatternsMessageCondition c2 = suffixCondition();
|
||||
|
||||
assertEquals(condition(""), c1.combine(c2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void combineOnePatternWithEmptySet() {
|
||||
DestinationPatternsMessageCondition c1 = condition("/type1", "/type2");
|
||||
DestinationPatternsMessageCondition c2 = condition();
|
||||
DestinationPatternsMessageCondition c1 = condition("/type1",
|
||||
pathSeparator + "type2");
|
||||
DestinationPatternsMessageCondition c2 = suffixCondition();
|
||||
|
||||
assertEquals(condition("/type1", "/type2"), c1.combine(c2));
|
||||
assertEquals(condition("/type1", pathSeparator + "type2"), c1.combine(c2));
|
||||
|
||||
c1 = condition();
|
||||
c2 = condition("/method1", "/method2");
|
||||
c2 = suffixCondition("/method1", "/method2");
|
||||
|
||||
assertEquals(condition("/method1", "/method2"), c1.combine(c2));
|
||||
}
|
||||
@@ -68,10 +87,12 @@ public class DestinationPatternsMessageConditionTests {
|
||||
@Test
|
||||
public void combineMultiplePatterns() {
|
||||
DestinationPatternsMessageCondition c1 = condition("/t1", "/t2");
|
||||
DestinationPatternsMessageCondition c2 = condition("/m1", "/m2");
|
||||
DestinationPatternsMessageCondition c2 = suffixCondition(pathSeparator + "m1",
|
||||
pathSeparator + "m2");
|
||||
|
||||
assertEquals(new DestinationPatternsMessageCondition(
|
||||
"/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2"), c1.combine(c2));
|
||||
assertEquals(
|
||||
condition("/t1" + pathSeparator + "m1", "/t1" + pathSeparator + "m2",
|
||||
"/t2" + pathSeparator + "m1", "/t2" + pathSeparator + "m2"), c1.combine(c2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,35 +105,40 @@ public class DestinationPatternsMessageConditionTests {
|
||||
|
||||
@Test
|
||||
public void matchPattern() {
|
||||
DestinationPatternsMessageCondition condition = condition("/foo/*");
|
||||
DestinationPatternsMessageCondition match = condition.getMatchingCondition(messageTo("/foo/bar"));
|
||||
DestinationPatternsMessageCondition condition = condition(
|
||||
"/foo" + pathSeparator + "*");
|
||||
DestinationPatternsMessageCondition match = condition.getMatchingCondition(messageTo("/foo" + pathSeparator + "bar"));
|
||||
|
||||
assertNotNull(match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchSortPatterns() {
|
||||
DestinationPatternsMessageCondition condition = condition("/**", "/foo/bar", "/foo/*");
|
||||
DestinationPatternsMessageCondition match = condition.getMatchingCondition(messageTo("/foo/bar"));
|
||||
DestinationPatternsMessageCondition expected = condition("/foo/bar", "/foo/*", "/**");
|
||||
DestinationPatternsMessageCondition condition = suffixCondition(
|
||||
pathSeparator + "**", pathSeparator + "foo" + pathSeparator + "bar",
|
||||
pathSeparator + "foo" + pathSeparator + "*");
|
||||
DestinationPatternsMessageCondition match = condition.getMatchingCondition(messageTo(pathSeparator + "foo" + pathSeparator + "bar"));
|
||||
DestinationPatternsMessageCondition expected = suffixCondition(
|
||||
pathSeparator + "foo" + pathSeparator + "bar",
|
||||
pathSeparator + "foo" + pathSeparator + "*", pathSeparator + "**");
|
||||
|
||||
assertEquals(expected, match);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareEqualPatterns() {
|
||||
DestinationPatternsMessageCondition c1 = condition("/foo*");
|
||||
DestinationPatternsMessageCondition c2 = condition("/foo*");
|
||||
DestinationPatternsMessageCondition c1 = suffixCondition(pathSeparator + "foo*");
|
||||
DestinationPatternsMessageCondition c2 = suffixCondition(pathSeparator + "foo*");
|
||||
|
||||
assertEquals(0, c1.compareTo(c2, messageTo("/foo")));
|
||||
assertEquals(0, c1.compareTo(c2, messageTo(pathSeparator + "foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void comparePatternSpecificity() {
|
||||
DestinationPatternsMessageCondition c1 = condition("/fo*");
|
||||
DestinationPatternsMessageCondition c2 = condition("/foo");
|
||||
DestinationPatternsMessageCondition c1 = suffixCondition(pathSeparator + "fo*");
|
||||
DestinationPatternsMessageCondition c2 = suffixCondition(pathSeparator + "foo");
|
||||
|
||||
assertEquals(1, c1.compareTo(c2, messageTo("/foo")));
|
||||
assertEquals(1, c1.compareTo(c2, messageTo(pathSeparator + "foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -130,7 +156,11 @@ public class DestinationPatternsMessageConditionTests {
|
||||
|
||||
|
||||
private DestinationPatternsMessageCondition condition(String... patterns) {
|
||||
return new DestinationPatternsMessageCondition(patterns);
|
||||
return new DestinationPatternsMessageCondition(patterns, new AntPathMatcher(this.pathSeparator));
|
||||
}
|
||||
|
||||
private DestinationPatternsMessageCondition suffixCondition(String... patterns) {
|
||||
return new DestinationPatternsMessageCondition(patterns, new AntPathMatcher(this.pathSeparator), false);
|
||||
}
|
||||
|
||||
private Message<?> messageTo(String destination) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
||||
import org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry;
|
||||
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
|
||||
import org.springframework.messaging.simp.user.UserDestinationMessageHandler;
|
||||
import org.springframework.messaging.simp.user.UserSessionRegistry;
|
||||
@@ -52,6 +54,7 @@ import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -64,6 +67,7 @@ import static org.junit.Assert.*;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class MessageBrokerConfigurationTests {
|
||||
|
||||
@@ -75,6 +79,8 @@ public class MessageBrokerConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext customChannelContext;
|
||||
|
||||
private AnnotationConfigApplicationContext customMatchingContext;
|
||||
|
||||
|
||||
@Before
|
||||
public void setupOnce() {
|
||||
@@ -94,6 +100,10 @@ public class MessageBrokerConfigurationTests {
|
||||
this.customChannelContext = new AnnotationConfigApplicationContext();
|
||||
this.customChannelContext.register(CustomChannelConfig.class);
|
||||
this.customChannelContext.refresh();
|
||||
|
||||
this.customMatchingContext = new AnnotationConfigApplicationContext();
|
||||
this.customMatchingContext.register(CustomMatchingSimpleBrokerConfig.class);
|
||||
this.customMatchingContext.refresh();
|
||||
}
|
||||
|
||||
|
||||
@@ -396,6 +406,20 @@ public class MessageBrokerConfigurationTests {
|
||||
assertThat(messageHandler.getValidator(), Matchers.notNullValue(Validator.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customMatching() {
|
||||
SimpleBrokerMessageHandler brokerHandler = this.customMatchingContext.getBean(SimpleBrokerMessageHandler.class);
|
||||
DefaultSubscriptionRegistry subscriptionRegistry = (DefaultSubscriptionRegistry)brokerHandler.getSubscriptionRegistry();
|
||||
AntPathMatcher pathMatcher = (AntPathMatcher)subscriptionRegistry.getPathMatcher();
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(pathMatcher);
|
||||
assertEquals(".", accessor.getPropertyValue("pathSeparator"));
|
||||
|
||||
SimpAnnotationMethodMessageHandler messageHandler = customMatchingContext.getBean(SimpAnnotationMethodMessageHandler.class);
|
||||
pathMatcher = (AntPathMatcher)messageHandler.getPathMatcher();
|
||||
accessor = new DirectFieldAccessor(pathMatcher);
|
||||
assertEquals(".", accessor.getPropertyValue("pathSeparator"));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
static class TestController {
|
||||
@@ -479,6 +503,15 @@ public class MessageBrokerConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomMatchingSimpleBrokerConfig extends SimpleBrokerConfig {
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.defaultSeparator(".").enableSimpleBroker("/topic", "/queue");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestChannel extends ExecutorSubscribableChannel {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user