Revamped "persona selection" support. Things now actually work, and in as
sensible a way as we can hope for. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1717 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
//
|
//
|
||||||
// $Id: CrowdClient.java,v 1.9 2002/09/17 01:23:09 mdb Exp $
|
// $Id: CrowdClient.java,v 1.10 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.crowd.server;
|
package com.threerings.crowd.server;
|
||||||
|
|
||||||
import com.threerings.presents.server.PresentsClient;
|
import com.threerings.presents.server.PresentsClient;
|
||||||
|
|
||||||
import com.threerings.crowd.data.BodyObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The crowd client extends the presents client but doesn't really do
|
* The crowd client extends the presents client but doesn't really do
|
||||||
* anything at present. It exists mainly so that implementation systems
|
* anything at present. It exists mainly so that implementation systems
|
||||||
@@ -15,12 +13,4 @@ import com.threerings.crowd.data.BodyObject;
|
|||||||
*/
|
*/
|
||||||
public class CrowdClient extends PresentsClient
|
public class CrowdClient extends PresentsClient
|
||||||
{
|
{
|
||||||
// documentation inherited
|
|
||||||
public void setUsername (String username)
|
|
||||||
{
|
|
||||||
super.setUsername(username);
|
|
||||||
|
|
||||||
// update the username in our body object
|
|
||||||
((BodyObject)_clobj).setUsername(username);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: LogonPanel.java,v 1.7 2002/07/17 18:11:02 mdb Exp $
|
// $Id: LogonPanel.java,v 1.8 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.micasa.client;
|
package com.threerings.micasa.client;
|
||||||
|
|
||||||
@@ -156,6 +156,12 @@ public class LogonPanel extends JPanel
|
|||||||
setLogonEnabled(true);
|
setLogonEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void clientObjectDidChange (Client client)
|
||||||
|
{
|
||||||
|
// nothing we can do here...
|
||||||
|
}
|
||||||
|
|
||||||
// documentation inherited from interface
|
// documentation inherited from interface
|
||||||
public void clientConnectionFailed (Client client, Exception cause)
|
public void clientConnectionFailed (Client client, Exception cause)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: Client.java,v 1.28 2002/08/14 19:07:54 mdb Exp $
|
// $Id: Client.java,v 1.29 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.client;
|
package com.threerings.presents.client;
|
||||||
|
|
||||||
@@ -333,20 +333,7 @@ public class Client
|
|||||||
protected void clockDeltaEstablished ()
|
protected void clockDeltaEstablished ()
|
||||||
{
|
{
|
||||||
// initialize our invocation director
|
// initialize our invocation director
|
||||||
ResultListener rl = new ResultListener() {
|
_invdir.init(_comm.getDObjectManager(), _cloid, this);
|
||||||
public void requestCompleted (Object result) {
|
|
||||||
// keep this around
|
|
||||||
_clobj = (ClientObject)result;
|
|
||||||
// let the client know that logon has now fully succeeded
|
|
||||||
notifyObservers(Client.CLIENT_DID_LOGON, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestFailed (Exception cause) {
|
|
||||||
// pass the buck onto the listeners
|
|
||||||
notifyObservers(Client.CLIENT_FAILED_TO_LOGON, cause);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_invdir.init(_comm.getDObjectManager(), _cloid, rl);
|
|
||||||
|
|
||||||
// we can't quite call initialization completed at this point
|
// we can't quite call initialization completed at this point
|
||||||
// because we need for the invocation director to fully initialize
|
// because we need for the invocation director to fully initialize
|
||||||
@@ -354,6 +341,42 @@ public class Client
|
|||||||
// client loose to do things like request invocation services
|
// client loose to do things like request invocation services
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the invocation director when it successfully subscribes
|
||||||
|
* to the client object immediately following logon.
|
||||||
|
*/
|
||||||
|
protected void gotClientObject (ClientObject clobj)
|
||||||
|
{
|
||||||
|
// keep this around
|
||||||
|
_clobj = clobj;
|
||||||
|
|
||||||
|
// let the client know that logon has now fully succeeded
|
||||||
|
notifyObservers(Client.CLIENT_DID_LOGON, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the invocation director if it fails to subscribe to the
|
||||||
|
* client object after logon.
|
||||||
|
*/
|
||||||
|
protected void getClientObjectFailed (Exception cause)
|
||||||
|
{
|
||||||
|
// pass the buck onto the listeners
|
||||||
|
notifyObservers(Client.CLIENT_FAILED_TO_LOGON, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the invocation director when it discovers that the client
|
||||||
|
* object has changed.
|
||||||
|
*/
|
||||||
|
protected void clientObjectDidChange (ClientObject clobj)
|
||||||
|
{
|
||||||
|
// slip the new client object into the business
|
||||||
|
_clobj = clobj;
|
||||||
|
|
||||||
|
// report to our observers
|
||||||
|
notifyObservers(Client.CLIENT_OBJECT_CHANGED, null);
|
||||||
|
}
|
||||||
|
|
||||||
boolean notifyObservers (int code, Exception cause)
|
boolean notifyObservers (int code, Exception cause)
|
||||||
{
|
{
|
||||||
final Notifier noty = new Notifier(code, cause);
|
final Notifier noty = new Notifier(code, cause);
|
||||||
@@ -365,8 +388,11 @@ public class Client
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// we need to run immediately if this is WILL_LOGOFF
|
// we need to run immediately if this is WILL_LOGOFF or if we have
|
||||||
if (code == CLIENT_WILL_LOGOFF) {
|
// no invoker (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 || _invoker == null) {
|
||||||
unit.run();
|
unit.run();
|
||||||
return noty.getRejected();
|
return noty.getRejected();
|
||||||
|
|
||||||
@@ -475,6 +501,12 @@ public class Client
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLIENT_OBJECT_CHANGED:
|
||||||
|
if (obs instanceof ClientObserver) {
|
||||||
|
((ClientObserver)obs).clientObjectDidChange(Client.this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case CLIENT_CONNECTION_FAILED:
|
case CLIENT_CONNECTION_FAILED:
|
||||||
if (obs instanceof ClientObserver) {
|
if (obs instanceof ClientObserver) {
|
||||||
((ClientObserver)obs).clientConnectionFailed(
|
((ClientObserver)obs).clientConnectionFailed(
|
||||||
@@ -554,7 +586,8 @@ public class Client
|
|||||||
// client observer codes
|
// client observer codes
|
||||||
static final int CLIENT_DID_LOGON = 0;
|
static final int CLIENT_DID_LOGON = 0;
|
||||||
static final int CLIENT_FAILED_TO_LOGON = 1;
|
static final int CLIENT_FAILED_TO_LOGON = 1;
|
||||||
static final int CLIENT_CONNECTION_FAILED = 2;
|
static final int CLIENT_OBJECT_CHANGED = 2;
|
||||||
static final int CLIENT_WILL_LOGOFF = 3;
|
static final int CLIENT_CONNECTION_FAILED = 3;
|
||||||
static final int CLIENT_DID_LOGOFF = 4;
|
static final int CLIENT_WILL_LOGOFF = 4;
|
||||||
|
static final int CLIENT_DID_LOGOFF = 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientAdapter.java,v 1.3 2001/10/11 04:07:52 mdb Exp $
|
// $Id: ClientAdapter.java,v 1.4 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.client;
|
package com.threerings.presents.client;
|
||||||
|
|
||||||
@@ -24,6 +24,11 @@ public class ClientAdapter implements ClientObserver
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void clientObjectDidChange (Client client)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
public void clientConnectionFailed (Client client, Exception cause)
|
public void clientConnectionFailed (Client client, Exception cause)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientObserver.java,v 1.5 2002/05/16 18:17:27 shaper Exp $
|
// $Id: ClientObserver.java,v 1.6 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.client;
|
package com.threerings.presents.client;
|
||||||
|
|
||||||
@@ -43,6 +43,14 @@ public interface ClientObserver extends SessionObserver
|
|||||||
*/
|
*/
|
||||||
public void clientFailedToLogon (Client client, Exception cause);
|
public void clientFailedToLogon (Client client, Exception cause);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For systems that allow switching screen names after logon, this
|
||||||
|
* method is called whenever a screen name change takes place to
|
||||||
|
* report that the client object has been replaced to potential
|
||||||
|
* client-side subscribers.
|
||||||
|
*/
|
||||||
|
public void clientObjectDidChange (Client client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the connection to the server went away for some
|
* Called when the connection to the server went away for some
|
||||||
* unexpected reason. This will be followed by a call to
|
* unexpected reason. This will be followed by a call to
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: InvocationDirector.java,v 1.21 2002/08/14 19:07:54 mdb Exp $
|
// $Id: InvocationDirector.java,v 1.22 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.client;
|
package com.threerings.presents.client;
|
||||||
|
|
||||||
@@ -20,10 +20,12 @@ import com.threerings.presents.data.InvocationMarshaller;
|
|||||||
import com.threerings.presents.dobj.DEvent;
|
import com.threerings.presents.dobj.DEvent;
|
||||||
import com.threerings.presents.dobj.DObject;
|
import com.threerings.presents.dobj.DObject;
|
||||||
import com.threerings.presents.dobj.DObjectManager;
|
import com.threerings.presents.dobj.DObjectManager;
|
||||||
|
import com.threerings.presents.dobj.DSet;
|
||||||
import com.threerings.presents.dobj.EventListener;
|
import com.threerings.presents.dobj.EventListener;
|
||||||
import com.threerings.presents.dobj.InvocationNotificationEvent;
|
import com.threerings.presents.dobj.InvocationNotificationEvent;
|
||||||
import com.threerings.presents.dobj.InvocationRequestEvent;
|
import com.threerings.presents.dobj.InvocationRequestEvent;
|
||||||
import com.threerings.presents.dobj.InvocationResponseEvent;
|
import com.threerings.presents.dobj.InvocationResponseEvent;
|
||||||
|
import com.threerings.presents.dobj.MessageEvent;
|
||||||
import com.threerings.presents.dobj.ObjectAccessException;
|
import com.threerings.presents.dobj.ObjectAccessException;
|
||||||
import com.threerings.presents.dobj.Subscriber;
|
import com.threerings.presents.dobj.Subscriber;
|
||||||
|
|
||||||
@@ -41,25 +43,22 @@ public class InvocationDirector
|
|||||||
* manager will send and receive events.
|
* manager will send and receive events.
|
||||||
* @param cloid the oid of the object on which invocation
|
* @param cloid the oid of the object on which invocation
|
||||||
* notifications as well as invocation responses will be received.
|
* notifications as well as invocation responses will be received.
|
||||||
* @param initListener a result listener that will be notified when
|
* @param client a reference to the client for whom we're doing our
|
||||||
* the invocation director is up and running (meaning it has
|
* business.
|
||||||
* subscribed successfully to the client object and is ready to
|
|
||||||
* process invocation requests); or when initialization has failed.
|
|
||||||
*/
|
*/
|
||||||
public void init (DObjectManager omgr, final int cloid,
|
public void init (DObjectManager omgr, final int cloid, Client client)
|
||||||
final ResultListener initListener)
|
|
||||||
{
|
{
|
||||||
// keep this for later
|
// keep these for later
|
||||||
_omgr = omgr;
|
_omgr = omgr;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
// add ourselves as a subscriber to the client object
|
// add ourselves as a subscriber to the client object
|
||||||
_omgr.subscribeToObject(cloid, new Subscriber() {
|
_omgr.subscribeToObject(cloid, new Subscriber() {
|
||||||
public void objectAvailable (DObject object)
|
public void objectAvailable (DObject object) {
|
||||||
{
|
|
||||||
// keep a handle on this bad boy
|
// keep a handle on this bad boy
|
||||||
_clobj = (ClientObject)object;
|
_clobj = (ClientObject)object;
|
||||||
|
|
||||||
// add ourselves as a message listener
|
// add ourselves as an event listener
|
||||||
_clobj.addListener(InvocationDirector.this);
|
_clobj.addListener(InvocationDirector.this);
|
||||||
|
|
||||||
// assign a mapping to already registered receivers
|
// assign a mapping to already registered receivers
|
||||||
@@ -67,16 +66,16 @@ public class InvocationDirector
|
|||||||
|
|
||||||
// let the client know that we're ready to go now that
|
// let the client know that we're ready to go now that
|
||||||
// we've got our subscription to the client object
|
// we've got our subscription to the client object
|
||||||
initListener.requestCompleted(object);
|
_client.gotClientObject(_clobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestFailed (int oid, ObjectAccessException cause)
|
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||||
{
|
|
||||||
// aiya! we were unable to subscribe to the client object.
|
// aiya! we were unable to subscribe to the client object.
|
||||||
// we're hosed, hosed, hosed
|
// we're hosed, hosed, hosed
|
||||||
Log.warning("Invocation director unable to subscribe to " +
|
Log.warning("Invocation director unable to subscribe to " +
|
||||||
"client object [cloid=" + cloid + "]!");
|
"client object [cloid=" + cloid +
|
||||||
initListener.requestFailed(cause);
|
", cause=" + cause + "]!");
|
||||||
|
_client.getClientObjectFailed(cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -215,6 +214,13 @@ public class InvocationDirector
|
|||||||
(InvocationNotificationEvent)event;
|
(InvocationNotificationEvent)event;
|
||||||
handleInvocationNotification(
|
handleInvocationNotification(
|
||||||
ine.getReceiverId(), ine.getMethodId(), ine.getArgs());
|
ine.getReceiverId(), ine.getMethodId(), ine.getArgs());
|
||||||
|
|
||||||
|
} else if (event instanceof MessageEvent) {
|
||||||
|
MessageEvent mevt = (MessageEvent)event;
|
||||||
|
if (mevt.getName().equals(ClientObject.CLOBJ_CHANGED)) {
|
||||||
|
handleClientObjectChanged(
|
||||||
|
((Integer)mevt.getArgs()[0]).intValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +289,49 @@ public class InvocationDirector
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Called when the server has informed us that our previous client
|
||||||
|
* object is going the way of the Dodo because we're changing screen
|
||||||
|
* names. We subscribe to the new object and report to the client once
|
||||||
|
* we've got our hands on it.
|
||||||
|
*/
|
||||||
|
protected void handleClientObjectChanged (int newCloid)
|
||||||
|
{
|
||||||
|
// subscribe to the new client object
|
||||||
|
_omgr.subscribeToObject(newCloid, new Subscriber() {
|
||||||
|
public void objectAvailable (DObject object) {
|
||||||
|
// grab a reference to our old receiver registrations
|
||||||
|
DSet receivers = _clobj.receivers;
|
||||||
|
|
||||||
|
// replace the client object
|
||||||
|
_clobj = (ClientObject)object;
|
||||||
|
|
||||||
|
// add ourselves as an event listener
|
||||||
|
_clobj.addListener(InvocationDirector.this);
|
||||||
|
|
||||||
|
// reregister our receivers
|
||||||
|
try {
|
||||||
|
_clobj.startTransaction();
|
||||||
|
Iterator iter = receivers.entries();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
_clobj.addToReceivers((Registration)iter.next());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
_clobj.commitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// and report the switcheroo back to the client
|
||||||
|
_client.clientObjectDidChange(_clobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||||
|
Log.warning("Aiya! Unable to subscribe to changed " +
|
||||||
|
"client object [cloid=" + oid +
|
||||||
|
", cause=" + cause + "].");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Used to generate monotonically increasing invocation request ids.
|
* Used to generate monotonically increasing invocation request ids.
|
||||||
*/
|
*/
|
||||||
protected synchronized short nextRequestId ()
|
protected synchronized short nextRequestId ()
|
||||||
@@ -301,6 +350,9 @@ public class InvocationDirector
|
|||||||
/** The distributed object manager with which we interact. */
|
/** The distributed object manager with which we interact. */
|
||||||
protected DObjectManager _omgr;
|
protected DObjectManager _omgr;
|
||||||
|
|
||||||
|
/** The client for whom we're working. */
|
||||||
|
protected Client _client;
|
||||||
|
|
||||||
/** Our client object; invocation responses and notifications are
|
/** Our client object; invocation responses and notifications are
|
||||||
* received on this object. */
|
* received on this object. */
|
||||||
protected ClientObject _clobj;
|
protected ClientObject _clobj;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientObject.dobj,v 1.1 2002/08/14 19:07:54 mdb Exp $
|
// $Id: ClientObject.dobj,v 1.2 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.data;
|
package com.threerings.presents.data;
|
||||||
|
|
||||||
@@ -14,6 +14,10 @@ import com.threerings.presents.dobj.DSet;
|
|||||||
*/
|
*/
|
||||||
public class ClientObject extends DObject
|
public class ClientObject extends DObject
|
||||||
{
|
{
|
||||||
|
/** The name of a message event delivered to the client when they
|
||||||
|
* switch usernames (and therefore user objects). */
|
||||||
|
public static final String CLOBJ_CHANGED = "!clobj_changed!";
|
||||||
|
|
||||||
/** Used to publish all invocation service receivers registered on
|
/** Used to publish all invocation service receivers registered on
|
||||||
* this client. */
|
* this client. */
|
||||||
public DSet receivers = new DSet();
|
public DSet receivers = new DSet();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientObject.java,v 1.3 2002/08/14 19:07:54 mdb Exp $
|
// $Id: ClientObject.java,v 1.4 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.data;
|
package com.threerings.presents.data;
|
||||||
|
|
||||||
@@ -17,6 +17,10 @@ public class ClientObject extends DObject
|
|||||||
/** The field name of the <code>receivers</code> field. */
|
/** The field name of the <code>receivers</code> field. */
|
||||||
public static final String RECEIVERS = "receivers";
|
public static final String RECEIVERS = "receivers";
|
||||||
|
|
||||||
|
/** The name of a message event delivered to the client when they
|
||||||
|
* switch usernames (and therefore user objects). */
|
||||||
|
public static final String CLOBJ_CHANGED = "!clobj_changed!";
|
||||||
|
|
||||||
/** Used to publish all invocation service receivers registered on
|
/** Used to publish all invocation service receivers registered on
|
||||||
* this client. */
|
* this client. */
|
||||||
public DSet receivers = new DSet();
|
public DSet receivers = new DSet();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: ClientManager.java,v 1.22 2002/09/16 23:34:25 mdb Exp $
|
// $Id: ClientManager.java,v 1.23 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.server;
|
package com.threerings.presents.server;
|
||||||
|
|
||||||
@@ -86,12 +86,12 @@ public class ClientManager implements ConnectionObserver
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the client instance that manages the client session for the
|
* Returns the client instance that manages the client session for the
|
||||||
* specified username or null if that client is not currently
|
* specified credentials or null if that client is not currently
|
||||||
* connected to the server.
|
* connected to the server.
|
||||||
*/
|
*/
|
||||||
public PresentsClient getClient (String username)
|
public PresentsClient getClient (Credentials creds)
|
||||||
{
|
{
|
||||||
return (PresentsClient)_usermap.get(username);
|
return (PresentsClient)_usermap.get(creds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,7 +101,17 @@ public class ClientManager implements ConnectionObserver
|
|||||||
*/
|
*/
|
||||||
public ClientObject getClientObject (String username)
|
public ClientObject getClientObject (String username)
|
||||||
{
|
{
|
||||||
return (ClientObject)_objmap.get(username);
|
return (ClientObject)_objmap.get(toKey(username));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We convert usernames to lower case in the username to client object
|
||||||
|
* mapping so that we can pass arbitrarily cased usernames (like those
|
||||||
|
* that might be typed in by a "user") straight on through.
|
||||||
|
*/
|
||||||
|
protected final String toKey (String username)
|
||||||
|
{
|
||||||
|
return username.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,14 +125,15 @@ public class ClientManager implements ConnectionObserver
|
|||||||
String username, ClientResolutionListener listener)
|
String username, ClientResolutionListener listener)
|
||||||
{
|
{
|
||||||
// look to see if the client object is already resolved
|
// look to see if the client object is already resolved
|
||||||
ClientObject clobj = (ClientObject)_objmap.get(username);
|
String key = toKey(username);
|
||||||
|
ClientObject clobj = (ClientObject)_objmap.get(key);
|
||||||
if (clobj != null) {
|
if (clobj != null) {
|
||||||
listener.clientResolved(username, clobj);
|
listener.clientResolved(username, clobj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// look to see if it's currently being resolved
|
// look to see if it's currently being resolved
|
||||||
ClientResolver clr = (ClientResolver)_penders.get(username);
|
ClientResolver clr = (ClientResolver)_penders.get(key);
|
||||||
if (clr != null) {
|
if (clr != null) {
|
||||||
// throw this guy onto the bandwagon
|
// throw this guy onto the bandwagon
|
||||||
clr.addResolutionListener(listener);
|
clr.addResolutionListener(listener);
|
||||||
@@ -154,10 +165,11 @@ public class ClientManager implements ConnectionObserver
|
|||||||
String username, ClientObject clobj)
|
String username, ClientObject clobj)
|
||||||
{
|
{
|
||||||
// stuff the object into the mapping table
|
// stuff the object into the mapping table
|
||||||
_objmap.put(username, clobj);
|
String key = toKey(username);
|
||||||
|
_objmap.put(key, clobj);
|
||||||
|
|
||||||
// and remove the resolution listener
|
// and remove the resolution listener
|
||||||
_penders.remove(username);
|
_penders.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,11 +184,12 @@ public class ClientManager implements ConnectionObserver
|
|||||||
{
|
{
|
||||||
// we only remove the mapping if there's not a session in progress
|
// we only remove the mapping if there's not a session in progress
|
||||||
// (which is indicated by an entry in the locks table)
|
// (which is indicated by an entry in the locks table)
|
||||||
if (_locks.contains(username)) {
|
String key = toKey(username);
|
||||||
|
if (_locks.contains(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientObject clobj = (ClientObject)_objmap.remove(username);
|
ClientObject clobj = (ClientObject)_objmap.remove(key);
|
||||||
if (clobj != null) {
|
if (clobj != null) {
|
||||||
PresentsServer.omgr.destroyObject(clobj.getOid());
|
PresentsServer.omgr.destroyObject(clobj.getOid());
|
||||||
} else {
|
} else {
|
||||||
@@ -185,45 +198,6 @@ public class ClientManager implements ConnectionObserver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remaps a client from its old username to the specified new
|
|
||||||
* username. The client must end its session using the new username.
|
|
||||||
* This most likely shouldn't be called anywhere except from {@link
|
|
||||||
* PresentsClient#setUsername}.
|
|
||||||
*
|
|
||||||
* @return true if the remapping succeeded, false if it failed.
|
|
||||||
*/
|
|
||||||
protected synchronized boolean remapClient (
|
|
||||||
String oldname, String newname)
|
|
||||||
{
|
|
||||||
// make sure they are already mapped
|
|
||||||
PresentsClient client = (PresentsClient)_usermap.remove(oldname);
|
|
||||||
if (client == null) {
|
|
||||||
Log.warning("Aiya! Can't remap non-existent user " +
|
|
||||||
"[oldname=" + oldname + ", newname=" + newname + "].");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// map them under their new name
|
|
||||||
_usermap.put(newname, client);
|
|
||||||
|
|
||||||
// release their old lock and create a lock for their new name
|
|
||||||
releaseClient(oldname);
|
|
||||||
lockClient(newname);
|
|
||||||
|
|
||||||
// update their client object mapping
|
|
||||||
ClientObject clobj = (ClientObject)_objmap.remove(oldname);
|
|
||||||
if (clobj == null) {
|
|
||||||
Log.warning("Aiya! Unable to unmap old client object when " +
|
|
||||||
"remapping user [oldname=" + oldname +
|
|
||||||
", newname=" + newname + "]. Hoping for the best.");
|
|
||||||
} else {
|
|
||||||
_objmap.put(newname, clobj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a client object becomes part of an active session, this method
|
* When a client object becomes part of an active session, this method
|
||||||
* should be called to ensure that it is not unloaded by any entities
|
* should be called to ensure that it is not unloaded by any entities
|
||||||
@@ -231,30 +205,31 @@ public class ClientManager implements ConnectionObserver
|
|||||||
* automatically when a real user starts a session by establishing a
|
* automatically when a real user starts a session by establishing a
|
||||||
* network connection with the server. If a client session is managed
|
* network connection with the server. If a client session is managed
|
||||||
* via some other mechanism (bots managed by the server, for example),
|
* via some other mechanism (bots managed by the server, for example),
|
||||||
* this method and its corresponding {@link #releaseClient} should be
|
* this method and its corresponding {@link #releaseClientObject}
|
||||||
* called at the beginning and end of the faked client session
|
* should be called at the beginning and end of the faked client
|
||||||
* respectively.
|
* session respectively.
|
||||||
*/
|
*/
|
||||||
public synchronized void lockClient (String username)
|
public synchronized void lockClientObject (String username)
|
||||||
{
|
{
|
||||||
if (_locks.contains(username)) {
|
String key = toKey(username);
|
||||||
|
if (_locks.contains(key)) {
|
||||||
Log.warning("Requested to lock already locked user " +
|
Log.warning("Requested to lock already locked user " +
|
||||||
"[username=" + username + "].");
|
"[username=" + username + "].");
|
||||||
Thread.dumpStack();
|
Thread.dumpStack();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_locks.add(username);
|
_locks.add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases a client object when their session has ended.
|
* Releases a client object when their session has ended.
|
||||||
*
|
*
|
||||||
* @see #lockClient
|
* @see #lockClientObject
|
||||||
*/
|
*/
|
||||||
public synchronized void releaseClient (String username)
|
public synchronized void releaseClientObject (String username)
|
||||||
{
|
{
|
||||||
if (!_locks.remove(username)) {
|
if (!_locks.remove(toKey(username))) {
|
||||||
Log.warning("Requested to unlock a user that was not locked " +
|
Log.warning("Requested to unlock a user that was not locked " +
|
||||||
"[username=" + username + "].");
|
"[username=" + username + "].");
|
||||||
Thread.dumpStack();
|
Thread.dumpStack();
|
||||||
@@ -268,8 +243,8 @@ public class ClientManager implements ConnectionObserver
|
|||||||
Credentials creds = req.getCredentials();
|
Credentials creds = req.getCredentials();
|
||||||
String username = creds.getUsername();
|
String username = creds.getUsername();
|
||||||
|
|
||||||
// see if there's a client already registered with this username
|
// see if a client is already registered with these credentials
|
||||||
PresentsClient client = (PresentsClient)_usermap.get(username);
|
PresentsClient client = (PresentsClient)_usermap.get(creds);
|
||||||
|
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
Log.info("Session resumed [username=" + username +
|
Log.info("Session resumed [username=" + username +
|
||||||
@@ -283,13 +258,10 @@ public class ClientManager implements ConnectionObserver
|
|||||||
try {
|
try {
|
||||||
// create a client and start up its session
|
// create a client and start up its session
|
||||||
client = (PresentsClient)_clientClass.newInstance();
|
client = (PresentsClient)_clientClass.newInstance();
|
||||||
client.startSession(this, username, conn);
|
client.startSession(this, creds, conn);
|
||||||
|
|
||||||
// lock this client for the duration of this session
|
|
||||||
lockClient(username);
|
|
||||||
|
|
||||||
// map their client instance
|
// map their client instance
|
||||||
_usermap.put(username, client);
|
_usermap.put(creds, client);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.warning("Failed to instantiate client instance to " +
|
Log.warning("Failed to instantiate client instance to " +
|
||||||
@@ -350,9 +322,11 @@ public class ClientManager implements ConnectionObserver
|
|||||||
*/
|
*/
|
||||||
synchronized void clientDidEndSession (PresentsClient client)
|
synchronized void clientDidEndSession (PresentsClient client)
|
||||||
{
|
{
|
||||||
|
Credentials creds = client.getCredentials();
|
||||||
String username = client.getUsername();
|
String username = client.getUsername();
|
||||||
|
|
||||||
// remove the client from the username map
|
// remove the client from the username map
|
||||||
PresentsClient rc = (PresentsClient)_usermap.remove(username);
|
PresentsClient rc = (PresentsClient)_usermap.remove(creds);
|
||||||
|
|
||||||
// sanity check just because we can
|
// sanity check just because we can
|
||||||
if (rc == null) {
|
if (rc == null) {
|
||||||
@@ -372,9 +346,7 @@ public class ClientManager implements ConnectionObserver
|
|||||||
Log.info("Ending session [client=" + client + "].");
|
Log.info("Ending session [client=" + client + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the client session
|
// unmap (and destroy) the client object
|
||||||
releaseClient(username);
|
|
||||||
// and unmap (and destroy) their client object
|
|
||||||
unmapClientObject(username);
|
unmapClientObject(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: PresentsClient.java,v 1.37 2002/09/18 01:10:27 shaper Exp $
|
// $Id: PresentsClient.java,v 1.38 2002/09/19 23:36:59 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.presents.server;
|
package com.threerings.presents.server;
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ import com.threerings.presents.dobj.Subscriber;
|
|||||||
|
|
||||||
import com.threerings.presents.net.BootstrapData;
|
import com.threerings.presents.net.BootstrapData;
|
||||||
import com.threerings.presents.net.BootstrapNotification;
|
import com.threerings.presents.net.BootstrapNotification;
|
||||||
|
import com.threerings.presents.net.Credentials;
|
||||||
import com.threerings.presents.net.EventNotification;
|
import com.threerings.presents.net.EventNotification;
|
||||||
import com.threerings.presents.net.UpstreamMessage;
|
import com.threerings.presents.net.UpstreamMessage;
|
||||||
|
|
||||||
@@ -54,6 +55,32 @@ public class PresentsClient
|
|||||||
implements Subscriber, EventListener, MessageHandler,
|
implements Subscriber, EventListener, MessageHandler,
|
||||||
ClientResolutionListener
|
ClientResolutionListener
|
||||||
{
|
{
|
||||||
|
/** 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. */
|
||||||
|
public void changeReported (ClientObject newObj);
|
||||||
|
|
||||||
|
/** 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. */
|
||||||
|
public void changeFailed (Exception cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the credentials used to authenticate this client.
|
||||||
|
*/
|
||||||
|
public Credentials getCredentials ()
|
||||||
|
{
|
||||||
|
return _creds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the username with which this client instance is associated.
|
* Returns the username with which this client instance is associated.
|
||||||
*/
|
*/
|
||||||
@@ -79,17 +106,58 @@ public class PresentsClient
|
|||||||
* services when the user logs on, but anything else that has had its
|
* 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
|
* grubby mits on the username will be left to its own devices, hence
|
||||||
* the care that must be exercised when using this method.
|
* 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.
|
||||||
*/
|
*/
|
||||||
public void setUsername (String username)
|
public void setUsername (String username, final UserChangeListener ucl)
|
||||||
{
|
{
|
||||||
// remap the client object in the client manager
|
ClientResolutionListener clr = new ClientResolutionListener() {
|
||||||
if (_cmgr.remapClient(_username, username)) {
|
public void clientResolved (String username, ClientObject clobj) {
|
||||||
// change our internal business
|
// let the client know that the rug has been yanked out
|
||||||
_username = username;
|
// from under their ass
|
||||||
} else {
|
Object[] args = new Object[] { new Integer(clobj.getOid()) };
|
||||||
Log.warning("Unable to remap username [client=" + this +
|
_clobj.postMessage(ClientObject.CLOBJ_CHANGED, args);
|
||||||
", newname=" + username + "].");
|
|
||||||
}
|
// let the caller know that we've got some new business
|
||||||
|
if (ucl != null) {
|
||||||
|
ucl.changeReported(clobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// release our old client object
|
||||||
|
_cmgr.releaseClientObject(_username);
|
||||||
|
|
||||||
|
// unmap the old client object; this will destroy it and
|
||||||
|
// clear out our username mapping
|
||||||
|
_cmgr.unmapClientObject(_username);
|
||||||
|
|
||||||
|
// update our internal fields
|
||||||
|
_username = username;
|
||||||
|
_clobj = clobj;
|
||||||
|
|
||||||
|
// lock our new client object
|
||||||
|
_cmgr.lockClientObject(_username);
|
||||||
|
|
||||||
|
// let our listener know we're groovy
|
||||||
|
if (ucl != null) {
|
||||||
|
ucl.changeCompleted(_clobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolutionFailed (String username, Exception reason) {
|
||||||
|
Log.warning("Unable to resolve new client object " +
|
||||||
|
"[oldname=" + _username + ", newname=" + username +
|
||||||
|
", reason=" + reason + "].");
|
||||||
|
|
||||||
|
// let our listener know we're hosed
|
||||||
|
if (ucl != null) {
|
||||||
|
ucl.changeFailed(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// resolve the new client object
|
||||||
|
_cmgr.resolveClientObject(username, clr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,14 +173,34 @@ public class PresentsClient
|
|||||||
* connection instance and client object and begins a client session.
|
* connection instance and client object and begins a client session.
|
||||||
*/
|
*/
|
||||||
protected void startSession (
|
protected void startSession (
|
||||||
ClientManager cmgr, String username, Connection conn)
|
ClientManager cmgr, Credentials creds, Connection conn)
|
||||||
{
|
{
|
||||||
_cmgr = cmgr;
|
_cmgr = cmgr;
|
||||||
_username = username;
|
_creds = creds;
|
||||||
setConnection(conn);
|
setConnection(conn);
|
||||||
|
|
||||||
|
// obtain our starting username
|
||||||
|
assignStartingUsername();
|
||||||
|
|
||||||
|
// obtain a lock for our username->client object mapping while we
|
||||||
|
// have an active session
|
||||||
|
cmgr.lockClientObject(_username);
|
||||||
|
|
||||||
// resolve our client object before we get fully underway
|
// resolve our client object before we get fully underway
|
||||||
cmgr.resolveClientObject(username, this);
|
cmgr.resolveClientObject(_username, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ()
|
||||||
|
{
|
||||||
|
_username = _creds.getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface
|
// documentation inherited from interface
|
||||||
@@ -307,6 +395,9 @@ public class PresentsClient
|
|||||||
// about to generate
|
// about to generate
|
||||||
clearSubscrips();
|
clearSubscrips();
|
||||||
|
|
||||||
|
// release our locked client object
|
||||||
|
_cmgr.releaseClientObject(_username);
|
||||||
|
|
||||||
// then let the client manager know what's up (it will take care
|
// then let the client manager know what's up (it will take care
|
||||||
// of destroying our client object for us)
|
// of destroying our client object for us)
|
||||||
_cmgr.clientDidEndSession(this);
|
_cmgr.clientDidEndSession(this);
|
||||||
@@ -616,6 +707,7 @@ public class PresentsClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ClientManager _cmgr;
|
protected ClientManager _cmgr;
|
||||||
|
protected Credentials _creds;
|
||||||
protected String _username;
|
protected String _username;
|
||||||
protected Connection _conn;
|
protected Connection _conn;
|
||||||
protected ClientObject _clobj;
|
protected ClientObject _clobj;
|
||||||
|
|||||||
Reference in New Issue
Block a user