updateSessionReadTime(sessionId); if (!checkDestinationPrefix(destination)) { return; logMessage(message); sendMessageToSubscribers(destination, message); logMessage(message); if (sessionId != null) { long[] heartbeatIn = SimpMessageHeaderAccessor.getHeartbeat(headers); long[] heartbeatOut = getHeartbeatValue(); Principal user = SimpMessageHeaderAccessor.getUser(headers); MessageChannel outChannel = getClientOutboundChannelForSession(sessionId); this.sessions.put(sessionId, new SessionInfo(sessionId, user, outChannel, heartbeatIn, heartbeatOut)); SimpMessageHeaderAccessor connectAck = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT_ACK); initHeaders(connectAck); connectAck.setSessionId(sessionId); if (user != null) { connectAck.setHeader(SimpMessageHeaderAccessor.HEART_BEAT_HEADER, heartbeatOut); Message<byte[]> messageOut = MessageBuilder.createMessage(EMPTY_PAYLOAD, connectAck.getMessageHeaders()); getClientOutboundChannel().send(messageOut); logMessage(message); if (sessionId != null) { Principal user = SimpMessageHeaderAccessor.getUser(headers); handleDisconnect(sessionId, user, message);
@Override protected SimpleBrokerMessageHandler getMessageHandler(SubscribableChannel brokerChannel) { SimpleBrokerMessageHandler handler = new SimpleBrokerMessageHandler(getClientInboundChannel(), getClientOutboundChannel(), brokerChannel, getDestinationPrefixes()); if (this.taskScheduler != null) { handler.setTaskScheduler(this.taskScheduler); } if (this.heartbeat != null) { handler.setHeartbeatValue(this.heartbeat); } handler.setSelectorHeaderName(this.selectorHeaderName); return handler; }
private void initHeaders(SimpMessageHeaderAccessor accessor) { if (getHeaderInitializer() != null) { getHeaderInitializer().initHeaders(accessor); } }
@Override public void startInternal() { publishBrokerAvailableEvent(); if (this.taskScheduler != null) { long interval = initHeartbeatTaskDelay(); if (interval > 0) { this.heartbeatFuture = this.taskScheduler.scheduleWithFixedDelay(new HeartbeatTask(), interval); } } else { Assert.isTrue(getHeartbeatValue() == null || (getHeartbeatValue()[0] == 0 && getHeartbeatValue()[1] == 0), "Heartbeat values configured but no TaskScheduler provided"); } }
@Test(expected = IllegalArgumentException.class) public void startWithHeartbeatValueWithoutTaskScheduler() { this.messageHandler.setHeartbeatValue(new long[] {10000, 10000}); this.messageHandler.start(); }
@Test public void readWriteIntervalCalculation() throws Exception { this.messageHandler.setHeartbeatValue(new long[] {1, 1}); this.messageHandler.setTaskScheduler(this.taskScheduler); this.messageHandler.start(); ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.forClass(Runnable.class); verify(this.taskScheduler).scheduleWithFixedDelay(taskCaptor.capture(), eq(1L)); Runnable heartbeatTask = taskCaptor.getValue(); assertNotNull(heartbeatTask); String id = "sess1"; TestPrincipal user = new TestPrincipal("joe"); Message<String> connectMessage = createConnectMessage(id, user, new long[] {10000, 10000}); this.messageHandler.handleMessage(connectMessage); Thread.sleep(10); heartbeatTask.run(); verify(this.clientOutChannel, times(1)).send(this.messageCaptor.capture()); List<Message<?>> messages = this.messageCaptor.getAllValues(); assertEquals(1, messages.size()); assertEquals(SimpMessageType.CONNECT_ACK, messages.get(0).getHeaders().get(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER)); }
Collection<String> prefixes = brokerMessageHandler.getDestinationPrefixes(); assertEquals(Arrays.asList("/topic", "/queue"), new ArrayList<>(prefixes)); DefaultSubscriptionRegistry registry = (DefaultSubscriptionRegistry) brokerMessageHandler.getSubscriptionRegistry(); assertEquals("my-selector", registry.getSelectorHeaderName()); assertNotNull(brokerMessageHandler.getTaskScheduler()); assertArrayEquals(new long[] {15000, 15000}, brokerMessageHandler.getHeartbeatValue()); assertTrue(brokerMessageHandler.isPreservePublishOrder());
@SuppressWarnings("unchecked") @Test public void startAndStopWithHeartbeatValue() { ScheduledFuture future = mock(ScheduledFuture.class); when(this.taskScheduler.scheduleWithFixedDelay(any(Runnable.class), eq(15000L))).thenReturn(future); this.messageHandler.setTaskScheduler(this.taskScheduler); this.messageHandler.setHeartbeatValue(new long[] {15000, 16000}); this.messageHandler.start(); verify(this.taskScheduler).scheduleWithFixedDelay(any(Runnable.class), eq(15000L)); verifyNoMoreInteractions(this.taskScheduler, future); this.messageHandler.stop(); verify(future).cancel(true); verifyNoMoreInteractions(future); }
@Test public void customCacheLimit() { ApplicationContext context = loadConfig(CustomConfig.class); SimpleBrokerMessageHandler broker = context.getBean(SimpleBrokerMessageHandler.class); DefaultSubscriptionRegistry registry = (DefaultSubscriptionRegistry) broker.getSubscriptionRegistry(); assertEquals(8192, registry.getCacheLimit()); }
@SuppressWarnings("unchecked") @Test public void startWithOneZeroHeartbeatValue() { this.messageHandler.setTaskScheduler(this.taskScheduler); this.messageHandler.setHeartbeatValue(new long[] {0, 10000}); this.messageHandler.start(); verify(this.taskScheduler).scheduleWithFixedDelay(any(Runnable.class), eq(10000L)); }
private void handleDisconnect(String sessionId, @Nullable Principal user, @Nullable Message<?> origMessage) { this.sessions.remove(sessionId); this.subscriptionRegistry.unregisterAllSubscriptions(sessionId); SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create(SimpMessageType.DISCONNECT_ACK); accessor.setSessionId(sessionId); if (user != null) { accessor.setUser(user); } if (origMessage != null) { accessor.setHeader(SimpMessageHeaderAccessor.DISCONNECT_MESSAGE_HEADER, origMessage); } initHeaders(accessor); Message<byte[]> message = MessageBuilder.createMessage(EMPTY_PAYLOAD, accessor.getMessageHeaders()); getClientOutboundChannel().send(message); }
@Test public void heartbeatValueWithAndWithoutTaskScheduler() { assertNull(this.messageHandler.getHeartbeatValue()); this.messageHandler.setTaskScheduler(this.taskScheduler); assertNotNull(this.messageHandler.getHeartbeatValue()); assertArrayEquals(new long[] {10000, 10000}, this.messageHandler.getHeartbeatValue()); }
private long initHeartbeatTaskDelay() { if (getHeartbeatValue() == null) { return 0; } else if (getHeartbeatValue()[0] > 0 && getHeartbeatValue()[1] > 0) { return Math.min(getHeartbeatValue()[0], getHeartbeatValue()[1]); } else { return (getHeartbeatValue()[0] > 0 ? getHeartbeatValue()[0] : getHeartbeatValue()[1]); } }
private Message<String> startSession(String id) { this.messageHandler.start(); Message<String> connectMessage = createConnectMessage(id, new TestPrincipal("joe"), null); this.messageHandler.setTaskScheduler(this.taskScheduler); this.messageHandler.handleMessage(connectMessage); verify(this.clientOutChannel, times(1)).send(this.messageCaptor.capture()); reset(this.clientOutChannel); return connectMessage; }
@Test public void taskScheduler() { ApplicationContext config = createConfig(TestChannelConfig.class, TestConfigurer.class); String name = "messageBrokerSockJsTaskScheduler"; ThreadPoolTaskScheduler taskScheduler = config.getBean(name, ThreadPoolTaskScheduler.class); ScheduledThreadPoolExecutor executor = taskScheduler.getScheduledThreadPoolExecutor(); assertEquals(Runtime.getRuntime().availableProcessors(), executor.getCorePoolSize()); assertTrue(executor.getRemoveOnCancelPolicy()); SimpleBrokerMessageHandler handler = config.getBean(SimpleBrokerMessageHandler.class); assertNotNull(handler.getTaskScheduler()); assertArrayEquals(new long[] {15000, 15000}, handler.getHeartbeatValue()); }
@Before public void setup() { MockitoAnnotations.initMocks(this); this.messageHandler = new SimpleBrokerMessageHandler( this.clientInChannel, this.clientOutChannel, this.brokerChannel, Collections.emptyList()); }
@Override public void startInternal() { publishBrokerAvailableEvent(); if (this.taskScheduler != null) { long interval = initHeartbeatTaskDelay(); if (interval > 0) { this.heartbeatFuture = this.taskScheduler.scheduleWithFixedDelay(new HeartbeatTask(), interval); } } else { Assert.isTrue(getHeartbeatValue() == null || (getHeartbeatValue()[0] == 0 && getHeartbeatValue()[1] == 0), "Heartbeat values configured but no TaskScheduler provided"); } }
@Test public void writeInactivity() throws Exception { this.messageHandler.setHeartbeatValue(new long[] {1, 0}); this.messageHandler.setTaskScheduler(this.taskScheduler); this.messageHandler.start(); ArgumentCaptor<Runnable> taskCaptor = ArgumentCaptor.forClass(Runnable.class); verify(this.taskScheduler).scheduleWithFixedDelay(taskCaptor.capture(), eq(1L)); Runnable heartbeatTask = taskCaptor.getValue(); assertNotNull(heartbeatTask); String id = "sess1"; TestPrincipal user = new TestPrincipal("joe"); Message<String> connectMessage = createConnectMessage(id, user, new long[] {0, 1}); this.messageHandler.handleMessage(connectMessage); Thread.sleep(10); heartbeatTask.run(); verify(this.clientOutChannel, times(2)).send(this.messageCaptor.capture()); List<Message<?>> messages = this.messageCaptor.getAllValues(); assertEquals(2, messages.size()); MessageHeaders headers = messages.get(0).getHeaders(); assertEquals(SimpMessageType.CONNECT_ACK, headers.get(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER)); headers = messages.get(1).getHeaders(); assertEquals(SimpMessageType.HEARTBEAT, headers.get(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER)); assertEquals(id, headers.get(SimpMessageHeaderAccessor.SESSION_ID_HEADER)); assertEquals(user, headers.get(SimpMessageHeaderAccessor.USER_HEADER)); }
@Test public void customPathMatcher() { ApplicationContext context = loadConfig(CustomConfig.class); SimpleBrokerMessageHandler broker = context.getBean(SimpleBrokerMessageHandler.class); DefaultSubscriptionRegistry registry = (DefaultSubscriptionRegistry) broker.getSubscriptionRegistry(); assertEquals("a.a", registry.getPathMatcher().combine("a", "a")); PathMatcher pathMatcher = context.getBean(SimpAnnotationMethodMessageHandler.class).getPathMatcher(); assertEquals("a.a", pathMatcher.combine("a", "a")); DefaultUserDestinationResolver resolver = context.getBean(DefaultUserDestinationResolver.class); assertNotNull(resolver); assertEquals(false, resolver.isRemoveLeadingSlash()); }
private void handleDisconnect(String sessionId, @Nullable Principal user, @Nullable Message<?> origMessage) { this.sessions.remove(sessionId); this.subscriptionRegistry.unregisterAllSubscriptions(sessionId); SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create(SimpMessageType.DISCONNECT_ACK); accessor.setSessionId(sessionId); if (user != null) { accessor.setUser(user); } if (origMessage != null) { accessor.setHeader(SimpMessageHeaderAccessor.DISCONNECT_MESSAGE_HEADER, origMessage); } initHeaders(accessor); Message<byte[]> message = MessageBuilder.createMessage(EMPTY_PAYLOAD, accessor.getMessageHeaders()); getClientOutboundChannel().send(message); }