Modify PresentsClient and ClientResolver creation so that we can inject

dependencies into both. Moved the legacy statics into CrowdServer so that at
least Presents can be pure (we should probably eventually move them into
BangServer and PiracyServer and fix everything else). Added some useful manager
references to PlaceManager delegate (_omgr, _invmgr) that handle the majority
of their service needs.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5170 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2008-06-08 20:23:49 +00:00
parent eeb2584c0d
commit 0128f6525a
13 changed files with 133 additions and 103 deletions
@@ -27,29 +27,30 @@ import com.threerings.presents.data.ClientObject;
import com.threerings.presents.net.AuthRequest;
/**
* Used to create a {@link PresentsClient} instance to manage an authenticated
* client.
* Used to determine what type of {@link PresentsClient} to use to manage an authenticated client
* as well the type of {@link ClientResolver} to use when resolving clients' runtime data.
*/
public interface ClientFactory
{
/** The default client factory. */
public static ClientFactory DEFAULT = new ClientFactory () {
public PresentsClient createClient (AuthRequest areq) {
return new PresentsClient();
public Class<? extends PresentsClient> getClientClass (AuthRequest areq) {
return PresentsClient.class;
}
public ClientResolver createClientResolver (Name username) {
return new ClientResolver();
public Class<? extends ClientResolver> getClientResolverClass (Name username) {
return ClientResolver.class;
}
};
/**
* Creates an uninitialized client instance for the client that has
* authenticated using the supplied request.
* Returns the {@link PresentsClient} derived class to use for the session that authenticated
* with the supplied request.
*/
public PresentsClient createClient (AuthRequest areq);
public Class<? extends PresentsClient> getClientClass (AuthRequest areq);
/**
* Requests a resolver for the client identified by the specified username.
* Returns the {@link ClientResolver} derived class to use to resolve a client with the
* specified username.
*/
public ClientResolver createClientResolver (Name username);
public Class <? extends ClientResolver> getClientResolverClass (Name username);
}
@@ -29,6 +29,7 @@ import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import com.samskivert.util.Interval;
@@ -112,6 +113,15 @@ public class ClientManager
}.schedule(CLIENT_FLUSH_INTERVAL, true);
}
/**
* Configures the injector we'll use to resolve dependencies for {@link PresentsClient}
* instances.
*/
public void setInjector (Injector injector)
{
_injector = injector;
}
// from interface ShutdownManager.Shutdowner
public void shutdown ()
{
@@ -261,7 +271,7 @@ public class ClientManager
try {
// create a client resolver instance which will create our client object, populate it
// and notify the listeners
clr = _factory.createClientResolver(username);
clr = _injector.getInstance(_factory.getClientResolverClass(username));
clr.init(username);
clr.addResolutionListener(this);
clr.addResolutionListener(listener);
@@ -368,8 +378,8 @@ public class ClientManager
} else {
log.info("Session initiated [username=" + username + ", conn=" + conn + "].");
// create a new client and stick'em in the table
client = _factory.createClient(req);
client.startSession(this, req, conn, rsp.authdata);
client = _injector.getInstance(_factory.getClientClass(req));
client.startSession(req, conn, rsp.authdata);
// map their client instance
synchronized (_usermap) {
@@ -534,6 +544,9 @@ public class ClientManager
protected ClientOp _clop;
}
/** Used to resolve dependencies in {@link PresentClient} instances that we create. */
protected Injector _injector;
/** A mapping from auth username to client instances. */
protected Map<Name,PresentsClient> _usermap = Maps.newHashMap();
@@ -546,7 +559,7 @@ public class ClientManager
/** A mapping of pending client resolvers. */
protected Map<Name,ClientResolver> _penders = Maps.newHashMap();
/** The client class in use. */
/** Lets us know what sort of client classes to use. */
protected ClientFactory _factory = ClientFactory.DEFAULT;
/** Tracks registered {@link ClientObserver}s. */
@@ -21,15 +21,20 @@
package com.threerings.presents.server;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.samskivert.util.Invoker;
import com.threerings.util.Name;
import com.threerings.presents.annotation.MainInvoker;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.PermissionPolicy;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.ObjectAccessException;
import com.threerings.presents.dobj.RootDObjectManager;
import static com.threerings.presents.Log.log;
@@ -84,7 +89,7 @@ public class ClientResolver extends Invoker.Unit
// we've got our object, so shunt ourselves over to the invoker thread to perform database
// loading
_clobj = object;
PresentsServer.invoker.postUnit(this);
_invoker.postUnit(this);
}
// documentation inherited
@@ -128,7 +133,7 @@ public class ClientResolver extends Invoker.Unit
} else {
// destroy the dangling user object
PresentsServer.omgr.destroyObject(_clobj.getOid());
_omgr.destroyObject(_clobj.getOid());
// let our listener know that we're hosed
reportFailure(_failure);
@@ -182,12 +187,14 @@ public class ClientResolver extends Invoker.Unit
protected Name _username;
/** The entities to notify of success or failure. */
protected ArrayList<ClientResolutionListener> _listeners =
new ArrayList<ClientResolutionListener>();
protected List<ClientResolutionListener> _listeners = Lists.newArrayList();
/** The resolving client object. */
protected ClientObject _clobj;
/** A place to keep an exception around for a moment. */
protected Exception _failure;
@Inject @MainInvoker Invoker _invoker;
@Inject RootDObjectManager _omgr;
}
@@ -26,6 +26,7 @@ import java.net.InetAddress;
import java.util.HashMap;
import java.util.TimeZone;
import com.google.inject.Inject;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.ResultListener;
import com.samskivert.util.Throttle;
@@ -60,6 +61,7 @@ import com.threerings.presents.net.PongResponse;
import com.threerings.presents.net.UnsubscribeResponse;
import com.threerings.presents.server.net.Connection;
import com.threerings.presents.server.net.ConnectionManager;
import com.threerings.presents.server.net.MessageHandler;
import static com.threerings.presents.Log.log;
@@ -196,7 +198,7 @@ public class PresentsClient
log.warning("Client disappeared before we could complete the switch to a " +
"new client object [ousername=" + _username +
", nusername=" + username + "].");
_cmgr.releaseClientObject(username);
_clmgr.releaseClientObject(username);
Exception error = new Exception("Early withdrawal");
resolutionFailed(username, error);
return;
@@ -230,7 +232,7 @@ public class PresentsClient
_clobj.postMessage(ClientObject.CLOBJ_CHANGED, args);
// release our old client object; this will destroy it
_cmgr.releaseClientObject(_username);
_clmgr.releaseClientObject(_username);
// update our internal fields
_username = username;
@@ -257,7 +259,7 @@ public class PresentsClient
};
// resolve the new client object
_cmgr.resolveClientObject(username, clr);
_clmgr.resolveClientObject(username, clr);
}
/**
@@ -271,7 +273,7 @@ public class PresentsClient
*/
public boolean updateUsername (Name username)
{
if (_cmgr.renameClientObject(_username, username)) {
if (_clmgr.renameClientObject(_username, username)) {
_username = username;
return true;
}
@@ -297,7 +299,7 @@ public class PresentsClient
// 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
PresentsServer.conmgr.closeConnection(conn);
_conmgr.closeConnection(conn);
}
// if we don't have a client object, we failed to resolve in the first place, in which case
@@ -311,11 +313,11 @@ public class PresentsClient
}
// release (and destroy) our client object
_cmgr.releaseClientObject(_username);
_clmgr.releaseClientObject(_username);
}
// let the client manager know that we're audi 5000
_cmgr.clientSessionDidEnd(this);
_clmgr.clientSessionDidEnd(this);
// clear out the client object so that we know the session is over
_clobj = null;
@@ -356,7 +358,7 @@ public class PresentsClient
sendBootstrap();
// let the client manager know that we're operational
_cmgr.clientSessionDidStart(this);
_clmgr.clientSessionDidStart(this);
}
// from interface ClientResolutionListener
@@ -420,10 +422,8 @@ public class PresentsClient
* 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)
protected void startSession (AuthRequest req, Connection conn, Object authdata)
{
_cmgr = cmgr;
_areq = req;
_authdata = authdata;
setConnection(conn);
@@ -432,7 +432,7 @@ public class PresentsClient
assignStartingUsername();
// resolve our client object before we get fully underway
cmgr.resolveClientObject(_username, this);
_clmgr.resolveClientObject(_username, this);
// make a note of our session start time
_sessionStamp = System.currentTimeMillis();
@@ -481,7 +481,7 @@ public class PresentsClient
}
// we need to get onto the dobj thread so that we can finalize resumption of the session
PresentsServer.omgr.postRunnable(new Runnable() {
_omgr.postRunnable(new Runnable() {
public void run () {
// now that we're on the dobjmgr thread we can resume our session resumption
finishResumeSession();
@@ -516,7 +516,7 @@ public class PresentsClient
*/
protected void safeEndSession ()
{
PresentsServer.omgr.postRunnable(new Runnable() {
_omgr.postRunnable(new Runnable() {
public void run () {
endSession();
}
@@ -679,7 +679,7 @@ public class PresentsClient
log.warning("Client provided no invocation service boot groups? " + this);
data.services = new StreamableArrayList<InvocationMarshaller>();
} else {
data.services = PresentsServer.invmgr.getBootstrapServices(_areq.getBootGroups());
data.services = _invmgr.getBootstrapServices(_areq.getBootGroups());
}
}
@@ -699,7 +699,7 @@ public class PresentsClient
// 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() {
_omgr.postRunnable(new Runnable() {
public void run () {
sessionConnectionClosed();
}
@@ -773,7 +773,7 @@ public class PresentsClient
* the supplied message to this client. */
protected final void safePostMessage (final DownstreamMessage msg)
{
PresentsServer.omgr.postRunnable(new Runnable() {
_omgr.postRunnable(new Runnable() {
public void run () {
postMessage(msg);
}
@@ -851,7 +851,7 @@ public class PresentsClient
public void objectAvailable (DObject object)
{
if (postMessage(new ObjectResponse<DObject>(object))) {
_firstEventId = PresentsServer.omgr.getNextEventId(false);
_firstEventId = _omgr.getNextEventId(false);
this.object = object;
synchronized (_subscrips) {
// make a note of this new subscription
@@ -918,7 +918,7 @@ public class PresentsClient
// log.info("Subscribing [client=" + client + ", oid=" + req.getOid() + "].");
// forward the subscribe request to the omgr for processing
PresentsServer.omgr.subscribeToObject(req.getOid(), client.createProxySubscriber());
client._omgr.subscribeToObject(req.getOid(), client.createProxySubscriber());
}
}
@@ -965,7 +965,7 @@ public class PresentsClient
// log.info("Forwarding event [client=" + client + ", event=" + fevt + "].");
// forward the event to the omgr for processing
PresentsServer.omgr.postEvent(fevt);
client._omgr.postEvent(fevt);
}
}
@@ -994,7 +994,11 @@ public class PresentsClient
}
}
protected ClientManager _cmgr;
@Inject protected ClientManager _clmgr;
@Inject protected ConnectionManager _conmgr;
@Inject protected PresentsDObjectMgr _omgr;
@Inject protected InvocationManager _invmgr;
protected AuthRequest _areq;
protected Object _authdata;
protected Name _username;
@@ -65,21 +65,6 @@ public class PresentsServer
}
}
/** OBSOLETE! Don't use me. */
public static ConnectionManager conmgr;
/** OBSOLETE! Don't use me. */
public static ClientManager clmgr;
/** OBSOLETE! Don't use me. */
public static PresentsDObjectMgr omgr;
/** OBSOLETE! Don't use me. */
public static InvocationManager invmgr;
/** OBSOLETE! Don't use me. */
public static Invoker invoker;
/**
* The default entry point for the server.
*/
@@ -120,13 +105,6 @@ public class PresentsServer
public void init (Injector injector)
throws Exception
{
// populate our legacy statics
conmgr = _conmgr;
clmgr = _clmgr;
omgr = _omgr;
invmgr = _invmgr;
invoker = _invoker;
// output general system information
SystemInfo si = new SystemInfo();
log.info("Starting up server [os=" + si.osToString() + ", jvm=" + si.jvmToString() +
@@ -150,11 +128,14 @@ public class PresentsServer
_invoker.start();
_authInvoker.start();
// provide our client manager with the injector it needs
_clmgr.setInjector(injector);
// configure our connection manager
_conmgr.init(getListenPorts(), getDatagramPorts());
// initialize the time base services
TimeBaseProvider.init(invmgr, omgr);
TimeBaseProvider.init(_invmgr, _omgr);
}
/**
@@ -189,14 +170,14 @@ public class PresentsServer
{
// post a unit that will start up the connection manager when everything else in the
// dobjmgr queue is processed
omgr.postRunnable(new Runnable() {
_omgr.postRunnable(new Runnable() {
public void run () {
// start up the connection manager
_conmgr.start();
}
});
// invoke the dobjmgr event loop
omgr.run();
_omgr.run();
}
/**