Skip to content

Commit a5bdddd

Browse files
artembilangaryrussell
authored andcommitted
INT-3515: Fix Some WebSockets Issues
JIRA: https://jira.spring.io/browse/INT-3515 Change test suite to the Tomcat according IO INT-3515: IllegalStateException for the `WebSocketInboundChannelAdapter`, when `useBroker = true`, but there is no Broker Relay in the Context
1 parent 2587ed6 commit a5bdddd

16 files changed

+196
-125
lines changed

build.gradle

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ subprojects { subproject ->
108108
saajImplVersion = '1.3.23'
109109
servletApiVersion = '3.1.0'
110110
slf4jVersion = "1.7.6"
111+
tomcatVersion = "7.0.55"
111112
smack3Version = '3.2.1'
112113
smackVersion = '4.0.0'
113114
springAmqpVersion = project.hasProperty('springAmqpVersion') ? project.springAmqpVersion : '1.4.0.M1'
@@ -565,15 +566,8 @@ project('spring-integration-websocket') {
565566

566567
compile ("org.springframework:spring-webmvc:$springVersion", optional)
567568

568-
testCompile("org.eclipse.jetty:jetty-webapp:$jettyVersion") {
569-
exclude group: "javax.servlet", module: "javax.servlet"
570-
}
571-
testCompile("org.eclipse.jetty.websocket:websocket-server:$jettyVersion") {
572-
exclude group: "javax.servlet", module: "javax.servlet"
573-
}
574-
testCompile "org.eclipse.jetty.websocket:websocket-client:$jettyVersion"
575-
testCompile"org.eclipse.jetty:jetty-client:$jettyVersion"
576-
testCompile "org.slf4j:slf4j-jcl:$slf4jVersion"
569+
testCompile "org.apache.tomcat.embed:tomcat-embed-websocket:$tomcatVersion"
570+
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
577571
}
578572
}
579573

spring-integration-websocket/src/main/java/org/springframework/integration/websocket/IntegrationWebSocketContainer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public List<String> getSubProtocols() {
116116
return Collections.unmodifiableList(protocols);
117117
}
118118

119+
public Map<String, WebSocketSession> getSessions() {
120+
return Collections.unmodifiableMap(this.sessions);
121+
}
122+
119123
public WebSocketSession getSession(String sessionId) throws Exception {
120124
WebSocketSession session = this.sessions.get(sessionId);
121125
Assert.notNull(session, "Session not found for id '" + sessionId + "'");

spring-integration-websocket/src/main/java/org/springframework/integration/websocket/config/ClientWebSocketContainerParser.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,9 @@ protected boolean shouldGenerateIdAsFallback() {
5050
@Override
5151
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
5252
builder.addConstructorArgReference(element.getAttribute("client"))
53-
.addConstructorArgValue(element.getAttribute("uri"));
54-
String uriVariables = element.getAttribute("uri-variables");
55-
if (StringUtils.hasText(uriVariables)) {
56-
builder.addConstructorArgValue(StringUtils.commaDelimitedListToStringArray(uriVariables));
57-
}
53+
.addConstructorArgValue(element.getAttribute("uri"))
54+
.addConstructorArgValue(StringUtils.commaDelimitedListToStringArray(element.getAttribute("uri-variables")));
55+
5856
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-buffer-size-limit");
5957
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-time-limit");
6058
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "origin");

spring-integration-websocket/src/main/java/org/springframework/integration/websocket/inbound/WebSocketInboundChannelAdapter.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,9 @@ protected void onInit() {
189189
break;
190190
}
191191
}
192-
if (this.brokerHandler == null) {
193-
logger.warn("'AbstractBrokerMessageHandler' isn't present in the application context. " +
194-
"The non-MESSAGE WebSocketMessages will be ignored.");
195-
}
192+
Assert.state(this.brokerHandler != null,
193+
"WebSocket Broker Relay isn't present in the application context; " +
194+
"it is required when 'useBroker = true'.");
196195
}
197196
}
198197

spring-integration-websocket/src/main/java/org/springframework/integration/websocket/support/SubProtocolHandlerRegistry.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.messaging.Message;
2828
import org.springframework.util.Assert;
2929
import org.springframework.util.CollectionUtils;
30+
import org.springframework.util.StringUtils;
3031
import org.springframework.web.socket.WebSocketSession;
3132
import org.springframework.web.socket.messaging.SubProtocolHandler;
3233

@@ -108,7 +109,7 @@ public SubProtocolHandlerRegistry(List<SubProtocolHandler> protocolHandlers,
108109
public SubProtocolHandler findProtocolHandler(WebSocketSession session) {
109110
SubProtocolHandler handler;
110111
String protocol = session.getAcceptedProtocol();
111-
if (protocol != null) {
112+
if (StringUtils.hasText(protocol)) {
112113
handler = this.protocolHandlers.get(protocol);
113114
Assert.state(handler != null,
114115
"No handler for sub-protocol '" + protocol + "', handlers = " + this.protocolHandlers);

spring-integration-websocket/src/test/java/org/springframework/integration/websocket/ClientWebSocketContainerTests.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import static org.junit.Assert.assertTrue;
2626
import static org.junit.Assert.fail;
2727

28-
import java.nio.ByteBuffer;
2928
import java.util.Collections;
3029
import java.util.List;
3130
import java.util.concurrent.CountDownLatch;
@@ -40,15 +39,15 @@
4039
import org.springframework.web.socket.PongMessage;
4140
import org.springframework.web.socket.WebSocketMessage;
4241
import org.springframework.web.socket.WebSocketSession;
43-
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
42+
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
4443

4544
/**
4645
* @author Artem Bilan
4746
* @since 4.1
4847
*/
4948
public class ClientWebSocketContainerTests {
5049

51-
private final static JettyWebSocketTestServer server = new JettyWebSocketTestServer(TestServerConfig.class);
50+
private final static TomcatWebSocketTestServer server = new TomcatWebSocketTestServer(TestServerConfig.class);
5251

5352
@BeforeClass
5453
public static void setup() throws Exception {
@@ -63,7 +62,7 @@ public static void tearDown() throws Exception {
6362
@Test
6463
public void testClientWebSocketContainer() throws Exception {
6564
ClientWebSocketContainer container =
66-
new ClientWebSocketContainer(new JettyWebSocketClient(), server.getWsBaseUrl() + "/ws/websocket");
65+
new ClientWebSocketContainer(new StandardWebSocketClient(), server.getWsBaseUrl() + "/ws/websocket");
6766

6867
TestWebSocketListener messageListener = new TestWebSocketListener();
6968
container.setMessageListener(messageListener);
@@ -75,8 +74,7 @@ public void testClientWebSocketContainer() throws Exception {
7574
assertTrue(session.isOpen());
7675
assertEquals("v10.stomp", session.getAcceptedProtocol());
7776

78-
//TODO Jetty Server treats empty ByteBuffer as 'null' for PongMessage
79-
session.sendMessage(new PingMessage(ByteBuffer.wrap("ping".getBytes())));
77+
session.sendMessage(new PingMessage());
8078

8179
assertTrue(messageListener.messageLatch.await(10, TimeUnit.SECONDS));
8280

spring-integration-websocket/src/test/java/org/springframework/integration/websocket/JettyWebSocketTestServer.java

Lines changed: 0 additions & 75 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.integration.websocket;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
22+
import org.apache.catalina.Context;
23+
import org.apache.catalina.connector.Connector;
24+
import org.apache.catalina.startup.Tomcat;
25+
import org.apache.coyote.http11.Http11NioProtocol;
26+
import org.apache.tomcat.websocket.server.WsContextListener;
27+
28+
import org.springframework.beans.factory.DisposableBean;
29+
import org.springframework.beans.factory.InitializingBean;
30+
import org.springframework.util.SocketUtils;
31+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
32+
import org.springframework.web.servlet.DispatcherServlet;
33+
34+
/**
35+
* @author Rossen Stoyanchev
36+
* @author Artem Bilan
37+
* @since 4.1
38+
*/
39+
public class TomcatWebSocketTestServer implements InitializingBean, DisposableBean {
40+
41+
private final Tomcat tomcatServer;
42+
43+
private final int port;
44+
45+
private final AnnotationConfigWebApplicationContext serverContext;
46+
47+
public TomcatWebSocketTestServer(Class<?>... serverConfigs) {
48+
this.port = SocketUtils.findAvailableTcpPort();
49+
Connector connector = new Connector(Http11NioProtocol.class.getName());
50+
connector.setPort(this.port);
51+
52+
File baseDir = createTempDir("tomcat");
53+
String baseDirPath = baseDir.getAbsolutePath();
54+
55+
this.tomcatServer = new Tomcat();
56+
this.tomcatServer.setBaseDir(baseDirPath);
57+
this.tomcatServer.setPort(this.port);
58+
this.tomcatServer.getService().addConnector(connector);
59+
this.tomcatServer.setConnector(connector);
60+
61+
this.serverContext = new AnnotationConfigWebApplicationContext();
62+
this.serverContext.register(serverConfigs);
63+
64+
Context context = this.tomcatServer.addContext("", System.getProperty("java.io.tmpdir"));
65+
context.addApplicationListener(WsContextListener.class.getName());
66+
Tomcat.addServlet(context, "dispatcherServlet", new DispatcherServlet(this.serverContext)).setAsyncSupported(true);
67+
context.addServletMapping("/", "dispatcherServlet");
68+
}
69+
70+
private File createTempDir(String prefix) {
71+
try {
72+
File tempFolder = File.createTempFile(prefix + ".", "." + this.port);
73+
tempFolder.delete();
74+
tempFolder.mkdir();
75+
tempFolder.deleteOnExit();
76+
return tempFolder;
77+
}
78+
catch (IOException ex) {
79+
throw new RuntimeException("Unable to create temp directory", ex);
80+
}
81+
}
82+
83+
public AnnotationConfigWebApplicationContext getServerContext() {
84+
return this.serverContext;
85+
}
86+
87+
public String getWsBaseUrl() {
88+
return "ws://localhost:" + this.port;
89+
}
90+
91+
@Override
92+
public void afterPropertiesSet() throws Exception {
93+
this.tomcatServer.start();
94+
}
95+
96+
@Override
97+
public void destroy() throws Exception {
98+
this.tomcatServer.stop();
99+
}
100+
101+
}

spring-integration-websocket/src/test/java/org/springframework/integration/websocket/client/StompIntegrationTests.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
import org.springframework.integration.transformer.ExpressionEvaluatingTransformer;
5353
import org.springframework.integration.websocket.ClientWebSocketContainer;
5454
import org.springframework.integration.websocket.IntegrationWebSocketContainer;
55-
import org.springframework.integration.websocket.JettyWebSocketTestServer;
55+
import org.springframework.integration.websocket.TomcatWebSocketTestServer;
5656
import org.springframework.integration.websocket.inbound.WebSocketInboundChannelAdapter;
5757
import org.springframework.integration.websocket.outbound.WebSocketOutboundMessageHandler;
5858
import org.springframework.integration.websocket.support.SubProtocolHandlerRegistry;
@@ -72,12 +72,13 @@
7272
import org.springframework.test.context.ContextConfiguration;
7373
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
7474
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
75+
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
7576
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
7677
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
7778
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
7879
import org.springframework.web.socket.messaging.StompSubProtocolHandler;
7980
import org.springframework.web.socket.messaging.SubProtocolHandler;
80-
import org.springframework.web.socket.server.jetty.JettyRequestUpgradeStrategy;
81+
import org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy;
8182
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
8283

8384
/**
@@ -247,13 +248,13 @@ public void sendMessageToGateway() throws Exception {
247248
public static class ContextConfiguration {
248249

249250
@Bean
250-
public JettyWebSocketTestServer server() {
251-
return new JettyWebSocketTestServer(ServerConfig.class);
251+
public TomcatWebSocketTestServer server() {
252+
return new TomcatWebSocketTestServer(ServerConfig.class);
252253
}
253254

254255
@Bean
255256
public IntegrationWebSocketContainer clientWebSocketContainer() {
256-
return new ClientWebSocketContainer(new JettyWebSocketClient(), server().getWsBaseUrl() + "/ws/websocket");
257+
return new ClientWebSocketContainer(new StandardWebSocketClient(), server().getWsBaseUrl() + "/ws/websocket");
257258
}
258259

259260
@Bean
@@ -370,7 +371,7 @@ public ExpressionEvaluatingTransformer greetingTransformer() {
370371

371372
@Bean
372373
public DefaultHandshakeHandler handshakeHandler() {
373-
return new DefaultHandshakeHandler(new JettyRequestUpgradeStrategy());
374+
return new DefaultHandshakeHandler(new TomcatRequestUpgradeStrategy());
374375
}
375376

376377
@Override

spring-integration-websocket/src/test/java/org/springframework/integration/websocket/client/WebSocketClientTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
import org.springframework.integration.transformer.ObjectToStringTransformer;
4141
import org.springframework.integration.websocket.ClientWebSocketContainer;
4242
import org.springframework.integration.websocket.IntegrationWebSocketContainer;
43-
import org.springframework.integration.websocket.JettyWebSocketTestServer;
4443
import org.springframework.integration.websocket.TestServerConfig;
44+
import org.springframework.integration.websocket.TomcatWebSocketTestServer;
4545
import org.springframework.integration.websocket.inbound.WebSocketInboundChannelAdapter;
4646
import org.springframework.integration.websocket.outbound.WebSocketOutboundMessageHandler;
4747
import org.springframework.integration.websocket.support.SubProtocolHandlerRegistry;
@@ -56,7 +56,7 @@
5656
import org.springframework.test.context.ContextConfiguration;
5757
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
5858
import org.springframework.web.socket.client.WebSocketClient;
59-
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
59+
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
6060
import org.springframework.web.socket.messaging.StompSubProtocolHandler;
6161
import org.springframework.web.socket.messaging.SubProtocolHandler;
6262
import org.springframework.web.socket.sockjs.client.SockJsClient;
@@ -99,13 +99,13 @@ public void testWebSocketOutboundMessageHandler() throws Exception {
9999
public static class ContextConfiguration {
100100

101101
@Bean
102-
public JettyWebSocketTestServer server() {
103-
return new JettyWebSocketTestServer(ServerFlowConfig.class);
102+
public TomcatWebSocketTestServer server() {
103+
return new TomcatWebSocketTestServer(ServerFlowConfig.class);
104104
}
105105

106106
@Bean
107107
public WebSocketClient webSocketClient() {
108-
return new SockJsClient(Collections.<Transport>singletonList(new WebSocketTransport(new JettyWebSocketClient())));
108+
return new SockJsClient(Collections.<Transport>singletonList(new WebSocketTransport(new StandardWebSocketClient())));
109109
}
110110

111111
@Bean

0 commit comments

Comments
 (0)