INT-4345: ServerWebSocketContainer: Fix Lifecycle
JIRA: https://jira.spring.io/browse/INT-4345 Resolves https://github.com/spring-projects/spring-integration/issues/2238 The `DefaultHandshakeHandler` doesn't implement `SmartLifecycle` (just `Lifecycle`) there it doesn't delegate its `start()` to the `RequestUpgradeStrategy`, e.g. `JettyRequestUpgradeStrategy`. On the other hand `DefaultHandshakeHandler` can be started as a dependant `Lifecycle` from some other `SmartLifecycle`, like it happens with the `WebSocketHandlerMapping` * Implement `SmartLifecycle` for the `ServerWebSocketContainer` and delegate its lifecycle to the provided `HandshakeHandler` * Fix `WebSocketInboundChannelAdapter` to properly implement `doStop()` with the propagation to the provided `webSocketContainer` * Fix deprecation warning in the `StompMessageHandlerWebSocketIntegrationTests` **Cherry-pick to 4.3.x**
This commit is contained in:
committed by
Gary Russell
parent
077b5ffffc
commit
bf1fef39db
@@ -91,6 +91,7 @@ import org.springframework.web.socket.sockjs.client.WebSocketTransport;
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
@ContextConfiguration(classes = StompMessageHandlerWebSocketIntegrationTests.ContextConfiguration.class)
|
||||
@@ -269,7 +270,7 @@ public class StompMessageHandlerWebSocketIntegrationTests extends LogAdjustingTe
|
||||
|
||||
@Override
|
||||
public void configureClientInboundChannel(ChannelRegistration registration) {
|
||||
registration.setInterceptors(new ChannelInterceptorAdapter() {
|
||||
registration.interceptors(new ChannelInterceptorAdapter() {
|
||||
|
||||
private final AtomicBoolean invoked = new AtomicBoolean();
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.integration.websocket;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -46,7 +48,8 @@ import org.springframework.web.socket.sockjs.transport.TransportHandler;
|
||||
* @author Gary Russell
|
||||
* @since 4.1
|
||||
*/
|
||||
public class ServerWebSocketContainer extends IntegrationWebSocketContainer implements WebSocketConfigurer {
|
||||
public class ServerWebSocketContainer extends IntegrationWebSocketContainer
|
||||
implements WebSocketConfigurer, SmartLifecycle {
|
||||
|
||||
private final String[] paths;
|
||||
|
||||
@@ -60,6 +63,10 @@ public class ServerWebSocketContainer extends IntegrationWebSocketContainer impl
|
||||
|
||||
private String[] origins;
|
||||
|
||||
private boolean autoStartup = true;
|
||||
|
||||
private int phase = 0;
|
||||
|
||||
public ServerWebSocketContainer(String... paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
@@ -178,6 +185,51 @@ public class ServerWebSocketContainer extends IntegrationWebSocketContainer impl
|
||||
|
||||
}
|
||||
|
||||
public void setAutoStartup(boolean autoStartup) {
|
||||
this.autoStartup = autoStartup;
|
||||
}
|
||||
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return this.autoStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return this.phase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.handshakeHandler instanceof Lifecycle && ((Lifecycle) this.handshakeHandler).isRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
if (this.handshakeHandler instanceof Lifecycle && !isRunning()) {
|
||||
((Lifecycle) this.handshakeHandler).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (isRunning()) {
|
||||
((Lifecycle) this.handshakeHandler).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
if (isRunning()) {
|
||||
((Lifecycle) this.handshakeHandler).stop();
|
||||
}
|
||||
callback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.web.socket.config.annotation.SockJsServiceRegistration
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,7 @@ import org.springframework.web.socket.messaging.SessionConnectedEvent;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
public class WebSocketInboundChannelAdapter extends MessageProducerSupport
|
||||
@@ -255,6 +256,9 @@ public class WebSocketInboundChannelAdapter extends MessageProducerSupport
|
||||
@Override
|
||||
protected void doStop() {
|
||||
this.active = false;
|
||||
if (this.webSocketContainer instanceof Lifecycle) {
|
||||
((Lifecycle) this.webSocketContainer).stop();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isActive() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the original author or authors.
|
||||
* Copyright 2014-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.
|
||||
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
@@ -41,6 +43,7 @@ import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.context.PayloadApplicationEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -86,12 +89,16 @@ import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
|
||||
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
|
||||
import org.springframework.web.socket.messaging.StompSubProtocolHandler;
|
||||
import org.springframework.web.socket.messaging.SubProtocolHandler;
|
||||
import org.springframework.web.socket.server.RequestUpgradeStrategy;
|
||||
import org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy;
|
||||
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
|
||||
import org.springframework.web.socket.sockjs.client.SockJsClient;
|
||||
import org.springframework.web.socket.sockjs.client.Transport;
|
||||
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = WebSocketServerTests.ContextConfiguration.class)
|
||||
@@ -115,6 +122,9 @@ public class WebSocketServerTests {
|
||||
@Value("#{server.serverContext.getBean('webSocketEvents')}")
|
||||
private PollableChannel webSocketEvents;
|
||||
|
||||
@Value("#{server.serverContext.getBean('requestUpgradeStrategy')}")
|
||||
private Lifecycle requestUpgradeStrategy;
|
||||
|
||||
@Test
|
||||
public void testWebSocketOutboundMessageHandler() throws Exception {
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
|
||||
@@ -151,6 +161,8 @@ public class WebSocketServerTests {
|
||||
Message<?> event = this.webSocketEvents.receive(10000);
|
||||
assertNotNull(event);
|
||||
assertThat(event.getPayload(), instanceOf(WebSocketSession.class));
|
||||
|
||||
verify(this.requestUpgradeStrategy).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -250,9 +262,20 @@ public class WebSocketServerTests {
|
||||
return new TestWebSocketHandlerDecoratorFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestUpgradeStrategy requestUpgradeStrategy() {
|
||||
return spy(new MyTomcatRequestUpgradeStrategy());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultHandshakeHandler handshakeHandler() {
|
||||
return new DefaultHandshakeHandler(requestUpgradeStrategy());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerWebSocketContainer serverWebSocketContainer() {
|
||||
return new ServerWebSocketContainer("/ws")
|
||||
.setHandshakeHandler(handshakeHandler())
|
||||
.setDecoratorFactories(testWebSocketHandlerDecoratorFactory())
|
||||
.setAllowedOrigins("http://foo.com")
|
||||
.withSockJs();
|
||||
@@ -353,4 +376,23 @@ public class WebSocketServerTests {
|
||||
|
||||
}
|
||||
|
||||
public static class MyTomcatRequestUpgradeStrategy extends TomcatRequestUpgradeStrategy implements Lifecycle {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user