diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DelayedStartClientOnServerTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DelayedStartClientOnServerTest.java index fff2270bf12..00f442554de 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DelayedStartClientOnServerTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DelayedStartClientOnServerTest.java @@ -247,7 +247,7 @@ public class DelayedStartClientOnServerTest assertThat("Response", response, startsWith("Connected to ws://")); List threadNames = getThreadNames(server); assertNoHttpClientPoolThreads(threadNames); - assertThat("Threads", threadNames, hasItem(containsString("WebSocketContainer@"))); + assertThat("Threads", threadNames, hasItem(containsString("WebSocketClient@"))); } finally { @@ -255,7 +255,7 @@ public class DelayedStartClientOnServerTest } } - @Test + @Test(timeout = 5000) public void testHttpClientThreads_AfterServerConnectTo() throws Exception { Server server = new Server(0); diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPolicy.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPolicy.java index f210f42bd7c..da643d73857 100644 --- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPolicy.java +++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPolicy.java @@ -144,7 +144,12 @@ public class WebSocketPolicy public WebSocketPolicy clonePolicy() { - WebSocketPolicy clone = new WebSocketPolicy(this.behavior); + return clonePolicy(this.behavior); + } + + public WebSocketPolicy clonePolicy(WebSocketBehavior behavior) + { + WebSocketPolicy clone = new WebSocketPolicy(behavior); clone.idleTimeout = this.idleTimeout; clone.maxTextMessageSize = this.maxTextMessageSize; clone.maxTextMessageBufferSize = this.maxTextMessageBufferSize; diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/DefaultHttpClientProvider.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/DefaultHttpClientProvider.java index 4d12703fe87..39e4e9bb5c6 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/DefaultHttpClientProvider.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/DefaultHttpClientProvider.java @@ -21,6 +21,8 @@ package org.eclipse.jetty.websocket.client; import java.util.concurrent.Executor; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; @@ -31,11 +33,13 @@ class DefaultHttpClientProvider { SslContextFactory sslContextFactory = null; Executor executor = null; + ByteBufferPool bufferPool = null; if (scope != null) { sslContextFactory = scope.getSslContextFactory(); executor = scope.getExecutor(); + bufferPool = scope.getBufferPool(); } if (sslContextFactory == null) @@ -53,6 +57,13 @@ class DefaultHttpClientProvider executor = threadPool; } client.setExecutor(executor); + + if (bufferPool == null) + { + bufferPool = new MappedByteBufferPool(); + } + client.setByteBufferPool(bufferPool); + return client; } } diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java index 331eb7f8fd3..404aa16a8c2 100644 --- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java +++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java @@ -29,11 +29,10 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Future; -import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.component.ContainerLifeCycle; @@ -56,7 +55,6 @@ import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.WebSocketSessionFactory; import org.eclipse.jetty.websocket.common.events.EventDriverFactory; import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory; -import org.eclipse.jetty.websocket.common.scopes.DelegatedContainerScope; import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope; import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; @@ -70,14 +68,15 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont // From HttpClient private final HttpClient httpClient; - // - private final WebSocketContainerScope containerScope; + // CDI layer + private final Supplier objectFactorySupplier; + + // WebSocket Specifics + private final WebSocketPolicy policy; private final WebSocketExtensionFactory extensionRegistry; private final EventDriverFactory eventDriverFactory; private final SessionFactory sessionFactory; - private final int id = ThreadLocalRandom.current().nextInt(); - // defaults to true for backwards compatibility private boolean stopAtShutdown = true; @@ -86,9 +85,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient() { - // Create synthetic HttpClient - this(HttpClientProvider.get(null)); - addBean(this.httpClient); + this((HttpClient)null); } /** @@ -99,7 +96,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(HttpClient httpClient) { - this(httpClient,new DecoratedObjectFactory()); + this(httpClient, null); } /** @@ -112,11 +109,20 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(HttpClient httpClient, DecoratedObjectFactory objectFactory) { - this.containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy(),new MappedByteBufferPool(),objectFactory); - this.httpClient = httpClient; - this.extensionRegistry = new WebSocketExtensionFactory(containerScope); - this.eventDriverFactory = new EventDriverFactory(containerScope); - this.sessionFactory = new WebSocketSessionFactory(containerScope); + this(new SimpleContainerScope(new WebSocketPolicy(WebSocketBehavior.CLIENT), null, null, null, objectFactory), null, null, httpClient); + } + + /** + * Create a new WebSocketClient + * + * @param sslContextFactory + * ssl context factory to use + * @deprecated use {@link #WebSocketClient(HttpClient)} instead + */ + @Deprecated + public WebSocketClient(SslContextFactory sslContextFactory) + { + this(sslContextFactory,null, null); } /** @@ -126,10 +132,9 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont * the executor to use * @deprecated use {@link #WebSocketClient(HttpClient)} instead */ - @Deprecated public WebSocketClient(Executor executor) { - this(null,executor); + this(null, executor, null); } /** @@ -137,21 +142,12 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont * * @param bufferPool * byte buffer pool to use + * @deprecated use {@link #WebSocketClient(HttpClient)} instead */ + @Deprecated public WebSocketClient(ByteBufferPool bufferPool) { - this(null,null,bufferPool); - } - - /** - * Create a new WebSocketClient - * - * @param sslContextFactory - * ssl context factory to use - */ - public WebSocketClient(SslContextFactory sslContextFactory) - { - this(sslContextFactory,null); + this(null, null, bufferPool); } /** @@ -166,7 +162,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont @Deprecated public WebSocketClient(SslContextFactory sslContextFactory, Executor executor) { - this(sslContextFactory,executor,new MappedByteBufferPool()); + this(sslContextFactory, executor, null); } /** @@ -178,7 +174,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(WebSocketContainerScope scope) { - this(scope.getSslContextFactory(),scope.getExecutor(),scope.getBufferPool(),scope.getObjectFactory()); + this(scope, null, null, null); } /** @@ -193,7 +189,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(WebSocketContainerScope scope, SslContextFactory sslContextFactory) { - this(sslContextFactory,scope.getExecutor(),scope.getBufferPool(),scope.getObjectFactory()); + this(sslContextFactory, scope.getExecutor(), scope.getBufferPool(), scope.getObjectFactory()); } /** @@ -209,7 +205,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool) { - this(sslContextFactory,executor,bufferPool,new DecoratedObjectFactory()); + this(sslContextFactory, executor, bufferPool, null); } /** @@ -227,17 +223,8 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ private WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory) { - this.httpClient = new HttpClient(sslContextFactory); - this.httpClient.setExecutor(executor); - this.httpClient.setByteBufferPool(bufferPool); + this(new SimpleContainerScope(new WebSocketPolicy(WebSocketBehavior.CLIENT), bufferPool, executor, sslContextFactory, objectFactory)); addBean(this.httpClient); - - this.containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy(), bufferPool, objectFactory); - - this.extensionRegistry = new WebSocketExtensionFactory(containerScope); - - this.eventDriverFactory = new EventDriverFactory(containerScope); - this.sessionFactory = new WebSocketSessionFactory(containerScope); } /** @@ -271,20 +258,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public WebSocketClient(final WebSocketContainerScope scope, EventDriverFactory eventDriverFactory, SessionFactory sessionFactory, HttpClient httpClient) { - WebSocketContainerScope clientScope; - if (scope.getPolicy().getBehavior() == WebSocketBehavior.CLIENT) - { - clientScope = scope; - } - else - { - // We need to wrap the scope - clientScope = new DelegatedContainerScope(WebSocketPolicy.newClientPolicy(), scope); - } - - this.containerScope = clientScope; - - if(httpClient == null) + if (httpClient == null) { this.httpClient = HttpClientProvider.get(scope); addBean(this.httpClient); @@ -293,11 +267,15 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont { this.httpClient = httpClient; } - - this.extensionRegistry = new WebSocketExtensionFactory(containerScope); - - this.eventDriverFactory = eventDriverFactory; - this.sessionFactory = sessionFactory; + + // Ensure we get a Client version of the policy. + this.policy = scope.getPolicy().clonePolicy(WebSocketBehavior.CLIENT); + // Support Late Binding of Object Factory (for CDI) + this.objectFactorySupplier = () -> scope.getObjectFactory(); + this.extensionRegistry = new WebSocketExtensionFactory(this); + + this.eventDriverFactory = eventDriverFactory == null ? new EventDriverFactory(this) : eventDriverFactory; + this.sessionFactory = sessionFactory == null ? new WebSocketSessionFactory(this) : sessionFactory; } public Future connect(Object websocket, URI toUri) throws IOException @@ -439,7 +417,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont */ public long getAsyncWriteTimeout() { - return this.containerScope.getPolicy().getAsyncWriteTimeout(); + return getPolicy().getAsyncWriteTimeout(); } public SocketAddress getBindAddress() @@ -548,7 +526,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont @Override public DecoratedObjectFactory getObjectFactory() { - return this.containerScope.getObjectFactory(); + return this.objectFactorySupplier.get(); } public Set getOpenSessions() @@ -559,7 +537,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont @Override public WebSocketPolicy getPolicy() { - return this.containerScope.getPolicy(); + return this.policy; } public Scheduler getScheduler() @@ -753,11 +731,27 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont return stopAtShutdown; } + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (!(o instanceof WebSocketClient)) return false; + WebSocketClient that = (WebSocketClient) o; + return Objects.equals(this.httpClient, that.httpClient) && + Objects.equals(this.policy, that.policy); + } + + @Override + public int hashCode() + { + return Objects.hash(httpClient, policy); + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("WebSocketClient@"); - sb.append(Integer.toHexString(id)); + sb.append(Integer.toHexString(hashCode())); sb.append("[httpClient=").append(httpClient); sb.append(",openSessions.size="); sb.append(getOpenSessions().size()); diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java index 7fb3983e32a..51aaf78e285 100644 --- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java +++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java @@ -18,6 +18,16 @@ package org.eclipse.jetty.websocket.client; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + import java.io.IOException; import java.lang.reflect.Field; import java.net.SocketTimeoutException; @@ -73,15 +83,6 @@ import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - public class ClientCloseTest { private static final Logger LOG = Log.getLogger(ClientCloseTest.class); @@ -351,6 +352,8 @@ public class ClientCloseTest // client close event on ws-endpoint clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.NORMAL), containsString("From Server")); } + + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } @Ignore("Need sbordet's help here") @@ -452,6 +455,7 @@ public class ClientCloseTest // client triggers close event on client ws-endpoint clientSocket.assertReceivedCloseEvent(timeout,is(StatusCode.PROTOCOL),allOf(containsString("Invalid control frame"),containsString("length"))); + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } @Test @@ -495,6 +499,7 @@ public class ClientCloseTest containsString("Disconnected") )); } + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } @Test @@ -533,10 +538,17 @@ public class ClientCloseTest // client idle timeout triggers close event on client ws-endpoint assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true)); assertThat("OnError", clientSocket.error.get(), instanceOf(TimeoutException.class)); + + // client close should occur + clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.ABNORMAL), + anyOf( + containsString("Timeout"), + containsString("Disconnected") + )); } + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } - @Ignore("Issue #2625") @Test(timeout = 5000L) public void testStopLifecycle() throws Exception { @@ -585,6 +597,7 @@ public class ClientCloseTest { clientSockets.get(i).assertReceivedCloseEvent(timeout, is(StatusCode.SHUTDOWN), containsString("Shutdown")); } + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } finally { @@ -638,5 +651,6 @@ public class ClientCloseTest // assert - close reason message contains (write failure) clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.ABNORMAL), containsString("EOF")); } + assertThat("Client Open Sessions", client.getOpenSessions(), empty()); } } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java index 0cd32fbe585..6513b0a29e6 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java @@ -23,9 +23,11 @@ import java.util.concurrent.Executor; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.MappedByteBufferPool; import org.eclipse.jetty.util.DecoratedObjectFactory; +import org.eclipse.jetty.util.DeprecationWarning; import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.websocket.api.WebSocketBehavior; import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.common.WebSocketSession; @@ -54,6 +56,11 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke } public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, Executor executor, DecoratedObjectFactory objectFactory) + { + this(policy, bufferPool, executor, null, objectFactory); + } + + public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, Executor executor, SslContextFactory ssl, DecoratedObjectFactory objectFactory) { this.policy = policy; this.bufferPool = bufferPool; @@ -61,16 +68,34 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke if (objectFactory == null) { this.objectFactory = new DecoratedObjectFactory(); + this.objectFactory.addDecorator(new DeprecationWarning()); } else { this.objectFactory = objectFactory; } + + if(ssl == null) + { + this.sslContextFactory = new SslContextFactory(); + } + else + { + this.sslContextFactory = ssl; + } if (executor == null) { QueuedThreadPool threadPool = new QueuedThreadPool(); - String name = "WebSocketContainer@" + hashCode(); + String behavior = "Container"; + if (policy != null) + { + if (policy.getBehavior() == WebSocketBehavior.CLIENT) + behavior = "Client"; + else if (policy.getBehavior() == WebSocketBehavior.SERVER) + behavior = "Server"; + } + String name = String.format("WebSocket%s@%s", behavior, hashCode()); threadPool.setName(name); threadPool.setDaemon(true); this.executor = threadPool; @@ -82,18 +107,6 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke } } - @Override - protected void doStart() throws Exception - { - super.doStart(); - } - - @Override - protected void doStop() throws Exception - { - super.doStop(); - } - @Override public ByteBufferPool getBufferPool() { diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketServletContainerInitializer.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketServletContainerInitializer.java index d57346ba16d..f7c7d761a1f 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketServletContainerInitializer.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/NativeWebSocketServletContainerInitializer.java @@ -22,7 +22,8 @@ import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; -import javax.servlet.ServletException; + +import org.eclipse.jetty.server.handler.ContextHandler; public class NativeWebSocketServletContainerInitializer implements ServletContainerInitializer { @@ -33,14 +34,23 @@ public class NativeWebSocketServletContainerInitializer implements ServletContai NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getAttribute(KEY); if (configuration == null) { + // Not provided to us, create a new default one. configuration = new NativeWebSocketConfiguration(context); context.setAttribute(KEY, configuration); + + // Attach default configuration to context lifecycle + if (context instanceof ContextHandler.Context) + { + ContextHandler handler = ((ContextHandler.Context)context).getContextHandler(); + // Let ContextHandler handle configuration lifecycle + handler.addManaged(configuration); + } } return configuration; } @Override - public void onStartup(Set> c, ServletContext ctx) throws ServletException + public void onStartup(Set> c, ServletContext ctx) { // initialize getDefaultFrom(ctx); diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java index a9c6cc06eef..9eef8ab1d2d 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java @@ -315,17 +315,14 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc { if(this.objectFactory == null) { - this.objectFactory = findDecorator(); + this.objectFactory = findDecoratedObjectFactory(); } if(this.executor == null) { this.executor = findExecutor(); } - - Objects.requireNonNull(this.objectFactory, DecoratedObjectFactory.class.getName()); - Objects.requireNonNull(this.executor, Executor.class.getName()); - + super.doStart(); } @@ -333,7 +330,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc * Attempt to find the DecoratedObjectFactory that should be used. * @return the DecoratedObjectFactory that should be used. (never null) */ - protected DecoratedObjectFactory findDecorator() + private DecoratedObjectFactory findDecoratedObjectFactory() { DecoratedObjectFactory objectFactory; @@ -356,30 +353,45 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc * Attempt to find the Executor that should be used. * @return the Executor that should be used. (never null) */ - protected Executor findExecutor() + private Executor findExecutor() { - if(context != null) + // Try as bean + Executor executor = getBean(Executor.class); + if (executor != null) { - // Attempt to pull Executor from ServletContext attribute - Executor contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.server.Executor"); - if(contextExecutor != null) + return executor; + } + + // Attempt to pull Executor from ServletContext attribute + if (context != null) + { + // Try websocket specific one first + Executor contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.websocket.Executor"); + if (contextExecutor != null) { return contextExecutor; } - // Attempt to pull Executor from Jetty Server, via ContextHandler + // Try ContextHandler version + contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.server.Executor"); + if (contextExecutor != null) + { + return contextExecutor; + } + + // Try Executor from Jetty Server ContextHandler contextHandler = ContextHandler.getContextHandler(context); if (contextHandler != null) { contextExecutor = contextHandler.getServer().getThreadPool(); - if(contextExecutor != null) + if (contextExecutor != null) // This should always be true! { return contextExecutor; } } } - // Create a new one + // All else fails, Create a new one QueuedThreadPool threadPool = new QueuedThreadPool(); threadPool.setName("WebSocketServerFactory"); addManaged(threadPool);