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:
parent
f54938178e
commit
70247d74d9
|
@ -190,7 +190,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
|
|||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
|
||||
// Initialize the default decoder / encoder factories
|
||||
EmptyClientEndpointConfig empty = new EmptyClientEndpointConfig();
|
||||
this.decoderFactory.init(empty);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -53,8 +53,9 @@ public abstract class WebSocketHandler extends HandlerWrapper
|
|||
factory.register(websocketPojo);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -83,7 +82,7 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
|||
public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
|
||||
|
||||
|
||||
private final ClassLoader contextClassloader;
|
||||
private final Map<Integer, WebSocketHandshake> handshakes = new HashMap<>();
|
||||
/**
|
||||
|
@ -96,47 +95,58 @@ 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())
|
||||
|
@ -155,23 +165,72 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
public void addSessionListener(WebSocketSession.Listener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
public void removeSessionListener(WebSocketSession.Listener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
return acceptWebSocket(getCreator(), request, response);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
|
@ -179,32 +238,32 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(contextClassloader);
|
||||
|
||||
|
||||
// Create Servlet Specific Upgrade Request/Response objects
|
||||
ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request);
|
||||
ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response);
|
||||
|
||||
|
||||
Object websocketPojo = creator.createWebSocket(sockreq, sockresp);
|
||||
|
||||
|
||||
// Handle response forbidden (and similar paths)
|
||||
if (sockresp.isCommitted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (websocketPojo == null)
|
||||
{
|
||||
// no creation, sorry
|
||||
sockresp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Endpoint Creation Failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Allow Decorators to do their thing
|
||||
websocketPojo = getObjectFactory().decorate(websocketPojo);
|
||||
|
||||
|
||||
// Get the original HTTPConnection
|
||||
HttpConnection connection = (HttpConnection)request.getAttribute("org.eclipse.jetty.server.HttpConnection");
|
||||
|
||||
HttpConnection connection = (HttpConnection) request.getAttribute("org.eclipse.jetty.server.HttpConnection");
|
||||
|
||||
// Send the upgrade
|
||||
EventDriver driver = eventDriverFactory.wrap(websocketPojo);
|
||||
return upgrade(connection, sockreq, sockresp, driver);
|
||||
|
@ -218,7 +277,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
Thread.currentThread().setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addSessionFactory(SessionFactory sessionFactory)
|
||||
{
|
||||
if (sessionFactories.contains(sessionFactory))
|
||||
|
@ -227,33 +286,20 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
this.sessionFactories.add(sessionFactory);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
public WebSocketServletFactory createFactory(ServletContext context, WebSocketPolicy policy)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
return new WebSocketServerFactory(context, policy, bufferPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketServletFactory createFactory(WebSocketPolicy policy)
|
||||
{
|
||||
return new WebSocketServerFactory(policy, bufferPool);
|
||||
}
|
||||
|
||||
|
||||
private WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
if (websocket == null)
|
||||
{
|
||||
throw new InvalidWebSocketException("Unable to create Session from null websocket");
|
||||
}
|
||||
|
||||
|
||||
for (SessionFactory impl : sessionFactories)
|
||||
{
|
||||
if (impl.supports(websocket))
|
||||
|
@ -268,10 +314,10 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw new InvalidWebSocketException("Unable to create Session: unrecognized internal EventDriver type: " + websocket.getClass().getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default Creator logic
|
||||
*/
|
||||
|
@ -282,12 +328,12 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
{
|
||||
throw new WebSocketException("No WebSockets have been registered with the factory. Cannot use default implementation of WebSocketCreator.");
|
||||
}
|
||||
|
||||
|
||||
if (registeredSocketClasses.size() > 1)
|
||||
{
|
||||
LOG.warn("You have registered more than 1 websocket object, and are using the default WebSocketCreator! Using first registered websocket.");
|
||||
}
|
||||
|
||||
|
||||
Class<?> firstClass = registeredSocketClasses.get(0);
|
||||
try
|
||||
{
|
||||
|
@ -298,63 +344,76 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
throw new WebSocketException("Unable to create instance of " + firstClass, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if(this.objectFactory == null)
|
||||
if(this.objectFactory == null && context != null)
|
||||
{
|
||||
this.objectFactory = new DecoratedObjectFactory();
|
||||
this.objectFactory = (DecoratedObjectFactory) context.getAttribute(DecoratedObjectFactory.ATTR);
|
||||
if (this.objectFactory == null)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return this.bufferPool;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebSocketCreator getCreator()
|
||||
{
|
||||
return this.creator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return this.executor;
|
||||
}
|
||||
|
||||
|
||||
public DecoratedObjectFactory getObjectFactory()
|
||||
{
|
||||
return objectFactory;
|
||||
}
|
||||
|
||||
|
||||
public EventDriverFactory getEventDriverFactory()
|
||||
{
|
||||
return eventDriverFactory;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExtensionFactory getExtensionFactory()
|
||||
{
|
||||
return extensionFactory;
|
||||
}
|
||||
|
||||
|
||||
public Collection<WebSocketSession> getOpenSessions()
|
||||
{
|
||||
return getBeans(WebSocketSession.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return defaultPolicy;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SslContextFactory getSslContextFactory()
|
||||
{
|
||||
|
@ -363,53 +422,7 @@ 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)
|
||||
{
|
||||
|
@ -434,7 +447,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
// no "Connection: upgrade" header present.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Test for "Upgrade" token
|
||||
boolean foundUpgradeToken = false;
|
||||
Iterator<String> iter = QuoteUtil.splitAt(connection, ",");
|
||||
|
@ -447,7 +460,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!foundUpgradeToken)
|
||||
{
|
||||
return false;
|
||||
|
@ -458,30 +471,30 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
// not a "GET" request (not a websocket upgrade)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!"HTTP/1.1".equals(request.getProtocol()))
|
||||
{
|
||||
LOG.debug("Not a 'HTTP/1.1' request (was [" + request.getProtocol() + "])");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSessionOpened(WebSocketSession session)
|
||||
{
|
||||
addManaged(session);
|
||||
notifySessionListeners(listener -> listener.onOpened(session));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSessionClosed(WebSocketSession session)
|
||||
{
|
||||
removeBean(session);
|
||||
notifySessionListeners(listener -> listener.onClosed(session));
|
||||
}
|
||||
|
||||
|
||||
private void notifySessionListeners(Consumer<WebSocketSession.Listener> consumer)
|
||||
{
|
||||
for (WebSocketSession.Listener listener : listeners)
|
||||
|
@ -496,30 +509,29 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void register(Class<?> websocketPojo)
|
||||
{
|
||||
registeredSocketClasses.add(websocketPojo);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setCreator(WebSocketCreator creator)
|
||||
{
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Upgrade the request/response to a WebSocket Connection.
|
||||
* <p/>
|
||||
* This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the
|
||||
* connection.
|
||||
*
|
||||
* @param http the raw http connection
|
||||
* @param request The request to upgrade
|
||||
* @param http the raw http connection
|
||||
* @param request The request to upgrade
|
||||
* @param response The response to upgrade
|
||||
* @param driver The websocket handler implementation to use
|
||||
* @throws IOException
|
||||
* @param driver The websocket handler implementation to use
|
||||
*/
|
||||
private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver) throws IOException
|
||||
{
|
||||
|
@ -531,14 +543,14 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
{
|
||||
throw new IllegalStateException("Not a 'HTTP/1.1' request");
|
||||
}
|
||||
|
||||
|
||||
int version = request.getHeaderInt("Sec-WebSocket-Version");
|
||||
if (version < 0)
|
||||
{
|
||||
// Old pre-RFC version specifications (header not present in RFC-6455)
|
||||
version = request.getHeaderInt("Sec-WebSocket-Draft");
|
||||
}
|
||||
|
||||
|
||||
WebSocketHandshake handshaker = handshakes.get(version);
|
||||
if (handshaker == null)
|
||||
{
|
||||
|
@ -563,14 +575,14 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
warn.append(": [").append(supportedVersions).append("]");
|
||||
LOG.warn(warn.toString());
|
||||
|
||||
|
||||
// Per RFC 6455 - 4.4 - Supporting Multiple Versions of WebSocket Protocol
|
||||
// Using the examples as outlined
|
||||
response.setHeader("Sec-WebSocket-Version", supportedVersions);
|
||||
response.sendError(HttpStatus.BAD_REQUEST_400, "Unsupported websocket version specification");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Initialize / Negotiate Extensions
|
||||
ExtensionStack extensionStack = new ExtensionStack(getExtensionFactory());
|
||||
// The JSR allows for the extensions to be pre-negotiated, filtered, etc...
|
||||
|
@ -585,26 +597,26 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
// Use raw extension list from request
|
||||
extensionStack.negotiate(request.getExtensions());
|
||||
}
|
||||
|
||||
|
||||
// Get original HTTP connection
|
||||
EndPoint endp = http.getEndPoint();
|
||||
Connector connector = http.getConnector();
|
||||
Executor executor = connector.getExecutor();
|
||||
ByteBufferPool bufferPool = connector.getByteBufferPool();
|
||||
|
||||
|
||||
// Setup websocket connection
|
||||
AbstractWebSocketConnection wsConnection = new WebSocketServerConnection(endp, executor, scheduler, driver.getPolicy(), bufferPool);
|
||||
|
||||
|
||||
extensionStack.setPolicy(driver.getPolicy());
|
||||
extensionStack.configure(wsConnection.getParser());
|
||||
extensionStack.configure(wsConnection.getGenerator());
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("HttpConnection: {}", http);
|
||||
LOG.debug("WebSocketConnection: {}", wsConnection);
|
||||
}
|
||||
|
||||
|
||||
// Setup Session
|
||||
WebSocketSession session = createSession(request.getRequestURI(), driver, wsConnection);
|
||||
session.setPolicy(driver.getPolicy());
|
||||
|
@ -613,51 +625,51 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
response.setExtensions(extensionStack.getNegotiatedExtensions());
|
||||
session.setUpgradeResponse(response);
|
||||
wsConnection.addListener(session);
|
||||
|
||||
|
||||
// Setup Incoming Routing
|
||||
wsConnection.setNextIncomingFrames(extensionStack);
|
||||
extensionStack.setNextIncoming(session);
|
||||
|
||||
|
||||
// Setup Outgoing Routing
|
||||
session.setOutgoingHandler(extensionStack);
|
||||
extensionStack.setNextOutgoing(wsConnection);
|
||||
|
||||
|
||||
// Start Components
|
||||
session.addManaged(extensionStack);
|
||||
this.addManaged(session);
|
||||
|
||||
|
||||
if (session.isFailed())
|
||||
{
|
||||
throw new IOException("Session failed to start");
|
||||
}
|
||||
|
||||
|
||||
// Tell jetty about the new upgraded connection
|
||||
request.setServletAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE, wsConnection);
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Handshake Response: {}", handshaker);
|
||||
|
||||
|
||||
if (getSendServerVersion(connector))
|
||||
response.setHeader("Server",HttpConfiguration.SERVER_VERSION);
|
||||
|
||||
response.setHeader("Server", HttpConfiguration.SERVER_VERSION);
|
||||
|
||||
// Process (version specific) handshake response
|
||||
handshaker.doHandshakeResponse(request, response);
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Websocket upgrade {} {} {} {}", request.getRequestURI(), version, response.getAcceptedSubProtocol(), wsConnection);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean getSendServerVersion(Connector connector)
|
||||
{
|
||||
ConnectionFactory connFactory = connector.getConnectionFactory(HttpVersion.HTTP_1_1.asString());
|
||||
if (connFactory == null)
|
||||
return false;
|
||||
|
||||
|
||||
if (connFactory instanceof HttpConnectionFactory)
|
||||
{
|
||||
HttpConfiguration httpConf = ((HttpConnectionFactory)connFactory).getHttpConfiguration();
|
||||
HttpConfiguration httpConf = ((HttpConnectionFactory) connFactory).getHttpConfiguration();
|
||||
if (httpConf != null)
|
||||
return httpConf.getSendServerVersion();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -90,7 +90,14 @@ public abstract class WebSocketServlet extends HttpServlet
|
|||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
factory.cleanup();
|
||||
try
|
||||
{
|
||||
factory.stop();
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
// ignore;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,14 +133,13 @@ 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);
|
||||
}
|
||||
|
|
|
@ -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,77 +35,62 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
|
|||
*/
|
||||
public interface WebSocketServletFactory
|
||||
{
|
||||
public static class Loader
|
||||
class Loader
|
||||
{
|
||||
private static WebSocketServletFactory INSTANCE;
|
||||
|
||||
public static WebSocketServletFactory create(WebSocketPolicy policy) throws ClassNotFoundException, InstantiationException, IllegalAccessException
|
||||
final static String DEFAULT_IMPL = "org.eclipse.jetty.websocket.server.WebSocketServerFactory";
|
||||
|
||||
public static WebSocketServletFactory load(ServletContext ctx, WebSocketPolicy policy)
|
||||
{
|
||||
return load().createFactory(policy);
|
||||
}
|
||||
|
||||
public static WebSocketServletFactory load() throws ClassNotFoundException, InstantiationException, IllegalAccessException
|
||||
{
|
||||
if (INSTANCE != null)
|
||||
try
|
||||
{
|
||||
return INSTANCE;
|
||||
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);
|
||||
}
|
||||
WebSocketServletFactory baseFactory;
|
||||
Iterator<WebSocketServletFactory> factories = ServiceLoader.load(WebSocketServletFactory.class).iterator();
|
||||
|
||||
if (factories.hasNext())
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
baseFactory = factories.next();
|
||||
throw new RuntimeException("Unable to load " + DEFAULT_IMPL, e);
|
||||
}
|
||||
else
|
||||
catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e)
|
||||
{
|
||||
// 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();
|
||||
throw new RuntimeException("Unable to instantiate " + DEFAULT_IMPL, e);
|
||||
}
|
||||
|
||||
INSTANCE = baseFactory;
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
|
||||
public boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
|
||||
public void cleanup();
|
||||
|
||||
public WebSocketServletFactory createFactory(WebSocketPolicy policy);
|
||||
|
||||
public abstract WebSocketCreator getCreator();
|
||||
|
||||
public abstract ExtensionFactory getExtensionFactory();
|
||||
|
||||
|
||||
boolean acceptWebSocket(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
|
||||
boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
|
||||
void start() throws Exception;
|
||||
void stop() throws Exception;
|
||||
|
||||
WebSocketServletFactory createFactory(ServletContext context, WebSocketPolicy policy);
|
||||
|
||||
WebSocketCreator getCreator();
|
||||
|
||||
ExtensionFactory getExtensionFactory();
|
||||
|
||||
/**
|
||||
* Get the base policy in use for WebSockets.
|
||||
* <p>
|
||||
* Note: individual WebSocket implementations can override some of the values in here by using the {@link WebSocket @WebSocket} annotation.
|
||||
*
|
||||
*
|
||||
* @return the base policy
|
||||
*/
|
||||
public WebSocketPolicy getPolicy();
|
||||
|
||||
public void init(ServletContext servletContext) throws Exception;
|
||||
|
||||
public boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
WebSocketPolicy getPolicy();
|
||||
|
||||
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);
|
||||
|
||||
public abstract void setCreator(WebSocketCreator creator);
|
||||
void register(Class<?> websocketPojo);
|
||||
|
||||
void setCreator(WebSocketCreator creator);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue