@Test
  public void sockJsAttributesSupport() {
    loadBeanDefinitions("websocket-config-handlers-sockjs-attributes.xml");
    SimpleUrlHandlerMapping handlerMapping = appContext.getBean(SimpleUrlHandlerMapping.class);
    assertNotNull(handlerMapping);
    SockJsHttpRequestHandler handler =
        (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/test/**");
    assertNotNull(handler);
    checkDelegateHandlerType(handler.getWebSocketHandler(), TestWebSocketHandler.class);
    SockJsService sockJsService = handler.getSockJsService();
    assertNotNull(sockJsService);
    assertThat(sockJsService, Matchers.instanceOf(TransportHandlingSockJsService.class));
    TransportHandlingSockJsService defaultSockJsService =
        (TransportHandlingSockJsService) sockJsService;
    assertThat(
        defaultSockJsService.getTaskScheduler(), Matchers.instanceOf(TestTaskScheduler.class));
    assertThat(
        defaultSockJsService.getTransportHandlers().values(),
        Matchers.containsInAnyOrder(
            Matchers.instanceOf(XhrPollingTransportHandler.class),
            Matchers.instanceOf(XhrStreamingTransportHandler.class)));

    assertEquals("testSockJsService", defaultSockJsService.getName());
    assertFalse(defaultSockJsService.isWebSocketEnabled());
    assertFalse(defaultSockJsService.isSessionCookieNeeded());
    assertEquals(2048, defaultSockJsService.getStreamBytesLimit());
    assertEquals(256, defaultSockJsService.getDisconnectDelay());
    assertEquals(1024, defaultSockJsService.getHttpMessageCacheSize());
    assertEquals(20, defaultSockJsService.getHeartbeatTime());
  }
  @Test
  public void sockJsSupport() {
    loadBeanDefinitions("websocket-config-handlers-sockjs.xml");
    SimpleUrlHandlerMapping handlerMapping = appContext.getBean(SimpleUrlHandlerMapping.class);
    assertNotNull(handlerMapping);
    SockJsHttpRequestHandler testHandler =
        (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/test/**");
    assertNotNull(testHandler);
    checkDelegateHandlerType(testHandler.getWebSocketHandler(), TestWebSocketHandler.class);
    SockJsService testSockJsService = testHandler.getSockJsService();
    SockJsHttpRequestHandler fooHandler =
        (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/foo/**");
    assertNotNull(fooHandler);
    checkDelegateHandlerType(fooHandler.getWebSocketHandler(), FooWebSocketHandler.class);

    SockJsService sockJsService = fooHandler.getSockJsService();
    assertNotNull(sockJsService);
    assertEquals(testSockJsService, sockJsService);

    assertThat(sockJsService, Matchers.instanceOf(DefaultSockJsService.class));
    DefaultSockJsService defaultSockJsService = (DefaultSockJsService) sockJsService;
    assertThat(
        defaultSockJsService.getTaskScheduler(),
        Matchers.instanceOf(ThreadPoolTaskScheduler.class));
    assertThat(
        defaultSockJsService.getTransportHandlers().values(),
        Matchers.containsInAnyOrder(
            Matchers.instanceOf(XhrPollingTransportHandler.class),
            Matchers.instanceOf(XhrReceivingTransportHandler.class),
            Matchers.instanceOf(JsonpPollingTransportHandler.class),
            Matchers.instanceOf(JsonpReceivingTransportHandler.class),
            Matchers.instanceOf(XhrStreamingTransportHandler.class),
            Matchers.instanceOf(EventSourceTransportHandler.class),
            Matchers.instanceOf(HtmlFileTransportHandler.class),
            Matchers.instanceOf(WebSocketTransportHandler.class)));
  }
  @Test
  public void simpleBroker() {
    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)));

    WebSocketHandler wsHandler = unwrapWebSocketHandler(wsHttpRequestHandler.getWebSocketHandler());
    assertNotNull(wsHandler);
    assertThat(wsHandler, Matchers.instanceOf(SubProtocolWebSocketHandler.class));

    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());

    StompSubProtocolHandler stompHandler =
        (StompSubProtocolHandler) subProtocolWsHandler.getProtocolHandlerMap().get("v12.stomp");
    assertNotNull(stompHandler);
    assertEquals(128 * 1024, stompHandler.getMessageSizeLimit());

    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));

    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)));

    UserSessionRegistry userSessionRegistry = this.appContext.getBean(UserSessionRegistry.class);
    assertNotNull(userSessionRegistry);

    UserDestinationResolver userDestResolver =
        this.appContext.getBean(UserDestinationResolver.class);
    assertNotNull(userDestResolver);
    assertThat(userDestResolver, Matchers.instanceOf(DefaultUserDestinationResolver.class));
    DefaultUserDestinationResolver defaultUserDestResolver =
        (DefaultUserDestinationResolver) userDestResolver;
    assertEquals("/personal/", defaultUserDestResolver.getDestinationPrefix());
    assertSame(
        stompHandler.getUserSessionRegistry(), defaultUserDestResolver.getUserSessionRegistry());

    UserDestinationMessageHandler userDestHandler =
        this.appContext.getBean(UserDestinationMessageHandler.class);
    assertNotNull(userDestHandler);

    SimpleBrokerMessageHandler brokerMessageHandler =
        this.appContext.getBean(SimpleBrokerMessageHandler.class);
    assertNotNull(brokerMessageHandler);
    assertEquals(
        Arrays.asList("/topic", "/queue"),
        new ArrayList<String>(brokerMessageHandler.getDestinationPrefixes()));

    List<Class<? extends MessageHandler>> subscriberTypes =
        Arrays.<Class<? extends MessageHandler>>asList(
            SimpAnnotationMethodMessageHandler.class,
            UserDestinationMessageHandler.class,
            SimpleBrokerMessageHandler.class);
    testChannel("clientInboundChannel", subscriberTypes, 0);
    testExecutor(
        "clientInboundChannel",
        Runtime.getRuntime().availableProcessors() * 2,
        Integer.MAX_VALUE,
        60);

    subscriberTypes =
        Arrays.<Class<? extends MessageHandler>>asList(SubProtocolWebSocketHandler.class);
    testChannel("clientOutboundChannel", subscriberTypes, 0);
    testExecutor(
        "clientOutboundChannel",
        Runtime.getRuntime().availableProcessors() * 2,
        Integer.MAX_VALUE,
        60);

    subscriberTypes =
        Arrays.<Class<? extends MessageHandler>>asList(
            SimpleBrokerMessageHandler.class, UserDestinationMessageHandler.class);
    testChannel("brokerChannel", subscriberTypes, 0);
    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, 0);
    testExecutor(
        "clientInboundChannel",
        Runtime.getRuntime().availableProcessors() * 2,
        Integer.MAX_VALUE,
        60);

    subscriberTypes =
        Arrays.<Class<? extends MessageHandler>>asList(SubProtocolWebSocketHandler.class);
    testChannel("clientOutboundChannel", subscriberTypes, 0);
    testExecutor(
        "clientOutboundChannel",
        Runtime.getRuntime().availableProcessors() * 2,
        Integer.MAX_VALUE,
        60);

    subscriberTypes =
        Arrays.<Class<? extends MessageHandler>>asList(
            StompBrokerRelayMessageHandler.class, UserDestinationMessageHandler.class);
    testChannel("brokerChannel", subscriberTypes, 0);
    try {
      this.appContext.getBean("brokerChannelExecutor", ThreadPoolTaskExecutor.class);
      fail("expected exception");
    } catch (NoSuchBeanDefinitionException ex) {
      // expected
    }

    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));
  }