From ddb30e640ec24134df0b37f84a8c8e937ac3036d Mon Sep 17 00:00:00 2001 From: Jamie Doornbos Date: Tue, 5 Apr 2011 17:46:29 +0000 Subject: [PATCH] Allow session observers to hook into the part of the session lifecycle before the session subclasses start nuking things, but once it is known that it will end. It always bugged me in msoy that the session subclass has to do this (poorly). Seems patently observer-ish. This fix has almost no runtime overhead and is backwards compatible. The name isn't great, but I was leaving room for more methods in there should someone else find it useful, such as sessionWillStart or even clientObject[Will|Did]Release. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6603 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../presents/server/ClientManager.java | 85 ++++++++++++------- .../presents/server/PresentsSession.java | 2 + 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/threerings/presents/server/ClientManager.java b/src/main/java/com/threerings/presents/server/ClientManager.java index a8669151f..eaacc43ba 100644 --- a/src/main/java/com/threerings/presents/server/ClientManager.java +++ b/src/main/java/com/threerings/presents/server/ClientManager.java @@ -98,6 +98,20 @@ public class ClientManager void clientSessionDidEnd (PresentsSession session); } + /** + * Methods for observing additional events in the session lifecycle. + */ + public static interface DetailedClientObserver extends ClientObserver + { + /** + * Called prior to the sessions ending. Subclasses and this class tend to nuke a lot of + * information in the process of ending. This will allow callers to act on session events + * without creating a subclass of a session. For example lightweight management of dobj + * fields such as flushing stats or notifying party members of a logout. + */ + void clientSessionWillEnd (PresentsSession session); + } + /** * Constructs a client manager that will interact with the supplied connection manager. */ @@ -205,6 +219,9 @@ public class ClientManager public void addClientObserver (ClientObserver observer) { _clobservers.add(observer); + if (observer instanceof DetailedClientObserver) { + _dclobservers.add((DetailedClientObserver)observer); + } } /** @@ -213,6 +230,9 @@ public class ClientManager public void removeClientObserver (ClientObserver observer) { _clobservers.remove(observer); + if (observer instanceof DetailedClientObserver) { + _dclobservers.remove(observer); + } } /** @@ -239,9 +259,25 @@ public class ClientManager * Resolves the specified client, applies the supplied client operation to them and releases * the client. */ - public void applyToClient (Name username, ClientOp clop) + public void applyToClient (Name username, final ClientOp clop) { - resolveClientObject(username, new ClientOpResolver(clop)); + resolveClientObject(username, new ClientResolutionListener() { + public void clientResolved (Name username, ClientObject clobj) { + try { + clop.apply(clobj); + + } catch (Exception e) { + log.warning("Client op failed", "username", username, "clop", clop, e); + + } finally { + releaseClientObject(username); + } + } + + public void resolutionFailed (Name username, Exception reason) { + clop.resolutionFailed(reason); + } + }); } /** @@ -509,6 +545,21 @@ public class ClientManager }); } + /** + * Called by PresentsSession when it is about to end its session. + */ + @EventThread + protected void clientSessionWillEnd (final PresentsSession session) + { + // notify the observers that the session is ended + _dclobservers.apply(new ObserverList.ObserverOp() { + public boolean apply (DetailedClientObserver observer) { + observer.clientSessionWillEnd(session); + return true; + } + }); + } + /** * Called by PresentsSession when it has ended its session. */ @@ -575,33 +626,6 @@ public class ClientManager } } - /** Used by {@link ClientManager#applyToClient}. */ - protected class ClientOpResolver - implements ClientResolutionListener - { - public ClientOpResolver (ClientOp clop) { - _clop = clop; - } - - public void clientResolved (Name username, ClientObject clobj) { - try { - _clop.apply(clobj); - - } catch (Exception e) { - log.warning("Client op failed", "username", username, "clop", _clop, e); - - } finally { - releaseClientObject(username); - } - } - - public void resolutionFailed (Name username, Exception reason) { - _clop.resolutionFailed(reason); - } - - protected ClientOp _clop; - } - /** Used to resolve dependencies in {@link PresentsSession} instances that we create. */ protected Injector _injector; @@ -623,6 +647,9 @@ public class ClientManager /** Tracks registered {@link ClientObserver}s. */ protected ObserverList _clobservers = ObserverList.newSafeInOrder(); + /** Tracks registered {@link DetailedClientObserver}s. */ + protected ObserverList _dclobservers = ObserverList.newSafeInOrder(); + // our injected dependencies @Inject protected PresentsDObjectMgr _omgr; diff --git a/src/main/java/com/threerings/presents/server/PresentsSession.java b/src/main/java/com/threerings/presents/server/PresentsSession.java index 0b70a74c2..a47d5c59f 100644 --- a/src/main/java/com/threerings/presents/server/PresentsSession.java +++ b/src/main/java/com/threerings/presents/server/PresentsSession.java @@ -338,6 +338,8 @@ public class PresentsSession @EventThread public void endSession () { + _clmgr.clientSessionWillEnd(this); + // queue up a request for our connection to be closed (if we have a connection, that is) Connection conn = getConnection(); if (conn != null) {