Support user destinations without leading slash
Before this commit the DefaultUserDestinationResolver did not support well broker destinations that use dot as separator with a built in assumptions that the destinations it resolves must start with slash. This change adds PathMatcher property that is used to determine if an alternative path separator is in use and if so the leading slash is left out. Issue: SPR-14044
This commit is contained in:
parent
e904ce4ead
commit
183594207f
|
@ -384,6 +384,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
|||
if (prefix != null) {
|
||||
resolver.setUserDestinationPrefix(prefix);
|
||||
}
|
||||
resolver.setPathMatcher(getBrokerRegistry().getPathMatcher());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -29,6 +29,7 @@ import org.springframework.messaging.MessageHeaders;
|
|||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -57,6 +58,8 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
|
|||
|
||||
private String prefix = "/user/";
|
||||
|
||||
private boolean keepLeadingSlash = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance that will access user session id information through
|
||||
|
@ -94,6 +97,26 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
|
|||
return this.prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the {@code PathMatcher} in use for working with destinations
|
||||
* which in turn helps to determine whether the leading slash should be
|
||||
* kept in actual destinations after removing the
|
||||
* {@link #setUserDestinationPrefix userDestinationPrefix}.
|
||||
* <p>By default actual destinations have a leading slash, e.g.
|
||||
* {@code /queue/position-updates} which makes sense with brokers that
|
||||
* support destinations with slash as separator. When a {@code PathMatcher}
|
||||
* is provided that supports an alternative separator, then resulting
|
||||
* destinations won't have a leading slash, e.g. {@code
|
||||
* jms.queue.position-updates}.
|
||||
* @param pathMatcher the PathMatcher used to work with destinations
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
if (pathMatcher != null) {
|
||||
this.keepLeadingSlash = pathMatcher.combine("1", "2").equals("1/2");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserDestinationResult resolveDestination(Message<?> message) {
|
||||
|
@ -131,6 +154,9 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
|
|||
}
|
||||
int prefixEnd = this.prefix.length() - 1;
|
||||
String actualDestination = destination.substring(prefixEnd);
|
||||
if (!this.keepLeadingSlash) {
|
||||
actualDestination = actualDestination.substring(1);
|
||||
}
|
||||
String user = (principal != null ? principal.getName() : null);
|
||||
return new ParseResult(actualDestination, destination, Collections.singleton(sessionId), user);
|
||||
}
|
||||
|
@ -165,6 +191,9 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
|
|||
sessionIds = Collections.<String>emptySet();
|
||||
}
|
||||
}
|
||||
if (!this.keepLeadingSlash) {
|
||||
actualDestination = actualDestination.substring(1);
|
||||
}
|
||||
return new ParseResult(actualDestination, subscribeDestination, sessionIds, userName);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -54,9 +55,11 @@ import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
|
|||
import org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler;
|
||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||
import org.springframework.messaging.simp.user.DefaultUserDestinationResolver;
|
||||
import org.springframework.messaging.simp.user.MultiServerUserRegistry;
|
||||
import org.springframework.messaging.simp.user.SimpUserRegistry;
|
||||
import org.springframework.messaging.simp.user.UserDestinationMessageHandler;
|
||||
import org.springframework.messaging.simp.user.UserDestinationResolver;
|
||||
import org.springframework.messaging.simp.user.UserRegistryMessageHandler;
|
||||
import org.springframework.messaging.support.AbstractSubscribableChannel;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
|
@ -384,6 +387,10 @@ public class MessageBrokerConfigurationTests {
|
|||
|
||||
SimpAnnotationMethodMessageHandler handler = this.customContext.getBean(SimpAnnotationMethodMessageHandler.class);
|
||||
assertEquals("a.a", handler.getPathMatcher().combine("a", "a"));
|
||||
|
||||
DefaultUserDestinationResolver resolver = this.customContext.getBean(DefaultUserDestinationResolver.class);
|
||||
assertNotNull(resolver);
|
||||
assertEquals(false, new DirectFieldAccessor(resolver).getPropertyValue("keepLeadingSlash"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -29,6 +29,8 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
|||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.TestPrincipal;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -71,9 +73,23 @@ public class DefaultUserDestinationResolverTests {
|
|||
assertEquals(user.getName(), actual.getUser());
|
||||
}
|
||||
|
||||
// SPR-11325
|
||||
@Test // SPR-14044
|
||||
public void handleSubscribeForDestinationWithoutLeadingSlash() {
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
pathMatcher.setPathSeparator(".");
|
||||
this.resolver.setPathMatcher(pathMatcher);
|
||||
|
||||
@Test
|
||||
TestPrincipal user = new TestPrincipal("joe");
|
||||
String destination = "/user/jms.queue.call";
|
||||
Message<?> message = createMessage(SimpMessageType.SUBSCRIBE, user, "123", destination);
|
||||
UserDestinationResult actual = this.resolver.resolveDestination(message);
|
||||
|
||||
assertEquals(1, actual.getTargetDestinations().size());
|
||||
assertEquals("jms.queue.call-user123", actual.getTargetDestinations().iterator().next());
|
||||
assertEquals(destination, actual.getSubscribeDestination());
|
||||
}
|
||||
|
||||
@Test // SPR-11325
|
||||
public void handleSubscribeOneUserMultipleSessions() {
|
||||
|
||||
TestSimpUser simpUser = new TestSimpUser("joe");
|
||||
|
@ -125,9 +141,23 @@ public class DefaultUserDestinationResolverTests {
|
|||
assertEquals(user.getName(), actual.getUser());
|
||||
}
|
||||
|
||||
// SPR-12444
|
||||
@Test // SPR-14044
|
||||
public void handleMessageForDestinationWithDotSeparator() {
|
||||
AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
pathMatcher.setPathSeparator(".");
|
||||
this.resolver.setPathMatcher(pathMatcher);
|
||||
|
||||
@Test
|
||||
TestPrincipal user = new TestPrincipal("joe");
|
||||
String destination = "/user/joe/jms.queue.call";
|
||||
Message<?> message = createMessage(SimpMessageType.MESSAGE, user, "123", destination);
|
||||
UserDestinationResult actual = this.resolver.resolveDestination(message);
|
||||
|
||||
assertEquals(1, actual.getTargetDestinations().size());
|
||||
assertEquals("jms.queue.call-user123", actual.getTargetDestinations().iterator().next());
|
||||
assertEquals("/user/jms.queue.call", actual.getSubscribeDestination());
|
||||
}
|
||||
|
||||
@Test // SPR-12444
|
||||
public void handleMessageToOtherUser() {
|
||||
|
||||
TestSimpUser otherSimpUser = new TestSimpUser("anna");
|
||||
|
|
|
@ -573,6 +573,10 @@ class MessageBrokerBeanDefinitionParser implements BeanDefinitionParser {
|
|||
if (brokerElem.hasAttribute("user-destination-prefix")) {
|
||||
beanDef.getPropertyValues().add("userDestinationPrefix", brokerElem.getAttribute("user-destination-prefix"));
|
||||
}
|
||||
if (brokerElem.hasAttribute("path-matcher")) {
|
||||
String pathMatcherRef = brokerElem.getAttribute("path-matcher");
|
||||
beanDef.getPropertyValues().add("pathMatcher", new RuntimeBeanReference(pathMatcherRef));
|
||||
}
|
||||
return new RuntimeBeanReference(registerBeanDef(beanDef, context, source));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue