Consolidate websocket/messaging code
Before this change spring-messaging contained a few WebSocket-related classes including WebSocket sub-protocol support for STOMP as well as @EnableWebSocketMessageBroker and related configuration classes. After this change those classes are located in the spring-websocket module under org.springframework.web.socket.messaging. This means the following classes in application configuration must have their packages updated: org.springframework.web.socket.messaging.config.EnableWebSocketMessageBroker org.springframework.web.socket.messaging.config.StompEndpointRegistry org.springframework.web.socket.messaging.config.WebSocketMessageBrokerConfigurer MessageBrokerConfigurer has been renamed to MessageBrokerRegistry and is also located in the above package.
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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 CONDITIOsNS 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.handler.websocket;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.web.socket.support.TestWebSocketSession;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link SubProtocolWebSocketHandler}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SubProtocolWebSocketHandlerTests {
|
||||
|
||||
private SubProtocolWebSocketHandler webSocketHandler;
|
||||
|
||||
private TestWebSocketSession session;
|
||||
|
||||
@Mock SubProtocolHandler stompHandler;
|
||||
|
||||
@Mock SubProtocolHandler mqttHandler;
|
||||
|
||||
@Mock SubProtocolHandler defaultHandler;
|
||||
|
||||
@Mock MessageChannel channel;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
this.webSocketHandler = new SubProtocolWebSocketHandler(this.channel);
|
||||
when(stompHandler.getSupportedProtocols()).thenReturn(Arrays.asList("v10.stomp", "v11.stomp", "v12.stomp"));
|
||||
when(mqttHandler.getSupportedProtocols()).thenReturn(Arrays.asList("MQTT"));
|
||||
|
||||
this.session = new TestWebSocketSession();
|
||||
this.session.setId("1");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void subProtocolMatch() throws Exception {
|
||||
this.webSocketHandler.setProtocolHandlers(Arrays.asList(stompHandler, mqttHandler));
|
||||
this.session.setAcceptedProtocol("v12.sToMp");
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
|
||||
verify(this.stompHandler).afterSessionStarted(session, this.channel);
|
||||
verify(this.mqttHandler, times(0)).afterSessionStarted(session, this.channel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subProtocolDefaultHandlerOnly() throws Exception {
|
||||
this.webSocketHandler.setDefaultProtocolHandler(stompHandler);
|
||||
this.session.setAcceptedProtocol("v12.sToMp");
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
|
||||
verify(this.stompHandler).afterSessionStarted(session, this.channel);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void subProtocolNoMatch() throws Exception {
|
||||
this.webSocketHandler.setDefaultProtocolHandler(defaultHandler);
|
||||
this.webSocketHandler.setProtocolHandlers(Arrays.asList(stompHandler, mqttHandler));
|
||||
this.session.setAcceptedProtocol("wamp");
|
||||
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSubProtocol() throws Exception {
|
||||
this.webSocketHandler.setDefaultProtocolHandler(defaultHandler);
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
|
||||
verify(this.defaultHandler).afterSessionStarted(session, this.channel);
|
||||
verify(this.stompHandler, times(0)).afterSessionStarted(session, this.channel);
|
||||
verify(this.mqttHandler, times(0)).afterSessionStarted(session, this.channel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptySubProtocol() throws Exception {
|
||||
this.session.setAcceptedProtocol("");
|
||||
this.webSocketHandler.setDefaultProtocolHandler(defaultHandler);
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
|
||||
verify(this.defaultHandler).afterSessionStarted(session, this.channel);
|
||||
verify(this.stompHandler, times(0)).afterSessionStarted(session, this.channel);
|
||||
verify(this.mqttHandler, times(0)).afterSessionStarted(session, this.channel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noSubProtocolOneHandler() throws Exception {
|
||||
this.webSocketHandler.setProtocolHandlers(Arrays.asList(stompHandler));
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
|
||||
verify(this.stompHandler).afterSessionStarted(session, this.channel);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void noSubProtocolTwoHandlers() throws Exception {
|
||||
this.webSocketHandler.setProtocolHandlers(Arrays.asList(stompHandler, mqttHandler));
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void noSubProtocolNoDefaultHandler() throws Exception {
|
||||
this.webSocketHandler.setProtocolHandlers(Arrays.asList(stompHandler, mqttHandler));
|
||||
this.webSocketHandler.afterConnectionEstablished(session);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolWebSocketHandler;
|
||||
import org.springframework.messaging.support.channel.ExecutorSubscribableChannel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.server.DefaultHandshakeHandler;
|
||||
import org.springframework.web.socket.server.HandshakeHandler;
|
||||
import org.springframework.web.socket.sockjs.SockJsService;
|
||||
import org.springframework.web.socket.sockjs.transport.TransportType;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.WebSocketTransportHandler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link AbstractStompEndpointRegistration}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class AbstractStompEndpointRegistrationTests {
|
||||
|
||||
private SubProtocolWebSocketHandler wsHandler;
|
||||
|
||||
private TaskScheduler scheduler;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.wsHandler = new SubProtocolWebSocketHandler(new ExecutorSubscribableChannel());
|
||||
this.scheduler = Mockito.mock(TaskScheduler.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimalRegistration() {
|
||||
|
||||
TestStompEndpointRegistration registration =
|
||||
new TestStompEndpointRegistration(new String[] {"/foo"}, this.wsHandler, this.scheduler);
|
||||
|
||||
List<Mapping> mappings = registration.getMappings();
|
||||
assertEquals(1, mappings.size());
|
||||
|
||||
Mapping m1 = mappings.get(0);
|
||||
assertSame(this.wsHandler, m1.webSocketHandler);
|
||||
assertEquals("/foo", m1.path);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customHandshakeHandler() {
|
||||
|
||||
DefaultHandshakeHandler handshakeHandler = new DefaultHandshakeHandler();
|
||||
|
||||
TestStompEndpointRegistration registration =
|
||||
new TestStompEndpointRegistration(new String[] {"/foo"}, this.wsHandler, this.scheduler);
|
||||
registration.setHandshakeHandler(handshakeHandler);
|
||||
|
||||
List<Mapping> mappings = registration.getMappings();
|
||||
assertEquals(1, mappings.size());
|
||||
|
||||
Mapping m1 = mappings.get(0);
|
||||
assertSame(this.wsHandler, m1.webSocketHandler);
|
||||
assertEquals("/foo", m1.path);
|
||||
assertSame(handshakeHandler, m1.handshakeHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customHandshakeHandlerPassedToSockJsService() {
|
||||
|
||||
DefaultHandshakeHandler handshakeHandler = new DefaultHandshakeHandler();
|
||||
|
||||
TestStompEndpointRegistration registration =
|
||||
new TestStompEndpointRegistration(new String[] {"/foo"}, this.wsHandler, this.scheduler);
|
||||
registration.setHandshakeHandler(handshakeHandler);
|
||||
registration.withSockJS();
|
||||
|
||||
List<Mapping> mappings = registration.getMappings();
|
||||
assertEquals(1, mappings.size());
|
||||
|
||||
Mapping m1 = mappings.get(0);
|
||||
assertSame(this.wsHandler, m1.webSocketHandler);
|
||||
assertEquals("/foo/**", m1.path);
|
||||
assertNotNull(m1.sockJsService);
|
||||
|
||||
WebSocketTransportHandler transportHandler =
|
||||
(WebSocketTransportHandler) m1.sockJsService.getTransportHandlers().get(TransportType.WEBSOCKET);
|
||||
assertSame(handshakeHandler, transportHandler.getHandshakeHandler());
|
||||
}
|
||||
|
||||
|
||||
private static class TestStompEndpointRegistration extends AbstractStompEndpointRegistration<List<Mapping>> {
|
||||
|
||||
public TestStompEndpointRegistration(String[] paths, SubProtocolWebSocketHandler wsh, TaskScheduler scheduler) {
|
||||
super(paths, wsh, scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Mapping> createMappings() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSockJsServiceMapping(List<Mapping> mappings, SockJsService sockJsService,
|
||||
WebSocketHandler wsHandler, String pathPattern) {
|
||||
|
||||
mappings.add(new Mapping(wsHandler, pathPattern, sockJsService));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addWebSocketHandlerMapping(List<Mapping> mappings, WebSocketHandler wsHandler,
|
||||
HandshakeHandler handshakeHandler, String path) {
|
||||
|
||||
mappings.add(new Mapping(wsHandler, path, handshakeHandler));
|
||||
}
|
||||
}
|
||||
|
||||
private static class Mapping {
|
||||
|
||||
private final WebSocketHandler webSocketHandler;
|
||||
|
||||
private final String path;
|
||||
|
||||
private final HandshakeHandler handshakeHandler;
|
||||
|
||||
private final DefaultSockJsService sockJsService;
|
||||
|
||||
public Mapping(WebSocketHandler handler, String path, SockJsService sockJsService) {
|
||||
this.webSocketHandler = handler;
|
||||
this.path = path;
|
||||
this.handshakeHandler = null;
|
||||
this.sockJsService = (DefaultSockJsService) sockJsService;
|
||||
}
|
||||
|
||||
public Mapping(WebSocketHandler h, String path, HandshakeHandler hh) {
|
||||
this.webSocketHandler = h;
|
||||
this.path = path;
|
||||
this.handshakeHandler = hh;
|
||||
this.sockJsService = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolWebSocketHandler;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||
import org.springframework.messaging.simp.handler.SimpAnnotationMethodMessageHandler;
|
||||
@@ -35,7 +34,6 @@ import org.springframework.messaging.simp.handler.UserSessionRegistry;
|
||||
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.stomp.StompTextMessageBuilder;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.messaging.support.channel.AbstractSubscribableChannel;
|
||||
import org.springframework.messaging.support.channel.ExecutorSubscribableChannel;
|
||||
@@ -43,24 +41,19 @@ import org.springframework.messaging.support.converter.CompositeMessageConverter
|
||||
import org.springframework.messaging.support.converter.DefaultContentTypeResolver;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.support.TestWebSocketSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link WebSocketMessageBrokerConfigurationSupport}.
|
||||
* Test fixture for {@link AbstractMessageBrokerConfiguration}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
public class MessageBrokerConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext cxtSimpleBroker;
|
||||
|
||||
@@ -71,29 +64,19 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
public void setupOnce() {
|
||||
|
||||
this.cxtSimpleBroker = new AnnotationConfigApplicationContext();
|
||||
this.cxtSimpleBroker.register(TestWebSocketMessageBrokerConfiguration.class, TestSimpleMessageBrokerConfig.class);
|
||||
this.cxtSimpleBroker.register(TestMessageBrokerConfiguration.class);
|
||||
this.cxtSimpleBroker.refresh();
|
||||
|
||||
this.cxtStompBroker = new AnnotationConfigApplicationContext();
|
||||
this.cxtStompBroker.register(TestWebSocketMessageBrokerConfiguration.class, TestStompMessageBrokerConfig.class);
|
||||
this.cxtStompBroker.register(TestStompMessageBrokerConfig.class);
|
||||
this.cxtStompBroker.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlerMapping() {
|
||||
|
||||
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.cxtSimpleBroker.getBean(HandlerMapping.class);
|
||||
assertEquals(1, hm.getOrder());
|
||||
|
||||
Map<String, Object> handlerMap = hm.getHandlerMap();
|
||||
assertEquals(1, handlerMap.size());
|
||||
assertNotNull(handlerMap.get("/simpleBroker"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannel() {
|
||||
public void clientInboundChannel() {
|
||||
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("webSocketRequestChannel", TestChannel.class);
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("clientInboundChannel", TestChannel.class);
|
||||
List<MessageHandler> handlers = channel.handlers;
|
||||
|
||||
assertEquals(3, handlers.size());
|
||||
@@ -103,8 +86,8 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannelWithStompBroker() {
|
||||
TestChannel channel = this.cxtStompBroker.getBean("webSocketRequestChannel", TestChannel.class);
|
||||
public void clientInboundChannelWithStompBroker() {
|
||||
TestChannel channel = this.cxtStompBroker.getBean("clientInboundChannel", TestChannel.class);
|
||||
List<MessageHandler> values = channel.handlers;
|
||||
|
||||
assertEquals(3, values.size());
|
||||
@@ -114,34 +97,9 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannelSendMessage() throws Exception {
|
||||
public void clientOutboundChannelUsedByAnnotatedMethod() {
|
||||
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("webSocketRequestChannel", TestChannel.class);
|
||||
SubProtocolWebSocketHandler webSocketHandler = this.cxtSimpleBroker.getBean(SubProtocolWebSocketHandler.class);
|
||||
|
||||
TextMessage textMessage = StompTextMessageBuilder.create(StompCommand.SEND).headers("destination:/foo").build();
|
||||
webSocketHandler.handleMessage(new TestWebSocketSession(), textMessage);
|
||||
|
||||
Message<?> message = channel.messages.get(0);
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/foo", headers.getDestination());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannel() {
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", TestChannel.class);
|
||||
List<MessageHandler> values = channel.handlers;
|
||||
|
||||
assertEquals(1, values.size());
|
||||
assertTrue(values.get(0) instanceof SubProtocolWebSocketHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannelUsedByAnnotatedMethod() {
|
||||
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", TestChannel.class);
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("clientOutboundChannel", TestChannel.class);
|
||||
SimpAnnotationMethodMessageHandler messageHandler = this.cxtSimpleBroker.getBean(SimpAnnotationMethodMessageHandler.class);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
|
||||
@@ -161,8 +119,8 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannelUsedBySimpleBroker() {
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", TestChannel.class);
|
||||
public void clientOutboundChannelUsedBySimpleBroker() {
|
||||
TestChannel channel = this.cxtSimpleBroker.getBean("clientOutboundChannel", TestChannel.class);
|
||||
SimpleBrokerMessageHandler broker = this.cxtSimpleBroker.getBean(SimpleBrokerMessageHandler.class);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
|
||||
@@ -252,7 +210,7 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
@Test
|
||||
public void messageConverter() {
|
||||
CompositeMessageConverter messageConverter = this.cxtStompBroker.getBean(
|
||||
"simpMessageConverter", CompositeMessageConverter.class);
|
||||
"brokerMessageConverter", CompositeMessageConverter.class);
|
||||
|
||||
DefaultContentTypeResolver resolver = (DefaultContentTypeResolver) messageConverter.getContentTypeResolver();
|
||||
assertEquals(MimeTypeUtils.APPLICATION_JSON, resolver.getDefaultMimeType());
|
||||
@@ -275,50 +233,26 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestSimpleMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/simpleBroker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
// SimpleBroker used by default
|
||||
}
|
||||
static class TestMessageBrokerConfiguration extends AbstractMessageBrokerConfiguration {
|
||||
|
||||
@Bean
|
||||
public TestController subscriptionController() {
|
||||
return new TestController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestStompMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/stompBrokerRelay");
|
||||
protected void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
configurer.enableStompBrokerRelay("/topic", "/queue").setAutoStartup(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestWebSocketMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AbstractSubscribableChannel webSocketRequestChannel() {
|
||||
public AbstractSubscribableChannel clientInboundChannel() {
|
||||
return new TestChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AbstractSubscribableChannel webSocketResponseChannel() {
|
||||
public AbstractSubscribableChannel clientOutboundChannel() {
|
||||
return new TestChannel();
|
||||
}
|
||||
|
||||
@@ -328,6 +262,16 @@ public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestStompMessageBrokerConfig extends TestMessageBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableStompBrokerRelay("/topic", "/queue").setAutoStartup(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestChannel extends ExecutorSubscribableChannel {
|
||||
|
||||
private final List<MessageHandler> handlers = new ArrayList<>();
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolHandler;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolWebSocketHandler;
|
||||
import org.springframework.messaging.simp.handler.DefaultUserSessionRegistry;
|
||||
import org.springframework.messaging.simp.handler.UserSessionRegistry;
|
||||
import org.springframework.messaging.simp.stomp.StompProtocolHandler;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link ServletStompEndpointRegistry}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ServletStompEndpointRegistryTests {
|
||||
|
||||
private ServletStompEndpointRegistry registry;
|
||||
|
||||
private SubProtocolWebSocketHandler webSocketHandler;
|
||||
|
||||
private UserSessionRegistry userSessionRegistry;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MessageChannel channel = Mockito.mock(MessageChannel.class);
|
||||
this.webSocketHandler = new SubProtocolWebSocketHandler(channel);
|
||||
this.userSessionRegistry = new DefaultUserSessionRegistry();
|
||||
TaskScheduler taskScheduler = Mockito.mock(TaskScheduler.class);
|
||||
this.registry = new ServletStompEndpointRegistry(webSocketHandler, userSessionRegistry, taskScheduler);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void stompProtocolHandler() {
|
||||
|
||||
this.registry.addEndpoint("/stomp");
|
||||
|
||||
Map<String, SubProtocolHandler> protocolHandlers = webSocketHandler.getProtocolHandlers();
|
||||
assertEquals(3, protocolHandlers.size());
|
||||
assertNotNull(protocolHandlers.get("v10.stomp"));
|
||||
assertNotNull(protocolHandlers.get("v11.stomp"));
|
||||
assertNotNull(protocolHandlers.get("v12.stomp"));
|
||||
|
||||
StompProtocolHandler stompHandler = (StompProtocolHandler) protocolHandlers.get("v10.stomp");
|
||||
assertSame(this.userSessionRegistry, stompHandler.getUserSessionRegistry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlerMapping() {
|
||||
|
||||
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
|
||||
assertEquals(0, hm.getUrlMap().size());
|
||||
|
||||
this.registry.addEndpoint("/stompOverWebSocket");
|
||||
this.registry.addEndpoint("/stompOverSockJS").withSockJS();
|
||||
|
||||
hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
|
||||
assertEquals(2, hm.getUrlMap().size());
|
||||
assertNotNull(hm.getUrlMap().get("/stompOverWebSocket"));
|
||||
assertNotNull(hm.getUrlMap().get("/stompOverSockJS/**"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
* 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 java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.simp.config.DelegatingWebSocketMessageBrokerConfiguration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerConfigurer;
|
||||
import org.springframework.messaging.simp.config.StompEndpointRegistry;
|
||||
import org.springframework.messaging.simp.config.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||
import org.springframework.messaging.support.channel.AbstractSubscribableChannel;
|
||||
import org.springframework.messaging.support.channel.ExecutorSubscribableChannel;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.socket.AbstractWebSocketIntegrationTests;
|
||||
import org.springframework.web.socket.JettyWebSocketTestServer;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.TomcatWebSocketTestServer;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;
|
||||
import org.springframework.web.socket.client.endpoint.StandardWebSocketClient;
|
||||
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
|
||||
import org.springframework.web.socket.server.HandshakeHandler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.messaging.simp.stomp.StompTextMessageBuilder.*;
|
||||
|
||||
|
||||
/**
|
||||
* Integration tests with annotated message-handling methods.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class SimpAnnotationMethodIntegrationTests extends AbstractWebSocketIntegrationTests {
|
||||
|
||||
@Parameters
|
||||
public static Iterable<Object[]> arguments() {
|
||||
return Arrays.asList(new Object[][] {
|
||||
{new JettyWebSocketTestServer(), new JettyWebSocketClient()},
|
||||
{new TomcatWebSocketTestServer(), new StandardWebSocketClient()}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedConfigClasses() {
|
||||
return new Class<?>[] { TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class };
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sendMessageToController() throws Exception {
|
||||
|
||||
TextMessage message = create(StompCommand.SEND).headers("destination:/app/simple").build();
|
||||
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(0, message), "/ws").get();
|
||||
|
||||
SimpleController controller = this.wac.getBean(SimpleController.class);
|
||||
try {
|
||||
assertTrue(controller.latch.await(2, TimeUnit.SECONDS));
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendMessageToControllerAndReceiveReplyViaTopic() throws Exception {
|
||||
|
||||
TextMessage message1 = create(StompCommand.SUBSCRIBE).headers(
|
||||
"id:subs1", "destination:/topic/increment").build();
|
||||
|
||||
TextMessage message2 = create(StompCommand.SEND).headers(
|
||||
"destination:/app/increment").body("5").build();
|
||||
|
||||
TestClientWebSocketHandler clientHandler = new TestClientWebSocketHandler(1, message1, message2);
|
||||
WebSocketSession session = doHandshake(clientHandler, "/ws").get();
|
||||
|
||||
try {
|
||||
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
// SPR-10930
|
||||
|
||||
@Test
|
||||
public void sendMessageToBrokerAndReceiveReplyViaTopic() throws Exception {
|
||||
|
||||
TextMessage message1 = create(StompCommand.SUBSCRIBE).headers("id:subs1", "destination:/topic/foo").build();
|
||||
TextMessage message2 = create(StompCommand.SEND).headers("destination:/topic/foo").body("5").build();
|
||||
|
||||
TestClientWebSocketHandler clientHandler = new TestClientWebSocketHandler(1, message1, message2);
|
||||
WebSocketSession session = doHandshake(clientHandler, "/ws").get();
|
||||
|
||||
try {
|
||||
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
|
||||
|
||||
String payload = clientHandler.actual.get(0).getPayload();
|
||||
assertTrue("Expected STOMP Command=MESSAGE, got " + payload, payload.startsWith("MESSAGE\n"));
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IntegrationTestController
|
||||
static class SimpleController {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@MessageMapping(value="/simple")
|
||||
public void handle() {
|
||||
this.latch.countDown();
|
||||
}
|
||||
|
||||
@MessageMapping(value="/exception")
|
||||
public void handleWithError() {
|
||||
throw new IllegalArgumentException("Bad input");
|
||||
}
|
||||
|
||||
@MessageExceptionHandler
|
||||
public void handleException(IllegalArgumentException ex) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@IntegrationTestController
|
||||
static class IncrementController {
|
||||
|
||||
@MessageMapping(value="/increment")
|
||||
public int handle(int i) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestClientWebSocketHandler extends TextWebSocketHandlerAdapter {
|
||||
|
||||
private final TextMessage[] messagesToSend;
|
||||
|
||||
private final int expected;
|
||||
|
||||
private final List<TextMessage> actual = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final CountDownLatch latch;
|
||||
|
||||
|
||||
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 {
|
||||
for (TextMessage message : this.messagesToSend) {
|
||||
session.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
this.actual.add(message);
|
||||
this.latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses=SimpAnnotationMethodIntegrationTests.class,
|
||||
useDefaultFilters=false,
|
||||
includeFilters=@ComponentScan.Filter(IntegrationTestController.class))
|
||||
static class TestMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Autowired
|
||||
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/ws").setHandshakeHandler(this.handshakeHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
configurer.setApplicationDestinationPrefixes("/app");
|
||||
configurer.enableSimpleBroker("/topic", "/queue");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AbstractSubscribableChannel webSocketRequestChannel() {
|
||||
return new ExecutorSubscribableChannel(); // synchronous
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public AbstractSubscribableChannel webSocketResponseChannel() {
|
||||
return new ExecutorSubscribableChannel(); // synchronous
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Controller
|
||||
private @interface IntegrationTestController {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -146,9 +146,9 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
private static class TestSimpAnnotationMethodMessageHandler extends SimpAnnotationMethodMessageHandler {
|
||||
|
||||
public TestSimpAnnotationMethodMessageHandler(SimpMessageSendingOperations brokerTemplate,
|
||||
MessageChannel webSocketResponseChannel) {
|
||||
MessageChannel clientOutboundChannel) {
|
||||
|
||||
super(brokerTemplate, webSocketResponseChannel);
|
||||
super(brokerTemplate, clientOutboundChannel);
|
||||
}
|
||||
|
||||
public void registerHandler(Object handler) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
@@ -146,7 +145,7 @@ public class StompHeaderAccessorTests {
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.MESSAGE);
|
||||
headers.setSubscriptionId("s1");
|
||||
headers.setDestination("/d");
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setContentType(MimeTypeUtils.APPLICATION_JSON);
|
||||
|
||||
Map<String, List<String>> actual = headers.toNativeHeaderMap();
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* 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.stomp;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
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.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.support.TestWebSocketSession;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link StompProtocolHandler} tests.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class StompProtocolHandlerTests {
|
||||
|
||||
private StompProtocolHandler stompHandler;
|
||||
|
||||
private TestWebSocketSession session;
|
||||
|
||||
private MessageChannel channel;
|
||||
|
||||
private ArgumentCaptor<Message> messageCaptor;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.stompHandler = new StompProtocolHandler();
|
||||
this.channel = Mockito.mock(MessageChannel.class);
|
||||
this.messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
|
||||
this.session = new TestWebSocketSession();
|
||||
this.session.setId("s1");
|
||||
this.session.setPrincipal(new TestPrincipal("joe"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectedResponseIsSentWhenConnectAckIsToBeSentToClient() {
|
||||
StompHeaderAccessor connectHeaders = StompHeaderAccessor.create(StompCommand.CONNECT);
|
||||
connectHeaders.setHeartbeat(10000, 10000);
|
||||
connectHeaders.setNativeHeader(StompHeaderAccessor.STOMP_ACCEPT_VERSION_HEADER, "1.0,1.1");
|
||||
|
||||
Message<?> connectMessage = MessageBuilder.withPayload(new byte[0]).setHeaders(connectHeaders).build();
|
||||
|
||||
SimpMessageHeaderAccessor connectAckHeaders = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT_ACK);
|
||||
connectAckHeaders.setHeader(SimpMessageHeaderAccessor.CONNECT_MESSAGE_HEADER, connectMessage);
|
||||
|
||||
Message<byte[]> connectAck = MessageBuilder.withPayload(new byte[0]).setHeaders(connectAckHeaders).build();
|
||||
this.stompHandler.handleMessageToClient(this.session, connectAck);
|
||||
|
||||
verifyNoMoreInteractions(this.channel);
|
||||
|
||||
// Check CONNECTED reply
|
||||
|
||||
assertEquals(1, this.session.getSentMessages().size());
|
||||
TextMessage textMessage = (TextMessage) this.session.getSentMessages().get(0);
|
||||
Message<?> message = new StompDecoder().decode(ByteBuffer.wrap(textMessage.getPayload().getBytes()));
|
||||
StompHeaderAccessor replyHeaders = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(StompCommand.CONNECTED, replyHeaders.getCommand());
|
||||
assertEquals("1.1", replyHeaders.getVersion());
|
||||
assertArrayEquals(new long[] {0, 0}, replyHeaders.getHeartbeat());
|
||||
assertEquals("joe", replyHeaders.getNativeHeader("user-name").get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesAreAugmentedAndForwarded() {
|
||||
|
||||
TextMessage textMessage = StompTextMessageBuilder.create(StompCommand.CONNECT).headers(
|
||||
"login:guest", "passcode:guest", "accept-version:1.1,1.0", "heart-beat:10000,10000").build();
|
||||
|
||||
this.stompHandler.handleMessageFromClient(this.session, textMessage, this.channel);
|
||||
|
||||
verify(this.channel).send(this.messageCaptor.capture());
|
||||
Message<?> actual = this.messageCaptor.getValue();
|
||||
assertNotNull(actual);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.wrap(actual);
|
||||
assertEquals(StompCommand.CONNECT, headers.getCommand());
|
||||
assertEquals("s1", headers.getSessionId());
|
||||
assertEquals("joe", headers.getUser().getName());
|
||||
assertEquals("guest", headers.getLogin());
|
||||
assertEquals("PROTECTED", headers.getPasscode());
|
||||
assertArrayEquals(new long[] {10000, 10000}, headers.getHeartbeat());
|
||||
assertEquals(new HashSet<>(Arrays.asList("1.1","1.0")), headers.getAcceptVersion());
|
||||
|
||||
assertEquals(0, this.session.getSentMessages().size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.stomp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
|
||||
|
||||
/**
|
||||
* A builder for creating WebSocket messages with STOMP frame content.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class StompTextMessageBuilder {
|
||||
|
||||
private StompCommand command;
|
||||
|
||||
private final List<String> headerLines = new ArrayList<String>();
|
||||
|
||||
private String body;
|
||||
|
||||
|
||||
private StompTextMessageBuilder(StompCommand command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public static StompTextMessageBuilder create(StompCommand command) {
|
||||
return new StompTextMessageBuilder(command);
|
||||
}
|
||||
|
||||
public StompTextMessageBuilder headers(String... headerLines) {
|
||||
this.headerLines.addAll(Arrays.asList(headerLines));
|
||||
return this;
|
||||
}
|
||||
|
||||
public StompTextMessageBuilder body(String body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextMessage build() {
|
||||
StringBuilder sb = new StringBuilder(this.command.name()).append("\n");
|
||||
for (String line : this.headerLines) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
if (this.body != null) {
|
||||
sb.append(this.body);
|
||||
}
|
||||
sb.append("\u0000");
|
||||
return new TextMessage(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user