From 69485a88eec49a6ff70536ba3d4e2d0d00d3d038 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 4 May 2007 02:11:33 +0000 Subject: [PATCH] Widened, fixed documentation and nixed unneeded runnable posting for clientSessionDidEnd() which is called on the dobjmgr thread directly. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4680 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../presents/server/ClientManager.java | 199 +++++++----------- .../presents/server/PresentsClient.java | 12 +- 2 files changed, 83 insertions(+), 128 deletions(-) diff --git a/src/java/com/threerings/presents/server/ClientManager.java b/src/java/com/threerings/presents/server/ClientManager.java index 01a57207b..4181f60d2 100644 --- a/src/java/com/threerings/presents/server/ClientManager.java +++ b/src/java/com/threerings/presents/server/ClientManager.java @@ -41,15 +41,13 @@ import com.threerings.presents.net.Credentials; import com.threerings.presents.server.net.*; /** - * The client manager is responsible for managing the clients (surprise, - * surprise) which are slightly more than just connections. Clients - * persist in the absence of connections in case a user goes bye bye - * unintentionally and wants to reconnect and continue their session. + * The client manager is responsible for managing the clients (surprise, surprise) which are + * slightly more than just connections. Clients persist in the absence of connections in case a + * user goes bye bye unintentionally and wants to reconnect and continue their session. * - *

The client manager operates with thread safety because it is called - * both from the conmgr thread (to notify of connections showing up or - * going away) and from the dobjmgr thread (when clients are given the - * boot for application-defined reasons). + *

The client manager operates with thread safety because it is called both from the conmgr + * thread (to notify of connections showing up or going away) and from the dobjmgr thread (when + * clients are given the boot for application-defined reasons). */ public class ClientManager implements ConnectionObserver, ClientResolutionListener, @@ -72,35 +70,32 @@ public class ClientManager } /** - * Used by entites that wish to track when clients initiate and end - * sessions on this server. + * Used by entites that wish to track when clients initiate and end sessions on this server. */ public static interface ClientObserver { /** - * Called when a client has authenticated and been resolved and has - * started their session. + * Called when a client has authenticated and been resolved and has started their session. */ public void clientSessionDidStart (PresentsClient client); /** - * Called when a client has logged off or been forcibly logged off due - * to inactivity and has thus ended their session. + * Called when a client has logged off or been forcibly logged off due to inactivity and + * has thus ended their session. */ public void clientSessionDidEnd (PresentsClient client); } /** - * Constructs a client manager that will interact with the supplied - * connection manager. + * Constructs a client manager that will interact with the supplied connection manager. */ public ClientManager (ConnectionManager conmgr) { // register ourselves as a connection observer conmgr.addConnectionObserver(this); - // start up an interval that will check for expired clients and - // flush them from the bowels of the server + // start up an interval that will check for expired clients and flush them from the bowels + // of the server new Interval(PresentsServer.omgr) { public void expired () { flushClients(); @@ -115,8 +110,7 @@ public class ClientManager // documentation inherited from interface public void shutdown () { - Log.info("Client manager shutting down " + - "[ccount=" + _usermap.size() + "]."); + Log.info("Client manager shutting down [ccount=" + _usermap.size() + "]."); // inform all of our clients that they are being shut down for (Iterator iter = _usermap.values().iterator(); iter.hasNext(); ) { @@ -124,17 +118,16 @@ public class ClientManager try { pc.shutdown(); } catch (Exception e) { - Log.warning("Client choked in shutdown() [client=" + - StringUtil.safeToString(pc) + "]."); + Log.warning( + "Client choked in shutdown() [client=" + StringUtil.safeToString(pc) + "]."); Log.logStackTrace(e); } } } /** - * Configures the client manager with a factory for creating {@link - * PresentsClient} and {@link ClientResolver} classes for authenticated - * client connections. + * Configures the client manager with a factory for creating {@link PresentsClient} and {@link + * ClientResolver} classes for authenticated client connections. */ public void setClientFactory (ClientFactory factory) { @@ -182,8 +175,7 @@ public class ClientManager } /** - * Registers an observer that will be notified when clients start and end - * their sessions. + * Registers an observer that will be notified when clients start and end their sessions. */ public void addClientObserver (ClientObserver observer) { @@ -191,8 +183,7 @@ public class ClientManager } /** - * Removes an observer previously registered with {@link - * #addClientObserver}. + * Removes an observer previously registered with {@link #addClientObserver}. */ public void removeClientObserver (ClientObserver observer) { @@ -200,9 +191,8 @@ public class ClientManager } /** - * Returns the client instance that manages the client session for the - * specified authentication username or null if that client is not - * currently connected to the server. + * Returns the client instance that manages the client session for the specified authentication + * username or null if that client is not currently connected to the server. */ public PresentsClient getClient (Name authUsername) { @@ -210,9 +200,8 @@ public class ClientManager } /** - * Returns the client object associated with the specified username. - * This will return null unless the client object is resolved for some - * reason (like they are logged on). + * Returns the client object associated with the specified username. This will return null + * unless the client object is resolved for some reason (like they are logged on). */ public ClientObject getClientObject (Name username) { @@ -220,8 +209,8 @@ public class ClientManager } /** - * Resolves the specified client, applies the supplied client - * operation to them and releases the client. + * Resolves the specified client, applies the supplied client operation to them and releases + * the client. */ public void applyToClient (Name username, ClientOp clop) { @@ -229,13 +218,11 @@ public class ClientManager } /** - * Requests that the client object for the specified user be resolved. - * If the client object is already resolved, the request will be - * processed immediately, otherwise the appropriate client object will - * be instantiated and populated by the registered client resolver - * (which may involve talking to databases). Note: this - * must be paired with a call to {@link #releaseClientObject} - * when the caller is finished with the client object. + * Requests that the client object for the specified user be resolved. If the client object is + * already resolved, the request will be processed immediately, otherwise the appropriate + * client object will be instantiated and populated by the registered client resolver (which + * may involve talking to databases). Note: this must be paired with a call to + * {@link #releaseClientObject} when the caller is finished with the client object. */ public synchronized void resolveClientObject ( Name username, final ClientResolutionListener listener) @@ -257,18 +244,16 @@ public class ClientManager } try { - // create a client resolver instance which will create our - // client object, populate it and notify the listeners + // create a client resolver instance which will create our client object, populate it + // and notify the listeners clr = _factory.createClientResolver(username); clr.init(username); clr.addResolutionListener(this); clr.addResolutionListener(listener); _penders.put(username, clr); - // create and register our client object and give it back to the - // client resolver - clr.objectAvailable( - PresentsServer.omgr.registerObject(clr.createClientObject())); + // create and register our client object and give it back to the client resolver + clr.objectAvailable(PresentsServer.omgr.registerObject(clr.createClientObject())); } catch (Exception e) { // let the listener know that we're hosed @@ -277,22 +262,19 @@ public class ClientManager } /** - * Releases a client object that was obtained via a call to {@link - * #resolveClientObject}. If this caller is the last reference, the - * object will be flushed and destroyed. + * Releases a client object that was obtained via a call to {@link #resolveClientObject}. If + * this caller is the last reference, the object will be flushed and destroyed. */ public void releaseClientObject (Name username) { ClientObject clobj = _objmap.get(username); if (clobj == null) { - Log.warning("Requested to release unmapped client object " + - "[username=" + username + "]."); + Log.warning("Requested to release unmapped client object [username=" + username + "]."); Thread.dumpStack(); return; } - // decrement the reference count and stop here if there are - // remaining references + // decrement the reference count and stop here if there are remaining references if (clobj.release()) { return; } @@ -309,10 +291,10 @@ public class ClientManager // documentation inherited from interface ClientResolutionListener public synchronized void clientResolved (Name username, ClientObject clobj) { - // because we added ourselves as a client resolution listener, the - // client object reference count was increased, but we're not a real - // resolver (who would have to call releaseClientObject() to release - // their reference), so we release our reference immediately + // because we added ourselves as a client resolution listener, the client object reference + // count was increased, but we're not a real resolver (who would have to call + // releaseClientObject() to release their reference), so we release our reference + // immediately clobj.release(); // stuff the object into the mapping table @@ -340,13 +322,11 @@ public class ClientManager PresentsClient client = getClient(username); if (client != null) { - Log.info("Resuming session [username=" + username + - ", conn=" + conn + "]."); + Log.info("Resuming session [username=" + username + ", conn=" + conn + "]."); client.resumeSession(req, conn); } else { - Log.info("Session initiated [username=" + username + - ", conn=" + conn + "]."); + Log.info("Session initiated [username=" + username + ", conn=" + conn + "]."); // create a new client and stick'em in the table client = _factory.createClient(req); client.startSession(this, req, conn, rsp.authdata); @@ -360,22 +340,20 @@ public class ClientManager } // documentation inherited - public synchronized void connectionFailed ( - Connection conn, IOException fault) + public synchronized void connectionFailed (Connection conn, IOException fault) { // remove the client from the connection map PresentsClient client = _conmap.remove(conn); if (client != null) { - Log.info("Unmapped failed client [client=" + client + - ", conn=" + conn + ", fault=" + fault + "]."); + Log.info("Unmapped failed client [client=" + client + ", conn=" + conn + + ", fault=" + fault + "]."); // let the client know the connection went away client.wasUnmapped(); // and let the client know things went haywire client.connectionFailed(fault); } else if (!(conn instanceof AuthingConnection)) { - Log.info("Unmapped connection failed? [conn=" + conn + - ", fault=" + fault + "]."); + Log.info("Unmapped connection failed? [conn=" + conn + ", fault=" + fault + "]."); Thread.dumpStack(); } } @@ -386,8 +364,7 @@ public class ClientManager // remove the client from the connection map PresentsClient client = _conmap.remove(conn); if (client != null) { - Log.debug("Unmapped client [client=" + client + - ", conn=" + conn + "]."); + Log.debug("Unmapped client [client=" + client + ", conn=" + conn + "]."); // let the client know the connection went away client.wasUnmapped(); @@ -398,8 +375,7 @@ public class ClientManager } // documentation inherited from interface PresentsServer.Reporter - public void appendReport ( - StringBuilder report, long now, long sinceLast, boolean reset) + public void appendReport (StringBuilder report, long now, long sinceLast, boolean reset) { report.append("* presents.ClientManager:\n"); report.append("- Sessions: "); @@ -410,8 +386,8 @@ public class ClientManager } /** - * Called by the client instance when it has started its session. This is - * called from the dobjmgr thread. + * Called by the client instance when it has started its session. This is called from the + * dobjmgr thread. */ protected void clientSessionDidStart (final PresentsClient client) { @@ -425,15 +401,13 @@ public class ClientManager } /** - * Called by the client instance when the client requests a logoff. - * This is called from the conmgr thread. + * Called by the client instance when the client requests a logoff. This is called from the + * dobjmgr thread. */ - protected synchronized void clientSessionDidEnd ( - final PresentsClient client) + protected void clientSessionDidEnd (final PresentsClient client) { // remove the client from the username map - PresentsClient rc = _usermap.remove( - client.getCredentials().getUsername()); + PresentsClient rc = _usermap.remove(client.getCredentials().getUsername()); // sanity check just because we can if (rc == null) { @@ -446,33 +420,26 @@ public class ClientManager Log.info("Ending session " + client + "."); } - // queue up a unit on the dobjmgr thread to notify the client observers - // that the session is ended - PresentsServer.omgr.postRunnable(new Runnable() { - public void run () { - _clobservers.apply( - new ObserverList.ObserverOp() { - public boolean apply (ClientObserver observer) { - observer.clientSessionDidEnd(client); - return true; - } - }); + // notify the observers that the session is ended + _clobservers.apply(new ObserverList.ObserverOp() { + public boolean apply (ClientObserver observer) { + observer.clientSessionDidEnd(client); + return true; } }); } /** - * Called once per minute to check for clients that have been - * disconnected too long and forcibly end their sessions. + * Called once per minute to check for clients that have been disconnected too long and + * forcibly end their sessions. */ protected void flushClients () { ArrayList victims = null; long now = System.currentTimeMillis(); - // first build a list of our victims (we can't flush clients - // directly while iterating due to risk of a - // ConcurrentModificationException) + // first build a list of our victims (we can't flush clients directly while iterating due + // to risk of a ConcurrentModificationException) for (PresentsClient client : _usermap.values()) { if (client.checkExpired(now)) { if (victims == null) { @@ -485,13 +452,11 @@ public class ClientManager if (victims != null) { for (PresentsClient client : victims) { try { - Log.info("Client expired, ending session " + - "[client=" + client + - ", dtime=" + (now-client.getNetworkStamp()) + "ms]."); + Log.info("Client expired, ending session [client=" + client + + ", dtime=" + (now-client.getNetworkStamp()) + "ms]."); client.endSession(); } catch (Exception e) { - Log.warning("Choke while flushing client " + - "[victim=" + client + "]."); + Log.warning("Choke while flushing client [victim=" + client + "]."); Log.logStackTrace(e); } } @@ -502,20 +467,16 @@ public class ClientManager protected class ClientOpResolver implements ClientResolutionListener { - public ClientOpResolver (ClientOp clop) - { + public ClientOpResolver (ClientOp clop) { _clop = clop; } - // documentation inherited from interface - public void clientResolved (Name username, ClientObject clobj) - { + public void clientResolved (Name username, ClientObject clobj) { try { _clop.apply(clobj); } catch (Exception e) { - Log.warning("Client op failed [username=" + username + - ", clop=" + _clop + "]."); + Log.warning("Client op failed [username=" + username + ", clop=" + _clop + "]."); Log.logStackTrace(e); } finally { @@ -523,9 +484,7 @@ public class ClientManager } } - // documentation inherited from interface - public void resolutionFailed (Name username, Exception reason) - { + public void resolutionFailed (Name username, Exception reason) { _clop.resolutionFailed(reason); } @@ -533,20 +492,16 @@ public class ClientManager } /** A mapping from auth username to client instances. */ - protected HashMap _usermap = - new HashMap(); + protected HashMap _usermap = new HashMap(); /** A mapping from connections to client instances. */ - protected HashMap _conmap = - new HashMap(); + protected HashMap _conmap = new HashMap(); /** A mapping from usernames to client object instances. */ - protected HashMap _objmap = - new HashMap(); + protected HashMap _objmap = new HashMap(); /** A mapping of pending client resolvers. */ - protected HashMap _penders = - new HashMap(); + protected HashMap _penders = new HashMap(); /** The client class in use. */ protected ClientFactory _factory = ClientFactory.DEFAULT; diff --git a/src/java/com/threerings/presents/server/PresentsClient.java b/src/java/com/threerings/presents/server/PresentsClient.java index 85fc1c217..809c00db2 100644 --- a/src/java/com/threerings/presents/server/PresentsClient.java +++ b/src/java/com/threerings/presents/server/PresentsClient.java @@ -346,7 +346,7 @@ public class PresentsClient } } - // documentation inherited from interface + // from interface ClientResolutionListener public void clientResolved (Name username, ClientObject clobj) { // we'll be keeping this bad boy @@ -360,7 +360,7 @@ public class PresentsClient _cmgr.clientSessionDidStart(this); } - // documentation inherited from interface + // from interface ClientResolutionListener public void resolutionFailed (Name username, Exception reason) { // urk; nothing to do but complain and get the f**k out of dodge @@ -371,7 +371,7 @@ public class PresentsClient endSession(); } - // documentation inherited from interface + // from interface MessageHandler public void handleMessage (UpstreamMessage message) { _messagesIn++; // count 'em up! @@ -403,7 +403,7 @@ public class PresentsClient disp.dispatch(this, message); } - // documentation inherited from interface + // from interface ProxySubscriber public void objectAvailable (DObject object) { if (postMessage(new ObjectResponse(object))) { @@ -415,13 +415,13 @@ public class PresentsClient } } - // documentation inherited from interface + // from interface ProxySubscriber public void requestFailed (int oid, ObjectAccessException cause) { postMessage(new FailureResponse(oid)); } - // documentation inherited from interface + // from interface ProxySubscriber public void eventReceived (DEvent event) { if (event instanceof PresentsDObjectMgr.AccessObjectEvent) {