67a3dabac2
it is ready. Then the client hangs on to it because the invocation manager doesn't really need to hang on to the client object. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@288 542714f4-19e9-0310-aa3c-eee0fc999fb1
321 lines
9.7 KiB
Java
321 lines
9.7 KiB
Java
//
|
|
// $Id: Client.java,v 1.13 2001/08/21 19:33:06 mdb Exp $
|
|
|
|
package com.threerings.cocktail.cher.client;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import com.threerings.cocktail.cher.Log;
|
|
import com.threerings.cocktail.cher.data.ClientObject;
|
|
import com.threerings.cocktail.cher.dobj.DObjectManager;
|
|
import com.threerings.cocktail.cher.net.BootstrapData;
|
|
import com.threerings.cocktail.cher.net.Credentials;
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
/**
|
|
* This is used by the client to allow dobj event dispatching to take
|
|
* place along side the activities of the rest of the application
|
|
* (usually this means running dobj events on the AWT thread).
|
|
*/
|
|
public static interface Invoker
|
|
{
|
|
/**
|
|
* Requests that the supplied runnable be queued up for invocation
|
|
* on the main event dispatching thread of the application.
|
|
*/
|
|
public void invokeLater (Runnable run);
|
|
}
|
|
|
|
/**
|
|
* Constructs a client object with the supplied credentials and
|
|
* invoker. The creds will be used to authenticate with any server to
|
|
* which this client attempts to connect. The invoker 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 invoker queue up a
|
|
* runnable whenever there are distributed object events that need to
|
|
* be processed. The invoker 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 <code>setCredentials</code> must then be
|
|
* called before any call to <code>logon</code>.
|
|
* @param invoker an invoker that can be used to process incoming
|
|
* events.
|
|
*/
|
|
public Client (Credentials creds, Invoker invoker)
|
|
{
|
|
_creds = creds;
|
|
_invoker = invoker;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
public void addObserver (ClientObserver observer)
|
|
{
|
|
synchronized (_observers) {
|
|
// disallow multiple instances of the same observer
|
|
if (!_observers.contains(observer)) {
|
|
_observers.add(observer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unregisters the supplied observer. Upon return of this function,
|
|
* the observer will no longer receive notifications of state changes
|
|
* within the client.
|
|
*/
|
|
public void removeObserver (ClientObserver observer)
|
|
{
|
|
synchronized (_observers) {
|
|
_observers.remove(observer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Configures the client to communicate with the server on the
|
|
* supplied hostname/port combination.
|
|
*
|
|
* @see #logon
|
|
*/
|
|
public void setServer (String hostname, int port)
|
|
{
|
|
_hostname = hostname;
|
|
_port = port;
|
|
}
|
|
|
|
/**
|
|
* Returns the invoker in use by this client. This can be used to
|
|
* queue up event dispatching stints.
|
|
*/
|
|
public Invoker getInvoker ()
|
|
{
|
|
return _invoker;
|
|
}
|
|
|
|
/**
|
|
* Returns the hostname of the server to which this client is
|
|
* currently configured to connect.
|
|
*/
|
|
public String getHostname ()
|
|
{
|
|
return _hostname;
|
|
}
|
|
|
|
/**
|
|
* Returns the port on which this client is currently configured to
|
|
* connect to the server.
|
|
*/
|
|
public int getPort ()
|
|
{
|
|
return _port;
|
|
}
|
|
|
|
/**
|
|
* Returns the credentials with which this client is currently
|
|
* configured to connect to the server.
|
|
*/
|
|
public Credentials getCredentials ()
|
|
{
|
|
return _creds;
|
|
}
|
|
|
|
/**
|
|
* Sets the credentials that will be used by this client to
|
|
* authenticate with the server. This should be done before any call
|
|
* to <code>logon</code>.
|
|
*/
|
|
public void setCredentials (Credentials creds)
|
|
{
|
|
_creds = creds;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
public DObjectManager getDObjectManager ()
|
|
{
|
|
return (_comm != null) ? _comm.getDObjectManager() : null;
|
|
}
|
|
|
|
/**
|
|
* Returns the oid of the client object associated with this session.
|
|
* It is only valid for the duration of the session.
|
|
*/
|
|
public int getClientOid ()
|
|
{
|
|
return _cloid;
|
|
}
|
|
|
|
/**
|
|
* Returns a reference to the client object associated with this
|
|
* session. It is only valid for the duration of the session.
|
|
*/
|
|
public ClientObject getClientObject ()
|
|
{
|
|
return _clobj;
|
|
}
|
|
|
|
/**
|
|
* Returns the invocation manager associated with this session. This
|
|
* reference is only valid for the duration of the session.
|
|
*/
|
|
public InvocationManager getInvocationManager ()
|
|
{
|
|
return _invmgr;
|
|
}
|
|
|
|
/**
|
|
* Requests that this client connect and logon to the server with
|
|
* which it was previously configured.
|
|
*/
|
|
public synchronized void logon ()
|
|
{
|
|
// if we have a communicator reference, we're already logged on
|
|
if (_comm != null) {
|
|
return;
|
|
}
|
|
|
|
// otherwise create a new communicator instance and start it up.
|
|
// this will initiate the logon process
|
|
_comm = new Communicator(this);
|
|
_comm.logon();
|
|
}
|
|
|
|
/**
|
|
* Requests that the client log off of the server to which it is
|
|
* connected.
|
|
*
|
|
* @param abortable If true, the client will call
|
|
* <code>clientWillDisconnect</code> on all of the client observers
|
|
* and abort the logoff process if any of them return false. If false,
|
|
* <code>clientWillDisconnect</code> will not be called at all.
|
|
*
|
|
* @return true if the logoff succeeded, false if it failed due to a
|
|
* disagreeable observer.
|
|
*/
|
|
public boolean logoff (boolean abortable)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
// ask the communicator to send a logoff message and disconnect
|
|
// from the server
|
|
_comm.logoff();
|
|
|
|
return true;
|
|
}
|
|
|
|
boolean notifyObservers (int code, Exception cause)
|
|
{
|
|
boolean rejected = false;
|
|
synchronized (_observers) {
|
|
for (int i = 0; i < _observers.size(); i++) {
|
|
ClientObserver obs = (ClientObserver)_observers.get(i);
|
|
switch (code) {
|
|
case CLIENT_DID_LOGON:
|
|
obs.clientDidLogon(this);
|
|
break;
|
|
case CLIENT_FAILED_TO_LOGON:
|
|
obs.clientFailedToLogon(this, cause);
|
|
break;
|
|
case CLIENT_CONNECTION_FAILED:
|
|
obs.clientConnectionFailed(this, cause);
|
|
break;
|
|
case CLIENT_WILL_LOGOFF:
|
|
if (!obs.clientWillLogoff(this)) {
|
|
rejected = true;
|
|
}
|
|
break;
|
|
case CLIENT_DID_LOGOFF:
|
|
obs.clientDidLogoff(this);
|
|
break;
|
|
default:
|
|
throw new RuntimeException("Invalid code supplied to " +
|
|
"notifyObservers: " + code);
|
|
}
|
|
}
|
|
}
|
|
return rejected;
|
|
}
|
|
|
|
synchronized void communicatorDidExit ()
|
|
{
|
|
// clear out our communicator reference
|
|
_comm = null;
|
|
}
|
|
|
|
/**
|
|
* Called by the omgr when a bootstrap notification arrives.
|
|
*/
|
|
void gotBootstrap (BootstrapData data)
|
|
{
|
|
// extract bootstrap information
|
|
_cloid = data.clientOid;
|
|
|
|
// create our invocation manager
|
|
_invmgr = new InvocationManager(this, data.invOid);
|
|
|
|
// we can't quite call initialization completed at this point
|
|
// because we need for the invocation manager to fully initialize
|
|
// (which requires a round trip to the server) before turning the
|
|
// client loose to do things like request invocation services
|
|
}
|
|
|
|
void invocationManagerReady (ClientObject clobj)
|
|
{
|
|
// keep this around
|
|
_clobj = clobj;
|
|
|
|
// let the client know that logon has now fully succeeded
|
|
notifyObservers(Client.CLIENT_DID_LOGON, null);
|
|
}
|
|
|
|
protected Credentials _creds;
|
|
protected Invoker _invoker;
|
|
protected ClientObject _clobj;
|
|
|
|
protected String _hostname;
|
|
protected int _port;
|
|
|
|
/** Our list of client observers. */
|
|
protected List _observers = new ArrayList();
|
|
|
|
/** The entity that manages our network communications. */
|
|
protected Communicator _comm;
|
|
|
|
protected int _cloid;
|
|
protected InvocationManager _invmgr;
|
|
|
|
// client observer codes
|
|
static final int CLIENT_DID_LOGON = 0;
|
|
static final int CLIENT_FAILED_TO_LOGON = 1;
|
|
static final int CLIENT_CONNECTION_FAILED = 2;
|
|
static final int CLIENT_WILL_LOGOFF = 3;
|
|
static final int CLIENT_DID_LOGOFF = 4;
|
|
}
|