diff --git a/jetty-websocket/websocket-javax-client/pom.xml b/jetty-websocket/websocket-javax-client/pom.xml
index c9f5585a308..a7e9654819e 100644
--- a/jetty-websocket/websocket-javax-client/pom.xml
+++ b/jetty-websocket/websocket-javax-client/pom.xml
@@ -34,6 +34,11 @@
jetty-client
${project.version}
+
+ org.eclipse.jetty.toolchain
+ jetty-servlet-api
+ true
+
org.eclipse.jetty
jetty-xml
diff --git a/jetty-websocket/websocket-javax-client/src/main/java/module-info.java b/jetty-websocket/websocket-javax-client/src/main/java/module-info.java
index c827261eb6f..7e16f2a0b99 100644
--- a/jetty-websocket/websocket-javax-client/src/main/java/module-info.java
+++ b/jetty-websocket/websocket-javax-client/src/main/java/module-info.java
@@ -20,6 +20,7 @@ module org.eclipse.jetty.websocket.javax.client
exports org.eclipse.jetty.websocket.javax.client;
exports org.eclipse.jetty.websocket.javax.client.internal to org.eclipse.jetty.websocket.javax.server;
+ requires static jetty.servlet.api;
requires org.slf4j;
requires org.eclipse.jetty.client;
requires org.eclipse.jetty.websocket.core.client;
diff --git a/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientShutdown.java b/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientShutdown.java
new file mode 100644
index 00000000000..ed73c307642
--- /dev/null
+++ b/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientShutdown.java
@@ -0,0 +1,48 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.websocket.javax.client;
+
+import java.util.Set;
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletException;
+
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer;
+
+public class JavaxWebSocketClientShutdown extends ContainerLifeCycle implements ServletContainerInitializer, ServletContextListener
+{
+ @Override
+ public void onStartup(Set> c, ServletContext ctx) throws ServletException
+ {
+ JavaxWebSocketClientContainer.SHUTDOWN_CONTAINER.compareAndSet(null, this);
+ ctx.addListener(this);
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce)
+ {
+ LifeCycle.start(this);
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce)
+ {
+ LifeCycle.stop(this);
+ removeBeans();
+ }
+}
diff --git a/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/internal/JavaxWebSocketClientContainer.java b/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/internal/JavaxWebSocketClientContainer.java
index e54f02df27a..196cff6de83 100644
--- a/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/internal/JavaxWebSocketClientContainer.java
+++ b/jetty-websocket/websocket-javax-client/src/main/java/org/eclipse/jetty/websocket/javax/client/internal/JavaxWebSocketClientContainer.java
@@ -23,6 +23,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;
@@ -34,6 +35,7 @@ import javax.websocket.Session;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.thread.ShutdownThread;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
@@ -58,6 +60,7 @@ import org.slf4j.LoggerFactory;
public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer implements javax.websocket.WebSocketContainer
{
private static final Logger LOG = LoggerFactory.getLogger(JavaxWebSocketClientContainer.class);
+ public static final AtomicReference SHUTDOWN_CONTAINER = new AtomicReference<>();
protected WebSocketCoreClient coreClient;
protected Function coreClientFactory;
@@ -287,6 +290,24 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
}
protected void doClientStart()
+ {
+ // If we are running in Jetty register shutdown with the ContextHandler.
+ // TODO: add test mode to disable this.
+ if (shutdownWithContextHandler(this))
+ return;
+
+ // If we are running inside a different ServletContainer we can register with the SHUTDOWN_CONTAINER static.
+ ContainerLifeCycle shutdownContainer = SHUTDOWN_CONTAINER.get();
+ if (shutdownContainer != null)
+ {
+ shutdownContainer.addManaged(this);
+ return;
+ }
+
+ ShutdownThread.register(this);
+ }
+
+ private boolean shutdownWithContextHandler(LifeCycle lifeCycle)
{
try
{
@@ -301,7 +322,7 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
contextHandler.getClass()
.getMethod("addManaged", LifeCycle.class)
- .invoke(contextHandler, this);
+ .invoke(contextHandler, lifeCycle);
AbstractLifeCycleListener shutdownListener = new AbstractLifeCycleListener()
{
@@ -324,22 +345,11 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
contextHandler.getClass()
.getMethod("addEventListener", EventListener.class)
.invoke(contextHandler, shutdownListener);
+ return true;
}
- catch (Throwable ignored)
+ catch (Throwable throwable)
{
- ShutdownThread.register(this);
+ return false;
}
}
-
- @Override
- protected void doStop() throws Exception
- {
- super.doStop();
- doClientStop();
- }
-
- protected void doClientStop()
- {
- ShutdownThread.deregister(this);
- }
}
diff --git a/jetty-websocket/websocket-javax-client/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-websocket/websocket-javax-client/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
new file mode 100644
index 00000000000..b9a2f2d58b9
--- /dev/null
+++ b/jetty-websocket/websocket-javax-client/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
@@ -0,0 +1 @@
+org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientShutdown
\ No newline at end of file
diff --git a/jetty-websocket/websocket-javax-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java b/jetty-websocket/websocket-javax-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
index 005179d917d..f928baf444a 100644
--- a/jetty-websocket/websocket-javax-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
+++ b/jetty-websocket/websocket-javax-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/JavaxWebSocketServerContainer.java
@@ -302,10 +302,4 @@ public class JavaxWebSocketServerContainer extends JavaxWebSocketClientContainer
{
// Do nothing to avoid registration with the ShutdownThread.
}
-
- @Override
- protected void doClientStop()
- {
- // Do nothing to avoid de-registration with the ShutdownThread.
- }
}
diff --git a/jetty-websocket/websocket-javax-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/ClientInWebappTest.java b/jetty-websocket/websocket-javax-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/ClientInWebappTest.java
index 14fb5a7099f..a85793ea76a 100644
--- a/jetty-websocket/websocket-javax-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/ClientInWebappTest.java
+++ b/jetty-websocket/websocket-javax-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/ClientInWebappTest.java
@@ -30,6 +30,8 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.listener.ContainerInitializer;
+import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientShutdown;
import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -63,13 +65,17 @@ public class ClientInWebappTest
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
- connector.setPort(8080);
server.addConnector(connector);
contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/");
contextHandler.addServlet(new ServletHolder(new WebSocketClientInServlet()), "/");
server.setHandler(contextHandler);
+
+ // Because we are using embedded we must manually add the Javax WS Client Shutdown SCI.
+ // TODO: fix to not use ContainerInitializer.asContextListener
+ contextHandler.addEventListener(ContainerInitializer.asContextListener(new JavaxWebSocketClientShutdown()));
+
server.start();
serverUri = WSURI.toWebsocket(server.getURI());