The basis of cluster support for Presents servers. All servers in a cluster
make connections to other servers in the cluster and can exchange events (in a limited fashion). This is different than Liz's project wherein servers share an oid space and one can interchangably work with distributed objects from any server. This package provides a means by which certain services (by default, presence and chat) can be communicated between servers to allow communication between players scattered around a bunch of otherwise independent server instances. This is less general purpose but also less likely to encourage people to write code that tightly couples multiple servers and then falls over because it generates gobs of network traffic as events are flung willy nilly behind the scenes. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4238 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -112,41 +112,21 @@ public class ClientManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the client manager to construct instances of this derived
|
||||
* class of {@link PresentsClient} to managed newly accepted client
|
||||
* connections.
|
||||
* Configures the client manager with a factory for creating {@link
|
||||
* PresentsClient} and {@link ClientResolver} classes for authenticated
|
||||
* client connections.
|
||||
*/
|
||||
public void setClientClass (Class clientClass)
|
||||
public void setClientFactory (ClientFactory factory)
|
||||
{
|
||||
// sanity check
|
||||
if (!PresentsClient.class.isAssignableFrom(clientClass)) {
|
||||
Log.warning("Requested to use client class that does not " +
|
||||
"derive from PresentsClient " +
|
||||
"[class=" + clientClass.getName() + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// make a note of it
|
||||
_clientClass = clientClass;
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the client to use instances of this {@link
|
||||
* ClientResolver} derived class when resolving clients in preparation
|
||||
* for starting a client session.
|
||||
* Returns the {@link ClientFactory} currently in use.
|
||||
*/
|
||||
public void setClientResolverClass (Class clrClass)
|
||||
public ClientFactory getClientFactory ()
|
||||
{
|
||||
// sanity check
|
||||
if (!ClientResolver.class.isAssignableFrom(clrClass)) {
|
||||
Log.warning("Requested to use client resolver class that does " +
|
||||
"not derive from ClientResolver " +
|
||||
"[class=" + clrClass.getName() + "].");
|
||||
|
||||
} else {
|
||||
// make a note of it
|
||||
_clrClass = clrClass;
|
||||
}
|
||||
return _factory;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +152,7 @@ public class ClientManager
|
||||
*/
|
||||
public PresentsClient getClient (Name authUsername)
|
||||
{
|
||||
return (PresentsClient)_usermap.get(authUsername);
|
||||
return _usermap.get(authUsername);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +162,7 @@ public class ClientManager
|
||||
*/
|
||||
public ClientObject getClientObject (Name username)
|
||||
{
|
||||
return (ClientObject)_objmap.get(username);
|
||||
return _objmap.get(username);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,7 +187,7 @@ public class ClientManager
|
||||
Name username, final ClientResolutionListener listener)
|
||||
{
|
||||
// look to see if the client object is already resolved
|
||||
ClientObject clobj = (ClientObject)_objmap.get(username);
|
||||
ClientObject clobj = _objmap.get(username);
|
||||
if (clobj != null) {
|
||||
clobj.reference();
|
||||
listener.clientResolved(username, clobj);
|
||||
@@ -215,7 +195,7 @@ public class ClientManager
|
||||
}
|
||||
|
||||
// look to see if it's currently being resolved
|
||||
ClientResolver clr = (ClientResolver)_penders.get(username);
|
||||
ClientResolver clr = _penders.get(username);
|
||||
if (clr != null) {
|
||||
// throw this guy onto the bandwagon
|
||||
clr.addResolutionListener(listener);
|
||||
@@ -225,7 +205,7 @@ public class ClientManager
|
||||
try {
|
||||
// create a client resolver instance which will create our
|
||||
// client object, populate it and notify the listeners
|
||||
clr = (ClientResolver)_clrClass.newInstance();
|
||||
clr = _factory.createClientResolver(username);
|
||||
clr.init(username);
|
||||
clr.addResolutionListener(new ClientResolutionListener() {
|
||||
public void clientResolved (Name username, ClientObject clobj) {
|
||||
@@ -270,7 +250,7 @@ public class ClientManager
|
||||
*/
|
||||
public void releaseClientObject (Name username)
|
||||
{
|
||||
ClientObject clobj = (ClientObject)_objmap.get(username);
|
||||
ClientObject clobj = _objmap.get(username);
|
||||
if (clobj == null) {
|
||||
Log.warning("Requested to release unmapped client object " +
|
||||
"[username=" + username + "].");
|
||||
@@ -312,19 +292,11 @@ public class ClientManager
|
||||
Log.info("Session initiated [username=" + username +
|
||||
", conn=" + conn + "].");
|
||||
// create a new client and stick'em in the table
|
||||
try {
|
||||
// create a client and start up its session
|
||||
client = (PresentsClient)_clientClass.newInstance();
|
||||
client.startSession(this, creds, conn, rsp.authdata);
|
||||
client = _factory.createClient(req);
|
||||
client.startSession(this, creds, conn, rsp.authdata);
|
||||
|
||||
// map their client instance
|
||||
_usermap.put(username, client);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Failed to instantiate client instance to " +
|
||||
"manage new client connection '" + conn + "'.");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
// map their client instance
|
||||
_usermap.put(username, client);
|
||||
}
|
||||
|
||||
// map this connection to this client
|
||||
@@ -336,7 +308,7 @@ public class ClientManager
|
||||
Connection conn, IOException fault)
|
||||
{
|
||||
// remove the client from the connection map
|
||||
PresentsClient client = (PresentsClient)_conmap.remove(conn);
|
||||
PresentsClient client = _conmap.remove(conn);
|
||||
if (client != null) {
|
||||
Log.info("Unmapped failed client [client=" + client +
|
||||
", conn=" + conn + ", fault=" + fault + "].");
|
||||
@@ -356,7 +328,7 @@ public class ClientManager
|
||||
public synchronized void connectionClosed (Connection conn)
|
||||
{
|
||||
// remove the client from the connection map
|
||||
PresentsClient client = (PresentsClient)_conmap.remove(conn);
|
||||
PresentsClient client = _conmap.remove(conn);
|
||||
if (client != null) {
|
||||
Log.debug("Unmapped client [client=" + client +
|
||||
", conn=" + conn + "].");
|
||||
@@ -405,8 +377,7 @@ public class ClientManager
|
||||
{
|
||||
// remove the client from the username map
|
||||
Credentials creds = client.getCredentials();
|
||||
PresentsClient rc = (PresentsClient)
|
||||
_usermap.remove(creds.getUsername());
|
||||
PresentsClient rc = _usermap.remove(creds.getUsername());
|
||||
|
||||
// sanity check just because we can
|
||||
if (rc == null) {
|
||||
@@ -426,26 +397,23 @@ public class ClientManager
|
||||
*/
|
||||
protected void flushClients ()
|
||||
{
|
||||
ArrayList victims = null;
|
||||
ArrayList<PresentsClient> victims = null;
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
// first build a list of our victims (we can't flush clients
|
||||
// directly while iterating due to risk of a
|
||||
// ConcurrentModificationException)
|
||||
Iterator iter = _usermap.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
PresentsClient client = (PresentsClient)iter.next();
|
||||
for (PresentsClient client : _usermap.values()) {
|
||||
if (client.checkExpired(now)) {
|
||||
if (victims == null) {
|
||||
victims = new ArrayList();
|
||||
victims = new ArrayList<PresentsClient>();
|
||||
}
|
||||
victims.add(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (victims != null) {
|
||||
for (int ii = 0; ii < victims.size(); ii++) {
|
||||
PresentsClient client = (PresentsClient)victims.get(ii);
|
||||
for (PresentsClient client : victims) {
|
||||
try {
|
||||
Log.info("Client expired, ending session " +
|
||||
"[client=" + client +
|
||||
@@ -495,25 +463,23 @@ public class ClientManager
|
||||
}
|
||||
|
||||
/** A mapping from auth username to client instances. */
|
||||
protected HashMap _usermap = new HashMap();
|
||||
protected HashMap<Name,PresentsClient> _usermap =
|
||||
new HashMap<Name,PresentsClient>();
|
||||
|
||||
/** A mapping from connections to client instances. */
|
||||
protected HashMap _conmap = new HashMap();
|
||||
protected HashMap<Connection,PresentsClient> _conmap =
|
||||
new HashMap<Connection,PresentsClient>();
|
||||
|
||||
/** A mapping from usernames to client object instances. */
|
||||
protected HashMap _objmap = new HashMap();
|
||||
protected HashMap<Name,ClientObject> _objmap =
|
||||
new HashMap<Name,ClientObject>();
|
||||
|
||||
/** A mapping of pending client resolvers. */
|
||||
protected HashMap _penders = new HashMap();
|
||||
|
||||
/** A set containing the usernames of all locked clients. */
|
||||
protected HashSet _locks = new HashSet();
|
||||
protected HashMap<Name,ClientResolver> _penders =
|
||||
new HashMap<Name,ClientResolver>();
|
||||
|
||||
/** The client class in use. */
|
||||
protected Class _clientClass = PresentsClient.class;
|
||||
|
||||
/** The client resolver class in use. */
|
||||
protected Class _clrClass = ClientResolver.class;
|
||||
protected ClientFactory _factory = ClientFactory.DEFAULT;
|
||||
|
||||
/** A count of how many client objects are currently being resolved. */
|
||||
protected int _outstandingResolutions;
|
||||
|
||||
Reference in New Issue
Block a user