@Override public void init() { registerBeanDefinitionParser("handlers", new HandlersBeanDefinitionParser()); if (isSpringMessagingPresent) { registerBeanDefinitionParser("message-broker", new MessageBrokerBeanDefinitionParser()); } }
/** * Get stats about the executor processing incoming messages from WebSocket clients. */ public String getClientInboundExecutorStatsInfo() { return (this.inboundChannelExecutor != null ? getExecutorStatsInfo(this.inboundChannelExecutor) : "null"); }
public String toString() { return "WebSocketSession[" + getWebSocketSessionStatsInfo() + "]" + ", stompSubProtocol[" + getStompSubProtocolStatsInfo() + "]" + ", stompBrokerRelay[" + getStompBrokerRelayStatsInfo() + "]" + ", inboundChannel[" + getClientInboundExecutorStatsInfo() + "]" + ", outboundChannel[" + getClientOutboundExecutorStatsInfo() + "]" + ", sockJsScheduler[" + getSockJsTaskSchedulerStatsInfo() + "]"; }
@Bean public WebSocketMessageBrokerStats webSocketMessageBrokerStats() { AbstractBrokerMessageHandler relayBean = stompBrokerRelayMessageHandler(); // Ensure STOMP endpoints are registered stompWebSocketHandlerMapping(); WebSocketMessageBrokerStats stats = new WebSocketMessageBrokerStats(); stats.setSubProtocolWebSocketHandler((SubProtocolWebSocketHandler) subProtocolWebSocketHandler()); if (relayBean instanceof StompBrokerRelayMessageHandler) { stats.setStompBrokerRelay((StompBrokerRelayMessageHandler) relayBean); } stats.setInboundChannelExecutor(clientInboundChannelExecutor()); stats.setOutboundChannelExecutor(clientOutboundChannelExecutor()); stats.setSockJsTaskScheduler(messageBrokerTaskScheduler()); return stats; }
private RuntimeBeanReference registerUserRegistryMessageHandler( RuntimeBeanReference userRegistry, RuntimeBeanReference brokerTemplate, String destination, ParserContext context, @Nullable Object source) { Object scheduler = WebSocketNamespaceUtils.registerScheduler(SCHEDULER_BEAN_NAME, context, source); RootBeanDefinition beanDef = new RootBeanDefinition(UserRegistryMessageHandler.class); beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, userRegistry); beanDef.getConstructorArgumentValues().addIndexedArgumentValue(1, brokerTemplate); beanDef.getConstructorArgumentValues().addIndexedArgumentValue(2, destination); beanDef.getConstructorArgumentValues().addIndexedArgumentValue(3, scheduler); String beanName = registerBeanDef(beanDef, context, source); return new RuntimeBeanReference(beanName); }
private void registerWebSocketMessageBrokerStats(RootBeanDefinition broker, RuntimeBeanReference inChannel, RuntimeBeanReference outChannel, ParserContext context, @Nullable Object source) { RootBeanDefinition beanDef = new RootBeanDefinition(WebSocketMessageBrokerStats.class); RuntimeBeanReference webSocketHandler = new RuntimeBeanReference(WEB_SOCKET_HANDLER_BEAN_NAME); beanDef.getPropertyValues().add("subProtocolWebSocketHandler", webSocketHandler); if (StompBrokerRelayMessageHandler.class == broker.getBeanClass()) { beanDef.getPropertyValues().add("stompBrokerRelay", broker); } String name = inChannel.getBeanName() + "Executor"; if (context.getRegistry().containsBeanDefinition(name)) { beanDef.getPropertyValues().add("inboundChannelExecutor", context.getRegistry().getBeanDefinition(name)); } name = outChannel.getBeanName() + "Executor"; if (context.getRegistry().containsBeanDefinition(name)) { beanDef.getPropertyValues().add("outboundChannelExecutor", context.getRegistry().getBeanDefinition(name)); } Object scheduler = WebSocketNamespaceUtils.registerScheduler(SCHEDULER_BEAN_NAME, context, source); beanDef.getPropertyValues().add("sockJsTaskScheduler", scheduler); registerBeanDefByName("webSocketMessageBrokerStats", beanDef, context, source); }
@Test public void webSocketMessageBrokerStats() { ApplicationContext config = createConfig(TestChannelConfig.class, TestConfigurer.class); String name = "webSocketMessageBrokerStats"; WebSocketMessageBrokerStats stats = config.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\\[null\\], " + "inboundChannel\\[pool size = \\d, active threads = \\d, queued tasks = \\d, completed tasks = \\d\\], " + "outboundChannel\\[pool 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)); }
@Nullable private ScheduledFuture<?> initLoggingTask(long initialDelay) { if (this.sockJsTaskScheduler != null && this.loggingPeriod > 0 && logger.isInfoEnabled()) { return this.sockJsTaskScheduler.scheduleAtFixedRate(() -> logger.info(WebSocketMessageBrokerStats.this.toString()), initialDelay, this.loggingPeriod, TimeUnit.MILLISECONDS); } return null; }
/** * Set the frequency for logging information at INFO level in milliseconds. * If set 0 or less than 0, the logging task is cancelled. * <p>By default this property is set to 30 minutes (30 * 60 * 1000). */ public void setLoggingPeriod(long period) { if (this.loggingTask != null) { this.loggingTask.cancel(true); } this.loggingPeriod = period; this.loggingTask = initLoggingTask(0); }
private static String registerBeanDef(RootBeanDefinition beanDef, ParserContext context, @Nullable Object source) { String name = context.getReaderContext().generateBeanName(beanDef); registerBeanDefByName(name, beanDef, context, source); return name; }
public void setSubProtocolWebSocketHandler(SubProtocolWebSocketHandler webSocketHandler) { this.webSocketHandler = webSocketHandler; this.stompSubProtocolHandler = initStompSubProtocolHandler(); }
private RuntimeBeanReference registerUserDestResolver(Element brokerElem, RuntimeBeanReference userRegistry, ParserContext context, @Nullable Object source) { RootBeanDefinition beanDef = new RootBeanDefinition(DefaultUserDestinationResolver.class); beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, userRegistry); if (brokerElem.hasAttribute("user-destination-prefix")) { beanDef.getPropertyValues().add("userDestinationPrefix", brokerElem.getAttribute("user-destination-prefix")); } if (brokerElem.hasAttribute("path-matcher")) { String pathMatcherRef = brokerElem.getAttribute("path-matcher"); beanDef.getPropertyValues().add("pathMatcher", new RuntimeBeanReference(pathMatcherRef)); } return new RuntimeBeanReference(registerBeanDef(beanDef, context, source)); }
@Test // SPR-11623 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))); }
@Override public WebSocketHandler decorate(WebSocketHandler handler) { return new TestWebSocketHandlerDecorator(handler); } }
/** * Get stats about the SockJS task scheduler. */ public String getSockJsTaskSchedulerStatsInfo() { return (this.sockJsTaskScheduler != null ? getExecutorStatsInfo(this.sockJsTaskScheduler) : "null"); }
public void setSockJsTaskScheduler(ThreadPoolTaskScheduler sockJsTaskScheduler) { this.sockJsTaskScheduler = sockJsTaskScheduler.getScheduledThreadPoolExecutor(); this.loggingTask = initLoggingTask(TimeUnit.MINUTES.toMillis(1)); }
private RuntimeBeanReference registerMessagingTemplate(Element element, RuntimeBeanReference brokerChannel, RuntimeBeanReference messageConverter, ParserContext context, @Nullable Object source) { ConstructorArgumentValues cargs = new ConstructorArgumentValues(); cargs.addIndexedArgumentValue(0, brokerChannel); RootBeanDefinition beanDef = new RootBeanDefinition(SimpMessagingTemplate.class, cargs, null); if (element.hasAttribute("user-destination-prefix")) { beanDef.getPropertyValues().add("userDestinationPrefix", element.getAttribute("user-destination-prefix")); } beanDef.getPropertyValues().add("messageConverter", messageConverter); String name = MESSAGING_TEMPLATE_BEAN_NAME; registerBeanDefByName(name, beanDef, context, source); return new RuntimeBeanReference(name); }
@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()); }
/** * Get stats about the executor processing outgoing messages to WebSocket clients. */ public String getClientOutboundExecutorStatsInfo() { return (this.outboundChannelExecutor != null ? getExecutorStatsInfo(this.outboundChannelExecutor) : "null"); }