Issue #5832 - fix bugs when stopping the JavaxWebSocketClientContainer

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-01-18 23:23:35 +11:00
parent 29f185931e
commit a60ecfa4cc
3 changed files with 44 additions and 14 deletions

View File

@ -23,9 +23,13 @@ import javax.servlet.ServletException;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer; import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JavaxWebSocketClientShutdown extends ContainerLifeCycle implements ServletContainerInitializer, ServletContextListener public class JavaxWebSocketClientShutdown extends ContainerLifeCycle implements ServletContainerInitializer, ServletContextListener
{ {
private static final Logger LOG = LoggerFactory.getLogger(JavaxWebSocketClientShutdown.class);
@Override @Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
{ {
@ -36,12 +40,17 @@ public class JavaxWebSocketClientShutdown extends ContainerLifeCycle implements
@Override @Override
public void contextInitialized(ServletContextEvent sce) public void contextInitialized(ServletContextEvent sce)
{ {
if (LOG.isDebugEnabled())
LOG.debug("contextInitialized({}) {}", sce, this);
LifeCycle.start(this); LifeCycle.start(this);
} }
@Override @Override
public void contextDestroyed(ServletContextEvent sce) public void contextDestroyed(ServletContextEvent sce)
{ {
if (LOG.isDebugEnabled())
LOG.debug("contextDestroyed({}) {}", sce, this);
LifeCycle.stop(this); LifeCycle.stop(this);
removeBeans(); removeBeans();
JavaxWebSocketClientContainer.initialize(null); JavaxWebSocketClientContainer.initialize(null);

View File

@ -64,12 +64,14 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
public static void initialize(ContainerLifeCycle container) public static void initialize(ContainerLifeCycle container)
{ {
SHUTDOWN_CONTAINER.set(container); SHUTDOWN_CONTAINER.set(container);
if (LOG.isDebugEnabled())
LOG.debug("initialized {} to {}", String.format("%s@%x", SHUTDOWN_CONTAINER.getClass().getSimpleName(), SHUTDOWN_CONTAINER.hashCode()), container);
} }
protected WebSocketCoreClient coreClient; protected WebSocketCoreClient coreClient;
protected Function<WebSocketComponents, WebSocketCoreClient> coreClientFactory; protected Function<WebSocketComponents, WebSocketCoreClient> coreClientFactory;
private final JavaxWebSocketClientFrameHandlerFactory frameHandlerFactory; private final JavaxWebSocketClientFrameHandlerFactory frameHandlerFactory;
private boolean allowContextHandlerRegistration = true; private boolean allowShutdownWithContextHandler = true;
public JavaxWebSocketClientContainer() public JavaxWebSocketClientContainer()
{ {
@ -110,9 +112,9 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
this.frameHandlerFactory = new JavaxWebSocketClientFrameHandlerFactory(this); this.frameHandlerFactory = new JavaxWebSocketClientFrameHandlerFactory(this);
} }
public void allowContextHandlerRegistration(boolean allowContextHandlerRegistration) public void allowShutdownWithContextHandler(boolean allowShutdownWithContextHandler)
{ {
this.allowContextHandlerRegistration = allowContextHandlerRegistration; this.allowShutdownWithContextHandler = allowShutdownWithContextHandler;
} }
protected HttpClient getHttpClient() protected HttpClient getHttpClient()
@ -302,37 +304,51 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
@Override @Override
protected void doStop() throws Exception protected void doStop() throws Exception
{ {
doClientStop();
super.doStop(); super.doStop();
doClientStop();
} }
protected void doClientStart() protected void doClientStart()
{ {
if (LOG.isDebugEnabled())
LOG.debug("doClientStart() {}", this);
// If we are running in Jetty register shutdown with the ContextHandler. // If we are running in Jetty register shutdown with the ContextHandler.
if (allowContextHandlerRegistration && addToContextHandler(this)) if (allowShutdownWithContextHandler && addToContextHandler())
{
if (LOG.isDebugEnabled())
LOG.debug("Shutdown registered with ContextHandler");
return; return;
}
// If we are running inside a different ServletContainer we can register with the SHUTDOWN_CONTAINER static. // If we are running inside a different ServletContainer we can register with the SHUTDOWN_CONTAINER static.
ContainerLifeCycle shutdownContainer = SHUTDOWN_CONTAINER.get(); ContainerLifeCycle shutdownContainer = SHUTDOWN_CONTAINER.get();
if (shutdownContainer != null) if (shutdownContainer != null)
{ {
shutdownContainer.addManaged(this); shutdownContainer.addManaged(this);
if (LOG.isDebugEnabled())
LOG.debug("Shutdown registered with ShutdownContainer {}", shutdownContainer);
return; return;
} }
ShutdownThread.register(this); ShutdownThread.register(this);
if (LOG.isDebugEnabled())
LOG.debug("Shutdown registered with ShutdownThread");
} }
protected void doClientStop() protected void doClientStop()
{ {
if (LOG.isDebugEnabled())
LOG.debug("doClientStop() {}", this);
// Remove from context handler if running in Jetty server. // Remove from context handler if running in Jetty server.
removeFromContextHandler(this); removeFromContextHandler();
// Remove from the Shutdown Container. // Remove from the Shutdown Container.
ContainerLifeCycle shutdownContainer = SHUTDOWN_CONTAINER.get(); ContainerLifeCycle shutdownContainer = SHUTDOWN_CONTAINER.get();
if (shutdownContainer != null && shutdownContainer.contains(this)) if (shutdownContainer != null && shutdownContainer.contains(this))
{ {
// Un-manage first as removeBean() will stop this, but this is already in STOPPING state. // Un-manage first as we don't want to call stop again while in STOPPING state.
shutdownContainer.unmanage(this); shutdownContainer.unmanage(this);
shutdownContainer.removeBean(this); shutdownContainer.removeBean(this);
} }
@ -341,7 +357,7 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
ShutdownThread.deregister(this); ShutdownThread.deregister(this);
} }
private boolean addToContextHandler(LifeCycle lifeCycle) private boolean addToContextHandler()
{ {
try try
{ {
@ -356,19 +372,19 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
contextHandler.getClass() contextHandler.getClass()
.getMethod("addManaged", LifeCycle.class) .getMethod("addManaged", LifeCycle.class)
.invoke(contextHandler, lifeCycle); .invoke(contextHandler, this);
return true; return true;
} }
catch (Throwable throwable) catch (Throwable throwable)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("error from addToContextHandler({})", lifeCycle, throwable); LOG.debug("error from addToContextHandler() for {}", this, throwable);
return false; return false;
} }
} }
private void removeFromContextHandler(LifeCycle lifeCycle) private void removeFromContextHandler()
{ {
try try
{ {
@ -381,14 +397,19 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
.getMethod("getContextHandler") .getMethod("getContextHandler")
.invoke(context); .invoke(context);
// Un-manage first as we don't want to call stop again while in STOPPING state.
contextHandler.getClass()
.getMethod("unmanage", Object.class)
.invoke(contextHandler, this);
contextHandler.getClass() contextHandler.getClass()
.getMethod("removeBean", Object.class) .getMethod("removeBean", Object.class)
.invoke(contextHandler, JavaxWebSocketClientContainer.this); .invoke(contextHandler, this);
} }
catch (Throwable throwable) catch (Throwable throwable)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("error from removeFromContextHandler({})", lifeCycle, throwable); LOG.debug("error from removeFromContextHandler() for {}", this, throwable);
} }
} }
} }

View File

@ -69,7 +69,7 @@ public class JavaxClientShutdownWithServerTest
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{ {
JavaxWebSocketClientContainer clientContainer = new JavaxWebSocketClientContainer(); JavaxWebSocketClientContainer clientContainer = new JavaxWebSocketClientContainer();
clientContainer.allowContextHandlerRegistration(false); clientContainer.allowShutdownWithContextHandler(false);
LifeCycle.start(clientContainer); LifeCycle.start(clientContainer);
container = clientContainer; container = clientContainer;
} }