/*
* Copyright 2002-2017 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.web.socket.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.CustomScopeConfigurer;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.MethodParameter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.converter.ByteArrayMessageConverter;
import org.springframework.messaging.converter.CompositeMessageConverter;
import org.springframework.messaging.converter.ContentTypeResolver;
import org.springframework.messaging.converter.DefaultContentTypeResolver;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
import org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler;
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;
import org.springframework.messaging.support.ImmutableMessageChannelInterceptor;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.MimeTypeUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator;
import org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator;
import org.springframework.web.socket.handler.TestWebSocketSession;
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
import org.springframework.web.socket.messaging.DefaultSimpUserRegistry;
import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler;
import org.springframework.web.socket.messaging.StompSubProtocolHandler;
import org.springframework.web.socket.messaging.SubProtocolHandler;
import org.springframework.web.socket.messaging.SubProtocolWebSocketHandler;
import org.springframework.web.socket.server.HandshakeHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.OriginHandshakeInterceptor;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler;
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.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Test fixture for MessageBrokerBeanDefinitionParser.
* See test configuration files websocket-config-broker-*.xml.
*
* @author Brian Clozel
* @author Artem Bilan
* @author Rossen Stoyanchev
*/
public class MessageBrokerBeanDefinitionParserTests {
private final GenericWebApplicationContext appContext = new GenericWebApplicationContext();
@Test
@SuppressWarnings("unchecked")
public void simpleBroker() throws Exception {
loadBeanDefinitions("websocket-config-broker-simple.xml");
HandlerMapping hm = this.appContext.getBean(HandlerMapping.class);
assertThat(hm, Matchers.instanceOf(SimpleUrlHandlerMapping.class));
SimpleUrlHandlerMapping suhm = (SimpleUrlHandlerMapping) hm;
assertThat(suhm.getUrlMap().keySet(), Matchers.hasSize(4));
assertThat(suhm.getUrlMap().values(), Matchers.hasSize(4));
HttpRequestHandler httpRequestHandler = (HttpRequestHandler) suhm.getUrlMap().get("/foo");
assertNotNull(httpRequestHandler);
assertThat(httpRequestHandler, Matchers.instanceOf(WebSocketHttpRequestHandler.class));
WebSocketHttpRequestHandler wsHttpRequestHandler = (WebSocketHttpRequestHandler) httpRequestHandler;
HandshakeHandler handshakeHandler = wsHttpRequestHandler.getHandshakeHandler();
assertNotNull(handshakeHandler);
assertTrue(handshakeHandler instanceof TestHandshakeHandler);
List<HandshakeInterceptor> interceptors = wsHttpRequestHandler.getHandshakeInterceptors();
assertThat(interceptors, contains(instanceOf(FooTestInterceptor.class),
instanceOf(BarTestInterceptor.class), instanceOf(OriginHandshakeInterceptor.class)));
WebSocketSession session = new TestWebSocketSession("id");
wsHttpRequestHandler.getWebSocketHandler().afterConnectionEstablished(session);
assertEquals(true, session.getAttributes().get("decorated"));
WebSocketHandler wsHandler = wsHttpRequestHandler.getWebSocketHandler();
assertThat(wsHandler, Matchers.instanceOf(ExceptionWebSocketHandlerDecorator.class));
wsHandler = ((ExceptionWebSocketHandlerDecorator) wsHandler).getDelegate();
assertThat(wsHandler, Matchers.instanceOf(LoggingWebSocketHandlerDecorator.class));
wsHandler = ((LoggingWebSocketHandlerDecorator) wsHandler).getDelegate();
assertThat(wsHandler, Matchers.instanceOf(TestWebSocketHandlerDecorator.class));
wsHandler = ((TestWebSocketHandlerDecorator) wsHandler).getDelegate();
assertThat(wsHandler, Matchers.instanceOf(SubProtocolWebSocketHandler.class));
assertSame(wsHandler, this.appContext.getBean(MessageBrokerBeanDefinitionParser.WEB_SOCKET_HANDLER_BEAN_NAME));
SubProtocolWebSocketHandler subProtocolWsHandler = (SubProtocolWebSocketHandler) wsHandler;
assertEquals(Arrays.asList("v10.stomp", "v11.stomp", "v12.stomp"), subProtocolWsHandler.getSubProtocols());
assertEquals(25 * 1000, subProtocolWsHandler.getSendTimeLimit());
assertEquals(1024 * 1024, subProtocolWsHandler.getSendBufferSizeLimit());
Map<String, SubProtocolHandler> handlerMap = subProtocolWsHandler.getProtocolHandlerMap();
StompSubProtocolHandler stompHandler = (StompSubProtocolHandler) handlerMap.get("v12.stomp");
assertNotNull(stompHandler);
assertEquals(128 * 1024, stompHandler.getMessageSizeLimit());
assertNotNull(stompHandler.getErrorHandler());
assertEquals(TestStompErrorHandler.class, stompHandler.getErrorHandler().getClass());
assertNotNull(new DirectFieldAccessor(stompHandler).getPropertyValue("eventPublisher"));
httpRequestHandler = (HttpRequestHandler) suhm.getUrlMap().get("/test/**");
assertNotNull(httpRequestHandler);
assertThat(httpRequestHandler, Matchers.instanceOf(SockJsHttpRequestHandler.class));
SockJsHttpRequestHandler sockJsHttpRequestHandler = (SockJsHttpRequestHandler) httpRequestHandler;
wsHandler = unwrapWebSocketHandler(sockJsHttpRequestHandler.getWebSocketHandler());
assertNotNull(wsHandler);
assertThat(wsHandler, Matchers.instanceOf(SubProtocolWebSocketHandler.class));
assertNotNull(sockJsHttpRequestHandler.getSockJsService());
assertThat(sockJsHttpRequestHandler.getSockJsService(), Matchers.instanceOf(DefaultSockJsService.class));
DefaultSockJsService defaultSockJsService = (DefaultSockJsService) sockJsHttpRequestHandler.getSockJsService();
WebSocketTransportHandler wsTransportHandler = (WebSocketTransportHandler) defaultSockJsService
.getTransportHandlers().get(TransportType.WEBSOCKET);
assertNotNull(wsTransportHandler.getHandshakeHandler());
assertThat(wsTransportHandler.getHandshakeHandler(), Matchers.instanceOf(TestHandshakeHandler.class));
assertFalse(defaultSockJsService.shouldSuppressCors());
ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler) defaultSockJsService.getTaskScheduler();
assertEquals(Runtime.getRuntime().availableProcessors(), scheduler.getScheduledThreadPoolExecutor().getCorePoolSize());
assertTrue(scheduler.getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy());
interceptors = defaultSockJsService.getHandshakeInterceptors();
assertThat(interceptors, contains(instanceOf(FooTestInterceptor.class),
instanceOf(BarTestInterceptor.class), instanceOf(OriginHandshakeInterceptor.class)));
assertTrue(defaultSockJsService.getAllowedOrigins().contains("http://mydomain3.com"));
assertTrue(defaultSockJsService.getAllowedOrigins().contains("http://mydomain4.com"));
SimpUserRegistry userRegistry = this.appContext.getBean(SimpUserRegistry.class);
assertNotNull(userRegistry);
assertEquals(DefaultSimpUserRegistry.class, userRegistry.getClass());
UserDestinationResolver userDestResolver = this.appContext.getBean(UserDestinationResolver.class);
assertNotNull(userDestResolver);
assertThat(userDestResolver, Matchers.instanceOf(DefaultUserDestinationResolver.class));
DefaultUserDestinationResolver defaultUserDestResolver = (DefaultUserDestinationResolver) userDestResolver;
assertEquals("/personal/", defaultUserDestResolver.getDestinationPrefix());
UserDestinationMessageHandler userDestHandler = this.appContext.getBean(UserDestinationMessageHandler.class);
assertNotNull(userDestHandler);
SimpleBrokerMessageHandler brokerMessageHandler = this.appContext.getBean(SimpleBrokerMessageHandler.class);
assertNotNull(brokerMessageHandler);
Collection<String> prefixes = brokerMessageHandler.getDestinationPrefixes();
assertEquals(Arrays.asList("/topic", "/queue"), new ArrayList<>(prefixes));
assertNotNull(brokerMessageHandler.getTaskScheduler());
assertArrayEquals(new long[] {15000, 15000}, brokerMessageHandler.getHeartbeatValue());
List<Class<? extends MessageHandler>> subscriberTypes =
Arrays.<Class<? extends MessageHandler>>asList(SimpAnnotationMethodMessageHandler.class,
UserDestinationMessageHandler.class, SimpleBrokerMessageHandler.class);
testChannel("clientInboundChannel", subscriberTypes, 2);
testExecutor("clientInboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
subscriberTypes = Collections.singletonList(SubProtocolWebSocketHandler.class);
testChannel("clientOutboundChannel", subscriberTypes, 1);
testExecutor("clientOutboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
subscriberTypes = Arrays.<Class<? extends MessageHandler>>asList(
SimpleBrokerMessageHandler.class, UserDestinationMessageHandler.class);
testChannel("brokerChannel", subscriberTypes, 1);
try {
this.appContext.getBean("brokerChannelExecutor", ThreadPoolTaskExecutor.class);
fail("expected exception");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
assertNotNull(this.appContext.getBean("webSocketScopeConfigurer", CustomScopeConfigurer.class));
DirectFieldAccessor subscriptionRegistryAccessor = new DirectFieldAccessor(brokerMessageHandler.getSubscriptionRegistry());
String pathSeparator = (String) new DirectFieldAccessor(subscriptionRegistryAccessor.getPropertyValue("pathMatcher")).getPropertyValue("pathSeparator");
assertEquals(".", pathSeparator);
}
@Test
public void stompBrokerRelay() {
loadBeanDefinitions("websocket-config-broker-relay.xml");
HandlerMapping hm = this.appContext.getBean(HandlerMapping.class);
assertNotNull(hm);
assertThat(hm, Matchers.instanceOf(SimpleUrlHandlerMapping.class));
SimpleUrlHandlerMapping suhm = (SimpleUrlHandlerMapping) hm;
assertThat(suhm.getUrlMap().keySet(), Matchers.hasSize(1));
assertThat(suhm.getUrlMap().values(), Matchers.hasSize(1));
assertEquals(2, suhm.getOrder());
HttpRequestHandler httpRequestHandler = (HttpRequestHandler) suhm.getUrlMap().get("/foo/**");
assertNotNull(httpRequestHandler);
assertThat(httpRequestHandler, Matchers.instanceOf(SockJsHttpRequestHandler.class));
SockJsHttpRequestHandler sockJsHttpRequestHandler = (SockJsHttpRequestHandler) httpRequestHandler;
WebSocketHandler wsHandler = unwrapWebSocketHandler(sockJsHttpRequestHandler.getWebSocketHandler());
assertNotNull(wsHandler);
assertThat(wsHandler, Matchers.instanceOf(SubProtocolWebSocketHandler.class));
assertNotNull(sockJsHttpRequestHandler.getSockJsService());
UserDestinationResolver userDestResolver = this.appContext.getBean(UserDestinationResolver.class);
assertNotNull(userDestResolver);
assertThat(userDestResolver, Matchers.instanceOf(DefaultUserDestinationResolver.class));
DefaultUserDestinationResolver defaultUserDestResolver = (DefaultUserDestinationResolver) userDestResolver;
assertEquals("/user/", defaultUserDestResolver.getDestinationPrefix());
StompBrokerRelayMessageHandler messageBroker = this.appContext.getBean(StompBrokerRelayMessageHandler.class);
assertNotNull(messageBroker);
assertEquals("clientlogin", messageBroker.getClientLogin());
assertEquals("clientpass", messageBroker.getClientPasscode());
assertEquals("syslogin", messageBroker.getSystemLogin());
assertEquals("syspass", messageBroker.getSystemPasscode());
assertEquals("relayhost", messageBroker.getRelayHost());
assertEquals(1234, messageBroker.getRelayPort());
assertEquals("spring.io", messageBroker.getVirtualHost());
assertEquals(5000, messageBroker.getSystemHeartbeatReceiveInterval());
assertEquals(5000, messageBroker.getSystemHeartbeatSendInterval());
assertThat(messageBroker.getDestinationPrefixes(), Matchers.containsInAnyOrder("/topic","/queue"));
List<Class<? extends MessageHandler>> subscriberTypes =
Arrays.<Class<? extends MessageHandler>>asList(SimpAnnotationMethodMessageHandler.class,
UserDestinationMessageHandler.class, StompBrokerRelayMessageHandler.class);
testChannel("clientInboundChannel", subscriberTypes, 2);
testExecutor("clientInboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
subscriberTypes = Collections.singletonList(SubProtocolWebSocketHandler.class);
testChannel("clientOutboundChannel", subscriberTypes, 1);
testExecutor("clientOutboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
subscriberTypes = Arrays.<Class<? extends MessageHandler>>asList(
StompBrokerRelayMessageHandler.class, UserDestinationMessageHandler.class);
testChannel("brokerChannel", subscriberTypes, 1);
try {
this.appContext.getBean("brokerChannelExecutor", ThreadPoolTaskExecutor.class);
fail("expected exception");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
String destination = "/topic/unresolved-user-destination";
UserDestinationMessageHandler userDestHandler = this.appContext.getBean(UserDestinationMessageHandler.class);
assertEquals(destination, userDestHandler.getBroadcastDestination());
assertNotNull(messageBroker.getSystemSubscriptions());
assertSame(userDestHandler, messageBroker.getSystemSubscriptions().get(destination));
destination = "/topic/simp-user-registry";
UserRegistryMessageHandler userRegistryHandler = this.appContext.getBean(UserRegistryMessageHandler.class);
assertEquals(destination, userRegistryHandler.getBroadcastDestination());
assertNotNull(messageBroker.getSystemSubscriptions());
assertSame(userRegistryHandler, messageBroker.getSystemSubscriptions().get(destination));
SimpUserRegistry userRegistry = this.appContext.getBean(SimpUserRegistry.class);
assertEquals(MultiServerUserRegistry.class, userRegistry.getClass());
String name = "webSocketMessageBrokerStats";
WebSocketMessageBrokerStats stats = this.appContext.getBean(name, WebSocketMessageBrokerStats.class);
String actual = stats.toString();
String expected = "WebSocketSession\\[0 current WS\\(0\\)-HttpStream\\(0\\)-HttpPoll\\(0\\), " +
"0 total, 0 closed abnormally \\(0 connect failure, 0 send limit, 0 transport error\\)\\], " +
"stompSubProtocol\\[processed CONNECT\\(0\\)-CONNECTED\\(0\\)-DISCONNECT\\(0\\)\\], " +
"stompBrokerRelay\\[0 sessions, relayhost:1234 \\(not available\\), processed CONNECT\\(0\\)-CONNECTED\\(0\\)-DISCONNECT\\(0\\)\\], " +
"inboundChannel\\[pool size = \\d, active threads = \\d, queued tasks = \\d, completed tasks = \\d\\], " +
"outboundChannelpool size = \\d, active threads = \\d, queued tasks = \\d, completed tasks = \\d\\], " +
"sockJsScheduler\\[pool size = \\d, active threads = \\d, queued tasks = \\d, completed tasks = \\d\\]";
assertTrue("\nExpected: " + expected.replace("\\", "") + "\n Actual: " + actual, actual.matches(expected));
}
@Test
public void annotationMethodMessageHandler() {
loadBeanDefinitions("websocket-config-broker-simple.xml");
SimpAnnotationMethodMessageHandler annotationMethodMessageHandler =
this.appContext.getBean(SimpAnnotationMethodMessageHandler.class);
assertNotNull(annotationMethodMessageHandler);
MessageConverter messageConverter = annotationMethodMessageHandler.getMessageConverter();
assertNotNull(messageConverter);
assertTrue(messageConverter instanceof CompositeMessageConverter);
String name = MessageBrokerBeanDefinitionParser.MESSAGE_CONVERTER_BEAN_NAME;
CompositeMessageConverter compositeMessageConverter = this.appContext.getBean(name, CompositeMessageConverter.class);
assertNotNull(compositeMessageConverter);
name = MessageBrokerBeanDefinitionParser.MESSAGING_TEMPLATE_BEAN_NAME;
SimpMessagingTemplate simpMessagingTemplate = this.appContext.getBean(name, SimpMessagingTemplate.class);
assertNotNull(simpMessagingTemplate);
assertEquals("/personal/", simpMessagingTemplate.getUserDestinationPrefix());
List<MessageConverter> converters = compositeMessageConverter.getConverters();
assertThat(converters.size(), Matchers.is(3));
assertThat(converters.get(0), Matchers.instanceOf(StringMessageConverter.class));
assertThat(converters.get(1), Matchers.instanceOf(ByteArrayMessageConverter.class));
assertThat(converters.get(2), Matchers.instanceOf(MappingJackson2MessageConverter.class));
ContentTypeResolver resolver = ((MappingJackson2MessageConverter) converters.get(2)).getContentTypeResolver();
assertEquals(MimeTypeUtils.APPLICATION_JSON, ((DefaultContentTypeResolver) resolver).getDefaultMimeType());
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(annotationMethodMessageHandler);
String pathSeparator = (String) new DirectFieldAccessor(handlerAccessor.getPropertyValue("pathMatcher")).getPropertyValue("pathSeparator");
assertEquals(".", pathSeparator);
}
@Test
public void customChannels() {
loadBeanDefinitions("websocket-config-broker-customchannels.xml");
SimpAnnotationMethodMessageHandler annotationMethodMessageHandler =
this.appContext.getBean(SimpAnnotationMethodMessageHandler.class);
Validator validator = annotationMethodMessageHandler.getValidator();
assertNotNull(validator);
assertSame(this.appContext.getBean("myValidator"), validator);
assertThat(validator, Matchers.instanceOf(TestValidator.class));
List<Class<? extends MessageHandler>> subscriberTypes =
Arrays.<Class<? extends MessageHandler>>asList(SimpAnnotationMethodMessageHandler.class,
UserDestinationMessageHandler.class, SimpleBrokerMessageHandler.class);
testChannel("clientInboundChannel", subscriberTypes, 3);
testExecutor("clientInboundChannel", 100, 200, 600);
subscriberTypes = Collections.singletonList(SubProtocolWebSocketHandler.class);
testChannel("clientOutboundChannel", subscriberTypes, 3);
testExecutor("clientOutboundChannel", 101, 201, 601);
subscriberTypes = Arrays.<Class<? extends MessageHandler>>asList(SimpleBrokerMessageHandler.class,
UserDestinationMessageHandler.class);
testChannel("brokerChannel", subscriberTypes, 1);
testExecutor("brokerChannel", 102, 202, 602);
}
// SPR-11623
@Test
public void customChannelsWithDefaultExecutor() {
loadBeanDefinitions("websocket-config-broker-customchannels-default-executor.xml");
testExecutor("clientInboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
testExecutor("clientOutboundChannel", Runtime.getRuntime().availableProcessors() * 2, Integer.MAX_VALUE, 60);
assertFalse(this.appContext.containsBean("brokerChannelExecutor"));
}
@Test
public void customArgumentAndReturnValueTypes() {
loadBeanDefinitions("websocket-config-broker-custom-argument-and-return-value-types.xml");
SimpAnnotationMethodMessageHandler handler = this.appContext.getBean(SimpAnnotationMethodMessageHandler.class);
List<HandlerMethodArgumentResolver> customResolvers = handler.getCustomArgumentResolvers();
assertEquals(2, customResolvers.size());
assertTrue(handler.getArgumentResolvers().contains(customResolvers.get(0)));
assertTrue(handler.getArgumentResolvers().contains(customResolvers.get(1)));
List<HandlerMethodReturnValueHandler> customHandlers = handler.getCustomReturnValueHandlers();
assertEquals(2, customHandlers.size());
assertTrue(handler.getReturnValueHandlers().contains(customHandlers.get(0)));
assertTrue(handler.getReturnValueHandlers().contains(customHandlers.get(1)));
}
@Test
public void messageConverters() {
loadBeanDefinitions("websocket-config-broker-converters.xml");
CompositeMessageConverter compositeConverter = this.appContext.getBean(CompositeMessageConverter.class);
assertNotNull(compositeConverter);
assertEquals(4, compositeConverter.getConverters().size());
assertEquals(StringMessageConverter.class, compositeConverter.getConverters().iterator().next().getClass());
}
@Test
public void messageConvertersDefaultsOff() {
loadBeanDefinitions("websocket-config-broker-converters-defaults-off.xml");
CompositeMessageConverter compositeConverter = this.appContext.getBean(CompositeMessageConverter.class);
assertNotNull(compositeConverter);
assertEquals(1, compositeConverter.getConverters().size());
assertEquals(StringMessageConverter.class, compositeConverter.getConverters().iterator().next().getClass());
}
private void testChannel(String channelName, List<Class<? extends MessageHandler>> subscriberTypes,
int interceptorCount) {
AbstractSubscribableChannel channel = this.appContext.getBean(channelName, AbstractSubscribableChannel.class);
for (Class<? extends MessageHandler> subscriberType : subscriberTypes) {
MessageHandler subscriber = this.appContext.getBean(subscriberType);
assertNotNull("No subsription for " + subscriberType, subscriber);
assertTrue(channel.hasSubscription(subscriber));
}
List<ChannelInterceptor> interceptors = channel.getInterceptors();
assertEquals(interceptorCount, interceptors.size());
assertEquals(ImmutableMessageChannelInterceptor.class, interceptors.get(interceptors.size()-1).getClass());
}
private void testExecutor(String channelName, int corePoolSize, int maxPoolSize, int keepAliveSeconds) {
ThreadPoolTaskExecutor taskExecutor =
this.appContext.getBean(channelName + "Executor", ThreadPoolTaskExecutor.class);
assertEquals(corePoolSize, taskExecutor.getCorePoolSize());
assertEquals(maxPoolSize, taskExecutor.getMaxPoolSize());
assertEquals(keepAliveSeconds, taskExecutor.getKeepAliveSeconds());
}
private void loadBeanDefinitions(String fileName) {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.appContext);
ClassPathResource resource = new ClassPathResource(fileName, MessageBrokerBeanDefinitionParserTests.class);
reader.loadBeanDefinitions(resource);
this.appContext.setServletContext(new MockServletContext());
this.appContext.refresh();
}
private WebSocketHandler unwrapWebSocketHandler(WebSocketHandler handler) {
return (handler instanceof WebSocketHandlerDecorator) ?
((WebSocketHandlerDecorator) handler).getLastHandler() : handler;
}
}
class CustomArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
return null;
}
}
class CustomReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return false;
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, Message<?> message) throws Exception {
}
}
class TestWebSocketHandlerDecoratorFactory implements WebSocketHandlerDecoratorFactory {
@Override
public WebSocketHandler decorate(WebSocketHandler handler) {
return new TestWebSocketHandlerDecorator(handler);
}
}
class TestWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
public TestWebSocketHandlerDecorator(WebSocketHandler delegate) {
super(delegate);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
session.getAttributes().put("decorated", true);
super.afterConnectionEstablished(session);
}
}
class TestStompErrorHandler extends StompSubProtocolErrorHandler {
}
class TestValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(Object target, Errors errors) { }
}