Issue #1124 - Fixing up merge issues

+ Making WebSocketServletFactory always load a new
  WebSocketServerFactory
+ Making WebSocketServerFactory need a ServletContext
  to construct it, if appropriate (the WebSocketHandler
  approach doesn't use a ServletContext)
+ NativeWebSocketConfiguration is now a bean of
  ServerContainer
+ Removed WebSocketServletFactory.init(ServletContext) method
+ Renamed WebSocketServletFactory.init() to .start()
+ Renamed WebSocketServletFactory.cleanup() to .stop()
+ CDI & Websocket now works
+ Using a ServletContextListener now works
+ DecoderFactory and EncoderFactory now work
This commit is contained in:
Joakim Erdfelt 2016-11-29 15:46:03 -07:00
parent f54938178e
commit 70247d74d9
16 changed files with 267 additions and 246 deletions

View File

@ -166,6 +166,12 @@ public class DecoderFactory implements Configurable
{
LOG.debug("init({})",config);
}
if(!containerScope.isRunning())
{
throw new RuntimeException(containerScope.getClass().getName() + " is not running yet");
}
// Instantiate all declared decoders
for (DecoderMetadata metadata : metadatas)
{

View File

@ -59,6 +59,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
this.configuration.getFactory().addSessionFactory(new JsrSessionFactory(this));
addBean(this.configuration);
}
public EndpointInstance newClientEndpointInstance(Object endpoint, ServerEndpointConfig config, String path)

View File

@ -85,6 +85,8 @@ public class OnPartialTest
URI requestURI = URI.create("ws://localhost/" + id);
DummyConnection connection = new DummyConnection();
ClientContainer container = new ClientContainer();
container.start();
@SuppressWarnings("resource")
JsrSession session = new JsrSession(container,id,requestURI,driver,connection);
session.setPolicy(policy);

View File

@ -67,7 +67,7 @@ public class SessionTrackingTest
serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
serverContainer.addEndpoint(EchoSocket.class);
wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class);
wsServerFactory = serverContainer.getWebSocketServerFactory();
server.start();

View File

@ -36,48 +36,54 @@ public interface WebSocketContainerScope
*
* @return the buffer pool (never null)
*/
public ByteBufferPool getBufferPool();
ByteBufferPool getBufferPool();
/**
* Executor in use by the container.
*
* @return the Executor in use by the container.
*/
public Executor getExecutor();
Executor getExecutor();
/**
* Object Factory used to create objects.
*
* @return Object Factory used to create instances of objects.
*/
public DecoratedObjectFactory getObjectFactory();
DecoratedObjectFactory getObjectFactory();
/**
* The policy the container is running on.
*
* @return the websocket policy
*/
public WebSocketPolicy getPolicy();
WebSocketPolicy getPolicy();
/**
* The SslContextFactory in use by the container.
*
* @return the SslContextFactory in use by the container (can be null if no SSL context is defined)
*/
public SslContextFactory getSslContextFactory();
SslContextFactory getSslContextFactory();
/**
* Test for if the container has been started.
*
* @return true if container is started and running
*/
boolean isRunning();
/**
* A Session has been opened
*
* @param session the session that was opened
*/
public void onSessionOpened(WebSocketSession session);
void onSessionOpened(WebSocketSession session);
/**
* A Session has been closed
*
* @param session the session that was closed
*/
public void onSessionClosed(WebSocketSession session);
void onSessionClosed(WebSocketSession session);
}

View File

@ -20,6 +20,8 @@ package org.eclipse.jetty.websocket.server;
import java.io.IOException;
import javax.servlet.ServletContext;
import org.eclipse.jetty.http.pathmap.MappedResource;
import org.eclipse.jetty.http.pathmap.PathMappings;
import org.eclipse.jetty.http.pathmap.PathSpec;
@ -44,9 +46,9 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
private final WebSocketServerFactory factory;
private final PathMappings<WebSocketCreator> mappings = new PathMappings<>();
public NativeWebSocketConfiguration()
public NativeWebSocketConfiguration(ServletContext context)
{
this(new WebSocketServerFactory());
this(new WebSocketServerFactory(context));
}
public NativeWebSocketConfiguration(WebSocketServerFactory webSocketServerFactory)

View File

@ -33,7 +33,7 @@ public class NativeWebSocketServletContainerInitializer implements ServletContai
NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getAttribute(KEY);
if (configuration == null)
{
configuration = new NativeWebSocketConfiguration();
configuration = new NativeWebSocketConfiguration(context);
context.setAttribute(KEY, configuration);
}
return configuration;

View File

@ -54,7 +54,8 @@ public abstract class WebSocketHandler extends HandlerWrapper
}
}
private final WebSocketServletFactory webSocketFactory;
private final ByteBufferPool bufferPool;
private WebSocketServletFactory webSocketFactory;
public WebSocketHandler()
{
@ -63,10 +64,7 @@ public abstract class WebSocketHandler extends HandlerWrapper
public WebSocketHandler(ByteBufferPool bufferPool)
{
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
configurePolicy(policy);
webSocketFactory = new WebSocketServerFactory(policy, bufferPool);
addBean(webSocketFactory);
this.bufferPool = bufferPool;
}
public abstract void configure(WebSocketServletFactory factory);
@ -79,12 +77,18 @@ public abstract class WebSocketHandler extends HandlerWrapper
@Override
protected void doStart() throws Exception
{
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
configurePolicy(policy);
webSocketFactory = new WebSocketServerFactory(policy, getServer().getThreadPool(), bufferPool);
addBean(webSocketFactory);
configure(webSocketFactory);
super.doStart();
}
public WebSocketServletFactory getWebSocketFactory()
{
if (!isRunning())
throw new IllegalStateException("Not Started yet");
return webSocketFactory;
}

View File

@ -28,12 +28,12 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -48,7 +48,6 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -96,29 +95,89 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
private final EventDriverFactory eventDriverFactory;
private final ByteBufferPool bufferPool;
private final WebSocketExtensionFactory extensionFactory;
private ServletContext context; // can be null when this factory is used from WebSocketHandler
private Executor executor;
private List<SessionFactory> sessionFactories;
private WebSocketCreator creator;
private List<Class<?>> registeredSocketClasses;
private DecoratedObjectFactory objectFactory;
public WebSocketServerFactory()
public WebSocketServerFactory(ServletContext context)
{
this(WebSocketPolicy.newServerPolicy(), new MappedByteBufferPool());
this(context, WebSocketPolicy.newServerPolicy(), new MappedByteBufferPool());
}
public WebSocketServerFactory(WebSocketPolicy policy)
public WebSocketServerFactory(ServletContext context, ByteBufferPool bufferPool)
{
this(policy, new MappedByteBufferPool());
this(context, WebSocketPolicy.newServerPolicy(), bufferPool);
}
public WebSocketServerFactory(ByteBufferPool bufferPool)
/**
* Entry point for {@link org.eclipse.jetty.websocket.servlet.WebSocketServletFactory.Loader}
*
* @param context the servlet context
* @param policy the policy to use
*/
public WebSocketServerFactory(ServletContext context, WebSocketPolicy policy)
{
this(WebSocketPolicy.newServerPolicy(), bufferPool);
this(context, policy, new MappedByteBufferPool());
}
public WebSocketServerFactory(WebSocketPolicy policy, ByteBufferPool bufferPool)
public WebSocketServerFactory(ServletContext context, WebSocketPolicy policy, ByteBufferPool bufferPool)
{
Objects.requireNonNull(context, ServletContext.class.getName());
this.context = context;
handshakes.put(HandshakeRFC6455.VERSION, new HandshakeRFC6455());
addBean(scheduler);
addBean(bufferPool);
this.contextClassloader = Thread.currentThread().getContextClassLoader();
this.registeredSocketClasses = new ArrayList<>();
this.defaultPolicy = policy;
this.eventDriverFactory = new EventDriverFactory(defaultPolicy);
this.bufferPool = bufferPool;
this.extensionFactory = new WebSocketExtensionFactory(this);
this.sessionFactories = new ArrayList<>();
this.sessionFactories.add(new WebSocketSessionFactory(this));
this.creator = this;
// Create supportedVersions
List<Integer> versions = new ArrayList<>();
for (int v : handshakes.keySet())
{
versions.add(v);
}
Collections.sort(versions, Collections.reverseOrder()); // newest first
StringBuilder rv = new StringBuilder();
for (int v : versions)
{
if (rv.length() > 0)
{
rv.append(", ");
}
rv.append(v);
}
supportedVersions = rv.toString();
}
/**
* Protected entry point for {@link WebSocketHandler}
*
* @param policy the policy to use
* @param executor the executor to use
* @param bufferPool the buffer pool to use
*/
protected WebSocketServerFactory(WebSocketPolicy policy, Executor executor, ByteBufferPool bufferPool)
{
this.objectFactory = new DecoratedObjectFactory();
this.executor = executor;
handshakes.put(HandshakeRFC6455.VERSION, new HandshakeRFC6455());
addBean(scheduler);
@ -229,22 +288,9 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
}
@Override
public void cleanup()
public WebSocketServletFactory createFactory(ServletContext context, WebSocketPolicy policy)
{
try
{
this.stop();
}
catch (Exception e)
{
LOG.warn(e);
}
}
@Override
public WebSocketServletFactory createFactory(WebSocketPolicy policy)
{
return new WebSocketServerFactory(policy, bufferPool);
return new WebSocketServerFactory(context, policy, bufferPool);
}
private WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
@ -302,10 +348,23 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
@Override
protected void doStart() throws Exception
{
if(this.objectFactory == null && context != null)
{
this.objectFactory = (DecoratedObjectFactory) context.getAttribute(DecoratedObjectFactory.ATTR);
if (this.objectFactory == null)
{
this.objectFactory = new DecoratedObjectFactory();
throw new RuntimeException("Unable to find required ServletContext attribute: " + DecoratedObjectFactory.ATTR);
}
}
if(this.executor == null && context != null)
{
ContextHandler contextHandler = ContextHandler.getContextHandler(context);
this.executor = contextHandler.getServer().getThreadPool();
}
Objects.requireNonNull(this.objectFactory, DecoratedObjectFactory.class.getName());
Objects.requireNonNull(this.executor, Executor.class.getName());
super.doStart();
}
@ -364,52 +423,6 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
return null;
}
public void init(ServletContextHandler context) throws ServletException
{
this.objectFactory = (DecoratedObjectFactory)context.getServletContext().getAttribute(DecoratedObjectFactory.ATTR);
if (this.objectFactory == null)
{
this.objectFactory = new DecoratedObjectFactory();
}
this.executor = context.getServer().getThreadPool();
}
@Override
public void init(ServletContext context) throws ServletException
{
// Setup ObjectFactory
this.objectFactory = (DecoratedObjectFactory)context.getAttribute(DecoratedObjectFactory.ATTR);
if (this.objectFactory == null)
{
this.objectFactory = new DecoratedObjectFactory();
}
// Validate Environment
ContextHandler handler = ContextHandler.getContextHandler(context);
if (handler == null)
{
throw new ServletException("Not running on Jetty, WebSocket support unavailable");
}
this.executor = handler.getServer().getThreadPool();
try
{
// start lifecycle
start();
}
catch (ServletException e)
{
throw e;
}
catch (Exception e)
{
throw new ServletException(e);
}
}
@Override
public boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response)
{
@ -519,7 +532,6 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
* @param request The request to upgrade
* @param response The response to upgrade
* @param driver The websocket handler implementation to use
* @throws IOException
*/
private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver) throws IOException
{

View File

@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.pathmap.MappedResource;
import org.eclipse.jetty.http.pathmap.PathSpec;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
@ -45,7 +44,6 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
@ -55,11 +53,9 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
@ManagedObject("WebSocket Upgrade Filter")
public class WebSocketUpgradeFilter extends AbstractLifeCycle implements Filter, MappedWebSocketCreator, Dumpable
{
private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class);
public static final String CONTEXT_ATTRIBUTE_KEY = "contextAttributeKey";
public static final String CONFIG_ATTRIBUTE_KEY = "configAttributeKey";
private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class);
private boolean localMapper;
private boolean localFactory;
public static WebSocketUpgradeFilter configureContext(ServletContextHandler context) throws ServletException
{
@ -122,9 +118,9 @@ public class WebSocketUpgradeFilter extends AbstractLifeCycle implements Filter,
// do nothing
}
public WebSocketUpgradeFilter(WebSocketPolicy policy, ByteBufferPool bufferPool)
public WebSocketUpgradeFilter(WebSocketServerFactory factory)
{
this(new NativeWebSocketConfiguration(new WebSocketServerFactory(policy, bufferPool)));
this(new NativeWebSocketConfiguration(factory));
}
public WebSocketUpgradeFilter(NativeWebSocketConfiguration configuration)

View File

@ -30,20 +30,21 @@ import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
public class WebSocketUpgradeHandlerWrapper extends HandlerWrapper implements MappedWebSocketCreator
{
private NativeWebSocketConfiguration configuration;
public WebSocketUpgradeHandlerWrapper()
public WebSocketUpgradeHandlerWrapper(ServletContextHandler context)
{
this(new MappedByteBufferPool());
this(context, new MappedByteBufferPool());
}
public WebSocketUpgradeHandlerWrapper(ByteBufferPool bufferPool)
public WebSocketUpgradeHandlerWrapper(ServletContextHandler context, ByteBufferPool bufferPool)
{
this.configuration = new NativeWebSocketConfiguration(new WebSocketServerFactory(bufferPool));
this.configuration = new NativeWebSocketConfiguration(new WebSocketServerFactory(context.getServletContext(), bufferPool));
}
@Override

View File

@ -31,7 +31,7 @@ public class InfoContextListener implements WebSocketCreator, ServletContextList
@Override
public void contextInitialized(ServletContextEvent sce)
{
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration();
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(sce.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping(new ServletPathSpec("/info/*"), this);
sce.getServletContext().setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);

View File

@ -163,7 +163,7 @@ public class WebSocketUpgradeFilterTest
server.setHandler(context);
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration();
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);

View File

@ -90,7 +90,14 @@ public abstract class WebSocketServlet extends HttpServlet
@Override
public void destroy()
{
factory.cleanup();
try
{
factory.stop();
}
catch (Exception ignore)
{
// ignore;
}
}
/**
@ -127,13 +134,12 @@ public abstract class WebSocketServlet extends HttpServlet
policy.setInputBufferSize(Integer.parseInt(max));
}
factory = WebSocketServletFactory.Loader.create(policy);
ServletContext ctx = getServletContext();
factory = WebSocketServletFactory.Loader.load(ctx, policy);
configure(factory);
ServletContext ctx = getServletContext();
factory.init(ctx);
factory.start();
ctx.setAttribute(WebSocketServletFactory.class.getName(),factory);
}

View File

@ -19,8 +19,8 @@
package org.eclipse.jetty.websocket.servlet;
import java.io.IOException;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@ -35,54 +35,42 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
*/
public interface WebSocketServletFactory
{
public static class Loader
class Loader
{
private static WebSocketServletFactory INSTANCE;
final static String DEFAULT_IMPL = "org.eclipse.jetty.websocket.server.WebSocketServerFactory";
public static WebSocketServletFactory create(WebSocketPolicy policy) throws ClassNotFoundException, InstantiationException, IllegalAccessException
public static WebSocketServletFactory load(ServletContext ctx, WebSocketPolicy policy)
{
return load().createFactory(policy);
try
{
Class<? extends WebSocketServletFactory> wsClazz =
(Class<? extends WebSocketServletFactory>) Class.forName(DEFAULT_IMPL);
Constructor<? extends WebSocketServletFactory> ctor = wsClazz.getDeclaredConstructor(new Class<?>[]{ServletContext.class, WebSocketPolicy.class});
return ctor.newInstance(ctx, policy);
}
public static WebSocketServletFactory load() throws ClassNotFoundException, InstantiationException, IllegalAccessException
catch (ClassNotFoundException e)
{
if (INSTANCE != null)
{
return INSTANCE;
throw new RuntimeException("Unable to load " + DEFAULT_IMPL, e);
}
WebSocketServletFactory baseFactory;
Iterator<WebSocketServletFactory> factories = ServiceLoader.load(WebSocketServletFactory.class).iterator();
if (factories.hasNext())
catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e)
{
baseFactory = factories.next();
throw new RuntimeException("Unable to instantiate " + DEFAULT_IMPL, e);
}
else
{
// Load the default class if ServiceLoader mechanism isn't valid in this environment. (such as OSGi)
ClassLoader loader = Thread.currentThread().getContextClassLoader();
@SuppressWarnings("unchecked")
Class<WebSocketServletFactory> wssf = (Class<WebSocketServletFactory>)loader
.loadClass("org.eclipse.jetty.websocket.server.WebSocketServerFactory");
baseFactory = wssf.newInstance();
}
INSTANCE = baseFactory;
return INSTANCE;
}
}
public boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException;
boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException;
public boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException;
boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException;
public void cleanup();
void start() throws Exception;
void stop() throws Exception;
public WebSocketServletFactory createFactory(WebSocketPolicy policy);
WebSocketServletFactory createFactory(ServletContext context, WebSocketPolicy policy);
public abstract WebSocketCreator getCreator();
WebSocketCreator getCreator();
public abstract ExtensionFactory getExtensionFactory();
ExtensionFactory getExtensionFactory();
/**
* Get the base policy in use for WebSockets.
@ -91,21 +79,18 @@ public interface WebSocketServletFactory
*
* @return the base policy
*/
public WebSocketPolicy getPolicy();
WebSocketPolicy getPolicy();
public void init(ServletContext servletContext) throws Exception;
public boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response);
boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response);
/**
* Register a websocket class pojo with the default {@link WebSocketCreator}.
* <p>
* Note: only required if using the default {@link WebSocketCreator} provided by this factory.
*
* @param websocketPojo
* the class to instantiate for each incoming websocket upgrade request.
* @param websocketPojo the class to instantiate for each incoming websocket upgrade request.
*/
public void register(Class<?> websocketPojo);
void register(Class<?> websocketPojo);
public abstract void setCreator(WebSocketCreator creator);
void setCreator(WebSocketCreator creator);
}