Issue #1114 - persisting NativeWebSocketConfiguration mappings

+ Mappings are persisted if added to the NativeWebSocketConfiguration
  before that configuration is started.  Otherwise they are cleared
  out on configuration.stop() lifecycle (like before)
This commit is contained in:
Joakim Erdfelt 2016-12-14 15:31:23 -07:00
parent 05f397caa4
commit bd104d59f9
4 changed files with 76 additions and 5 deletions

View File

@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ -69,6 +70,11 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
mappings.clear();
}
public void removeIf(Predicate<MappedResource<E>> predicate)
{
mappings.removeIf(predicate);
}
/**
* Return a list of MappedResource matches for the specified path.
*

View File

@ -60,7 +60,7 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
@Override
public void doStop() throws Exception
{
mappings.reset();
mappings.removeIf((mapped) -> !(mapped.getResource() instanceof PersistedWebSocketCreator));
super.doStop();
}
@ -111,13 +111,23 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
/**
* Manually add a WebSocket mapping.
* <p>
* If mapping is added before this configuration is started, then it is persisted through
* stop/start of this configuration's lifecycle. Otherwise it will be removed when
* this configuration is stopped.
* </p>
*
* @param pathSpec the pathspec to respond on
* @param creator the websocket creator to activate on the provided mapping.
*/
public void addMapping(PathSpec pathSpec, WebSocketCreator creator)
{
mappings.put(pathSpec, creator);
WebSocketCreator wsCreator = creator;
if (!isRunning())
{
wsCreator = new PersistedWebSocketCreator(creator);
}
mappings.put(pathSpec, wsCreator);
}
/**
@ -170,4 +180,26 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
}
});
}
private class PersistedWebSocketCreator implements WebSocketCreator
{
private final WebSocketCreator delegate;
public PersistedWebSocketCreator(WebSocketCreator delegate)
{
this.delegate = delegate;
}
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
return delegate.createWebSocket(req, resp);
}
@Override
public String toString()
{
return "Persisted[" + super.toString() + "]";
}
}
}

View File

@ -110,6 +110,7 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
}
private NativeWebSocketConfiguration configuration;
private boolean exportConfiguration = true;
private boolean localConfiguration = false;
private boolean alreadySetToAttribute = false;
@ -126,6 +127,7 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
public WebSocketUpgradeFilter(NativeWebSocketConfiguration configuration)
{
this.configuration = configuration;
this.exportConfiguration = false;
}
@Override
@ -304,7 +306,7 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
NativeWebSocketConfiguration.class.getName() + " at ServletContext attribute '" + configurationKey + "'");
}
}
else
else if (exportConfiguration)
{
// We have a NativeWebSocketConfiguration already present, make sure it exists on the ServletContext
if (config.getServletContext().getAttribute(configurationKey) == null)

View File

@ -34,6 +34,7 @@ import javax.servlet.DispatcherType;
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
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.toolchain.test.EventQueue;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -166,14 +167,44 @@ public class WebSocketUpgradeFilterTest
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping(new ServletPathSpec("/info/*"), infoCreator);
context.getServletContext().setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
context.setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via wsuf constructor
cases.add(new Object[]{"wsuf/addFilter/WSUF Constructor configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping(new ServletPathSpec("/info/*"), infoCreator);
context.addBean(configuration, true);
FilterHolder wsufHolder = new FilterHolder(new WebSocketUpgradeFilter(configuration));
context.addFilter(wsufHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf.configureContext/ServletContextListener configure", new ServerProvider()