Merged branch 'jetty-10.0.x' into 'jetty-11.0.x'.
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
commit
2d08ed6ca0
|
@ -339,6 +339,7 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
|
|||
_houseKeeper.stop();
|
||||
if (_ownHouseKeeper)
|
||||
{
|
||||
removeBean(_houseKeeper);
|
||||
_houseKeeper = null;
|
||||
}
|
||||
_random = null;
|
||||
|
|
|
@ -1195,6 +1195,34 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
}
|
||||
|
||||
public void removeFilterHolder(FilterHolder holder)
|
||||
{
|
||||
if (holder == null)
|
||||
return;
|
||||
|
||||
try (AutoLock ignored = lock())
|
||||
{
|
||||
FilterHolder[] holders = Arrays.stream(getFilters())
|
||||
.filter(h -> h != holder)
|
||||
.toArray(FilterHolder[]::new);
|
||||
setFilters(holders);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFilterMapping(FilterMapping mapping)
|
||||
{
|
||||
if (mapping == null)
|
||||
return;
|
||||
|
||||
try (AutoLock ignored = lock())
|
||||
{
|
||||
FilterMapping[] mappings = Arrays.stream(getFilterMappings())
|
||||
.filter(m -> m != mapping)
|
||||
.toArray(FilterMapping[]::new);
|
||||
setFilterMappings(mappings);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateNameMappings()
|
||||
{
|
||||
try (AutoLock ignored = lock())
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.server;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletContextEvent;
|
||||
import jakarta.servlet.ServletContextListener;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.compression.DeflaterPool;
|
||||
|
@ -92,17 +93,21 @@ public class WebSocketServerComponents extends WebSocketComponents
|
|||
if (server.contains(bufferPool))
|
||||
serverComponents.unmanage(bufferPool);
|
||||
|
||||
servletContext.setAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE, serverComponents);
|
||||
LifeCycle.start(serverComponents);
|
||||
servletContext.addListener(new ServletContextListener()
|
||||
// Stop the WebSocketComponents when the ContextHandler stops.
|
||||
ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
|
||||
contextHandler.addManaged(serverComponents);
|
||||
contextHandler.addEventListener(new LifeCycle.Listener()
|
||||
{
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce)
|
||||
public void lifeCycleStopping(LifeCycle event)
|
||||
{
|
||||
LifeCycle.stop(serverComponents);
|
||||
servletContext.removeAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE);
|
||||
contextHandler.removeBean(serverComponents);
|
||||
contextHandler.removeEventListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
servletContext.setAttribute(WEBSOCKET_COMPONENTS_ATTRIBUTE, serverComponents);
|
||||
return serverComponents;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,46 +60,60 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
if (contextHandler.getServer() == null)
|
||||
throw new IllegalStateException("Server has not been set on the ServletContextHandler");
|
||||
|
||||
JakartaWebSocketServerContainer container = getContainer(servletContext);
|
||||
if (container == null)
|
||||
JakartaWebSocketServerContainer containerFromServletContext = getContainer(servletContext);
|
||||
if (containerFromServletContext != null)
|
||||
return containerFromServletContext;
|
||||
|
||||
Function<WebSocketComponents, WebSocketCoreClient> coreClientSupplier = (wsComponents) ->
|
||||
{
|
||||
Function<WebSocketComponents, WebSocketCoreClient> coreClientSupplier = (wsComponents) ->
|
||||
WebSocketCoreClient coreClient = (WebSocketCoreClient)servletContext.getAttribute(WebSocketCoreClient.WEBSOCKET_CORECLIENT_ATTRIBUTE);
|
||||
if (coreClient == null)
|
||||
{
|
||||
WebSocketCoreClient coreClient = (WebSocketCoreClient)servletContext.getAttribute(WebSocketCoreClient.WEBSOCKET_CORECLIENT_ATTRIBUTE);
|
||||
if (coreClient == null)
|
||||
{
|
||||
// Find Pre-Existing (Shared?) HttpClient and/or executor
|
||||
HttpClient httpClient = (HttpClient)servletContext.getAttribute(JakartaWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE);
|
||||
if (httpClient == null)
|
||||
httpClient = (HttpClient)contextHandler.getServer().getAttribute(JakartaWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE);
|
||||
// Find Pre-Existing (Shared?) HttpClient and/or executor
|
||||
HttpClient httpClient = (HttpClient)servletContext.getAttribute(JakartaWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE);
|
||||
if (httpClient == null)
|
||||
httpClient = (HttpClient)contextHandler.getServer().getAttribute(JakartaWebSocketServletContainerInitializer.HTTPCLIENT_ATTRIBUTE);
|
||||
|
||||
Executor executor = httpClient == null ? null : httpClient.getExecutor();
|
||||
if (executor == null)
|
||||
executor = (Executor)servletContext.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
executor = contextHandler.getServer().getThreadPool();
|
||||
Executor executor = httpClient == null ? null : httpClient.getExecutor();
|
||||
if (executor == null)
|
||||
executor = (Executor)servletContext.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
executor = contextHandler.getServer().getThreadPool();
|
||||
|
||||
if (httpClient != null && httpClient.getExecutor() == null)
|
||||
httpClient.setExecutor(executor);
|
||||
if (httpClient != null && httpClient.getExecutor() == null)
|
||||
httpClient.setExecutor(executor);
|
||||
|
||||
// create the core client
|
||||
coreClient = new WebSocketCoreClient(httpClient, wsComponents);
|
||||
coreClient.getHttpClient().setName("Jakarta-WebSocketClient@" + Integer.toHexString(coreClient.getHttpClient().hashCode()));
|
||||
if (executor != null && httpClient == null)
|
||||
coreClient.getHttpClient().setExecutor(executor);
|
||||
servletContext.setAttribute(WebSocketCoreClient.WEBSOCKET_CORECLIENT_ATTRIBUTE, coreClient);
|
||||
}
|
||||
return coreClient;
|
||||
};
|
||||
// create the core client
|
||||
coreClient = new WebSocketCoreClient(httpClient, wsComponents);
|
||||
coreClient.getHttpClient().setName("Jakarta-WebSocketClient@" + Integer.toHexString(coreClient.getHttpClient().hashCode()));
|
||||
if (executor != null && httpClient == null)
|
||||
coreClient.getHttpClient().setExecutor(executor);
|
||||
servletContext.setAttribute(WebSocketCoreClient.WEBSOCKET_CORECLIENT_ATTRIBUTE, coreClient);
|
||||
}
|
||||
return coreClient;
|
||||
};
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
JakartaWebSocketServerContainer container = new JakartaWebSocketServerContainer(
|
||||
WebSocketMappings.ensureMappings(servletContext),
|
||||
WebSocketServerComponents.getWebSocketComponents(servletContext),
|
||||
coreClientSupplier);
|
||||
|
||||
// Manage the lifecycle of the Container.
|
||||
contextHandler.addManaged(container);
|
||||
contextHandler.addEventListener(container);
|
||||
contextHandler.addEventListener(new LifeCycle.Listener()
|
||||
{
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle event)
|
||||
{
|
||||
servletContext.removeAttribute(JAKARTA_WEBSOCKET_CONTAINER_ATTRIBUTE);
|
||||
contextHandler.removeBean(container);
|
||||
contextHandler.removeEventListener(container);
|
||||
contextHandler.removeEventListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
container = new JakartaWebSocketServerContainer(
|
||||
WebSocketMappings.ensureMappings(servletContext),
|
||||
WebSocketServerComponents.getWebSocketComponents(servletContext),
|
||||
coreClientSupplier);
|
||||
contextHandler.addManaged(container);
|
||||
contextHandler.addEventListener(container);
|
||||
}
|
||||
// Store a reference to the ServerContainer per - jakarta.websocket spec 1.0 final - section 6.4: Programmatic Server Deployment
|
||||
servletContext.setAttribute(JAKARTA_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
|
||||
return container;
|
||||
|
@ -141,18 +155,6 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
this.frameHandlerFactory = new JakartaWebSocketServerFrameHandlerFactory(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle context)
|
||||
{
|
||||
ContextHandler contextHandler = (ContextHandler)context;
|
||||
JakartaWebSocketServerContainer container = contextHandler.getBean(JakartaWebSocketServerContainer.class);
|
||||
if (container == this)
|
||||
{
|
||||
contextHandler.removeBean(container);
|
||||
LifeCycle.stop(container);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JakartaWebSocketServerFrameHandlerFactory getFrameHandlerFactory()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 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.jakarta.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.websocket.Session;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.client.internal.JakartaWebSocketClientContainer;
|
||||
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.jakarta.server.internal.JakartaWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JakartaWebSocketRestartTest
|
||||
{
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private JakartaWebSocketClientContainer client;
|
||||
private ServletContextHandler contextHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
client = new JakartaWebSocketClientContainer();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebSocketRestart() throws Exception
|
||||
{
|
||||
JakartaWebSocketServletContainerInitializer.configure(contextHandler, (context, container) ->
|
||||
container.addEndpoint(EchoSocket.class));
|
||||
server.start();
|
||||
|
||||
int numEventListeners = contextHandler.getEventListeners().size();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
server.stop();
|
||||
server.start();
|
||||
testEchoMessage();
|
||||
}
|
||||
|
||||
// We have not accumulated websocket resources by restarting.
|
||||
assertThat(contextHandler.getEventListeners().size(), is(numEventListeners));
|
||||
assertThat(contextHandler.getContainedBeans(JakartaWebSocketServerContainer.class).size(), is(1));
|
||||
assertThat(contextHandler.getContainedBeans(WebSocketServerComponents.class).size(), is(1));
|
||||
assertNotNull(contextHandler.getServletContext().getAttribute(WebSocketServerComponents.WEBSOCKET_COMPONENTS_ATTRIBUTE));
|
||||
assertNotNull(contextHandler.getServletContext().getAttribute(JakartaWebSocketServerContainer.JAKARTA_WEBSOCKET_CONTAINER_ATTRIBUTE));
|
||||
|
||||
// We have one filter, and it is a WebSocketUpgradeFilter.
|
||||
FilterHolder[] filters = contextHandler.getServletHandler().getFilters();
|
||||
assertThat(filters.length, is(1));
|
||||
assertThat(filters[0].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
||||
// After stopping the websocket resources are cleaned up.
|
||||
server.stop();
|
||||
assertThat(contextHandler.getEventListeners().size(), is(0));
|
||||
assertThat(contextHandler.getContainedBeans(JakartaWebSocketServerContainer.class).size(), is(0));
|
||||
assertThat(contextHandler.getContainedBeans(WebSocketServerComponents.class).size(), is(0));
|
||||
assertNull(contextHandler.getServletContext().getAttribute(WebSocketServerComponents.WEBSOCKET_COMPONENTS_ATTRIBUTE));
|
||||
assertNull(contextHandler.getServletContext().getAttribute(JakartaWebSocketServerContainer.JAKARTA_WEBSOCKET_CONTAINER_ATTRIBUTE));
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(0));
|
||||
}
|
||||
|
||||
private void testEchoMessage() throws Exception
|
||||
{
|
||||
// Test we can upgrade to websocket and send a message.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort());
|
||||
EventSocket socket = new EventSocket();
|
||||
try (Session session = client.connectToServer(socket, uri))
|
||||
{
|
||||
session.getBasicRemote().sendText("hello world");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
String msg = socket.textMessages.poll();
|
||||
assertThat(msg, is("hello world"));
|
||||
}
|
||||
}
|
|
@ -66,23 +66,37 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
if (contextHandler.getServer() == null)
|
||||
throw new IllegalStateException("Server has not been set on the ServletContextHandler");
|
||||
|
||||
JettyWebSocketServerContainer container = getContainer(servletContext);
|
||||
if (container == null)
|
||||
// If we find a container in the servlet context return it.
|
||||
JettyWebSocketServerContainer containerFromServletContext = getContainer(servletContext);
|
||||
if (containerFromServletContext != null)
|
||||
return containerFromServletContext;
|
||||
|
||||
// Find Pre-Existing executor.
|
||||
Executor executor = (Executor)servletContext.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
executor = contextHandler.getServer().getThreadPool();
|
||||
|
||||
// Create the Jetty ServerContainer implementation.
|
||||
WebSocketMappings mappings = WebSocketMappings.ensureMappings(servletContext);
|
||||
WebSocketComponents components = WebSocketServerComponents.getWebSocketComponents(servletContext);
|
||||
JettyWebSocketServerContainer container = new JettyWebSocketServerContainer(contextHandler, mappings, components, executor);
|
||||
|
||||
// Manage the lifecycle of the Container.
|
||||
contextHandler.addManaged(container);
|
||||
contextHandler.addEventListener(container);
|
||||
contextHandler.addEventListener(new LifeCycle.Listener()
|
||||
{
|
||||
// Find Pre-Existing executor
|
||||
Executor executor = (Executor)servletContext.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (executor == null)
|
||||
executor = contextHandler.getServer().getThreadPool();
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
WebSocketMappings mappings = WebSocketMappings.ensureMappings(servletContext);
|
||||
WebSocketComponents components = WebSocketServerComponents.getWebSocketComponents(servletContext);
|
||||
container = new JettyWebSocketServerContainer(contextHandler, mappings, components, executor);
|
||||
servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
|
||||
contextHandler.addManaged(container);
|
||||
contextHandler.addEventListener(container);
|
||||
}
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle event)
|
||||
{
|
||||
contextHandler.getServletContext().removeAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE);
|
||||
contextHandler.removeBean(container);
|
||||
contextHandler.removeEventListener(container);
|
||||
contextHandler.removeEventListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
|
||||
return container;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 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.tests;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketRestartTest
|
||||
{
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private WebSocketClient client;
|
||||
private ServletContextHandler contextHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
client = new WebSocketClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stop() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebSocketRestart() throws Exception
|
||||
{
|
||||
JettyWebSocketServletContainerInitializer.configure(contextHandler, (context, container) ->
|
||||
container.addMapping("/", EchoSocket.class));
|
||||
server.start();
|
||||
|
||||
int numEventListeners = contextHandler.getEventListeners().size();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
server.stop();
|
||||
server.start();
|
||||
testEchoMessage();
|
||||
}
|
||||
|
||||
// We have not accumulated websocket resources by restarting.
|
||||
assertThat(contextHandler.getEventListeners().size(), is(numEventListeners));
|
||||
assertThat(contextHandler.getContainedBeans(JettyWebSocketServerContainer.class).size(), is(1));
|
||||
assertThat(contextHandler.getContainedBeans(WebSocketServerComponents.class).size(), is(1));
|
||||
assertNotNull(contextHandler.getServletContext().getAttribute(WebSocketServerComponents.WEBSOCKET_COMPONENTS_ATTRIBUTE));
|
||||
assertNotNull(contextHandler.getServletContext().getAttribute(JettyWebSocketServerContainer.JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE));
|
||||
|
||||
// We have one filter, and it is a WebSocketUpgradeFilter.
|
||||
FilterHolder[] filters = contextHandler.getServletHandler().getFilters();
|
||||
assertThat(filters.length, is(1));
|
||||
assertThat(filters[0].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
||||
// After stopping the websocket resources are cleaned up.
|
||||
server.stop();
|
||||
assertThat(contextHandler.getEventListeners().size(), is(0));
|
||||
assertThat(contextHandler.getContainedBeans(JettyWebSocketServerContainer.class).size(), is(0));
|
||||
assertThat(contextHandler.getContainedBeans(WebSocketServerComponents.class).size(), is(0));
|
||||
assertNull(contextHandler.getServletContext().getAttribute(WebSocketServerComponents.WEBSOCKET_COMPONENTS_ATTRIBUTE));
|
||||
assertNull(contextHandler.getServletContext().getAttribute(JettyWebSocketServerContainer.JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE));
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(0));
|
||||
}
|
||||
|
||||
private void testEchoMessage() throws Exception
|
||||
{
|
||||
// Test we can upgrade to websocket and send a message.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort());
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
String msg = socket.textMessages.poll();
|
||||
assertThat(msg, is("hello world"));
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.eclipse.jetty.servlet.FilterMapping;
|
|||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketMappings;
|
||||
|
@ -123,6 +124,18 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
servletHandler.prependFilter(holder);
|
||||
servletHandler.prependFilterMapping(mapping);
|
||||
|
||||
// If we create the filter we must also make sure it is removed if the context is stopped.
|
||||
contextHandler.addEventListener(new LifeCycle.Listener()
|
||||
{
|
||||
@Override
|
||||
public void lifeCycleStopping(LifeCycle event)
|
||||
{
|
||||
servletHandler.removeFilterHolder(holder);
|
||||
servletHandler.removeFilterMapping(mapping);
|
||||
contextHandler.removeEventListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Adding {} mapped to {} in {}", holder, pathSpec, servletContext);
|
||||
return holder;
|
||||
|
|
Loading…
Reference in New Issue