diff --git a/src/java/com/threerings/presents/client/Client.java b/src/java/com/threerings/presents/client/Client.java
index 26146b609..004cfb4a1 100644
--- a/src/java/com/threerings/presents/client/Client.java
+++ b/src/java/com/threerings/presents/client/Client.java
@@ -21,6 +21,8 @@
package com.threerings.presents.client;
+import java.util.HashSet;
+
import com.samskivert.util.Interval;
import com.samskivert.util.ObserverList;
import com.samskivert.util.RunAnywhere;
@@ -36,9 +38,9 @@ import com.threerings.presents.net.PingRequest;
import com.threerings.presents.net.PongResponse;
/**
- * Through the client object, a connection to the system is established
- * and maintained. The client object maintains two separate threads (a
- * reader and a writer) by which all network traffic is managed.
+ * Through the client object, a connection to the system is established and maintained. The client
+ * object maintains two separate threads (a reader and a writer) by which all network traffic is
+ * managed.
*/
public class Client
{
@@ -47,22 +49,17 @@ public class Client
public static final int[] DEFAULT_SERVER_PORTS = { 47624 };
/**
- * Constructs a client object with the supplied credentials and
- * RunQueue. The creds will be used to authenticate with any server to
- * which this client attempts to connect. The RunQueue is used to
- * operate the distributed object event dispatch mechanism. To allow
- * the dobj event dispatch to coexist with threads like the AWT
- * thread, the client will request that the RunQueue queue up a
- * runnable whenever there are distributed object events that need to
- * be processed. The RunQueue can then queue that runnable up on the
- * AWT thread if it is so inclined to make life simpler for the rest
- * of the application.
+ * Constructs a client object with the supplied credentials and RunQueue. The creds will be
+ * used to authenticate with any server to which this client attempts to connect. The RunQueue
+ * is used to operate the distributed object event dispatch mechanism. To allow the dobj event
+ * dispatch to coexist with threads like the AWT thread, the client will request that the
+ * RunQueue queue up a runnable whenever there are distributed object events that need to be
+ * processed. The RunQueue can then queue that runnable up on the AWT thread if it is so
+ * inclined to make life simpler for the rest of the application.
*
- * @param creds the credentials to use when logging on to the server.
- * These can be null, but setCredentials must then be
- * called before any call to logon.
- * @param runQueue a RunQueue that can be used to process incoming
- * events.
+ * @param creds the credentials to use when logging on to the server. These can be null, but
+ * setCredentials must then be called before any call to logon.
+ * @param runQueue a RunQueue that can be used to process incoming events.
*/
public Client (Credentials creds, RunQueue runQueue)
{
@@ -71,10 +68,9 @@ public class Client
}
/**
- * Registers the supplied observer with this client. While registered
- * the observer will receive notifications of state changes within the
- * client. The function will refuse to register an already registered
- * observer.
+ * Registers the supplied observer with this client. While registered the observer will receive
+ * notifications of state changes within the client. The function will refuse to register an
+ * already registered observer.
*
* @see ClientObserver
* @see SessionObserver
@@ -87,9 +83,8 @@ public class Client
}
/**
- * Unregisters the supplied observer. Upon return of this function,
- * the observer will no longer receive notifications of state changes
- * within the client.
+ * Unregisters the supplied observer. Upon return of this function, the observer will no longer
+ * receive notifications of state changes within the client.
*/
public void removeClientObserver (SessionObserver observer)
{
@@ -105,7 +100,7 @@ public class Client
{
_standalone = standalone;
}
-
+
/**
* Checks whether or not this client is operating in a standalone mode.
*/
@@ -113,10 +108,10 @@ public class Client
{
return _standalone;
}
-
+
/**
- * Configures the client to communicate with the server on the supplied
- * hostname and set of ports (which will be tried in succession).
+ * Configures the client to communicate with the server on the supplied hostname and set of
+ * ports (which will be tried in succession).
*
* @see #logon
*/
@@ -127,8 +122,8 @@ public class Client
}
/**
- * Returns the RunQueue in use by this client. This can be used to
- * queue up event dispatching stints.
+ * Returns the RunQueue in use by this client. This can be used to queue up event dispatching
+ * stints.
*/
public RunQueue getRunQueue ()
{
@@ -136,8 +131,7 @@ public class Client
}
/**
- * Returns the hostname of the server to which this client is
- * currently configured to connect.
+ * Returns the hostname of the server to which this client is currently configured to connect.
*/
public String getHostname ()
{
@@ -145,8 +139,7 @@ public class Client
}
/**
- * Returns the port on which this client is currently configured to
- * connect to the server.
+ * Returns the port on which this client is currently configured to connect to the server.
*/
public int[] getPorts ()
{
@@ -154,8 +147,8 @@ public class Client
}
/**
- * Returns the credentials with which this client is currently
- * configured to connect to the server.
+ * Returns the credentials with which this client is currently configured to connect to the
+ * server.
*/
public Credentials getCredentials ()
{
@@ -163,9 +156,8 @@ public class Client
}
/**
- * Sets the credentials that will be used by this client to
- * authenticate with the server. This should be done before any call
- * to logon.
+ * Sets the credentials that will be used by this client to authenticate with the server. This
+ * should be done before any call to logon.
*/
public void setCredentials (Credentials creds)
{
@@ -181,9 +173,8 @@ public class Client
}
/**
- * Sets the version string reported to the server during
- * authentication. Some server implementations may wish to refuse
- * connections by old or invalid client versions.
+ * Sets the version string reported to the server during authentication. Some server
+ * implementations may wish to refuse connections by old or invalid client versions.
*/
public void setVersion (String version)
{
@@ -191,8 +182,8 @@ public class Client
}
/**
- * Configures the client with a custom class loader which will be used
- * when reading objects off of the network.
+ * Configures the client with a custom class loader which will be used when reading objects off
+ * of the network.
*/
public void setClassLoader (ClassLoader loader)
{
@@ -203,10 +194,19 @@ public class Client
}
/**
- * Returns the data associated with our authentication response. Users
- * of the Presents system may wish to communicate authentication
- * related information to their client by extending and augmenting
- * {@link AuthResponseData}.
+ * Marks this client as interested in the specified bootstrap services group. Any services
+ * registered as bootstrap services with the supplied group name will be included in this
+ * clients bootstrap services set. This must be called before {@link #logon}.
+ */
+ public void addBootstrapGroup (String group)
+ {
+ _bootGroups.add(group);
+ }
+
+ /**
+ * Returns the data associated with our authentication response. Users of the Presents system
+ * may wish to communicate authentication related information to their client by extending and
+ * augmenting {@link AuthResponseData}.
*/
public AuthResponseData getAuthResponseData ()
{
@@ -214,13 +214,11 @@ public class Client
}
/**
- * Returns the distributed object manager associated with this
- * session. This reference is only valid for the duration of the
- * session and a new reference must be obtained if the client
+ * Returns the distributed object manager associated with this session. This reference is only
+ * valid for the duration of the session and a new reference must be obtained if the client
* disconnects and reconnects to the server.
*
- * @return the dobjmgr in effect or null if we have no established
- * connection to the server.
+ * @return the dobjmgr in effect or null if we have no established connection to the server.
*/
public DObjectManager getDObjectManager ()
{
@@ -228,17 +226,15 @@ public class Client
}
/**
- * Instructs the distributed object manager associated with this
- * client to allow objects of the specified class to linger around the
- * specified number of milliseconds after their last subscriber has
- * been removed before the client finally removes its object proxy and
- * flushes the object. Normally, objects are flushed immediately
- * following the removal of their last subscriber.
+ * Instructs the distributed object manager associated with this client to allow objects of the
+ * specified class to linger around the specified number of milliseconds after their last
+ * subscriber has been removed before the client finally removes its object proxy and flushes
+ * the object. Normally, objects are flushed immediately following the removal of their last
+ * subscriber.
*
- *
Note: the delay will be applied to derived classes as - * well as exact matches. Note also: this method cannot be - * called until after the client has established a connection with the - * server and the distributed object manager is available. + *
Note: the delay will be applied to derived classes as well as exact
+ * matches. Note also: this method cannot be called until after the client has
+ * established a connection with the server and the distributed object manager is available.
*/
public void registerFlushDelay (Class objclass, long delay)
{
@@ -247,8 +243,8 @@ public class Client
}
/**
- * Returns the oid of the client object associated with this session.
- * It is only valid for the duration of the session.
+ * Returns the oid of the client object associated with this session. It is only valid for the
+ * duration of the session.
*/
public int getClientOid ()
{
@@ -256,8 +252,8 @@ public class Client
}
/**
- * Returns a reference to the client object associated with this
- * session. It is only valid for the duration of the session.
+ * Returns a reference to the client object associated with this session. It is only valid for
+ * the duration of the session.
*/
public ClientObject getClientObject ()
{
@@ -265,8 +261,8 @@ public class Client
}
/**
- * Returns the invocation director associated with this session. This
- * reference is only valid for the duration of the session.
+ * Returns the invocation director associated with this session. This reference is only valid
+ * for the duration of the session.
*/
public InvocationDirector getInvocationDirector ()
{
@@ -274,9 +270,9 @@ public class Client
}
/**
- * Returns the first bootstrap service that could be located that
- * implements the supplied {@link InvocationService} derivation.
- * Invocations are like remote procedure calls in that they are named
- * and take arguments. All arguments must be {@link Streamable} objects,
- * primitive types, or String objects. All arguments are passed by value
- * (by serializing and unserializing the arguments); there is no special
- * facility provided for referencing non-local objects (it is assumed that
- * the distributed object facility will already be in use for any objects
- * that should be shared).
+ * Invocations are like remote procedure calls in that they are named and take arguments. All
+ * arguments must be {@link Streamable} objects, primitive types, or String objects. All arguments
+ * are passed by value (by serializing and unserializing the arguments); there is no special
+ * facility provided for referencing non-local objects (it is assumed that the distributed object
+ * facility will already be in use for any objects that should be shared).
*
- * The server invocation manager listens for invocation requests from
- * the client and passes them on to the invocation provider registered for
- * the requested invocation module. It also provides a mechanism by which
- * responses and asynchronous notification invocations can be delivered to
- * the client.
+ * The server invocation manager listens for invocation requests from the client and passes
+ * them on to the invocation provider registered for the requested invocation module. It also
+ * provides a mechanism by which responses and asynchronous notification invocations can be
+ * delivered to the client.
*/
public class InvocationManager
implements EventListener
{
- /** The list of services that are to be provided to clients at boot
- * time. Don't mess with this list! */
- public StreamableArrayList A note on synchronization: the client object is structured
- * so that its A note on synchronization: the client object is structured so that its
+ * It exists to support systems wherein a user logs in with an
- * account username and then chooses a "screen name" by which they
- * will play (often from a small set of available "characters"
- * available per account). This will take care of remapping the
- * username to client object mappings that were made by the Presents
- * services when the user logs on, but anything else that has had its
- * grubby mits on the username will be left to its own devices, hence
- * the care that must be exercised when using this method.
+ * It exists to support systems wherein a user logs in with an account username and then
+ * chooses a "screen name" by which they will play (often from a small set of available
+ * "characters" available per account). This will take care of remapping the username to client
+ * object mappings that were made by the Presents services when the user logs on, but anything
+ * else that has had its grubby mits on the username will be left to its own devices, hence the
+ * care that must be exercised when using this method.
*
- * @param ucl an entity that will (optionally) be notified when the
- * username conversion process is complete.
+ * @param ucl an entity that will (optionally) be notified when the username conversion process
+ * is complete.
*/
public void setUsername (Name username, final UserChangeListener ucl)
{
ClientResolutionListener clr = new ClientResolutionListener() {
- public void clientResolved (final Name username,
- final ClientObject clobj)
+ public void clientResolved (final Name username, final ClientObject clobj)
{
- // if they old client object is gone by now, they ended
- // their session while we were switching, so freak out
+ // if they old client object is gone by now, they ended their session while we were
+ // switching, so freak out
if (_clobj == null) {
- Log.warning("Client disappeared before we could " +
- "complete the switch to a new client " +
- "object [ousername=" + _username +
+ Log.warning("Client disappeared before we could complete the switch to a " +
+ "new client object [ousername=" + _username +
", nusername=" + username + "].");
_cmgr.releaseClientObject(username);
Exception error = new Exception("Early withdrawal");
@@ -216,10 +202,8 @@ public class PresentsClient
return;
}
- // let the client know that the rug has been yanked out
- // from under their ass
- Object[] args = new Object[] {
- Integer.valueOf(clobj.getOid()) };
+ // let the client know that the rug has been yanked out from under their ass
+ Object[] args = new Object[] { Integer.valueOf(clobj.getOid()) };
_clobj.postMessage(ClientObject.CLOBJ_CHANGED, args);
// call down to any derived classes
@@ -231,7 +215,6 @@ public class PresentsClient
public void requestCompleted (Object result) {
finishResolved(username, clobj);
}
-
public void requestFailed (Exception cause) {
finishResolved(username, clobj);
}
@@ -263,9 +246,8 @@ public class PresentsClient
}
public void resolutionFailed (Name username, Exception reason) {
- Log.warning("Unable to resolve new client object " +
- "[oldname=" + _username + ", newname=" + username +
- ", reason=" + reason + "].");
+ Log.warning("Unable to resolve new client object [oldname=" + _username +
+ ", newname=" + username + ", reason=" + reason + "].");
Log.logStackTrace(reason);
// let our listener know we're hosed
@@ -288,25 +270,21 @@ public class PresentsClient
}
/**
- * Forcibly terminates a client's session. This must be called from
- * the dobjmgr thread.
+ * Forcibly terminates a client's session. This must be called from the dobjmgr thread.
*/
public void endSession ()
{
- // queue up a request for our connection to be closed (if we have
- // a connection, that is)
+ // queue up a request for our connection to be closed (if we have a connection, that is)
Connection conn = getConnection();
if (conn != null) {
- // go ahead and clear out our connection now to prevent
- // funniness
+ // go ahead and clear out our connection now to prevent funniness
setConnection(null);
- // have the connection manager close our connection when it is
- // next convenient
+ // have the connection manager close our connection when it is next convenient
PresentsServer.conmgr.closeConnection(conn);
}
- // if we don't have a client object, we failed to resolve in the
- // first place, in which case we have to cope as best we can
+ // if we don't have a client object, we failed to resolve in the first place, in which case
+ // we have to cope as best we can
if (_clobj != null) {
// and clean up after ourselves
try {
@@ -328,17 +306,15 @@ public class PresentsClient
}
/**
- * This is called when the server is shut down in the middle of a
- * client session. In this circumstance, {@link #endSession} will
- * not be called and so any persistent data that might
- * normally be flushed at the end of a client's session should likely
- * be flushed here.
+ * This is called when the server is shut down in the middle of a client session. In this
+ * circumstance, {@link #endSession} will not be called and so any persistent data
+ * that might normally be flushed at the end of a client's session should likely be flushed
+ * here.
*/
public void shutdown ()
{
- // if the client is connected, we need to fake the computation of
- // their final connect time because we won't be closing their
- // socket normally
+ // if the client is connected, we need to fake the computation of their final connect time
+ // because we won't be closing their socket normally
if (getConnection() != null) {
long now = System.currentTimeMillis();
_connectTime += ((now - _networkStamp) / 1000);
@@ -346,10 +322,9 @@ public class PresentsClient
}
/**
- * Makes a note that this client is subscribed to this object so that
- * we can clean up after ourselves if and when the client goes
- * away. This is called by the client internals and needn't be called
- * by code outside the client.
+ * Makes a note that this client is subscribed to this object so that we can clean up after
+ * ourselves if and when the client goes away. This is called by the client internals and
+ * needn't be called by code outside the client.
*/
public synchronized void mapSubscrip (DObject object)
{
@@ -357,10 +332,9 @@ public class PresentsClient
}
/**
- * Makes a note that this client is no longer subscribed to this
- * object. The subscription map is used to clean up after the client
- * when it goes away. This is called by the client internals and
- * needn't be called by code outside the client.
+ * Makes a note that this client is no longer subscribed to this object. The subscription map
+ * is used to clean up after the client when it goes away. This is called by the client
+ * internals and needn't be called by code outside the client.
*/
public synchronized void unmapSubscrip (int oid)
{
@@ -368,8 +342,7 @@ public class PresentsClient
if (object != null) {
object.removeSubscriber(this);
} else {
- Log.warning("Requested to unmap non-existent subscription " +
- "[oid=" + oid + "].");
+ Log.warning("Requested to unmap non-existent subscription [oid=" + oid + "].");
}
}
@@ -403,24 +376,23 @@ public class PresentsClient
{
_messagesIn++; // count 'em up!
- // if the client has been getting crazy with the cheeze whiz,
- // stick a fork in them; the first time through we end our
- // session, subsequently _throttle is null and we just drop any
- // messages that come in until we've fully shutdown
+ // if the client has been getting crazy with the cheeze whiz, stick a fork in them; the
+ // first time through we end our session, subsequently _throttle is null and we just drop
+ // any messages that come in until we've fully shutdown
if (_throttle == null) {
-// Log.info("Dropping message from force-quit client " +
-// "[conn=" + _conn +
+// Log.info("Dropping message from force-quit client [conn=" + _conn +
// ", msg=" + message + "].");
return;
+
} else if (_throttle.throttleOp(message.received)) {
- Log.warning("Client sent more than 100 messages in 10 seconds, " +
- "forcing disconnect " + this + ".");
+ Log.warning("Client sent more than 100 messages in 10 seconds, forcing " +
+ "disconnect " + this + ".");
safeEndSession();
_throttle = null;
}
- // we dispatch to a message dispatcher that is specialized for the
- // particular class of message that we received
+ // we dispatch to a message dispatcher that is specialized for the particular class of
+ // message that we received
MessageDispatcher disp = _disps.get(message.getClass());
if (disp == null) {
Log.warning("No dispatcher for message [msg=" + message + "].");
@@ -453,8 +425,7 @@ public class PresentsClient
public void eventReceived (DEvent event)
{
if (event instanceof PresentsDObjectMgr.AccessObjectEvent) {
- Log.warning("Ignoring event that shouldn't be forwarded " +
- event + ".");
+ Log.warning("Ignoring event that shouldn't be forwarded " + event + ".");
Thread.dumpStack();
} else {
postMessage(new EventNotification(event));
@@ -462,10 +433,9 @@ public class PresentsClient
}
/**
- * Called when {@link #setUsername} has been called and the new client
- * object is about to be applied to this client. The old client object
- * will not yet have been destroyed, so any final events can be sent
- * along prior to the new object being put into effect.
+ * Called when {@link #setUsername} has been called and the new client object is about to be
+ * applied to this client. The old client object will not yet have been destroyed, so any final
+ * events can be sent along prior to the new object being put into effect.
*/
protected void clientObjectWillChange (
ClientObject oldClobj, ClientObject newClobj)
@@ -473,16 +443,16 @@ public class PresentsClient
}
/**
- * Called after the new client object has been committed to this
- * client due to a call to {@link #setUsername}.
+ * Called after the new client object has been committed to this client due to a call to {@link
+ * #setUsername}.
*/
protected void clientObjectDidChange (ClientObject newClobj)
{
}
/**
- * Initializes this client instance with the specified username, connection
- * instance and client object and begins a client session.
+ * Initializes this client instance with the specified username, connection instance and client
+ * object and begins a client session.
*/
protected void startSession (
ClientManager cmgr, AuthRequest req, Connection conn, Object authdata)
@@ -503,12 +473,10 @@ public class PresentsClient
}
/**
- * This is factored out to allow derived classes to use a different
- * starting username than the one supplied in the user's credentials.
- * Generally one only wants to munge the starting username if the user
- * will subsequently choose a "screen name" and it is desirable to
- * avoid collision between the authentication user namespace and the
- * screen namespace.
+ * This is factored out to allow derived classes to use a different starting username than the
+ * one supplied in the user's credentials. Generally one only wants to munge the starting
+ * username if the user will subsequently choose a "screen name" and it is desirable to avoid
+ * collision between the authentication user namespace and the screen namespace.
*/
protected void assignStartingUsername ()
{
@@ -516,80 +484,67 @@ public class PresentsClient
}
/**
- * Called by the client manager when a new connection arrives that
- * authenticates as this already established client. This must only be
- * called from the congmr thread.
+ * Called by the client manager when a new connection arrives that authenticates as this
+ * already established client. This must only be called from the congmr thread.
*/
protected void resumeSession (Connection conn)
{
- // check to see if we've already got a connection object, in which
- // case it's probably stale
+ // check to see if we've already got a connection object, in which case it's probably stale
Connection oldconn = getConnection();
if (oldconn != null && !oldconn.isClosed()) {
- Log.info("Closing stale connection [old=" + oldconn +
- ", new=" + conn + "].");
- // close the old connection (which results in everything being
- // properly unregistered)
+ Log.info("Closing stale connection [old=" + oldconn + ", new=" + conn + "].");
+ // close the old connection (which results in everything being properly unregistered)
oldconn.close();
}
// start using the new connection
setConnection(conn);
- // if a client connects, drops the connection and reconnects
- // within the span of a very short period of time, we'll find
- // ourselves in resumeSession() before their client object was
- // resolved from the initial connection; in such a case, we can
- // simply bail out here and let the original session establishment
- // code take care of initializing this resumed session
+ // if a client connects, drops the connection and reconnects within the span of a very
+ // short period of time, we'll find ourselves in resumeSession() before their client object
+ // was resolved from the initial connection; in such a case, we can simply bail out here
+ // and let the original session establishment code take care of initializing this resumed
+ // session
if (_clobj == null) {
- Log.warning("Rapid-fire reconnect caused us to arrive in " +
- "resumeSession() before the original session " +
- "resolved its client object? " + this + ".");
+ Log.warning("Rapid-fire reconnect caused us to arrive in resumeSession() before the " +
+ "original session resolved its client object? " + this + ".");
return;
}
- // we need to get onto the distributed object thread so that we
- // can finalize the resumption of the session.
+ // we need to get onto the dobj thread so that we can finalize resumption of the session
PresentsServer.omgr.postRunnable(new Runnable() {
public void run () {
- // now that we're on the dobjmgr thread we can resume our
- // session resumption
+ // now that we're on the dobjmgr thread we can resume our session resumption
finishResumeSession();
}
});
}
/**
- * This is called from the dobjmgr thread to complete the session
- * resumption. We call some call backs and send the bootstrap info to
- * the client.
+ * This is called from the dobjmgr thread to complete the session resumption. We call some call
+ * backs and send the bootstrap info to the client.
*/
protected void finishResumeSession ()
{
// let derived classes do any session resuming
sessionWillResume();
- // send off a bootstrap notification immediately because we've
- // already got our client object
+ // send off a bootstrap notification immediately as we've already got our client object
sendBootstrap();
Log.info("Session resumed " + this + ".");
}
/**
- * Queues up a runnable on the object manager thread where we can
- * safely end the session.
+ * Queues up a runnable on the object manager thread where we can safely end the session.
*/
protected void safeEndSession ()
{
PresentsServer.omgr.postRunnable(new Runnable() {
public void run () {
if (getClientObject() == null) {
- // refuse to end the session unless the client is
- // fully resolved
- Log.warning("Refusing logoff request from " +
- "still-resolving client " + this + ".");
+ // refuse to end the session unless the client is fully resolved
+ Log.warning("Refusing logoff from still-resolving client " + this + ".");
} else {
// end the session in a civilized manner
endSession();
@@ -599,8 +554,8 @@ public class PresentsClient
}
/**
- * Clears out the tracked client subscriptions. Called when the client
- * goes away and shouldn't be called otherwise.
+ * Clears out the tracked client subscriptions. Called when the client goes away and shouldn't
+ * be called otherwise.
*/
protected void clearSubscrips (boolean verbose)
{
@@ -615,58 +570,50 @@ public class PresentsClient
}
/**
- * Called when the client session is first started. The client object
- * has been created at this point and after this method is executed,
- * the bootstrap information will be sent to the client which will
- * trigger the start of the session. Derived classes that override
- * this method should be sure to call
- * Note: This function will be called on the dobjmgr
- * thread which means that object manipulations are OK, but client
- * instance manipulations must done carefully.
+ * Note: This function will be called on the dobjmgr thread which means that object
+ * manipulations are OK, but client instance manipulations must done carefully.
*/
protected void sessionWillStart ()
{
}
/**
- * Called when the client resumes a session (after having disconnected
- * and reconnected). After this method is executed, the bootstrap
- * information will be sent to the client which will trigger the
- * resumption of the session. Derived classes that override this
- * method should be sure to call Note: This function will be called on the dobjmgr
- * thread which means that object manipulations are OK, but client
- * instance manipulations must done carefully.
+ * Note: This function will be called on the dobjmgr thread which means that object
+ * manipulations are OK, but client instance manipulations must done carefully.
*/
protected void sessionWillResume ()
{
}
/**
- * Called when the client session ends (either because the client
- * logged off or because the server forcibly terminated the session).
- * Derived classes that override this method should be sure to call
- * Note: This function will be called on the dobjmgr
- * thread which means that object manipulations are OK, but client
- * instance manipulations must done carefully.
+ * Note: This function will be called on the dobjmgr thread which means that object
+ * manipulations are OK, but client instance manipulations must done carefully.
*/
protected void sessionDidEnd ()
{
- // clear out our subscriptions so that we don't get a complaint
- // about inability to forward the object destroyed event we're
- // about to generate
+ // clear out our subscriptions so that we don't get a complaint about inability to forward
+ // the object destroyed event we're about to generate
clearSubscrips(false);
}
/**
- * This is called once we have a handle on the client distributed
- * object. It sends a bootstrap notification to the client with all
- * the information it will need to interact with the server.
+ * This is called once we have a handle on the client distributed object. It sends a bootstrap
+ * notification to the client with all the information it will need to interact with the
+ * server.
*/
protected void sendBootstrap ()
{
@@ -681,9 +628,8 @@ public class PresentsClient
}
/**
- * Derived client classes can override this member to create derived
- * bootstrap data classes that contain extra bootstrap information, if
- * desired.
+ * Derived client classes can override this member to create derived bootstrap data classes
+ * that contain extra bootstrap information, if desired.
*/
protected BootstrapData createBootstrapData ()
{
@@ -691,14 +637,12 @@ public class PresentsClient
}
/**
- * Derived client classes can override this member to populate the
- * bootstrap data with additional information. They should be sure to
- * call Note: This function will be called on the dobjmgr
- * thread which means that object manipulations are OK, but client
- * instance manipulations must be done carefully.
+ * Note: This function will be called on the dobjmgr thread which means that object
+ * manipulations are OK, but client instance manipulations must be done carefully.
*/
protected void populateBootstrapData (BootstrapData data)
{
@@ -706,28 +650,36 @@ public class PresentsClient
data.clientOid = _clobj.getOid();
// fill in the list of bootstrap services
- data.services = PresentsServer.invmgr.bootlist;
+ data.services = new StreamableArrayListnull is returned if no such service could be found.
+ * Returns the first bootstrap service that could be located that implements the supplied
+ * {@link InvocationService} derivation. null is returned if no such service
+ * could be found.
*/
public InvocationService getService (Class sclass)
{
@@ -295,10 +291,9 @@ public class Client
}
/**
- * Like {@link #getService} except that a {@link RuntimeException} is
- * thrown if the service is not available. Useful to avoid redundant
- * error checking when you know that the shit will hit the fan if a
- * particular invocation service is not available.
+ * Like {@link #getService} except that a {@link RuntimeException} is thrown if the service is
+ * not available. Useful to avoid redundant error checking when you know that the shit will hit
+ * the fan if a particular invocation service is not available.
*/
public InvocationService requireService (Class sclass)
{
@@ -312,8 +307,7 @@ public class Client
}
/**
- * Returns a reference to the bootstrap data provided to this client
- * at logon time.
+ * Returns a reference to the bootstrap data provided to this client at logon time.
*/
public BootstrapData getBootstrapData ()
{
@@ -321,30 +315,28 @@ public class Client
}
/**
- * Converts a server time stamp to a value comparable to client clock
- * readings.
+ * Converts a server time stamp to a value comparable to client clock readings.
*/
public long fromServerTime (long stamp)
{
- // when we calcuated our time delta, we did it such that: C - S =
- // dT, thus to convert server to client time we do: C = S + dT
+ // when we calcuated our time delta, we did it such that: C - S = dT, thus to convert
+ // server to client time we do: C = S + dT
return stamp + _serverDelta;
}
/**
- * Converts a client clock reading to a value comparable to a server
- * time stamp.
+ * Converts a client clock reading to a value comparable to a server time stamp.
*/
public long toServerTime (long stamp)
{
- // when we calcuated our time delta, we did it such that: C - S =
- // dT, thus to convert server to client time we do: S = C - dT
+ // when we calcuated our time delta, we did it such that: C - S = dT, thus to convert
+ // server to client time we do: S = C - dT
return stamp - _serverDelta;
}
/**
- * Returns true if we are in active communication (we may not yet be logged
- * on, but we could be trying to log on).
+ * Returns true if we are in active communication (we may not yet be logged on, but we could be
+ * trying to log on).
*/
public synchronized boolean isActive ()
{
@@ -357,17 +349,16 @@ public class Client
*/
public synchronized boolean isLoggedOn ()
{
- // we're not "logged on" until we're fully done with the
- // procedure, meaning we have a client object reference
+ // we're not "logged on" until we're fully done with the procedure, meaning we have a
+ // client object reference
return (_clobj != null);
}
/**
- * Requests that this client connect and logon to the server with
- * which it was previously configured.
+ * Requests that this client connect and logon to the server with which it was previously
+ * configured.
*
- * @return false if we're already logged on, true if a logon attempt
- * was initiated.
+ * @return false if we're already logged on, true if a logon attempt was initiated.
*/
public synchronized boolean logon ()
{
@@ -376,14 +367,14 @@ public class Client
return false;
}
- // otherwise create a new communicator instance and start it up.
- // this will initiate the logon process
+ // otherwise create a new communicator instance and start it up. this will initiate the
+ // logon process
_comm = new Communicator(this);
_comm.setClassLoader(_loader);
_comm.logon();
- // register an interval that we'll use to keep the clock synced
- // and to send pings when appropriate
+ // register an interval that we'll use to keep the clock synced and to send pings when
+ // appropriate
if (_tickInterval == null) {
_tickInterval = new Interval() {
public void expired () {
@@ -397,28 +388,23 @@ public class Client
}
/**
- * Requests that the client log off of the server to which it is
- * connected.
+ * Requests that the client log off of the server to which it is connected.
*
- * @param abortable If true, the client will call
- * clientWillDisconnect on all of the client observers
- * and abort the logoff process if any of them return false. If false,
+ * @param abortable If true, the client will call clientWillDisconnect on all of
+ * the client observers and abort the logoff process if any of them return false. If false,
* clientWillDisconnect will not be called at all.
*
- * @return true if the logoff succeeded, false if it failed due to a
- * disagreeable observer.
+ * @return true if the logoff succeeded, false if it failed due to a disagreeable observer.
*/
public boolean logoff (boolean abortable)
{
// if we have no communicator, we're not logged on anyway
if (_comm == null) {
- Log.warning("Ignoring request to logoff because we're not " +
- "logged on.");
+ Log.warning("Ignoring request to logoff because we're not logged on.");
return true;
}
- // if the request is abortable, let's run it past the observers
- // before we act upon it
+ // if the request is abortable, let's run it past the observers before we act upon it
if (abortable && notifyObservers(CLIENT_WILL_LOGOFF, null)) {
return false;
}
@@ -427,29 +413,25 @@ public class Client
_tickInterval.cancel();
_tickInterval = null;
- // ask the communicator to send a logoff message and disconnect
- // from the server
+ // ask the communicator to send a logoff message and disconnect from the server
_comm.logoff();
return true;
}
/**
- * For standalone mode, this notifies observers that the client has logged
- * off and cleans up.
+ * For standalone mode, this notifies observers that the client has logged off and cleans up.
*/
public void standaloneLogoff ()
{
notifyObservers(CLIENT_DID_LOGOFF, null);
cleanup(null);
}
-
+
/**
- * Called by the {@link ClientDObjectMgr} when our bootstrap
- * notification arrives. If the client and server are being run in
- * "merged" mode in a single JVM, this is how the client is configured
- * with the server's distributed object manager and provided with
- * bootstrap data.
+ * Called by the {@link ClientDObjectMgr} when our bootstrap notification arrives. If the
+ * client and server are being run in "merged" mode in a single JVM, this is how the client is
+ * configured with the server's distributed object manager and provided with bootstrap data.
*/
public void gotBootstrap (BootstrapData data, DObjectManager omgr)
{
@@ -465,20 +447,18 @@ public class Client
// initialize our invocation director
_invdir.init(omgr, _cloid, this);
- // send a few pings to the server to establish the clock offset
- // between this client and server standard time
+ // send a few pings to the server to establish the clock offset between this client and
+ // server standard time
establishClockDelta(System.currentTimeMillis());
- // we can't quite call initialization completed at this point
- // because we need for the invocation director to fully initialize
- // (which requires a round trip to the server) before turning the
- // client loose to do things like request invocation services
+ // we can't quite call initialization completed at this point because we need for the
+ // invocation director to fully initialize (which requires a round trip to the server)
+ // before turning the client loose to do things like request invocation services
}
/**
- * Called every five seconds; ensures that we ping the server if we
- * haven't communicated in a long while and periodically resyncs the
- * client and server clock deltas.
+ * Called every five seconds; ensures that we ping the server if we haven't communicated in a
+ * long while and periodically resyncs the client and server clock deltas.
*/
protected void tick ()
{
@@ -501,8 +481,8 @@ public class Client
}
} else if (now - _comm.getLastWrite() > PingRequest.PING_INTERVAL) {
- // if we haven't sent anything over the network in a while, we
- // ping the server to let it know that we're still alive
+ // if we haven't sent anything over the network in a while, we ping the server to let
+ // it know that we're still alive
_comm.postMessage(new PingRequest());
} else if (now - _lastSync > CLOCK_SYNC_INTERVAL) {
@@ -512,10 +492,9 @@ public class Client
}
/**
- * Called during initialization to initiate a sequence of ping/pong
- * messages which will be used to determine (with "good enough"
- * accuracy) the difference between the client clock and the server
- * clock so that we can later interpret server timestamps.
+ * Called during initialization to initiate a sequence of ping/pong messages which will be used
+ * to determine (with "good enough" accuracy) the difference between the client clock and the
+ * server clock so that we can later interpret server timestamps.
*/
protected void establishClockDelta (long now)
{
@@ -530,8 +509,8 @@ public class Client
}
/**
- * Called by the {@link Communicator} if it is experiencing trouble logging
- * on but is still trying fallback strategies.
+ * Called by the {@link Communicator} if it is experiencing trouble logging on but is still
+ * trying fallback strategies.
*/
protected void reportLogonTribulations (final LogonException cause)
{
@@ -543,8 +522,8 @@ public class Client
}
/**
- * Called by the invocation director when it successfully subscribes
- * to the client object immediately following logon.
+ * Called by the invocation director when it successfully subscribes to the client object
+ * immediately following logon.
*/
protected void gotClientObject (ClientObject clobj)
{
@@ -556,8 +535,7 @@ public class Client
}
/**
- * Called by the invocation director if it fails to subscribe to the
- * client object after logon.
+ * Called by the invocation director if it fails to subscribe to the client object after logon.
*/
protected void getClientObjectFailed (Exception cause)
{
@@ -566,8 +544,7 @@ public class Client
}
/**
- * Called by the invocation director when it discovers that the client
- * object has changed.
+ * Called by the invocation director when it discovers that the client object has changed.
*/
protected void clientObjectDidChange (ClientObject clobj)
{
@@ -589,17 +566,16 @@ public class Client
}
};
- // we need to run immediately if this is WILL_LOGOFF or if we have
- // no RunQueue (which currently only happens in some really obscure
- // circumstances where we're using a Client instance on the server
- // so that we can sort of pretend to be a real client)
+ // we need to run immediately if this is WILL_LOGOFF or if we have no RunQueue (which
+ // currently only happens in some really obscure circumstances where we're using a Client
+ // instance on the server so that we can sort of pretend to be a real client)
if (code == CLIENT_WILL_LOGOFF || _runQueue == null) {
unit.run();
return noty.getRejected();
} else {
- // otherwise we can queue this notification up with our
- // RunQueue and ensure that it's run on the proper thread
+ // otherwise we can queue this notification up with our RunQueue and ensure that it's
+ // run on the proper thread
_runQueue.postRunnable(unit);
return false;
}
@@ -607,12 +583,10 @@ public class Client
synchronized void cleanup (final Exception logonError)
{
- // we know that prior to the call to this method, the observers
- // were notified with CLIENT_DID_LOGOFF; that may not have been
- // invoked yet, so we don't want to clear out our communicator
- // reference immediately; instead we queue up a runnable unit to
- // do so to ensure that it won't happen until CLIENT_DID_LOGOFF
- // was dispatched
+ // we know that prior to the call to this method, the observers were notified with
+ // CLIENT_DID_LOGOFF; that may not have been invoked yet, so we don't want to clear out our
+ // communicator reference immediately; instead we queue up a runnable unit to do so to
+ // ensure that it won't happen until CLIENT_DID_LOGOFF was dispatched
_runQueue.postRunnable(new Runnable() {
public void run () {
// clear out our references
@@ -625,11 +599,10 @@ public class Client
// and let our invocation director know we're logged off
_invdir.cleanup();
- // if we were cleaned up due to a failure to logon, we can
- // report the logon error now that the communicator is
- // cleaned up; this allows a logon failure listener to
- // immediately try another logon (hopefully with something
- // changed like the server or port)
+ // if we were cleaned up due to a failure to logon, we can report the logon error
+ // now that the communicator is cleaned up; this allows a logon failure listener to
+ // immediately try another logon (hopefully with something changed like the server
+ // or port)
if (logonError != null) {
notifyObservers(CLIENT_FAILED_TO_LOGON, logonError);
} else {
@@ -640,18 +613,15 @@ public class Client
}
/**
- * Called when we receive a pong packet. We may be in the process of
- * calculating the client/server time differential, or we may have
- * already done that at which point we ignore pongs.
+ * Called when we receive a pong packet. We may be in the process of calculating the client/
+ * server time differential, or we may have already done that at which point we ignore pongs.
*/
void gotPong (PongResponse pong)
{
- // if we're not currently calculating our client/server delta, then
- // we can throw away the pong
+ // if we're not currently calculating our delta, then we can throw away the pong
if (_dcalc != null) {
- // we update the delta after every receipt so as to immediately
- // obtain an estimate of the clock delta and then refine it as
- // more packets come in
+ // we update the delta after every receipt so as to immediately obtain an estimate of
+ // the clock delta and then refine it as more packets come in
_dcalc.gotPong(pong);
_serverDelta = _dcalc.getTimeDelta();
}
@@ -684,8 +654,7 @@ public class Client
case CLIENT_FAILED_TO_LOGON:
if (obs instanceof ClientObserver) {
- ((ClientObserver)obs).clientFailedToLogon(
- Client.this, _cause);
+ ((ClientObserver)obs).clientFailedToLogon(Client.this, _cause);
}
break;
@@ -697,8 +666,7 @@ public class Client
case CLIENT_CONNECTION_FAILED:
if (obs instanceof ClientObserver) {
- ((ClientObserver)obs).clientConnectionFailed(
- Client.this, _cause);
+ ((ClientObserver)obs).clientConnectionFailed(Client.this, _cause);
}
break;
@@ -721,8 +689,7 @@ public class Client
break;
default:
- throw new RuntimeException("Invalid code supplied to " +
- "notifyObservers: " + _code);
+ throw new RuntimeException("Invalid code supplied to notifyObservers: " + _code);
}
return true;
@@ -739,8 +706,7 @@ public class Client
/** The version string reported to the server at auth time. */
protected String _version = "";
- /** An entity that gives us the ability to process events on the main
- * client thread. */
+ /** An entity that gives us the ability to process events on the main client thread. */
protected RunQueue _runQueue;
/** The distributed object manager we're using during this session. */
@@ -757,7 +723,7 @@ public class Client
/** Whether or not this client is operating in a standalone mode. */
protected boolean _standalone;
-
+
/** The game server host. */
protected String _hostname;
@@ -771,22 +737,23 @@ public class Client
/** The entity that manages our network communications. */
protected Communicator _comm;
- /** A custom class loader used to load objects that come in over the
- * network. */
+ /** A custom class loader used to load objects that come in over the network. */
protected ClassLoader _loader = getClass().getClassLoader();
/** General startup information provided by the server. */
protected BootstrapData _bstrap;
+ /** The set of bootstrap service groups this client cares about. */
+ protected HashSet
* Logon synopsis:
@@ -79,8 +78,7 @@ import com.threerings.presents.net.UpstreamMessage;
public class Communicator
{
/**
- * Creates a new communicator instance which is associated with the
- * supplied client.
+ * Creates a new communicator instance which is associated with the supplied client.
*/
public Communicator (Client client)
{
@@ -88,8 +86,7 @@ public class Communicator
}
/**
- * Logs on to the server and initiates our full-duplex message
- * exchange.
+ * Logs on to the server and initiates our full-duplex message exchange.
*/
public void logon ()
{
@@ -98,21 +95,19 @@ public class Communicator
throw new RuntimeException("Communicator already started.");
}
- // start up the reader thread. it will connect to the server and
- // start up the writer thread if everything went successfully
+ // start up the reader thread. it will connect to the server and start up the writer thread
+ // if everything went successfully
_reader = new Reader();
_reader.start();
}
/**
- * Delivers a logoff notification to the server and shuts down the
- * network connection. Also causes all communication threads to
- * terminate.
+ * Delivers a logoff notification to the server and shuts down the network connection. Also
+ * causes all communication threads to terminate.
*/
public synchronized void logoff ()
{
- // if our socket is already closed, we've already taken care of
- // this business
+ // if our socket is already closed, we've already taken care of this business
if (_channel == null) {
return;
}
@@ -122,27 +117,22 @@ public class Communicator
// let our reader and writer know that it's time to go
if (_reader != null) {
- // if logoff() is being called by the client as part of a
- // normal shutdown, this will cause the reader thread to be
- // interrupted and shutdown gracefully. if logoff is being
- // called by the reader thread as a result of a failed socket,
- // it won't interrupt itself as it is already shutting down
- // gracefully. if the JVM is buggy and calling interrupt() on
- // a thread that is blocked on a socket doesn't wake it up,
- // then when we close() the socket a bit further down, we have
- // another chance that the reader thread will wake up; this
- // time slightly less gracefully because it will think there's
- // a network error when in fact we're just shutting down, but
- // at least it will cleanly exit
+ // if logoff() is being called by the client as part of a normal shutdown, this will
+ // cause the reader thread to be interrupted and shutdown gracefully. if logoff is
+ // being called by the reader thread as a result of a failed socket, it won't interrupt
+ // itself as it is already shutting down gracefully. if the JVM is buggy and calling
+ // interrupt() on a thread that is blocked on a socket doesn't wake it up, then when we
+ // close() the socket a bit further down, we have another chance that the reader thread
+ // will wake up; this time slightly less gracefully because it will think there's a
+ // network error when in fact we're just shutting down, but at least it will cleanly
+ // exit
_reader.shutdown();
}
if (_writer != null) {
- // shutting down the writer thread is simpler because we can
- // post a termination message on the queue and be sure that it
- // will receive it. when the writer thread has delivered our
- // logoff request and exited, we will complete the logoff
- // process by closing our socket and invoking the
- // clientDidLogoff callback
+ // shutting down the writer thread is simpler because we can post a termination message
+ // on the queue and be sure that it will receive it. when the writer thread has
+ // delivered our logoff request and exited, we will complete the logoff process by
+ // closing our socket and invoking the clientDidLogoff callback
_writer.shutdown();
}
}
@@ -157,8 +147,8 @@ public class Communicator
}
/**
- * Configures this communicator with a custom class loader to be used
- * when reading and writing objects over the network.
+ * Configures this communicator with a custom class loader to be used when reading and writing
+ * objects over the network.
*/
public void setClassLoader (ClassLoader loader)
{
@@ -169,10 +159,9 @@ public class Communicator
}
/**
- * Callback called by the reader when the authentication process
- * completes successfully. Here we extract the bootstrap information
- * for the client and start up the writer thread to manage the other
- * half of our bi-directional message stream.
+ * Callback called by the reader when the authentication process completes successfully. Here
+ * we extract the bootstrap information for the client and start up the writer thread to manage
+ * the other half of our bi-directional message stream.
*/
protected synchronized void logonSucceeded (AuthResponseData data)
{
@@ -188,22 +177,21 @@ public class Communicator
_writer = new Writer();
_writer.start();
- // fill the auth data into the client's local field so that it can
- // be requested by external entities
+ // fill the auth data into the client's local field so that it can be requested by external
+ // entities
_client._authData = data;
- // wait for the bootstrap notification before we claim that we're
- // actually logged on
+ // wait for the bootstrap notification before we claim that we're actually logged on
}
/**
- * Callback called by the reader or writer thread when something goes
- * awry with our socket connection to the server.
+ * Callback called by the reader or writer thread when something goes awry with our socket
+ * connection to the server.
*/
protected synchronized void connectionFailed (IOException ioe)
{
- // make sure the socket isn't already closed down (meaning we've
- // already dealt with the failed connection)
+ // make sure the socket isn't already closed down (meaning we've already dealt with the
+ // failed connection)
if (_channel == null) {
return;
}
@@ -219,13 +207,12 @@ public class Communicator
}
/**
- * Callback called by the reader if the server closes the other end of
- * the connection.
+ * Callback called by the reader if the server closes the other end of the connection.
*/
protected synchronized void connectionClosed ()
{
- // make sure the socket isn't already closed down (meaning we've
- // already dealt with the closed connection)
+ // make sure the socket isn't already closed down (meaning we've already dealt with the
+ // closed connection)
if (_channel == null) {
return;
}
@@ -244,8 +231,8 @@ public class Communicator
_reader = null;
if (_writer == null) {
- // there's no writer during authentication, so we may be
- // responsible for closing the socket channel
+ // there's no writer during authentication, so we may be responsible for closing the
+ // socket channel
closeChannel();
// let the client know when we finally go away
@@ -267,9 +254,8 @@ public class Communicator
// let the client observers know that we're logged off
_client.notifyObservers(Client.CLIENT_DID_LOGOFF, null);
- // now that the writer thread has gone away, we can safely close
- // our socket and let the client know that the logoff process has
- // completed
+ // now that the writer thread has gone away, we can safely close our socket and let the
+ // client know that the logoff process has completed
closeChannel();
// let the client know when we finally go away
@@ -279,9 +265,8 @@ public class Communicator
}
/**
- * Closes the socket channel that we have open to the server. Called
- * by either {@link #readerDidExit} or {@link #writerDidExit}
- * whichever is called last.
+ * Closes the socket channel that we have open to the server. Called by either {@link
+ * #readerDidExit} or {@link #writerDidExit} whichever is called last.
*/
protected void closeChannel ()
{
@@ -319,16 +304,13 @@ public class Communicator
try {
ByteBuffer buffer = _fout.frameAndReturnBuffer();
if (buffer.limit() > 4096) {
- String txt = StringUtil.truncate(
- String.valueOf(msg), 80, "...");
- Log.info("Whoa, writin' a big one [msg=" + txt +
- ", size=" + buffer.limit() + "].");
+ String txt = StringUtil.truncate(String.valueOf(msg), 80, "...");
+ Log.info("Whoa, writin' a big one [msg=" + txt + ", size=" + buffer.limit() + "].");
}
int wrote = _channel.write(buffer);
if (wrote != buffer.limit()) {
Log.warning("Aiya! Couldn't write entire message [msg=" + msg +
- ", size=" + buffer.limit() +
- ", wrote=" + wrote + "].");
+ ", size=" + buffer.limit() + ", wrote=" + wrote + "].");
// } else {
// Log.info("Wrote " + wrote + " bytes.");
}
@@ -350,8 +332,7 @@ public class Communicator
}
/**
- * Makes a note of the time at which we last communicated with the
- * server.
+ * Makes a note of the time at which we last communicated with the server.
*/
protected synchronized void updateWriteStamp ()
{
@@ -359,17 +340,15 @@ public class Communicator
}
/**
- * Reads a new message from the socket (blocking until a message has
- * arrived).
+ * Reads a new message from the socket (blocking until a message has arrived).
*/
protected DownstreamMessage receiveMessage ()
throws IOException
{
- // read in the next message frame (readFrame() can return false
- // meaning it only read part of the frame from the network, in
- // which case we simply call it again because we can't do anything
- // until it has a whole frame; it will throw an exception if it
- // hits EOF or if something goes awry)
+ // read in the next message frame (readFrame() can return false meaning it only read part
+ // of the frame from the network, in which case we simply call it again because we can't do
+ // anything until it has a whole frame; it will throw an exception if it hits EOF or if
+ // something goes awry)
while (!_fin.readFrame(_channel));
try {
@@ -386,8 +365,8 @@ public class Communicator
}
/**
- * Callback called by the reader thread when it has parsed a new
- * message from the socket and wishes to have it processed.
+ * Callback called by the reader thread when it has parsed a new message from the socket and
+ * wishes to have it processed.
*/
protected void processMessage (DownstreamMessage msg)
{
@@ -396,9 +375,8 @@ public class Communicator
}
/**
- * Cancels our preferred port saving interval. This method is called from
- * the communication reader thread and the interval thread and must thus be
- * synchronized.
+ * Cancels our preferred port saving interval. This method is called from the communication
+ * reader thread and the interval thread and must thus be synchronized.
*/
protected synchronized boolean clearPPI (boolean cancel)
{
@@ -414,10 +392,9 @@ public class Communicator
}
/**
- * The reader encapsulates the authentication and message reading
- * process. It calls back to the Communicator class to do
- * things, but the general flow of the reader thread is encapsulated
- * in this class.
+ * The reader encapsulates the authentication and message reading process. It calls back to the
+ * {@link Communicator} class to do things, but the general flow of the reader thread is
+ * encapsulated in this class.
*/
protected class Reader extends LoopingThread
{
@@ -452,8 +429,8 @@ public class Communicator
// look up the address of the target server
InetAddress host = InetAddress.getByName(_client.getHostname());
- // obtain the list of available ports on which to attempt our
- // client connection and determine our preferred port
+ // obtain the list of available ports on which to attempt our client connection and
+ // determine our preferred port
String pportKey = _client.getHostname() + ".preferred_port";
int[] ports = _client.getPorts();
int pport = PresentsPrefs.config.getValue(pportKey, ports[0]);
@@ -468,18 +445,16 @@ public class Communicator
try {
synchronized (Communicator.this) {
clearPPI(true);
- _prefPortInterval =
- new PrefPortInterval(pportKey, port, nextPort);
+ _prefPortInterval = new PrefPortInterval(pportKey, port, nextPort);
_channel = SocketChannel.open(addr);
_prefPortInterval.schedule(PREF_PORT_DELAY);
}
break;
+
} catch (IOException ioe) {
- if (ioe instanceof ConnectException &&
- ii < (ports.length-1)) {
+ if (ioe instanceof ConnectException && ii < (ports.length-1)) {
_client.reportLogonTribulations(
- new LogonException(
- AuthCodes.TRYING_NEXT_PORT, true));
+ new LogonException(AuthCodes.TRYING_NEXT_PORT, true));
continue; // try the next port
}
throw ioe;
@@ -488,8 +463,8 @@ public class Communicator
_channel.configureBlocking(true);
- // our messages are framed (preceded by their length), so we
- // use these helper streams to manage the framing
+ // our messages are framed (preceded by their length), so we use these helper streams
+ // to manage the framing
_fin = new FramedInputStream();
_fout = new FramingOutputStream();
@@ -503,8 +478,8 @@ public class Communicator
throws IOException, LogonException
{
// construct an auth request and send it
- AuthRequest req = new AuthRequest(_client.getCredentials(),
- _client.getVersion());
+ AuthRequest req = new AuthRequest(
+ _client.getCredentials(), _client.getVersion(), _client._bootGroups);
sendMessage(req);
// now wait for the auth response
@@ -513,8 +488,8 @@ public class Communicator
AuthResponseData data = rsp.getData();
Log.debug("Got auth response: " + data);
- // if the auth request failed, we want to let the communicator
- // know by throwing a logon exception
+ // if the auth request failed, we want to let the communicator know by throwing a logon
+ // exception
if (!data.code.equals(AuthResponseData.SUCCESS)) {
throw new LogonException(data.code);
}
@@ -523,9 +498,8 @@ public class Communicator
logonSucceeded(data);
}
- // now that we're authenticated, we manage the reading
- // half of things by continuously reading messages from
- // the socket and processing them
+ // now that we're authenticated, we manage the reading half of things by continuously
+ // reading messages from the socket and processing them
protected void iterate ()
{
DownstreamMessage msg = null;
@@ -538,14 +512,12 @@ public class Communicator
processMessage(msg);
} catch (InterruptedIOException iioe) {
- // somebody set up us the bomb! we've been interrupted
- // which means that we're being shut down, so we just
- // report it and return from iterate() like a good monkey
+ // somebody set up us the bomb! we've been interrupted which means that we're being
+ // shut down, so we just report it and return from iterate() like a good monkey
Log.debug("Reader thread woken up in time to die.");
} catch (EOFException eofe) {
- // let the communicator know that our connection was
- // closed
+ // let the communicator know that our connection was closed
connectionClosed();
// and shut ourselves down
shutdown();
@@ -557,8 +529,7 @@ public class Communicator
shutdown();
} catch (Exception e) {
- Log.warning("Error processing message [msg=" + msg +
- ", error=" + e + "].");
+ Log.warning("Error processing message [msg=" + msg + ", error=" + e + "].");
}
}
@@ -570,8 +541,8 @@ public class Communicator
protected void didShutdown ()
{
- // If we haven't recorded a preferred port yet, instead do the
- // failure action since we didn't stay connected long enough.
+ // if we haven't recorded a preferred port yet, instead do the failure action since we
+ // didn't stay connected long enough
clearPPI(true);
// let the communicator know when we finally go away
@@ -580,17 +551,16 @@ public class Communicator
protected void kick ()
{
- // we want to interrupt the reader thread as it may be blocked
- // listening to the socket; this is only called if the reader
- // thread doesn't shut itself down
+ // we want to interrupt the reader thread as it may be blocked listening to the socket;
+ // this is only called if the reader thread doesn't shut itself down
// interrupt();
}
}
/**
- * The writer encapsulates the message writing process. It calls back
- * to the Communicator class to do things, but the
- * general flow of the writer thread is encapsulated in this class.
+ * The writer encapsulates the message writing process. It calls back to the {@link
+ * Communicator} class to do things, but the general flow of the writer thread is encapsulated
+ * in this class.
*/
protected class Writer extends LoopingThread
{
@@ -599,9 +569,8 @@ public class Communicator
// fetch the next message from the queue
UpstreamMessage msg = _msgq.get();
- // if this is a termination message, we're being
- // requested to exit, so we want to bail now rather
- // than continuing
+ // if this is a termination message, we're being requested to exit, so we want to bail
+ // now rather than continuing
if (msg instanceof TerminationMessage) {
return;
}
@@ -611,8 +580,7 @@ public class Communicator
sendMessage(msg);
} catch (IOException ioe) {
- // let the communicator know if we have any
- // problems
+ // let the communicator know if we have any problems
connectionFailed(ioe);
// and bail
shutdown();
@@ -632,8 +600,8 @@ public class Communicator
protected void kick ()
{
- // post a bogus message to the outgoing queue to ensure that
- // the writer thread notices that it's time to go
+ // post a bogus message to the outgoing queue to ensure that the writer thread notices
+ // that it's time to go
postMessage(new TerminationMessage());
}
}
@@ -643,12 +611,11 @@ public class Communicator
{
}
- /** Used to save our preferred port once we know our connection is not
- * going to be unceremoniously closed by Windows Connection Sharing. */
+ /** Used to save our preferred port once we know our connection is not going to be
+ * unceremoniously closed by Windows Connection Sharing. */
protected class PrefPortInterval extends Interval
{
- public PrefPortInterval (String key, int thisPort, int nextPort)
- {
+ public PrefPortInterval (String key, int thisPort, int nextPort) {
super();
_key = key;
_thisPort = thisPort;
@@ -691,8 +658,7 @@ public class Communicator
protected ClientDObjectMgr _omgr;
protected ClassLoader _loader;
- /** We use this interval to record the preferred port if it stays connected
- * long enough. */
+ /** We use this interval to record the preferred port if it stays connected long enough. */
protected PrefPortInterval _prefPortInterval;
/** Time a port must remain connected before we mark it as preferred. */
@@ -700,8 +666,7 @@ public class Communicator
/** Used to control low-level message logging. */
protected static RuntimeAdjust.BooleanAdjust _logMessages =
- new RuntimeAdjust.BooleanAdjust(
- "Toggles whether or not all sent and received low-level " +
- "network events are logged.", "narya.presents.log_events",
- PresentsPrefs.config, false);
+ new RuntimeAdjust.BooleanAdjust("Toggles whether or not all sent and received low-level " +
+ "network events are logged.", "narya.presents.log_events",
+ PresentsPrefs.config, false);
}
diff --git a/src/java/com/threerings/presents/net/AuthRequest.java b/src/java/com/threerings/presents/net/AuthRequest.java
index bf7ba3d2c..7a21b5721 100644
--- a/src/java/com/threerings/presents/net/AuthRequest.java
+++ b/src/java/com/threerings/presents/net/AuthRequest.java
@@ -21,8 +21,12 @@
package com.threerings.presents.net;
+import java.util.HashSet;
import java.util.TimeZone;
+/**
+ * Used to authenticate with the server.
+ */
public class AuthRequest extends UpstreamMessage
{
/**
@@ -34,14 +38,14 @@ public class AuthRequest extends UpstreamMessage
}
/**
- * Constructs a auth request with the supplied credentials and client
- * version information.
+ * Constructs a auth request with the supplied credentials and client version information.
*/
- public AuthRequest (Credentials creds, String version)
+ public AuthRequest (Credentials creds, String version, HashSetBootstrapData object is communicated back to the client
* after authentication has succeeded and after the server is fully
@@ -36,5 +38,5 @@ public class BootstrapData extends SimpleStreamableObject
public int clientOid;
/** A list of handles to invocation services. */
- public StreamableArrayList services;
+ public StreamableArrayListSubscriber implementation (which is called
- * from the dobjmgr thread) can proceed without synchronization. This does
- * not overlap with its other client duties which are called from the
- * conmgr thread and therefore also need not be synchronized.
+ * Subscriber implementation (which is called from the dobjmgr thread) can proceed
+ * without synchronization. This does not overlap with its other client duties which are called
+ * from the conmgr thread and therefore also need not be synchronized.
*/
public class PresentsClient
implements ProxySubscriber, MessageHandler, ClientResolutionListener
@@ -82,23 +81,19 @@ public class PresentsClient
/** Used by {@link #setUsername} to report success or failure. */
public static interface UserChangeListener
{
- /** Called when the new client object has been resolved and the
- * new client object reported to the client, but the old one has
- * not yet been destroyed. Any events delivered on this callback
- * to the old client object will be delivered.
+ /** Called when the new client object has been resolved and the new client object reported
+ * to the client, but the old one has not yet been destroyed. Any events delivered on this
+ * callback to the old client object will be delivered.
*
- * @param rl when this method is finished with its business and
- * the old client object can be destroyed, the result listener
- * should be called.
- * */
+ * @param rl when this method is finished with its business and the old client object can
+ * be destroyed, the result listener should be called. */
public void changeReported (ClientObject newObji, ResultListener rl);
- /** Called when the user change is completed, the old client
- * object is destroyed and all updates are committed. */
+ /** Called when the user change is completed, the old client object is destroyed and all
+ * updates are committed. */
public void changeCompleted (ClientObject newObj);
- /** Called if some failure occurs during the user change
- * process. */
+ /** Called if some failure occurs during the user change process. */
public void changeFailed (Exception cause);
}
@@ -119,8 +114,8 @@ public class PresentsClient
}
/**
- * Returns true if this client has been disconnected for sufficiently
- * long that its session should be forcibly ended.
+ * Returns true if this client has been disconnected for sufficiently long that its session
+ * should be forcibly ended.
*/
public boolean checkExpired (long now)
{
@@ -128,8 +123,7 @@ public class PresentsClient
}
/**
- * Returns the time at which this client started their network
- * session.
+ * Returns the time at which this client started their network session.
*/
public long getSessionStamp ()
{
@@ -137,8 +131,7 @@ public class PresentsClient
}
/**
- * Returns the time at which this client most recently connected or
- * disconnected.
+ * Returns the time at which this client most recently connected or disconnected.
*/
public long getNetworkStamp ()
{
@@ -154,8 +147,7 @@ public class PresentsClient
}
/**
- * Returns the address of the connected client or null if this client
- * is not connected.
+ * Returns the address of the connected client or null if this client is not connected.
*/
public InetAddress getInetAddress ()
{
@@ -164,8 +156,8 @@ public class PresentsClient
}
/**
- * Configures this client with a custom class loader that will be used
- * when unserializing classes from the network.
+ * Configures this client with a custom class loader that will be used when unserializing
+ * classes from the network.
*/
public void setClassLoader (ClassLoader loader)
{
@@ -177,38 +169,32 @@ public class PresentsClient
}
/**
- * Danger: this method is not for general consumption. This
- * changes the username of the client, but should only be done very
- * early in a user's session, when you know that no one has mapped the
- * user based on their username or has in any other way made use of
- * their username in a way that will break. However, it should not be
- * done too early in the session. The client must be fully
- * resolved.
+ * Danger: this method is not for general consumption. This changes the username of
+ * the client, but should only be done very early in a user's session, when you know that no
+ * one has mapped the user based on their username or has in any other way made use of their
+ * username in a way that will break. However, it should not be done too early in the
+ * session. The client must be fully resolved.
*
- * super.sessionWillStart.
+ * Called when the client session is first started. The client object has been created at this
+ * point and after this method is executed, the bootstrap information will be sent to the
+ * client which will trigger the start of the session. Derived classes that override this
+ * method should be sure to call super.sessionWillStart.
*
- * super.sessionWillResume.
+ * Called when the client resumes a session (after having disconnected and reconnected). After
+ * this method is executed, the bootstrap information will be sent to the client which will
+ * trigger the resumption of the session. Derived classes that override this method should be
+ * sure to call super.sessionWillResume.
*
- * super.sessionDidEnd.
+ * Called when the client session ends (either because the client logged off or because the
+ * server forcibly terminated the session). Derived classes that override this method should
+ * be sure to call super.sessionDidEnd.
*
- * super.populateBootstrapData before doing their
- * own populating, however.
+ * Derived client classes can override this member to populate the bootstrap data with
+ * additional information. They should be sure to call super.populateBootstrapData
+ * before doing their own populating, however.
*
- * connectionFailed) or it may be because of an orderly
- * closing of the connection. In either case, the client can deal with
- * its lack of a connection in this method. This is invoked by the
- * conmgr thread and should behave accordingly.
+ * Called by the connection manager when this client's connection is unmapped. That may be
+ * because of a connection failure (in which case this call will be followed up by a call to
+ * connectionFailed) or it may be because of an orderly closing of the
+ * connection. In either case, the client can deal with its lack of a connection in this
+ * method. This is invoked by the conmgr thread and should behave accordingly.
*/
protected void wasUnmapped ()
{
// clear out our connection reference
setConnection(null);
- // clear out our subscriptions. we need to do this on the dobjmgr
- // thread. it is important that we do this *after* we clear out
- // our connection reference. once the connection ref is null, no
- // more subscriptions will be processed (even those that were
- // queued up before the connection went away)
+ // clear out our subscriptions. we need to do this on the dobjmgr thread. it is important
+ // that we do this *after* we clear out our connection reference. once the connection ref
+ // is null, no more subscriptions will be processed (even those that were queued up before
+ // the connection went away)
PresentsServer.omgr.postRunnable(new Runnable() {
public void run () {
sessionConnectionClosed();
@@ -736,38 +688,33 @@ public class PresentsClient
}
/**
- * Called on the dobjmgr thread when the connection associated with
- * this session has been closed and unmapped. If the user logged off
- * before closing their connection, this will be preceded by a call to
- * {@link #sessionDidEnd}.
+ * Called on the dobjmgr thread when the connection associated with this session has been
+ * closed and unmapped. If the user logged off before closing their connection, this will be
+ * preceded by a call to {@link #sessionDidEnd}.
*/
protected void sessionConnectionClosed ()
{
- // clear out our dobj subscriptions in case they weren't cleared
- // by a call to sessionDidEnd
+ // clear out our dobj subscriptions in case they weren't cleared by a call to sessionDidEnd
clearSubscrips(false);
}
/**
- * Called by the connection manager when this client's connection
- * fails. This is invoked on the conmgr thread and should behave
- * accordingly.
+ * Called by the connection manager when this client's connection fails. This is invoked on the
+ * conmgr thread and should behave accordingly.
*/
protected void connectionFailed (IOException fault)
{
- // nothing to do here presently. the client manager already
- // complained about the failed connection
+ // nothing to do here, the client manager already complained about the failed connection
}
/**
- * Sets our connection reference in a thread safe way. Also
- * establishes the back reference to us as the connection's message
- * handler.
+ * Sets our connection reference in a thread safe way. Also establishes the back reference to
+ * us as the connection's message handler.
*/
protected synchronized void setConnection (Connection conn)
{
- // if our connection is being cleared out, record the amount of
- // time we were connected to our total connected time
+ // if our connection is being cleared out, record the amount of time we were connected to
+ // our total connected time
long now = System.currentTimeMillis();
if (_conn != null && conn == null) {
_connectTime += ((now - _networkStamp) / 1000);
@@ -776,8 +723,8 @@ public class PresentsClient
// keep a handle to the new connection
_conn = conn;
- // tell the connection to pass messages on to us (if we're setting
- // a connection rather than clearing one out)
+ // tell the connection to pass messages on to us (if we're setting a connection rather than
+ // clearing one out)
if (_conn != null) {
_conn.setMessageHandler(this);
@@ -792,20 +739,19 @@ public class PresentsClient
}
/**
- * The connection instance must be accessed via this member function
- * because it is read from both the dobjmgr and conmgr threads and is
- * modified by the conmgr thread.
+ * The connection instance must be accessed via this member function because it is read from
+ * both the dobjmgr and conmgr threads and is modified by the conmgr thread.
*
- * @return The connection instance associated with this client or null
- * if the client is not currently connected.
+ * @return The connection instance associated with this client or null if the client is not
+ * currently connected.
*/
protected synchronized Connection getConnection ()
{
return _conn;
}
- /** Callable from non-dobjmgr thread, this queues up a runnable on the
- * dobjmgr thread to post the supplied message to this client. */
+ /** Callable from non-dobjmgr thread, this queues up a runnable on the dobjmgr thread to post
+ * the supplied message to this client. */
protected final void safePostMessage (final DownstreamMessage msg)
{
PresentsServer.omgr.postRunnable(new Runnable() {
@@ -825,9 +771,8 @@ public class PresentsClient
return true;
}
- // don't log dropped messages unless we're dropping a lot of them
- // (meaning something is still queueing messages up for this dead
- // client even though it shouldn't be)
+ // don't log dropped messages unless we're dropping a lot of them (meaning something is
+ // still queueing messages up for this dead client even though it shouldn't be)
if (++_messagesDropped % 50 == 0) {
Log.warning("Dropping many messages? [client=" + this +
", count=" + _messagesDropped + "].");
@@ -859,17 +804,15 @@ public class PresentsClient
{
buf.append("username=").append(_username);
buf.append(", conn=").append(_conn);
- buf.append(", cloid=").append(
- (_clobj == null) ? -1 : _clobj.getOid());
+ buf.append(", cloid=").append((_clobj == null) ? -1 : _clobj.getOid());
buf.append(", in=").append(_messagesIn);
buf.append(", out=").append(_messagesOut);
}
/**
- * Message dispatchers are used to dispatch each different type of
- * upstream message. We can look the dispatcher up in a table and
- * invoke it through an overloaded member which is faster (so we
- * think) than doing a bunch of instanceofs.
+ * Message dispatchers are used to dispatch each different type of upstream message. We can
+ * look the dispatcher up in a table and invoke it through an overloaded member which is faster
+ * (so we think) than doing a bunch of instanceofs.
*/
protected static interface MessageDispatcher
{
@@ -887,8 +830,7 @@ public class PresentsClient
public void dispatch (PresentsClient client, UpstreamMessage msg)
{
SubscribeRequest req = (SubscribeRequest)msg;
-// Log.info("Subscribing [client=" + client +
-// ", oid=" + req.getOid() + "].");
+// Log.info("Subscribing [client=" + client + ", oid=" + req.getOid() + "].");
// forward the subscribe request to the omgr for processing
PresentsServer.omgr.subscribeToObject(req.getOid(), client);
@@ -911,8 +853,8 @@ public class PresentsClient
// update our subscription tracking table
client.unmapSubscrip(oid);
- // post a response to the client letting them know that we
- // will no longer send them events regarding this object
+ // post a response to the client letting them know that we will no longer send them
+ // events regarding this object
client.safePostMessage(new UnsubscribeResponse(oid));
}
}
@@ -930,8 +872,7 @@ public class PresentsClient
// fill in the proper source oid
fevt.setSourceOid(client.getClientObject().getOid());
-// Log.info("Forwarding event [client=" + client +
-// ", event=" + fevt + "].");
+// Log.info("Forwarding event [client=" + client + ", event=" + fevt + "].");
// forward the event to the omgr for processing
PresentsServer.omgr.postEvent(fevt);
@@ -975,16 +916,15 @@ public class PresentsClient
/** The time at which this client started their session. */
protected long _sessionStamp;
- /** The time at which this client most recently connected or
- * disconnected. */
+ /** The time at which this client most recently connected or disconnected. */
protected long _networkStamp;
- /** The total number of seconds for which the user was connected to
- * the server in this session. */
+ /** The total number of seconds for which the user was connected to the server in this
+ * session. */
protected int _connectTime;
- /** Prevent the client from sending too many messages too frequently.
- * 100 messages in 10 seconds and you're audi. */
+ /** Prevent the client from sending too many messages too frequently. 100 messages in 10
+ * seconds and you're audi like 5000. */
protected Throttle _throttle = new Throttle(100, 10 * 1000L);
// keep these for kicks and giggles
@@ -996,8 +936,8 @@ public class PresentsClient
protected static HashMap