Finished up session termination processing; added code to track

subscriptions and clear them out when the client disconnects.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@189 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-08-07 21:20:48 +00:00
parent 782e9501d6
commit 71de825456
3 changed files with 134 additions and 41 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ Cher Notes -*- outline -*-
* TODO
Pass cause back to client somehow via FailureResponse in Client.requestFailed
Implement object destroyed; finish wiring up oid list tracking.
Finish wiring up oid list tracking.
Ensure at time of OBJECT_ADDED that the object being added exists and has
not been destroyed.
@@ -1,5 +1,5 @@
//
// $Id: ClientManager.java,v 1.9 2001/08/04 01:54:34 mdb Exp $
// $Id: ClientManager.java,v 1.10 2001/08/07 21:20:48 mdb Exp $
package com.threerings.cocktail.cher.server;
@@ -140,7 +140,9 @@ public class ClientManager implements ConnectionObserver
if (client != null) {
Log.info("Unmapped failed client [client=" + client +
", conn=" + conn + ", fault=" + fault + "].");
// let the client know things went haywire
// let the client know the connection went away
client.wasUnmapped();
// and let the client know things went haywire
client.connectionFailed(fault);
} else {
@@ -161,6 +163,9 @@ public class ClientManager implements ConnectionObserver
if (client != null) {
Log.info("Unmapped client [client=" + client +
", conn=" + conn + "].");
// let the client know the connection went away
client.wasUnmapped();
} else {
Log.info("Closed unmapped connection? [conn=" + conn + "].");
}
@@ -1,16 +1,19 @@
//
// $Id: PresentsClient.java,v 1.15 2001/08/04 03:26:00 mdb Exp $
// $Id: PresentsClient.java,v 1.16 2001/08/07 21:20:48 mdb Exp $
package com.threerings.cocktail.cher.server;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import com.threerings.cocktail.cher.Log;
import com.threerings.cocktail.cher.data.ClientObject;
import com.threerings.cocktail.cher.dobj.*;
import com.threerings.cocktail.cher.net.*;
import com.threerings.cocktail.cher.server.net.*;
import com.threerings.cocktail.cher.util.IntMap;
/**
* A client object represents a client session in the server. It is
@@ -116,36 +119,18 @@ public class CherClient implements Subscriber, MessageHandler
// we need to get onto the distributed object thread so that we
// can finalize the resumption of the session. we do so by
// subscribing to the client object (to which we are normally not
// subscribed in between active connections)
Subscriber sub = new Subscriber() {
public void objectAvailable (DObject dobj)
// posting a special event
DEvent event = new DEvent(0)
{
public boolean applyToObject (DObject target)
{
// we don't want to continue to be subscribed to the
// client object so we remove our subscription
dobj.removeSubscriber(this);
// now that we're on the dobjmgr thread we can resume our
// session resumption
finishResumeSession();
}
public void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Not able to subscribe to client object and " +
"resume session!? [client=" + CherClient.this +
", cause=" + cause + "].");
}
public boolean handleEvent (DEvent event, DObject target)
{
Log.warning("Resuming subscriber received an event!? " +
"[client=" + CherClient.this +
", event=" + event + "].");
// we shouldn't have been subscribed in the first place
return false;
}
};
CherServer.omgr.subscribeToObject(_clobj.getOid(), sub);
CherServer.omgr.postEvent(event);
}
/**
@@ -165,6 +150,78 @@ public class CherClient implements Subscriber, MessageHandler
Log.info("Session resumed [client=" + this + "].");
}
/**
* Requests that the client session be terminated. This is normally
* invoked as a result of a logoff request by the client. It should
* only be invoked from the conmgr thread.
*/
public void endSession ()
{
// close our connection (which results in everything being
// properly unregistered)
Connection conn = getConnection();
if (conn != null) {
conn.close();
} else {
Log.info("Unable to close connection for logoff request " +
"[client=" + this + "].");
}
// then let the client manager know what's up
_cmgr.clientDidEndSession(this);
// we need to get onto the distributed object thread so that we
// can finalize the ending of the session. we do so by posting a
// special event
DEvent event = new DEvent(0)
{
public boolean applyToObject (DObject target)
{
// now that we're on the dobjmgr thread we can call into
// our derived classes to finish the session termination
sessionDidTerminate();
return false;
}
};
CherServer.omgr.postEvent(event);
}
/**
* 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)
{
_subscrips.put(object.getOid(), object);
}
/**
* 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)
{
_subscrips.remove(oid);
}
/**
* Clears out the tracked client subscriptions. Called when the client
* goes away and shouldn't be called otherwise.
*/
protected synchronized void clearSubscrips ()
{
Enumeration enum = _subscrips.elements();
while (enum.hasMoreElements()) {
DObject object = (DObject)enum.nextElement();
// Log.info("Clearing subscription [client=" + this +
// ", obj=" + object + "].");
object.removeSubscriber(this);
}
}
/**
* Called when the client session is first started. The client object
* has been created at this point and after this method is executed,
@@ -208,6 +265,8 @@ public class CherClient implements Subscriber, MessageHandler
*/
protected void sessionDidTerminate ()
{
// destroy the client object
CherServer.omgr.destroyObject(_clobj.getOid());
}
/**
@@ -256,15 +315,46 @@ public class CherClient implements Subscriber, MessageHandler
data.invOid = CherServer.invmgr.getOid();
}
/**
* 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
* <code>connectionFailed</code>) 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. so we do so by posting a special event. 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)
DEvent event = new DEvent(0)
{
public boolean applyToObject (DObject target)
{
clearSubscrips();
return false;
}
};
CherServer.omgr.postEvent(event);
}
/**
* Called by the connection manager when this client's connection
* fails. This is invoked on the conmgr thread, and should behave
* fails. This is invoked on the conmgr thread and should behave
* accordingly.
*/
protected void connectionFailed (IOException fault)
{
// clear out our connection reference
setConnection(null);
// nothing to do here presently. the client manager already
// complained about the failed connection
}
/**
@@ -319,7 +409,11 @@ public class CherClient implements Subscriber, MessageHandler
// queue up an object response
Connection conn = getConnection();
if (conn != null) {
// pass the successful subscrip on to the client
conn.postMessage(new ObjectResponse(object));
// make a note of this new subscription
mapSubscrip(object);
} else {
Log.info("Dropped object available notification " +
"[client=" + this + ", oid=" + object.getOid() + "].");
@@ -404,6 +498,8 @@ public class CherClient implements Subscriber, MessageHandler
", oid=" + req.getOid() + "].");
// forward the unsubscribe request to the omgr for processing
CherServer.omgr.unsubscribeFromObject(req.getOid(), client);
// update our subscription tracking table
client.unmapSubscrip(req.getOid());
}
}
@@ -455,17 +551,8 @@ public class CherClient implements Subscriber, MessageHandler
{
Log.info("Client requested logoff " +
"[client=" + client + "].");
// close our connection (which results in everything being
// properly unregistered)
Connection conn = client.getConnection();
if (conn != null) {
conn.close();
} else {
Log.info("Unable to close connection for logoff request " +
"[client=" + client + "].");
}
// then let the client manager know what's up
client._cmgr.clientDidEndSession(client);
// request that the client end the session
client.endSession();
}
}
@@ -473,6 +560,7 @@ public class CherClient implements Subscriber, MessageHandler
protected String _username;
protected Connection _conn;
protected ClientObject _clobj;
protected IntMap _subscrips = new IntMap();
protected static HashMap _disps = new HashMap();