From 57224ec3ca3b07e3fc0689857994c7749173de33 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 12 Jan 2016 16:15:51 -0700 Subject: [PATCH] 481986 - Dead JSR 356 Server Session still being tracked after Session/Connection closure + Removing SessionListener + Work in CDI layer for WebSocketContainerScope is reused for session tracking on the parent scope of the WebSocketSession only. no more multi-listener behavior + Reworked JsrSession ID behavior to not be based on AtomicLong + AbstractWebSocketConnection now has .hashCode and .equals --- .../websocket/jsr356/ClientContainer.java | 7 +- .../jetty/websocket/jsr356/JsrSession.java | 5 +- .../websocket/jsr356/JsrSessionFactory.java | 20 +- .../jsr356/server/ServerContainer.java | 15 +- .../jsr356/server/SessionTrackingTest.java | 183 ++++++++++++++++++ .../test/resources/jetty-logging.properties | 3 + .../websocket/client/WebSocketClient.java | 3 +- .../websocket/common/LogicalConnection.java | 7 +- .../websocket/common/SessionListener.java | 31 --- .../websocket/common/WebSocketSession.java | 44 ++--- .../common/WebSocketSessionFactory.java | 20 +- .../io/AbstractWebSocketConnection.java | 49 +++++ .../common/scopes/SimpleContainerScope.java | 11 ++ .../scopes/WebSocketContainerScope.java | 16 ++ .../common/io/LocalWebSocketConnection.java | 6 + .../common/test/DummyConnection.java | 6 + .../server/WebSocketServerConnection.java | 2 +- .../server/WebSocketServerFactory.java | 3 +- 18 files changed, 328 insertions(+), 103 deletions(-) create mode 100644 jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java delete mode 100644 jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java index 13c30b7f956..87e4e76fc2c 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java @@ -53,8 +53,6 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.websocket.client.io.UpgradeListener; -import org.eclipse.jetty.websocket.common.SessionFactory; -import org.eclipse.jetty.websocket.common.SessionListener; import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope; import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; @@ -73,7 +71,7 @@ import org.eclipse.jetty.websocket.jsr356.metadata.EndpointMetadata; *

* This should be specific to a JVM if run in a standalone mode. or specific to a WebAppContext if running on the Jetty server. */ -public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope, SessionListener +public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope { private static final Logger LOG = Log.getLogger(ClientContainer.class); @@ -105,8 +103,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont this.scopeDelegate = scope; client = new WebSocketClient(scope, new SslContextFactory(trustAll)); client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy())); - SessionFactory sessionFactory = new JsrSessionFactory(this,this,client); - client.setSessionFactory(sessionFactory); + client.setSessionFactory(new JsrSessionFactory(this)); addBean(client); this.endpointClientMetadataCache = new ConcurrentHashMap<>(); diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java index bb44774b1ba..82db0bd93b2 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java @@ -44,7 +44,6 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.api.BatchMode; import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.common.LogicalConnection; -import org.eclipse.jetty.websocket.common.SessionListener; import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.events.EventDriver; import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver; @@ -74,9 +73,9 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess private JsrAsyncRemote asyncRemote; private JsrBasicRemote basicRemote; - public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners) + public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection) { - super(container, requestURI, websocket, connection, sessionListeners); + super(container, requestURI, websocket, connection); if (!(websocket instanceof AbstractJsrEventDriver)) { throw new IllegalArgumentException("Cannot use, not a JSR WebSocket: " + websocket); diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java index f17734d7229..15cde46ebbb 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java @@ -19,36 +19,32 @@ package org.eclipse.jetty.websocket.jsr356; import java.net.URI; -import java.util.concurrent.atomic.AtomicLong; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.websocket.common.LogicalConnection; import org.eclipse.jetty.websocket.common.SessionFactory; -import org.eclipse.jetty.websocket.common.SessionListener; import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.events.EventDriver; import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver; public class JsrSessionFactory implements SessionFactory { - private AtomicLong idgen = new AtomicLong(0); + private static final Logger LOG = Log.getLogger(JsrSessionFactory.class); private final ClientContainer container; - private final SessionListener[] listeners; - public JsrSessionFactory(ClientContainer container, SessionListener... sessionListeners) + public JsrSessionFactory(ClientContainer container) { + if(LOG.isDebugEnabled()) { + LOG.debug("Container: {}", container); + } this.container = container; - this.listeners = sessionListeners; } @Override public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection) { - return new JsrSession(container,getNextId(),requestURI,websocket,connection,listeners); - } - - public String getNextId() - { - return String.format("websocket-%d",idgen.incrementAndGet()); + return new JsrSession(container,connection.getId(),requestURI,websocket,connection); } @Override diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java index 2128e8ec64d..8d114c37e05 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java @@ -30,6 +30,7 @@ import javax.websocket.server.ServerEndpointConfig; import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.events.EventDriverFactory; import org.eclipse.jetty.websocket.jsr356.ClientContainer; import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory; @@ -56,7 +57,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket. EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory(); eventDriverFactory.addImplementation(new JsrServerEndpointImpl()); eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl()); - this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this)); + this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this)); addBean(webSocketServerFactory); } @@ -240,4 +241,16 @@ public class ServerContainer extends ClientContainer implements javax.websocket. // incoming streaming buffer size webSocketServerFactory.getPolicy().setMaxTextMessageBufferSize(max); } + + @Override + public void onSessionClosed(WebSocketSession session) + { + webSocketServerFactory.onSessionClosed(session); + } + + @Override + public void onSessionOpened(WebSocketSession session) + { + webSocketServerFactory.onSessionOpened(session); + } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java new file mode 100644 index 00000000000..22733ea606a --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java @@ -0,0 +1,183 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.net.URI; +import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.websocket.CloseReason; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.websocket.common.WebSocketSession; +import org.eclipse.jetty.websocket.jsr356.ClientContainer; +import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; +import org.eclipse.jetty.websocket.server.WebSocketServerFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class SessionTrackingTest +{ + public static class ClientSocket extends Endpoint + { + public Session session; + public CountDownLatch openLatch = new CountDownLatch(1); + public CountDownLatch closeLatch = new CountDownLatch(1); + + @Override + public void onOpen(Session session, EndpointConfig config) + { + this.session = session; + openLatch.countDown(); + } + + @Override + public void onClose(Session session, CloseReason closeReason) + { + closeLatch.countDown(); + } + + public void waitForOpen(long timeout, TimeUnit unit) throws InterruptedException + { + assertThat("ClientSocket opened",openLatch.await(timeout,unit),is(true)); + } + + public void waitForClose(long timeout, TimeUnit unit) throws InterruptedException + { + assertThat("ClientSocket opened",closeLatch.await(timeout,unit),is(true)); + } + } + + @ServerEndpoint("/test") + public static class EchoSocket + { + @OnMessage + public String echo(String msg) + { + return msg; + } + } + + private static Server server; + private static WebSocketServerFactory wsServerFactory; + private static URI serverURI; + + @BeforeClass + public static void startServer() throws Exception + { + Server server = new Server(); + ServerConnector serverConnector = new ServerConnector(server); + serverConnector.setPort(0); + server.addConnector(serverConnector); + ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); + servletContextHandler.setContextPath("/"); + server.setHandler(servletContextHandler); + + ServerContainer serverContainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler); + serverContainer.addEndpoint(EchoSocket.class); + + wsServerFactory = serverContainer.getBean(WebSocketServerFactory.class); + + server.start(); + + String host = serverConnector.getHost(); + if (StringUtil.isBlank(host)) + { + host = "localhost"; + } + serverURI = new URI("ws://" + host + ":" + serverConnector.getLocalPort()); + } + + @AfterClass + public static void stopServer() throws Exception + { + if (server == null) + { + return; + } + + server.stop(); + } + + @Test + public void testAddRemoveSessions() throws Exception + { + // Create Client + ClientContainer clientContainer = new ClientContainer(); + try + { + clientContainer.start(); + + // Establish connections + ClientSocket cli1 = new ClientSocket(); + clientContainer.connectToServer(cli1,serverURI.resolve("/test")); + cli1.waitForOpen(1,TimeUnit.SECONDS); + + // Assert open connections + assertServerOpenConnectionCount(1); + + // Establish new connection + ClientSocket cli2 = new ClientSocket(); + clientContainer.connectToServer(cli2,serverURI.resolve("/test")); + cli2.waitForOpen(1,TimeUnit.SECONDS); + + // Assert open connections + assertServerOpenConnectionCount(2); + + // Establish close both connections + cli1.session.close(); + cli2.session.close(); + + cli1.waitForClose(1,TimeUnit.SECONDS); + cli2.waitForClose(1,TimeUnit.SECONDS); + + // Assert open connections + assertServerOpenConnectionCount(0); + } + finally + { + clientContainer.stop(); + } + } + + private void assertServerOpenConnectionCount(int expectedCount) + { + Collection sessions = wsServerFactory.getBeans(WebSocketSession.class); + int openCount = 0; + for (WebSocketSession session : sessions) + { + assertThat("Session.isopen: " + session,session.isOpen(),is(true)); + openCount++; + } + assertThat("Open Session Count",openCount,is(expectedCount)); + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties index c5a50f62391..9681d9168b4 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties +++ b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties @@ -6,6 +6,9 @@ org.eclipse.jetty.LEVEL=WARN # org.eclipse.jetty.websocket.LEVEL=WARN # org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG +org.eclipse.jetty.websocket.common.WebSocketSession.LEVEL=DEBUG +org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG + ### Show state changes on BrowserDebugTool # -- LEAVE THIS AT DEBUG LEVEL -- org.eclipse.jetty.websocket.jsr356.server.browser.LEVEL=DEBUG 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 bdd37a20094..b552d300ed0 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 @@ -53,7 +53,6 @@ import org.eclipse.jetty.websocket.client.io.UpgradeListener; import org.eclipse.jetty.websocket.client.masks.Masker; import org.eclipse.jetty.websocket.client.masks.RandomMasker; import org.eclipse.jetty.websocket.common.SessionFactory; -import org.eclipse.jetty.websocket.common.SessionListener; import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.WebSocketSessionFactory; import org.eclipse.jetty.websocket.common.events.EventDriver; @@ -64,7 +63,7 @@ import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; /** * WebSocketClient provides a means of establishing connections to remote websocket endpoints. */ -public class WebSocketClient extends ContainerLifeCycle implements SessionListener, WebSocketContainerScope +public class WebSocketClient extends ContainerLifeCycle implements WebSocketContainerScope { private static final Logger LOG = Log.getLogger(WebSocketClient.class); 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 4eda6fd7978..6e4c2ec84fe 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 @@ -22,7 +22,6 @@ import java.net.InetSocketAddress; import java.util.concurrent.Executor; import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.SuspendToken; import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.extensions.IncomingFrames; @@ -155,4 +154,10 @@ public interface LogicalConnection extends OutgoingFrames, SuspendToken * @return the suspend token */ SuspendToken suspend(); + + /** + * Get Unique ID for the Connection + * @return the unique ID for the connection + */ + public String getId(); } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java deleted file mode 100644 index c62facef7c7..00000000000 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/SessionListener.java +++ /dev/null @@ -1,31 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 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.common; - -/** - * Basic listener interface for Session open/close. - *

- * Used primarily for tracking open sessions. - */ -public interface SessionListener -{ - public void onSessionOpened(WebSocketSession session); - - public void onSessionClosed(WebSocketSession session); -} 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 33356b2f61c..1a52f59483e 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 @@ -67,7 +67,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web private final URI requestURI; private final LogicalConnection connection; private final EventDriver websocket; - private final SessionListener[] sessionListeners; private final Executor executor; private ClassLoader classLoader; private ExtensionFactory extensionFactory; @@ -80,7 +79,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web private UpgradeRequest upgradeRequest; private UpgradeResponse upgradeResponse; - public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners) + public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection) { Objects.requireNonNull(containerScope,"Container Scope cannot be null"); Objects.requireNonNull(requestURI,"Request URI cannot be null"); @@ -90,7 +89,6 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web this.requestURI = requestURI; this.websocket = websocket; this.connection = connection; - this.sessionListeners = sessionListeners; this.executor = connection.getExecutor(); this.outgoingHandler = connection; this.incomingHandler = websocket; @@ -435,36 +433,28 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Web CloseInfo close = ioState.getCloseInfo(); // confirmed close of local endpoint notifyClose(close.getStatusCode(),close.getReason()); - - // notify session listeners - for (SessionListener listener : sessionListeners) + try { - try - { - if (LOG.isDebugEnabled()) - LOG.debug("{}.onSessionClosed()",listener.getClass().getSimpleName()); - listener.onSessionClosed(this); - } - catch (Throwable t) - { - LOG.ignore(t); - } + if (LOG.isDebugEnabled()) + LOG.debug("{}.onSessionClosed()",containerScope.getClass().getSimpleName()); + containerScope.onSessionClosed(this); + } + catch (Throwable t) + { + LOG.ignore(t); } break; case CONNECTED: // notify session listeners - for (SessionListener listener : sessionListeners) + try { - try - { - if (LOG.isDebugEnabled()) - LOG.debug("{}.onSessionOpen()", listener.getClass().getSimpleName()); - listener.onSessionOpened(this); - } - catch (Throwable t) - { - LOG.ignore(t); - } + if (LOG.isDebugEnabled()) + LOG.debug("{}.onSessionOpened()",containerScope.getClass().getSimpleName()); + containerScope.onSessionOpened(this); + } + catch (Throwable t) + { + LOG.ignore(t); } break; } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java index 8494a26507b..e46a2313256 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java @@ -31,26 +31,10 @@ import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope; public class WebSocketSessionFactory implements SessionFactory { private final WebSocketContainerScope containerScope; - private final SessionListener[] listeners; - public WebSocketSessionFactory(WebSocketContainerScope containerScope, SessionListener... sessionListeners) + public WebSocketSessionFactory(WebSocketContainerScope containerScope) { this.containerScope = containerScope; - if ((sessionListeners != null) && (sessionListeners.length > 0)) - { - this.listeners = sessionListeners; - } - else - { - if (this.containerScope instanceof SessionListener) - { - this.listeners = new SessionListener[] { (SessionListener)containerScope }; - } - else - { - this.listeners = new SessionListener[0]; - } - } } @Override @@ -62,6 +46,6 @@ public class WebSocketSessionFactory implements SessionFactory @Override public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection) { - return new WebSocketSession(containerScope, requestURI,websocket,connection,listeners); + return new WebSocketSession(containerScope, requestURI,websocket,connection); } } 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 a3a0ed3e975..027e8e65d94 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 @@ -214,6 +214,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp private final WebSocketPolicy policy; private final AtomicBoolean suspendToken; private final FrameFlusher flusher; + private final String id; private List extensions; private boolean isFilling; private ByteBuffer prefillBuffer; @@ -224,6 +225,11 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp public AbstractWebSocketConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool) { super(endp,executor); + this.id = String.format("%s:%d->%s:%d", + endp.getLocalAddress().getAddress().getHostAddress(), + endp.getLocalAddress().getPort(), + endp.getRemoteAddress().getAddress().getHostAddress(), + endp.getRemoteAddress().getPort()); this.policy = policy; this.bufferPool = bufferPool; this.generator = new Generator(policy,bufferPool); @@ -347,6 +353,12 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp { return generator; } + + @Override + public String getId() + { + return id; + } @Override public long getIdleTimeout() @@ -747,6 +759,43 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp return String.format("%s@%X{endp=%s,ios=%s,f=%s,g=%s,p=%s}",getClass().getSimpleName(),hashCode(),getEndPoint(),ioState,flusher,generator,parser); } + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + + EndPoint endp = getEndPoint(); + if(endp != null) + { + result = prime * result + endp.getLocalAddress().hashCode(); + result = prime * result + endp.getRemoteAddress().hashCode(); + } + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractWebSocketConnection other = (AbstractWebSocketConnection)obj; + EndPoint endp = getEndPoint(); + EndPoint otherEndp = other.getEndPoint(); + if (endp == null) + { + if (otherEndp != null) + return false; + } + else if (!endp.equals(otherEndp)) + return false; + return true; + } + /** * Extra bytes from the initial HTTP upgrade that need to * be processed by the websocket parser before starting 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 a68574c47fc..0e8e0dd74de 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 @@ -27,6 +27,7 @@ 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.WebSocketPolicy; +import org.eclipse.jetty.websocket.common.WebSocketSession; public class SimpleContainerScope extends ContainerLifeCycle implements WebSocketContainerScope { @@ -105,4 +106,14 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke { this.sslContextFactory = sslContextFactory; } + + @Override + public void onSessionOpened(WebSocketSession session) + { + } + + @Override + public void onSessionClosed(WebSocketSession session) + { + } } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java index 0717cfc871f..9e1f5e06650 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.websocket.api.WebSocketPolicy; +import org.eclipse.jetty.websocket.common.WebSocketSession; /** * Defined Scope for a WebSocketContainer. @@ -64,4 +65,19 @@ public interface WebSocketContainerScope * @return the SslContextFactory in use by the container (can be null if no SSL context is defined) */ public SslContextFactory getSslContextFactory(); + + /** + * A Session has been opened + * + * @param the session that was opened + */ + public void onSessionOpened(WebSocketSession session); + + /** + * A Session has been closed + * + * @param the session that was closed + */ + public void onSessionClosed(WebSocketSession session); + } 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 71b8e3d7ffa..9c067f59137 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 @@ -107,6 +107,12 @@ public class LocalWebSocketConnection implements LogicalConnection, IncomingFram return this.bufferPool; } + @Override + public String getId() + { + return this.id; + } + @Override public long getIdleTimeout() { diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java index a5a1ba6c21e..b0ea4662413 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java @@ -70,6 +70,12 @@ public class DummyConnection implements LogicalConnection return null; } + @Override + public String getId() + { + return "dummy"; + } + @Override public long getIdleTimeout() { 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 c8f9ef4bc01..baebd44b8d7 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 @@ -39,7 +39,7 @@ public class WebSocketServerConnection extends AbstractWebSocketConnection imple endp.setIdleTimeout(policy.getIdleTimeout()); } } - + @Override public InetSocketAddress getLocalAddress() { 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 ec2dd3ab344..e30b4cac5de 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 @@ -58,7 +58,6 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory; import org.eclipse.jetty.websocket.api.util.QuoteUtil; import org.eclipse.jetty.websocket.common.LogicalConnection; import org.eclipse.jetty.websocket.common.SessionFactory; -import org.eclipse.jetty.websocket.common.SessionListener; import org.eclipse.jetty.websocket.common.WebSocketSession; import org.eclipse.jetty.websocket.common.WebSocketSessionFactory; import org.eclipse.jetty.websocket.common.events.EventDriver; @@ -75,7 +74,7 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory; /** * Factory to create WebSocket connections */ -public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory, SessionListener +public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory { private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);