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());