Refine destination semantics for msg-handling methods

After this change, annotated message handling methods configured to use
a destination prefix (e.g. "/app") no longer have to include the prefix
in their mapping. For example if a client sends a message to "/app/foo"
the annotated methods should be mapped with @MessageMapping("/foo").
This commit is contained in:
Rossen Stoyanchev
2013-09-03 11:04:00 -04:00
parent e1a46bb57a
commit 0ac6998e60
20 changed files with 325 additions and 126 deletions

View File

@@ -55,6 +55,8 @@ public class ReplyToMethodReturnValueHandlerTests {
private ReplyToMethodReturnValueHandler handler;
private ReplyToMethodReturnValueHandler handlerAnnotationNotRequired;
@Mock private MessageChannel messageChannel;
@Captor ArgumentCaptor<Message<?>> messageCaptor;
@@ -80,7 +82,8 @@ public class ReplyToMethodReturnValueHandlerTests {
SimpMessagingTemplate messagingTemplate = new SimpMessagingTemplate(this.messageChannel);
messagingTemplate.setConverter(this.messageConverter);
this.handler = new ReplyToMethodReturnValueHandler(messagingTemplate);
this.handler = new ReplyToMethodReturnValueHandler(messagingTemplate, true);
this.handlerAnnotationNotRequired = new ReplyToMethodReturnValueHandler(messagingTemplate, false);
Method method = this.getClass().getDeclaredMethod("handleAndReplyTo");
this.replyToReturnType = new MethodParameter(method, -1);
@@ -98,6 +101,7 @@ public class ReplyToMethodReturnValueHandlerTests {
assertTrue(this.handler.supportsReturnType(this.replyToReturnType));
assertTrue(this.handler.supportsReturnType(this.replyToUserReturnType));
assertFalse(this.handler.supportsReturnType(this.missingReplyToReturnType));
assertTrue(this.handlerAnnotationNotRequired.supportsReturnType(this.missingReplyToReturnType));
}
@Test

View File

@@ -83,12 +83,35 @@ public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrati
public void simpleController() throws Exception {
TextMessage message = create(StompCommand.SEND).headers("destination:/app/simple").build();
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(message, 0), "/ws");
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(0, message), "/ws");
SimpleController controller = this.wac.getBean(SimpleController.class);
assertTrue(controller.latch.await(2, TimeUnit.SECONDS));
try {
assertTrue(controller.latch.await(2, TimeUnit.SECONDS));
}
finally {
session.close();
}
}
session.close();
@Test
public void incrementController() throws Exception {
TextMessage message1 = create(StompCommand.SUBSCRIBE).headers(
"id:subs1", "destination:/topic/increment").body("5").build();
TextMessage message2 = create(StompCommand.SEND).headers(
"destination:/app/topic/increment").body("5").build();
TestClientWebSocketHandler clientHandler = new TestClientWebSocketHandler(1, message1, message2);
WebSocketSession session = doHandshake(clientHandler, "/ws");
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
}
finally {
session.close();
}
}
@@ -97,15 +120,25 @@ public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrati
private CountDownLatch latch = new CountDownLatch(1);
@MessageMapping(value="/app/simple")
@MessageMapping(value="/simple")
public void handle() {
this.latch.countDown();
}
}
@IntegrationTestController
static class IncrementController {
@MessageMapping(value="/topic/increment")
public int handle(int i) {
return i + 1;
}
}
private static class TestClientWebSocketHandler extends TextWebSocketHandlerAdapter {
private final TextMessage messageToSend;
private final TextMessage[] messagesToSend;
private final int expected;
@@ -114,15 +147,17 @@ public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrati
private final CountDownLatch latch;
public TestClientWebSocketHandler(TextMessage messageToSend, int expectedNumberOfMessages) {
this.messageToSend = messageToSend;
public TestClientWebSocketHandler(int expectedNumberOfMessages, TextMessage... messagesToSend) {
this.messagesToSend = messagesToSend;
this.expected = expectedNumberOfMessages;
this.latch = new CountDownLatch(this.expected);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.sendMessage(this.messageToSend);
for (TextMessage message : this.messagesToSend) {
session.sendMessage(message);
}
}
@Override
@@ -134,6 +169,7 @@ public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrati
@Configuration
@ComponentScan(basePackageClasses=AnnotationMethodIntegrationTests.class,
useDefaultFilters=false,
includeFilters=@ComponentScan.Filter(IntegrationTestController.class))
static class TestMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {
@@ -147,7 +183,7 @@ public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrati
@Override
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
configurer.setAnnotationMethodDestinationPrefixes("/app/");
configurer.setAnnotationMethodDestinationPrefixes("/app");
configurer.enableSimpleBroker("/topic", "/queue");
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.messaging.simp.handler;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
/**
* Test fixture for {@link AnnotationMethodMessageHandler}.
* @author Rossen Stoyanchev
*/
public class AnnotationMethodMessageHandlerTests {
@Test(expected=IllegalStateException.class)
public void duplicateMappings() {
StaticApplicationContext cxt = new StaticApplicationContext();
cxt.registerSingleton("d", DuplicateMappingController.class);
cxt.refresh();
MessageChannel channel = Mockito.mock(MessageChannel.class);
SimpMessageSendingOperations brokerTemplate = new SimpMessagingTemplate(channel);
AnnotationMethodMessageHandler mh = new AnnotationMethodMessageHandler(brokerTemplate, channel);
mh.setApplicationContext(cxt);
mh.afterPropertiesSet();
}
@Controller
static class DuplicateMappingController {
@MessageMapping(value="/duplicate")
public void handle1() { }
@MessageMapping(value="/duplicate")
public void handle2() { }
}
}

View File

@@ -12,7 +12,7 @@
</appender>
<logger name="org.springframework.messaging">
<level value="info" />
<level value="trace" />
</logger>
<logger name="org.apache.activemq">