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
This commit is contained in:
Jamie Doornbos
2011-04-05 17:46:29 +00:00
parent 1d3b40c4dc
commit ddb30e640e
2 changed files with 58 additions and 29 deletions
@@ -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<DetailedClientObserver>() {
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<ClientObserver> _clobservers = ObserverList.newSafeInOrder();
/** Tracks registered {@link DetailedClientObserver}s. */
protected ObserverList<DetailedClientObserver> _dclobservers = ObserverList.newSafeInOrder();
// our injected dependencies
@Inject protected PresentsDObjectMgr _omgr;
@@ -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) {