Merge branch 'master' into gcloud-session-manager
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
index 3afe51d..3a9342c 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
@@ -828,14 +828,9 @@
 
     /**
      * Get SCIs that are not excluded from consideration
-     * @param context
-     * @return
-     * @throws Exception
-     */
-    /**
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the web app context 
+     * @return the list of non-excluded servlet container initializers
+     * @throws Exception if unable to get list 
      */
     public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
     throws Exception
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java
index 3561b24..1b58920 100644
--- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java
@@ -57,6 +57,7 @@
 
     /**
      * Validation of Scope / Inject logic on non-websocket-scoped classes
+     * @throws Exception on test failure
      */
     @Test
     public void testBasicBehavior() throws Exception
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java
index 3c9e2e1..ba1fd99 100644
--- a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java
@@ -61,6 +61,7 @@
      * Test behavior of {@link WebSocketScope} in basic operation.
      * <p>
      * Food is declared as part of WebSocketScope, and as such, only 1 instance of it can exist.
+     * @throws Exception on test failure
      */
     @Test
     public void testScopeBehavior() throws Exception
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
index c46bc6c..c8b5556 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
@@ -26,7 +26,6 @@
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
@@ -119,7 +118,7 @@
                     {
                         String message = String.format("Cannot perform requests over SSL, no %s in %s",
                                 SslContextFactory.class.getSimpleName(), HttpClient.class.getSimpleName());
-                        promise.failed(new IllegalStateException(message));
+                        tunnelFailed(new IllegalStateException(message));
                     }
                 }
                 else
@@ -131,7 +130,7 @@
             @Override
             public void failed(Throwable x)
             {
-                promise.failed(x);
+                tunnelFailed(x);
             }
 
             private void tunnel(HttpDestination destination, final Connection connection)
@@ -139,33 +138,31 @@
                 String target = destination.getOrigin().getAddress().asString();
                 Origin.Address proxyAddress = destination.getConnectAddress();
                 HttpClient httpClient = destination.getHttpClient();
+                long connectTimeout = httpClient.getConnectTimeout();
                 Request connect = httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort())
                         .scheme(HttpScheme.HTTP.asString())
                         .method(HttpMethod.CONNECT)
                         .path(target)
                         .header(HttpHeader.HOST, target)
-                        .timeout(httpClient.getConnectTimeout(), TimeUnit.MILLISECONDS);
+                        .idleTimeout(2 * connectTimeout, TimeUnit.MILLISECONDS)
+                        .timeout(connectTimeout, TimeUnit.MILLISECONDS);
 
-                connection.send(connect, new Response.CompleteListener()
+                connection.send(connect, result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
+                    if (result.isFailed())
                     {
-                        if (result.isFailed())
+                        tunnelFailed(result.getFailure());
+                    }
+                    else
+                    {
+                        Response response = result.getResponse();
+                        if (response.getStatus() == 200)
                         {
-                            tunnelFailed(result.getFailure());
+                            tunnelSucceeded();
                         }
                         else
                         {
-                            Response response = result.getResponse();
-                            if (response.getStatus() == 200)
-                            {
-                                tunnelSucceeded();
-                            }
-                            else
-                            {
-                                tunnelFailed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
-                            }
+                            tunnelFailed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
                         }
                     }
                 });
@@ -198,7 +195,7 @@
             private void tunnelFailed(Throwable failure)
             {
                 endPoint.close();
-                failed(failure);
+                promise.failed(failure);
             }
         }
     }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
index 3030a97..9f0aff8 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
@@ -168,11 +168,11 @@
     }
 
     @Override
-    public void close(Connection oldConnection)
+    public void close(Connection connection)
     {
-        super.close(oldConnection);
+        super.close(connection);
 
-        connectionPool.remove(oldConnection);
+        boolean removed = connectionPool.remove(connection);
 
         if (getHttpExchanges().isEmpty())
         {
@@ -192,7 +192,8 @@
             // We need to execute queued requests even if this connection failed.
             // We may create a connection that is not needed, but it will eventually
             // idle timeout, so no worries.
-            process();
+            if (removed)
+                process();
         }
     }
 
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java
index 7ca6a58..d7da914 100644
--- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java
+++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java
@@ -77,19 +77,12 @@
     
     
     
-    /**
-     * @param server
-     */
     public InfinispanSessionIdManager(Server server)
     {
         super();
         _server = server;
     }
 
-    /**
-     * @param server
-     * @param random
-     */
     public InfinispanSessionIdManager(Server server, Random random)
     {
        super(random);
@@ -279,7 +272,7 @@
 
     /**
      * Get the cache.
-     * @return
+     * @return the cache
      */
     public BasicCache<String,Object> getCache() 
     {
@@ -288,7 +281,7 @@
 
     /**
      * Set the cache.
-     * @param cache
+     * @param cache the cache
      */
     public void setCache(BasicCache<String,Object> cache) 
     {
@@ -300,7 +293,7 @@
     /**
      * Do any operation to the session id in the cache to
      * ensure its idle expiry time moves forward
-     * @param id
+     * @param id the session id
      */
     public void touch (String id)
     {
@@ -312,8 +305,8 @@
     /**
      * Ask the cluster if a particular id exists.
      * 
-     * @param id
-     * @return
+     * @param id the session id
+     * @return true if exists
      */
     protected boolean exists (String id)
     {
@@ -327,7 +320,7 @@
     /**
      * Put a session id into the cluster.
      * 
-     * @param id
+     * @param id the session id
      */
     protected void insert (String id)
     {        
@@ -341,7 +334,8 @@
     /**
      * Put a session id into the cluster with an idle expiry.
      * 
-     * @param id
+     * @param id the session id
+     * @param idleTimeOutSec idle timeout in seconds
      */
     protected void insert (String id, long idleTimeOutSec)
     {
@@ -355,7 +349,7 @@
     /**
      * Remove a session id from the cluster.
      * 
-     * @param id
+     * @param id the session id
      */
     protected void delete (String id)
     {
@@ -370,8 +364,8 @@
     /**
      * Generate a unique cache key from the session id.
      * 
-     * @param id
-     * @return
+     * @param id the session id
+     * @return unique cache id
      */
     protected String makeKey (String id)
     {
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java
index b2e898d..039263a 100644
--- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java
+++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java
@@ -267,7 +267,7 @@
         /**
          * A new session.
          * 
-         * @param request
+         * @param request the request
          */
         protected Session (HttpServletRequest request)
         {
@@ -295,10 +295,10 @@
         /**
          * A restored session.
          * 
-         * @param sessionId
-         * @param created
-         * @param accessed
-         * @param maxInterval
+         * @param sessionId the session id
+         * @param created time created
+         * @param accessed time last accessed
+         * @param maxInterval max expiry interval
          */
         protected Session (String sessionId, long created, long accessed, long maxInterval)
         {
@@ -406,8 +406,8 @@
         }
         
         /** Test if the session is stale
-         * @param atTime
-         * @return
+         * @param atTime time when stale
+         * @return true if stale
          */
         protected boolean isStale (long atTime)
         {
@@ -416,7 +416,7 @@
         
         
         /** Test if the session is dirty
-         * @return
+         * @return true if dirty
          */
         protected boolean isDirty ()
         {
@@ -711,7 +711,7 @@
      * often.
      * 
      * 
-     * @param sec
+     * @param sec scavenge interval in seconds
      */
     public void setScavengeInterval (long sec)
     {
@@ -752,7 +752,7 @@
     /**
      * Get the clustered cache instance.
      * 
-     * @return
+     * @return the cache
      */
     public BasicCache<String, Object> getCache() 
     {
@@ -764,7 +764,7 @@
     /**
      * Set the clustered cache instance.
      * 
-     * @param cache
+     * @param cache the cache
      */
     public void setCache (BasicCache<String, Object> cache) 
     {
@@ -990,8 +990,8 @@
     /**
      * Load a session from the clustered cache.
      * 
-     * @param key
-     * @return
+     * @param key the session key
+     * @return the session
      */
     protected Session load (String key)
     {
@@ -1019,8 +1019,8 @@
     /**
      * Save or update the session to the cluster cache
      * 
-     * @param session
-     * @throws Exception
+     * @param session the session
+     * @throws Exception if unable to save
      */
     protected void save (InfinispanSessionManager.Session session)
     throws Exception
@@ -1053,7 +1053,7 @@
     /**
      * Remove the session from the cluster cache.
      * 
-     * @param session
+     * @param session the session
      */
     protected void delete (InfinispanSessionManager.Session session)
     {  
@@ -1067,7 +1067,7 @@
     /**
      * Invalidate a session for this context with the given id
      * 
-     * @param idInCluster
+     * @param idInCluster session id in cluster
      */
     public void invalidateSession (String idInCluster)
     {
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
index 22adeb0..402ad48 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
@@ -564,7 +564,7 @@
      * Run a scanner thread on the given list of files and directories, calling
      * stop/start on the given list of LifeCycle objects if any of the watched
      * files change.
-     *
+     * @throws Exception if unable to start scanner 
      */
     public void startScanner() throws Exception
     {
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
index caec583..e563962 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.proxy;
 
-import static org.junit.Assert.assertEquals;
-
 import java.io.IOException;
 import java.net.ConnectException;
 import java.net.Socket;
@@ -64,6 +62,8 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+
 public class ProxyTunnellingTest
 {
     @Rule
@@ -279,6 +279,59 @@
     }
 
     @Test
+    public void testShortIdleTimeoutOverriddenByRequest() throws Exception
+    {
+        // Short idle timeout for HttpClient.
+        long idleTimeout = 500;
+
+        startSSLServer(new ServerHandler());
+        startProxy(new ConnectHandler()
+        {
+            @Override
+            protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
+            {
+                try
+                {
+                    // Make sure the proxy remains idle enough.
+                    Thread.sleep(2 * idleTimeout);
+                    super.handleConnect(baseRequest, request, response, serverAddress);
+                }
+                catch (InterruptedException x)
+                {
+                    onConnectFailure(request, response, null, x);
+                }
+            }
+        });
+
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", proxyPort()));
+        // Short idle timeout for HttpClient.
+        httpClient.setIdleTimeout(idleTimeout);
+        httpClient.start();
+
+        try
+        {
+            String host = "localhost";
+            String body = "BODY";
+            ContentResponse response = httpClient.newRequest(host, serverConnector.getLocalPort())
+                    .scheme(HttpScheme.HTTPS.asString())
+                    .method(HttpMethod.GET)
+                    .path("/echo?body=" + URLEncoder.encode(body, "UTF-8"))
+                    // Long idle timeout for the request.
+                    .idleTimeout(10 * idleTimeout, TimeUnit.MILLISECONDS)
+                    .send();
+
+            assertEquals(HttpStatus.OK_200, response.getStatus());
+            String content = response.getContentAsString();
+            assertEquals(body, content);
+        }
+        finally
+        {
+            httpClient.stop();
+        }
+    }
+
+    @Test
     public void testProxyDown() throws Exception
     {
         startSSLServer(new ServerHandler());
diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml
index d7d295c..5412979 100644
--- a/jetty-server/src/main/config/etc/jetty.xml
+++ b/jetty-server/src/main/config/etc/jetty.xml
@@ -88,6 +88,7 @@
       <Set name="headerCacheSize"><Property name="jetty.httpConfig.headerCacheSize" default="512" /></Set>
       <Set name="delayDispatchUntilContent"><Property name="jetty.httpConfig.delayDispatchUntilContent" deprecated="jetty.delayDispatchUntilContent" default="true"/></Set>
       <Set name="maxErrorDispatches"><Property name="jetty.httpConfig.maxErrorDispatches" default="10"/></Set>
+      <Set name="blockingTimeout"><Property name="jetty.httpConfig.blockingTimeout" default="-1"/></Set>
       <!-- Uncomment to enable handling of X-Forwarded- style headers
       <Call name="addCustomizer">
         <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod
index 6857cca..14d6b58 100644
--- a/jetty-server/src/main/config/modules/server.mod
+++ b/jetty-server/src/main/config/modules/server.mod
@@ -64,6 +64,9 @@
 ## Maximum number of error dispatches to prevent looping
 # jetty.httpConfig.maxErrorDispatches=10
 
+## Maximum time to block in total for a blocking IO operation (default -1 is to use idleTimeout on progress)
+# jetty.httpConfig.blockingTimeout=-1
+
 ### Server configuration
 ## Whether ctrl+c on the console gracefully stops the Jetty server
 # jetty.server.stopAtShutdown=true
@@ -73,3 +76,4 @@
 
 ## Dump the state of the Jetty server, components, and webapps before shutdown
 # jetty.server.dumpBeforeStop=false
+
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
index af1a65e..773198c 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
-import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.*;
 
 import java.net.URI;
 import java.nio.ByteBuffer;
@@ -29,6 +29,7 @@
 
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
+import org.eclipse.jetty.websocket.common.test.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
 import org.eclipse.jetty.websocket.jsr356.client.SimpleEndpointMetadata;
 import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
@@ -37,7 +38,6 @@
 import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
 import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
 import org.eclipse.jetty.websocket.jsr356.handlers.StringWholeHandler;
-import org.eclipse.jetty.websocket.jsr356.samples.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.samples.DummyEndpoint;
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java
deleted file mode 100644
index 9a18951..0000000
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.samples;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.websocket.api.BatchMode;
-import org.eclipse.jetty.websocket.api.SuspendToken;
-import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.api.extensions.Frame;
-import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
-import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
-import org.eclipse.jetty.websocket.common.io.IOState;
-
-public class DummyConnection implements LogicalConnection
-{
-    private IOState iostate;
-
-    public DummyConnection()
-    {
-        this.iostate = new IOState();
-    }
-
-    @Override
-    public void close()
-    {
-    }
-
-    @Override
-    public void close(int statusCode, String reason)
-    {
-    }
-
-    @Override
-    public void disconnect()
-    {
-    }
-
-    @Override
-    public ByteBufferPool getBufferPool()
-    {
-        return null;
-    }
-
-    @Override
-    public Executor getExecutor()
-    {
-        return null;
-    }
-
-    @Override
-    public long getIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public IOState getIOState()
-    {
-        return this.iostate;
-    }
-
-    @Override
-    public InetSocketAddress getLocalAddress()
-    {
-        return null;
-    }
-
-    @Override
-    public long getMaxIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public WebSocketPolicy getPolicy()
-    {
-        return null;
-    }
-
-    @Override
-    public InetSocketAddress getRemoteAddress()
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public WebSocketSession getSession()
-    {
-        return null;
-    }
-
-    @Override
-    public boolean isOpen()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean isReading()
-    {
-        return false;
-    }
-
-    @Override
-    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
-    {
-    }
-
-    @Override
-    public void resume()
-    {
-    }
-
-    @Override
-    public void setMaxIdleTimeout(long ms)
-    {
-    }
-
-    @Override
-    public void setNextIncomingFrames(IncomingFrames incoming)
-    {
-    }
-
-    @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
-    public SuspendToken suspend()
-    {
-        return null;
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
index 84eec69..30d4549 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
@@ -37,6 +37,7 @@
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
 import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.test.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.ClientContainer;
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
index c4931c0..f8d1f90 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
@@ -47,8 +47,6 @@
             QUOTE_DOUBLE
         }
 
-        private static final boolean DEBUG = false;
-
         private final String input;
         private final String delims;
         private StringBuilder token;
@@ -83,14 +81,6 @@
             }
         }
 
-        private void debug(String format, Object... args)
-        {
-            if (DEBUG)
-            {
-                System.out.printf(format,args);
-            }
-        }
-
         @Override
         public boolean hasNext()
         {
@@ -133,7 +123,7 @@
                     {
                         if (delims.indexOf(c) >= 0)
                         {
-                            debug("hasNext/t: %b [%s]%n",hasToken,token);
+                            // System.out.printf("hasNext/t: %b [%s]%n",hasToken,token);
                             return hasToken;
                         }
                         else if (c == '\'')
@@ -192,10 +182,9 @@
                         break;
                     }
                 }
-                debug("%s <%s> : [%s]%n",state,c,token);
+                // System.out.printf("%s <%s> : [%s]%n",state,c,token);
             }
-
-            debug("hasNext/e: %b [%s]%n",hasToken,token);
+            // System.out.printf("hasNext/e: %b [%s]%n",hasToken,token);
             return hasToken;
         }
 
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 68a2b61..59a4d61 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
@@ -499,6 +499,7 @@
     {
         if (LOG.isDebugEnabled())
             LOG.debug("Session Opened: {}",session);
+        addManaged(session);
     }
     
     public void setAsyncWriteTimeout(long ms)
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
index 9230b6a..ef1a585 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
@@ -19,6 +19,8 @@
 package org.eclipse.jetty.websocket.client.io;
 
 import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.ClientUpgradeResponse;
@@ -32,12 +34,14 @@
  */
 public abstract class ConnectPromise extends FuturePromise<Session> implements Runnable
 {
+    private static final Logger LOG = Log.getLogger(ConnectPromise.class);
     private final WebSocketClient client;
     private final EventDriver driver;
     private final ClientUpgradeRequest request;
     private final Masker masker;
     private UpgradeListener upgradeListener;
     private ClientUpgradeResponse response;
+    private WebSocketSession session;
 
     public ConnectPromise(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
     {
@@ -97,11 +101,18 @@
         this.upgradeListener = upgradeListener;
     }
 
-    public void succeeded(WebSocketSession session)
+    public void succeeded()
     {
+        if(LOG.isDebugEnabled())
+            LOG.debug("{}.succeeded()",this.getClass().getSimpleName());
         session.setUpgradeRequest(request);
         session.setUpgradeResponse(response);
-        session.open();
+        // session.open();
         super.succeeded(session);
     }
+
+    public void setSession(WebSocketSession session)
+    {
+        this.session = session;
+    }
 }
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
index 580adea..fb00e8f 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
@@ -23,19 +23,13 @@
 import java.net.SocketAddress;
 import java.net.URI;
 import java.nio.channels.SocketChannel;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Locale;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.WebSocketClient;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 
 /**
@@ -136,7 +130,6 @@
         return new InetSocketAddress(uri.getHost(),port);
     }
 
-    private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
     private final WebSocketClient client;
     private WebSocketClientSelectorManager selector;
 
@@ -145,31 +138,6 @@
         this.client = client;
     }
 
-    public void addSession(WebSocketSession session)
-    {
-        sessions.add(session);
-    }
-
-    private void shutdownAllConnections()
-    {
-        for (WebSocketSession session : sessions)
-        {
-            if (session.getConnection() != null)
-            {
-                try
-                {
-                    session.getConnection().close(
-                            StatusCode.SHUTDOWN,
-                            "Shutdown");
-                }
-                catch (Throwable t)
-                {
-                    LOG.debug("During Shutdown All Connections",t);
-                }
-            }
-        }
-    }
-
     public ConnectPromise connect(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
     {
         return new PhysicalConnect(client,driver,request);
@@ -189,8 +157,6 @@
     @Override
     protected void doStop() throws Exception
     {
-        shutdownAllConnections();
-        sessions.clear();
         super.doStop();
         removeBean(selector);
     }
@@ -200,11 +166,6 @@
         return selector;
     }
 
-    public Collection<WebSocketSession> getSessions()
-    {
-        return Collections.unmodifiableCollection(sessions);
-    }
-
     /**
      * Factory method for new WebSocketClientSelectorManager (used by other projects like cometd)
      * 
@@ -216,9 +177,4 @@
     {
         return new WebSocketClientSelectorManager(client);
     }
-
-    public void removeSession(WebSocketSession session)
-    {
-        sessions.remove(session);
-    }
 }
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
index 0f0f837..310980c 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
@@ -316,8 +316,8 @@
         WebSocketSession session = sessionFactory.createSession(request.getRequestURI(),websocket,connection);
         session.setPolicy(policy);
         session.setUpgradeResponse(response);
-
-        connection.setSession(session);
+        connection.addListener(session);
+        connectPromise.setSession(session);
 
         // Initialize / Negotiate Extensions
         ExtensionStack extensionStack = new ExtensionStack(connectPromise.getClient().getExtensionFactory());
@@ -334,7 +334,7 @@
         session.setOutgoingHandler(extensionStack);
         extensionStack.setNextOutgoing(connection);
 
-        session.addBean(extensionStack);
+        session.addManaged(extensionStack);
         connectPromise.getClient().addManaged(session);
 
         // Now swap out the connection
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
index 4ed122b..0aecca9 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
@@ -30,7 +30,6 @@
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
 import org.eclipse.jetty.websocket.client.masks.Masker;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
 
 /**
@@ -63,25 +62,14 @@
     }
 
     @Override
-    public void onClose()
-    {
-        super.onClose();
-        ConnectionManager connectionManager = connectPromise.getClient().getConnectionManager();
-        connectionManager.removeSession(getSession());
-    }
-
-    @Override
     public void onOpen()
     {
+        super.onOpen();
         boolean beenOpened = opened.getAndSet(true);
         if (!beenOpened)
         {
-            WebSocketSession session = getSession();
-            ConnectionManager connectionManager = connectPromise.getClient().getConnectionManager();
-            connectionManager.addSession(session);
-            connectPromise.succeeded(session);
+            connectPromise.succeeded();
         }
-        super.onOpen();
     }
 
     /**
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
index 5f2b162..c1b9729 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
@@ -21,6 +21,7 @@
 import static org.hamcrest.Matchers.*;
 
 import java.net.URI;
+import java.util.Collection;
 import java.util.Set;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -81,7 +82,8 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             RemoteEndpoint remote = cliSock.getSession().getRemote();
             remote.sendStringByFuture("Hello World!");
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
index bef3f60..c2653ed 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
@@ -18,14 +18,12 @@
 
 package org.eclipse.jetty.websocket.client;
 
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.Matchers.*;
 
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Future;
@@ -37,6 +35,7 @@
 import org.eclipse.jetty.websocket.api.RemoteEndpoint;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.io.FutureWriteCallback;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
@@ -118,7 +117,8 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             RemoteEndpoint remote = cliSock.getSession().getRemote();
             remote.sendStringByFuture("Hello World!");
@@ -164,7 +164,8 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             FutureWriteCallback callback = new FutureWriteCallback();
 
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
index 69ae0c8..ebbd2ca 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
@@ -116,13 +116,6 @@
     InetSocketAddress getRemoteAddress();
 
     /**
-     * Get the Session for this connection
-     * 
-     * @return the Session for this connection
-     */
-    WebSocketSession getSession();
-
-    /**
      * Test if logical connection is still open
      * 
      *  @return true if connection is open
@@ -158,14 +151,6 @@
     void setNextIncomingFrames(IncomingFrames incoming);
 
     /**
-     * Set the session associated with this connection
-     * 
-     * @param session
-     *            the session
-     */
-    void setSession(WebSocketSession session);
-
-    /**
      * Suspend a the incoming read events on the connection.
      * @return the suspend token
      */
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
index 68c63dd..7e4bb33 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
@@ -28,6 +28,7 @@
 import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
@@ -58,13 +59,14 @@
 import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope;
 
 @ManagedObject("A Jetty WebSocket Session")
-public class WebSocketSession extends ContainerLifeCycle implements Session, WebSocketSessionScope, IncomingFrames, ConnectionStateListener
+public class WebSocketSession extends ContainerLifeCycle implements Session, WebSocketSessionScope, IncomingFrames, Connection.Listener, ConnectionStateListener
 {
     private static final Logger LOG = Log.getLogger(WebSocketSession.class);
+    private static final Logger LOG_OPEN = Log.getLogger(WebSocketSession.class.getName() + "_OPEN");
     private final WebSocketContainerScope containerScope;
     private final URI requestURI;
-    private final EventDriver websocket;
     private final LogicalConnection connection;
+    private final EventDriver websocket;
     private final SessionListener[] sessionListeners;
     private final Executor executor;
     private ClassLoader classLoader;
@@ -93,6 +95,9 @@
         this.outgoingHandler = connection;
         this.incomingHandler = websocket;
         this.connection.getIOState().addListener(this);
+        
+        addBean(this.connection);
+        addBean(this.websocket);
     }
 
     @Override
@@ -110,7 +115,7 @@
     @Override
     public void close(int statusCode, String reason)
     {
-        connection.close(statusCode,CloseStatus.trimMaxReasonLength(reason));
+        connection.close(statusCode,reason);
     }
 
     /**
@@ -131,6 +136,35 @@
     }
     
     @Override
+    protected void doStart() throws Exception
+    {
+        if(LOG.isDebugEnabled())
+            LOG.debug("starting - {}",this);
+
+        super.doStart();
+    }
+    
+    @Override
+    protected void doStop() throws Exception
+    {
+        if(LOG.isDebugEnabled())
+            LOG.debug("stopping - {}",this);
+        
+        if (getConnection() != null)
+        {
+            try
+            {
+                getConnection().close(StatusCode.SHUTDOWN,"Shutdown");
+            }
+            catch (Throwable t)
+            {
+                LOG.debug("During Connection Shutdown",t);
+            }
+        }
+        super.doStop();
+    }
+    
+    @Override
     public void dump(Appendable out, String indent) throws IOException
     {
         dumpThis(out);
@@ -253,6 +287,8 @@
     @Override
     public RemoteEndpoint getRemote()
     {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.getRemote()",policy.getBehavior(),this.getClass().getSimpleName());
         ConnectionState state = connection.getIOState().getConnectionState();
 
         if ((state == ConnectionState.OPEN) || (state == ConnectionState.CONNECTED))
@@ -373,6 +409,19 @@
     {
         incomingError(cause);
     }
+    
+    @Override
+    public void onClosed(Connection connection)
+    {
+    }
+    
+    @Override
+    public void onOpened(Connection connection)
+    {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.onOpened()",policy.getBehavior(),this.getClass().getSimpleName());
+        open();
+    }
 
     @SuppressWarnings("incomplete-switch")
     @Override
@@ -381,6 +430,11 @@
         switch (state)
         {
             case CLOSED:
+                IOState ioState = this.connection.getIOState();
+                CloseInfo close = ioState.getCloseInfo();
+                // confirmed close of local endpoint
+                notifyClose(close.getStatusCode(),close.getReason());
+                
                 // notify session listeners
                 for (SessionListener listener : sessionListeners)
                 {
@@ -395,10 +449,6 @@
                         LOG.ignore(t);
                     }
                 }
-                IOState ioState = this.connection.getIOState();
-                CloseInfo close = ioState.getCloseInfo();
-                // confirmed close of local endpoint
-                notifyClose(close.getStatusCode(),close.getReason());
                 break;
             case CONNECTED:
                 // notify session listeners
@@ -418,12 +468,15 @@
                 break;
         }
     }
-
+    
     /**
      * Open/Activate the session
      */
     public void open()
     {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.open()",policy.getBehavior(),this.getClass().getSimpleName());
+
         if (remote != null)
         {
             // already opened
@@ -437,6 +490,8 @@
     
             // Connect remote
             remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,getBatchMode());
+            if(LOG_OPEN.isDebugEnabled())
+                LOG_OPEN.debug("[{}] {}.open() remote={}",policy.getBehavior(),this.getClass().getSimpleName(),remote);
             
             // Open WebSocket
             websocket.openSession(this);
@@ -467,7 +522,7 @@
             close(statusCode,t.getMessage());
         }
     }
-
+    
     public void setExtensionFactory(ExtensionFactory extensionFactory)
     {
         this.extensionFactory = extensionFactory;
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
index b97b6a0..8ccce72 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
@@ -23,6 +23,7 @@
 
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.BatchMode;
@@ -40,11 +41,11 @@
 /**
  * EventDriver is the main interface between the User's WebSocket POJO and the internal jetty implementation of WebSocket.
  */
-public abstract class AbstractEventDriver implements IncomingFrames, EventDriver
+public abstract class AbstractEventDriver extends AbstractLifeCycle implements IncomingFrames, EventDriver
 {
     private static final Logger LOG = Log.getLogger(AbstractEventDriver.class);
     protected final Logger TARGET_LOG;
-    protected final WebSocketPolicy policy;
+    protected WebSocketPolicy policy;
     protected final Object websocket;
     protected WebSocketSession session;
     protected MessageAppender activeMessage;
@@ -233,6 +234,12 @@
             throw t;
         }
     }
+    
+    @Override
+    protected void doStop() throws Exception
+    {
+        session = null;
+    }
 
     protected void terminateConnection(int statusCode, String rawreason)
     {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
index 69b97c6..c44496a 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
@@ -55,7 +55,8 @@
 
         if (obj == null)
         {
-            LOG.warn("Cannot call {} on null object",this.method);
+            String err = String.format("Cannot call %s on null object", this.method);
+            LOG.warn(new RuntimeException(err));            
             return null;
         }
 
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
index e93085b..7366457 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
@@ -53,7 +53,6 @@
 import org.eclipse.jetty.websocket.common.Generator;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
 import org.eclipse.jetty.websocket.common.Parser;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
 
 /**
@@ -71,7 +70,7 @@
         @Override
         protected void onFailure(Throwable x)
         {
-            session.notifyError(x);
+            notifyError(x);
 
             if (ioState.wasAbnormalClose())
             {
@@ -200,7 +199,8 @@
     }
 
     private static final Logger LOG = Log.getLogger(AbstractWebSocketConnection.class);
-    private static final Logger LOG_CLOSE = Log.getLogger(AbstractWebSocketConnection.class.getName() + ".close");
+    private static final Logger LOG_OPEN = Log.getLogger(AbstractWebSocketConnection.class.getName() + "_OPEN");
+    private static final Logger LOG_CLOSE = Log.getLogger(AbstractWebSocketConnection.class.getName() + "_CLOSE");
 
     /**
      * Minimum size of a buffer is the determined to be what would be the maximum framing header size (not including payload)
@@ -214,7 +214,6 @@
     private final WebSocketPolicy policy;
     private final AtomicBoolean suspendToken;
     private final FrameFlusher flusher;
-    private WebSocketSession session;
     private List<ExtensionConfig> extensions;
     private boolean isFilling;
     private ByteBuffer prefillBuffer;
@@ -389,12 +388,6 @@
         return scheduler;
     }
 
-    @Override
-    public WebSocketSession getSession()
-    {
-        return session;
-    }
-
     public Stats getStats()
     {
         return stats;
@@ -544,9 +537,16 @@
         prefillBuffer = prefilled;
     }
     
+    private void notifyError(Throwable t)
+    {
+        getParser().getIncomingFramesHandler().incomingError(t);
+    }
+    
     @Override
     public void onOpen()
     {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.onOpened()",policy.getBehavior(),this.getClass().getSimpleName());
         super.onOpen();
         this.ioState.onOpened();
     }
@@ -573,7 +573,7 @@
 
         try
         {
-            session.notifyError(new SocketTimeoutException("Timeout on Read"));
+            notifyError(new SocketTimeoutException("Timeout on Read"));
         }
         finally
         {
@@ -723,12 +723,6 @@
     }
 
     @Override
-    public void setSession(WebSocketSession session)
-    {
-        this.session = session;
-    }
-
-    @Override
     public SuspendToken suspend()
     {
         suspendToken.set(true);
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
index de75cec..6c6de10 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
@@ -404,6 +404,9 @@
      */
     public void onOpened()
     {
+        if(LOG.isDebugEnabled())
+            LOG.debug(" onOpened()");
+        
         ConnectionState event = null;
         synchronized (this)
         {
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
index 5321d1a..3fa82c6 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
@@ -35,7 +35,6 @@
 import org.eclipse.jetty.websocket.common.CloseInfo;
 import org.eclipse.jetty.websocket.common.ConnectionState;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
 import org.junit.rules.TestName;
 
@@ -150,12 +149,6 @@
     }
 
     @Override
-    public WebSocketSession getSession()
-    {
-        return null;
-    }
-
-    @Override
     public void incomingError(Throwable e)
     {
         incoming.incomingError(e);
@@ -236,11 +229,6 @@
     }
 
     @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
     public SuspendToken suspend()
     {
         return null;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
index c0357e3..57e8db6 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
@@ -49,7 +49,6 @@
         {
             // Append a single message (simple, short)
             ByteBuffer payload = BufferUtil.toBuffer("Hello World",StandardCharsets.UTF_8);
-            System.out.printf("payload = %s%n",BufferUtil.toDetailString(payload));
             boolean fin = true;
             stream.appendFrame(payload,fin);
 
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
similarity index 90%
rename from jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java
rename to jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
index dc03d2a..012fd78 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
@@ -16,7 +16,7 @@
 //  ========================================================================
 //
 
-package org.eclipse.jetty.websocket.jsr356.server;
+package org.eclipse.jetty.websocket.common.test;
 
 import java.net.InetSocketAddress;
 import java.util.concurrent.Executor;
@@ -31,7 +31,6 @@
 import org.eclipse.jetty.websocket.api.extensions.Frame;
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.IOState;
 
 public class DummyConnection implements LogicalConnection
@@ -104,13 +103,6 @@
     @Override
     public InetSocketAddress getRemoteAddress()
     {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public WebSocketSession getSession()
-    {
         return null;
     }
 
@@ -150,11 +142,6 @@
     }
 
     @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
     public SuspendToken suspend()
     {
         return null;
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
index b3ffe52..880c9a4 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
@@ -20,7 +20,6 @@
 
 import java.net.InetSocketAddress;
 import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
@@ -32,8 +31,6 @@
 
 public class WebSocketServerConnection extends AbstractWebSocketConnection implements Connection.UpgradeTo
 {
-    private final AtomicBoolean opened = new AtomicBoolean(false);
-
     public WebSocketServerConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
     {
         super(endp,executor,scheduler,policy,bufferPool);
@@ -54,17 +51,6 @@
     {
         return getEndPoint().getRemoteAddress();
     }
-
-    @Override
-    public void onOpen()
-    {
-        boolean beenOpened = opened.getAndSet(true);
-        if (!beenOpened)
-        {
-            getSession().open();
-        }
-        super.onOpen();
-    }
     
     @Override
     public void setNextIncomingFrames(IncomingFrames incoming)
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 28a8c69..73419f6 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
@@ -22,13 +22,12 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executor;
 
 import javax.servlet.ServletContext;
@@ -53,7 +52,6 @@
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
-import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.api.WebSocketException;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
@@ -94,7 +92,6 @@
     private final WebSocketExtensionFactory extensionFactory;
     private Executor executor;
     private List<SessionFactory> sessionFactories;
-    private Set<WebSocketSession> openSessions = new CopyOnWriteArraySet<>();
     private WebSocketCreator creator;
     private List<Class<?>> registeredSocketClasses;
     private DecoratedObjectFactory objectFactory;
@@ -228,27 +225,6 @@
         }
     }
 
-    protected void shutdownAllConnections()
-    {
-        for (WebSocketSession session : openSessions)
-        {
-            if (session.getConnection() != null)
-            {
-                try
-                {
-                    session.getConnection().close(
-                            StatusCode.SHUTDOWN,
-                            "Shutdown");
-                }
-                catch (Throwable t)
-                {
-                    LOG.debug("During Shutdown All Connections",t);
-                }
-            }
-        }
-        openSessions.clear();
-    }
-
     @Override
     public WebSocketServletFactory createFactory(WebSocketPolicy policy)
     {
@@ -319,13 +295,6 @@
     }
 
     @Override
-    protected void doStop() throws Exception
-    {
-        shutdownAllConnections();
-        super.doStop();
-    }
-
-    @Override
     public ByteBufferPool getBufferPool()
     {
         return this.bufferPool;
@@ -359,9 +328,9 @@
         return extensionFactory;
     }
     
-    public Set<WebSocketSession> getOpenSessions()
+    public Collection<WebSocketSession> getOpenSessions()
     {
-        return Collections.unmodifiableSet(this.openSessions);
+        return getBeans(WebSocketSession.class);
     }
 
     @Override
@@ -484,13 +453,13 @@
     @Override
     public void onSessionClosed(WebSocketSession session)
     {
-        this.openSessions.remove(session);
+        removeBean(session);
     }
 
     @Override
     public void onSessionOpened(WebSocketSession session)
     {
-        this.openSessions.add(session);
+        addManaged(session);
     }
 
     protected String[] parseProtocols(String protocol)
@@ -625,7 +594,7 @@
         // set true negotiated extension list back to response 
         response.setExtensions(extensionStack.getNegotiatedExtensions());
         session.setUpgradeResponse(response);
-        wsConnection.setSession(session);
+        wsConnection.addListener(session);
 
         // Setup Incoming Routing
         wsConnection.setNextIncomingFrames(extensionStack);
@@ -636,24 +605,13 @@
         extensionStack.setNextOutgoing(wsConnection);
 
         // Start Components
-        session.addBean(extensionStack);
-        this.addBean(session);
+        session.addManaged(extensionStack);
+        this.addManaged(session);
         
         if (session.isFailed())
         {
             throw new IOException("Session failed to start");
         }
-        else if (!session.isRunning())
-        {
-            try
-            {
-                session.start();
-            }
-            catch (Exception e)
-            {
-                throw new IOException("Unable to start Session",e);
-            }
-        }
 
         // Tell jetty about the new upgraded connection
         request.setServletAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE, wsConnection);
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java
index f0d5f55..03a8a76 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java
@@ -22,8 +22,8 @@
 import static org.junit.Assert.*;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -144,7 +144,7 @@
             calls.incrementAndGet();
             if (message.equalsIgnoreCase("openSessions"))
             {
-                Set<WebSocketSession> sessions = container.getOpenSessions();
+                Collection<WebSocketSession> sessions = container.getOpenSessions();
 
                 StringBuilder ret = new StringBuilder();
                 ret.append("openSessions.size=").append(sessions.size()).append('\n');
@@ -336,7 +336,7 @@
                 client.sendStandardRequest();
                 client.expectUpgradeResponse();
                 
-                client.readFrames(1,1,TimeUnit.SECONDS);
+                // client.readFrames(1,2,TimeUnit.SECONDS);
 
                 CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
                 client.write(close.asFrame()); // respond with close
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
index 68664b8..c4507d4 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
@@ -22,8 +22,8 @@
 import static org.junit.Assert.*;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -139,7 +139,7 @@
             LOG.debug("onWebSocketText({})",message);
             if (message.equalsIgnoreCase("openSessions"))
             {
-                Set<WebSocketSession> sessions = container.getOpenSessions();
+                Collection<WebSocketSession> sessions = container.getOpenSessions();
 
                 StringBuilder ret = new StringBuilder();
                 ret.append("openSessions.size=").append(sessions.size()).append('\n');
diff --git a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
index 9165916..924d000 100644
--- a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
+++ b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
@@ -12,6 +12,11 @@
 # org.eclipse.jetty.websocket.server.blockhead.LEVEL=DEBUG
 # org.eclipse.jetty.websocket.server.helper.LEVEL=DEBUG
 
+# org.eclipse.jetty.websocket.client.io.ConnectPromise.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.WebSocketSession_OPEN.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.io.IOState.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection_OPEN.LEVEL=DEBUG
+
 ### Show state changes on BrowserDebugTool
 # -- LEAVE THIS AT DEBUG LEVEL --
 org.eclipse.jetty.websocket.server.browser.LEVEL=DEBUG
diff --git a/pom.xml b/pom.xml
index f20fb21..498fa58 100644
--- a/pom.xml
+++ b/pom.xml
@@ -609,14 +609,14 @@
     <dependency>
       <groupId>org.apache.taglibs</groupId>
       <artifactId>taglibs-standard-impl</artifactId>
-      <version>1.2.1</version>
+      <version>1.2.5</version>
     </dependency>
 
      <!-- JSTL API -->
       <dependency>
         <groupId>org.apache.taglibs</groupId>
         <artifactId>taglibs-standard-spec</artifactId>
-        <version>1.2.1</version>
+        <version>1.2.5</version>
       </dependency>