|
17 | 17 | package org.springframework.messaging.simp.config;
|
18 | 18 |
|
19 | 19 | import java.util.ArrayList;
|
| 20 | +import java.util.Collections; |
20 | 21 | import java.util.Iterator;
|
21 | 22 | import java.util.List;
|
| 23 | +import java.util.Map; |
22 | 24 | import java.util.Set;
|
23 | 25 | import java.util.concurrent.ConcurrentHashMap;
|
24 | 26 |
|
25 | 27 | import org.hamcrest.Matchers;
|
26 | 28 | import org.junit.Test;
|
27 | 29 |
|
28 |
| -import org.springframework.beans.DirectFieldAccessor; |
29 | 30 | import org.springframework.context.ApplicationContext;
|
30 | 31 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
31 | 32 | import org.springframework.context.annotation.Bean;
|
32 | 33 | import org.springframework.context.annotation.Configuration;
|
33 | 34 | import org.springframework.context.support.StaticApplicationContext;
|
34 | 35 | import org.springframework.lang.Nullable;
|
35 | 36 | import org.springframework.messaging.Message;
|
| 37 | +import org.springframework.messaging.MessageChannel; |
36 | 38 | import org.springframework.messaging.MessageHandler;
|
37 | 39 | import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
38 | 40 | import org.springframework.messaging.converter.CompositeMessageConverter;
|
|
45 | 47 | import org.springframework.messaging.handler.annotation.SendTo;
|
46 | 48 | import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
47 | 49 | import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
|
| 50 | +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; |
48 | 51 | import org.springframework.messaging.simp.SimpMessageType;
|
| 52 | +import org.springframework.messaging.simp.SimpMessagingTemplate; |
49 | 53 | import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
50 | 54 | import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
51 | 55 | import org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry;
|
@@ -414,7 +418,7 @@ public void customPathMatcher() {
|
414 | 418 |
|
415 | 419 | DefaultUserDestinationResolver resolver = context.getBean(DefaultUserDestinationResolver.class);
|
416 | 420 | assertNotNull(resolver);
|
417 |
| - assertEquals(false, new DirectFieldAccessor(resolver).getPropertyValue("keepLeadingSlash")); |
| 421 | + assertEquals(false, resolver.isRemoveLeadingSlash()); |
418 | 422 | }
|
419 | 423 |
|
420 | 424 | @Test
|
@@ -462,6 +466,67 @@ public void userBroadcastsDisabledWithSimpleBroker() {
|
462 | 466 | assertNotEquals(UserRegistryMessageHandler.class, messageHandler.getClass());
|
463 | 467 | }
|
464 | 468 |
|
| 469 | + @Test // SPR-16275 |
| 470 | + public void dotSeparatorWithBrokerSlashConvention() { |
| 471 | + ApplicationContext context = loadConfig(DotSeparatorWithSlashBrokerConventionConfig.class); |
| 472 | + testDotSeparator(context, true); |
| 473 | + } |
| 474 | + |
| 475 | + @Test // SPR-16275 |
| 476 | + public void dotSeparatorWithBrokerDotConvention() { |
| 477 | + ApplicationContext context = loadConfig(DotSeparatorWithDotBrokerConventionConfig.class); |
| 478 | + testDotSeparator(context, false); |
| 479 | + } |
| 480 | + |
| 481 | + private void testDotSeparator(ApplicationContext context, boolean expectLeadingSlash) { |
| 482 | + MessageChannel inChannel = context.getBean("clientInboundChannel", MessageChannel.class); |
| 483 | + TestChannel outChannel = context.getBean("clientOutboundChannel", TestChannel.class); |
| 484 | + MessageChannel brokerChannel = context.getBean("brokerChannel", MessageChannel.class); |
| 485 | + |
| 486 | + |
| 487 | + // 1. Subscribe to user destination |
| 488 | + |
| 489 | + StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE); |
| 490 | + headers.setSessionId("sess1"); |
| 491 | + headers.setSubscriptionId("subs1"); |
| 492 | + headers.setDestination("/user/queue.q1"); |
| 493 | + Message<?> message = MessageBuilder.createMessage(new byte[0], headers.getMessageHeaders()); |
| 494 | + inChannel.send(message); |
| 495 | + |
| 496 | + // 2. Send message to user via inboundChannel |
| 497 | + |
| 498 | + headers = StompHeaderAccessor.create(StompCommand.SEND); |
| 499 | + headers.setSessionId("sess1"); |
| 500 | + headers.setDestination("/user/sess1/queue.q1"); |
| 501 | + message = MessageBuilder.createMessage("123".getBytes(), headers.getMessageHeaders()); |
| 502 | + inChannel.send(message); |
| 503 | + |
| 504 | + assertEquals(1, outChannel.messages.size()); |
| 505 | + Message<?> outputMessage = outChannel.messages.remove(0); |
| 506 | + headers = StompHeaderAccessor.wrap(outputMessage); |
| 507 | + |
| 508 | + assertEquals(SimpMessageType.MESSAGE, headers.getMessageType()); |
| 509 | + assertEquals(expectLeadingSlash ? "/queue.q1-usersess1" : "queue.q1-usersess1", headers.getDestination()); |
| 510 | + assertEquals("123", new String((byte[]) outputMessage.getPayload())); |
| 511 | + |
| 512 | + |
| 513 | + // 3. Send message via broker channel |
| 514 | + |
| 515 | + SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel); |
| 516 | + SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create(); |
| 517 | + accessor.setSessionId("sess1"); |
| 518 | + template.convertAndSendToUser("sess1", "queue.q1", "456".getBytes(), accessor.getMessageHeaders()); |
| 519 | + |
| 520 | + assertEquals(1, outChannel.messages.size()); |
| 521 | + outputMessage = outChannel.messages.remove(0); |
| 522 | + headers = StompHeaderAccessor.wrap(outputMessage); |
| 523 | + |
| 524 | + assertEquals(SimpMessageType.MESSAGE, headers.getMessageType()); |
| 525 | + assertEquals(expectLeadingSlash ? "/queue.q1-usersess1" : "queue.q1-usersess1", headers.getDestination()); |
| 526 | + assertEquals("456", new String((byte[]) outputMessage.getPayload())); |
| 527 | + |
| 528 | + } |
| 529 | + |
465 | 530 | private AnnotationConfigApplicationContext loadConfig(Class<?> configClass) {
|
466 | 531 | return new AnnotationConfigApplicationContext(configClass);
|
467 | 532 | }
|
@@ -578,6 +643,60 @@ protected void configureMessageBroker(MessageBrokerRegistry registry) {
|
578 | 643 | }
|
579 | 644 |
|
580 | 645 |
|
| 646 | + @Configuration |
| 647 | + static abstract class BaseDotSeparatorConfig extends BaseTestMessageBrokerConfig { |
| 648 | + |
| 649 | + @Override |
| 650 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 651 | + registry.setPathMatcher(new AntPathMatcher(".")); |
| 652 | + } |
| 653 | + |
| 654 | + @Override |
| 655 | + @Bean |
| 656 | + public AbstractSubscribableChannel clientInboundChannel() { |
| 657 | + // synchronous |
| 658 | + return new ExecutorSubscribableChannel(null); |
| 659 | + } |
| 660 | + |
| 661 | + @Override |
| 662 | + @Bean |
| 663 | + public AbstractSubscribableChannel clientOutboundChannel() { |
| 664 | + return new TestChannel(); |
| 665 | + } |
| 666 | + |
| 667 | + @Override |
| 668 | + @Bean |
| 669 | + public AbstractSubscribableChannel brokerChannel() { |
| 670 | + // synchronous |
| 671 | + return new ExecutorSubscribableChannel(null); |
| 672 | + } |
| 673 | + } |
| 674 | + |
| 675 | + @Configuration |
| 676 | + static class DotSeparatorWithSlashBrokerConventionConfig extends BaseDotSeparatorConfig { |
| 677 | + |
| 678 | + // RabbitMQ-style broker convention for STOMP destinations |
| 679 | + |
| 680 | + @Override |
| 681 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 682 | + super.configureMessageBroker(registry); |
| 683 | + registry.enableSimpleBroker("/topic", "/queue"); |
| 684 | + } |
| 685 | + } |
| 686 | + |
| 687 | + @Configuration |
| 688 | + static class DotSeparatorWithDotBrokerConventionConfig extends BaseDotSeparatorConfig { |
| 689 | + |
| 690 | + // Artemis-style broker convention for STOMP destinations |
| 691 | + |
| 692 | + @Override |
| 693 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 694 | + super.configureMessageBroker(registry); |
| 695 | + registry.enableSimpleBroker("topic.", "queue."); |
| 696 | + } |
| 697 | + } |
| 698 | + |
| 699 | + |
581 | 700 | private static class TestChannel extends ExecutorSubscribableChannel {
|
582 | 701 |
|
583 | 702 | private final List<Message<?>> messages = new ArrayList<>();
|
|
0 commit comments