From a116579cfc8b34cbe4d38da7d4117f8cb3893c1b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 24 Dec 2016 11:21:26 -0800 Subject: [PATCH] Work around Jetty websocket client bug Add workaround for Jetty JsrSession NullPointerException bug (https://github.com/eclipse/jetty.project/issues/1202) in `spring-boot-sample-websocket-jetty`. See gh-7599 --- .../SampleWebSocketsApplicationTests.java | 10 ++- .../jetty/client/FixedClientContainer.java | 87 +++++++++++++++++++ ...omContainerWebSocketsApplicationTests.java | 12 +-- 3 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/client/FixedClientContainer.java diff --git a/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/SampleWebSocketsApplicationTests.java b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/SampleWebSocketsApplicationTests.java index bee8420fade..35031bc9b18 100644 --- a/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/SampleWebSocketsApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/SampleWebSocketsApplicationTests.java @@ -22,8 +22,10 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.websocket.jsr356.ClientContainer; import org.junit.Test; import org.junit.runner.RunWith; +import samples.websocket.jetty.client.FixedClientContainer; import samples.websocket.jetty.client.GreetingService; import samples.websocket.jetty.client.SimpleClientWebSocketHandler; import samples.websocket.jetty.client.SimpleGreetingService; @@ -108,7 +110,7 @@ public class SampleWebSocketsApplicationTests { } @Bean - public WebSocketConnectionManager wsConnectionManager() { + public WebSocketConnectionManager wsConnectionManager() throws Exception { WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri); @@ -118,8 +120,10 @@ public class SampleWebSocketsApplicationTests { } @Bean - public StandardWebSocketClient client() { - return new StandardWebSocketClient(); + public StandardWebSocketClient client() throws Exception { + ClientContainer clientContainer = new FixedClientContainer(); + clientContainer.start(); + return new StandardWebSocketClient(clientContainer); } @Bean diff --git a/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/client/FixedClientContainer.java b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/client/FixedClientContainer.java new file mode 100644 index 00000000000..3131be4baf4 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/client/FixedClientContainer.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package samples.websocket.jetty.client; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import javax.websocket.Extension; + +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.common.LogicalConnection; +import org.eclipse.jetty.websocket.common.WebSocketSession; +import org.eclipse.jetty.websocket.common.events.EventDriver; +import org.eclipse.jetty.websocket.jsr356.ClientContainer; +import org.eclipse.jetty.websocket.jsr356.JsrSession; +import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory; + +import org.springframework.test.util.ReflectionTestUtils; + +/** + * Jetty {@link ClientContainer} to work around + * https://github.com/eclipse/jetty.project/issues/1202. + * + * @author Phillip Webb + */ +public class FixedClientContainer extends ClientContainer { + + public FixedClientContainer() { + super(); + WebSocketClient client = getClient(); + ReflectionTestUtils.setField(client, "sessionFactory", + new FixedJsrSessionFactory(this)); + } + + private static class FixedJsrSessionFactory extends JsrSessionFactory { + + private final ClientContainer container; + + public FixedJsrSessionFactory(ClientContainer container) { + super(container); + this.container = container; + } + + @Override + public WebSocketSession createSession(URI requestURI, EventDriver websocket, + LogicalConnection connection) { + return new FixedJsrSession(this.container, connection.getId(), requestURI, + websocket, connection); + } + + } + + private static class FixedJsrSession extends JsrSession { + + public FixedJsrSession(ClientContainer container, String id, URI requestURI, + EventDriver websocket, LogicalConnection connection) { + super(container, id, requestURI, websocket, connection); + } + + @Override + public List getNegotiatedExtensions() { + try { + return super.getNegotiatedExtensions(); + } + catch (NullPointerException ex) { + return Collections.emptyList(); + } + } + + } + +} diff --git a/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java index d37cd59e2c2..675aa5c07f6 100644 --- a/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-websocket-jetty/src/test/java/samples/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java @@ -22,9 +22,11 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.eclipse.jetty.websocket.jsr356.ClientContainer; import org.junit.Test; import org.junit.runner.RunWith; import samples.websocket.jetty.SampleJettyWebSocketsApplication; +import samples.websocket.jetty.client.FixedClientContainer; import samples.websocket.jetty.client.GreetingService; import samples.websocket.jetty.client.SimpleClientWebSocketHandler; import samples.websocket.jetty.client.SimpleGreetingService; @@ -123,18 +125,18 @@ public class CustomContainerWebSocketsApplicationTests { } @Bean - public WebSocketConnectionManager wsConnectionManager() { - + public WebSocketConnectionManager wsConnectionManager() throws Exception { WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri); manager.setAutoStartup(true); - return manager; } @Bean - public StandardWebSocketClient client() { - return new StandardWebSocketClient(); + public StandardWebSocketClient client() throws Exception { + ClientContainer container = new FixedClientContainer(); + container.start(); + return new StandardWebSocketClient(container); } @Bean