Revamped distributed object creation. There was no particular reason to create
distributed objects by reflection since we don't allow clients to create objects, furthermore we needn't do it asynchronously. The object creation methods were moved into the server-side only interface and made "immediate", so the caller creates a derived instance of DObject and registers it with the system instead of creating it with a Subscriber callback. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4342 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -105,24 +105,9 @@ public class CrowdPeerManager extends PeerManager
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
protected void finishInit (NodeObject nodeobj)
|
||||
protected NodeObject createNodeObject ()
|
||||
{
|
||||
super.finishInit(nodeobj);
|
||||
|
||||
// register and initialize our invocation service
|
||||
CrowdNodeObject cnobj = (CrowdNodeObject)nodeobj;
|
||||
cnobj.setCrowdPeerService(
|
||||
(CrowdPeerMarshaller)CrowdServer.invmgr.registerDispatcher(
|
||||
new CrowdPeerDispatcher(this), false));
|
||||
|
||||
// register ourselves as a tell forwarder
|
||||
CrowdServer.chatprov.setTellForwarder(this);
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
protected Class<? extends NodeObject> getNodeObjectClass ()
|
||||
{
|
||||
return CrowdNodeObject.class;
|
||||
return new CrowdNodeObject();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
@@ -138,4 +123,19 @@ public class CrowdPeerManager extends PeerManager
|
||||
((CrowdClientInfo)info).visibleName =
|
||||
((BodyObject)client.getClientObject()).getVisibleName();
|
||||
}
|
||||
|
||||
@Override // documentation inherited
|
||||
protected void didInit ()
|
||||
{
|
||||
super.didInit();
|
||||
|
||||
// register and initialize our invocation service
|
||||
CrowdNodeObject cnobj = (CrowdNodeObject)_nodeobj;
|
||||
cnobj.setCrowdPeerService(
|
||||
(CrowdPeerMarshaller)CrowdServer.invmgr.registerDispatcher(
|
||||
new CrowdPeerDispatcher(this), false));
|
||||
|
||||
// register ourselves as a tell forwarder
|
||||
CrowdServer.chatprov.setTellForwarder(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ import com.threerings.crowd.data.BodyObject;
|
||||
public class CrowdClientResolver extends ClientResolver
|
||||
{
|
||||
// documentation inherited
|
||||
public Class<? extends ClientObject> getClientObjectClass ()
|
||||
public ClientObject createClientObject ()
|
||||
{
|
||||
return BodyObject.class;
|
||||
return new BodyObject();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
|
||||
@@ -161,17 +161,20 @@ public class PlaceManager
|
||||
}
|
||||
|
||||
/**
|
||||
* A place manager derived class is likely to have a corresponding
|
||||
* derived class of {@link com.threerings.crowd.data.PlaceObject} that
|
||||
* it will be managing. Derived classes should override this method
|
||||
* and return the class object for the place object derived class they
|
||||
* desire to use. The place registry will use this method to create
|
||||
* the proper place object during the place creation process.
|
||||
*
|
||||
* @return the class of the class, derived from {@link PlaceObject},
|
||||
* that this manager wishes to manage.
|
||||
*
|
||||
* @see PlaceRegistry#createPlace
|
||||
* Derived classes will generally override this method to create a custom
|
||||
* {@link PlaceObject} derivation that contains extra information.
|
||||
*/
|
||||
protected PlaceObject createPlaceObject ()
|
||||
{
|
||||
try {
|
||||
return getPlaceObjectClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createPlaceObject}.
|
||||
*/
|
||||
protected Class<? extends PlaceObject> getPlaceObjectClass ()
|
||||
{
|
||||
|
||||
@@ -24,13 +24,8 @@ package com.threerings.crowd.server;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.Tuple;
|
||||
import com.samskivert.util.Queue;
|
||||
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.RootDObjectManager;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
import com.threerings.presents.server.InvocationException;
|
||||
import com.threerings.presents.server.InvocationManager;
|
||||
|
||||
@@ -45,21 +40,11 @@ import com.threerings.crowd.data.PlaceObject;
|
||||
* places.
|
||||
*/
|
||||
public class PlaceRegistry
|
||||
implements Subscriber<PlaceObject>
|
||||
{
|
||||
/**
|
||||
* Used to receive a callback when the place object associated with a
|
||||
* place manager (created via {@link PlaceRegistry#createPlace}) is
|
||||
* created.
|
||||
*/
|
||||
public static interface CreationObserver
|
||||
/** Used in conjunction with {@link #createPlace}. */
|
||||
public static interface PreStartupHook
|
||||
{
|
||||
/**
|
||||
* Called when the place object is created and after it is
|
||||
* provided to the place manager that will be handling management
|
||||
* of the place.
|
||||
*/
|
||||
public void placeCreated (PlaceObject place, PlaceManager pmgr);
|
||||
public void invoke (PlaceManager plmgr);
|
||||
}
|
||||
|
||||
/** The location provider used by the place registry to provide
|
||||
@@ -98,31 +83,39 @@ public class PlaceRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and registers a new place manager along with the place
|
||||
* object to be managed. The registry takes care of tracking the
|
||||
* creation of the object and informing the manager when it is
|
||||
* created.
|
||||
* Creates and registers a new place manager along with the place object to
|
||||
* be managed. The registry takes care of tracking the creation of the
|
||||
* object and informing the manager when it is created.
|
||||
*
|
||||
* @param config the configuration object for the place to be
|
||||
* created. The {@link PlaceManager} derived class that should be
|
||||
* instantiated to manage the place will be determined from the config
|
||||
* object.
|
||||
* @param observer an observer that will be notified when the place
|
||||
* object creation has completed (called after the place object is
|
||||
* provided to the place manager).
|
||||
* @param config the configuration object for the place to be created. The
|
||||
* {@link PlaceManager} derived class that should be instantiated to manage
|
||||
* the place will be determined from the config object.
|
||||
*
|
||||
* @return a reference to the place manager that will manage the new
|
||||
* place object.
|
||||
* @return a reference to the place manager, which will have been
|
||||
* configured with its place object and started up (via a call to {@link
|
||||
* PlaceManager#startup}.
|
||||
*
|
||||
* @exception InstantiationException thrown if an error occurs trying
|
||||
* to instantiate and initialize the place manager.
|
||||
* @exception InstantiationException thrown if an error occurs trying to
|
||||
* instantiate and initialize the place manager.
|
||||
* @exception InvocationException thrown if the place manager returns
|
||||
* failure from the call to {@link PlaceManager#checkPermissions}. The
|
||||
* error string returned by that call will be provided as in the
|
||||
* exception.
|
||||
* error string returned by that call will be provided as in the exception.
|
||||
*/
|
||||
public PlaceManager createPlace (
|
||||
PlaceConfig config, CreationObserver observer)
|
||||
public PlaceManager createPlace (PlaceConfig config)
|
||||
throws InstantiationException, InvocationException
|
||||
{
|
||||
return createPlace(config, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't use this method, see {@link #createPlace(PlaceConfig)}..
|
||||
*
|
||||
* @param hook an optional pre-startup hook that allows a place manager to
|
||||
* be configured prior to having {@link PlaceManager#startup} called. This
|
||||
* mainly exists because it used to be possible to do such things. Try not
|
||||
* to use this in new code.
|
||||
*/
|
||||
public PlaceManager createPlace (PlaceConfig config, PreStartupHook hook)
|
||||
throws InstantiationException, InvocationException
|
||||
{
|
||||
PlaceManager pmgr = null;
|
||||
@@ -153,16 +146,25 @@ public class PlaceRegistry
|
||||
throw new InvocationException(errmsg);
|
||||
}
|
||||
|
||||
// stick the manager on the creation queue because we know
|
||||
// we'll get our calls to objectAvailable()/requestFailed() in
|
||||
// the order that we call createObject()
|
||||
_createq.append(
|
||||
new Tuple<PlaceManager,CreationObserver>(pmgr, observer));
|
||||
// and create and register the place object
|
||||
PlaceObject plobj = pmgr.createPlaceObject();
|
||||
_omgr.registerObject(plobj);
|
||||
|
||||
// and request to create the place object
|
||||
@SuppressWarnings("unchecked") Class<PlaceObject> pclass =
|
||||
(Class<PlaceObject>)pmgr.getPlaceObjectClass();
|
||||
_omgr.createObject(pclass, this);
|
||||
// stick the manager into our table
|
||||
_pmgrs.put(plobj.getOid(), pmgr);
|
||||
|
||||
// start the place manager up with the newly created place object
|
||||
try {
|
||||
if (hook != null) {
|
||||
hook.invoke(pmgr);
|
||||
}
|
||||
|
||||
pmgr.startup(plobj);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Error starting place manager [obj=" + plobj +
|
||||
", pmgr=" + pmgr + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
|
||||
return pmgr;
|
||||
}
|
||||
@@ -213,63 +215,6 @@ public class PlaceRegistry
|
||||
return _pmgrs.values().iterator();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void objectAvailable (PlaceObject plobj)
|
||||
{
|
||||
// pop the next place manager off of the queue and let it know
|
||||
// that everything went swimmingly
|
||||
Tuple<PlaceManager,CreationObserver> tuple = _createq.getNonBlocking();
|
||||
if (tuple == null) {
|
||||
Log.warning("Place created but no manager queued up to hear " +
|
||||
"about it!? [pobj=" + plobj + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
PlaceManager pmgr = tuple.left;
|
||||
CreationObserver observer = tuple.right;
|
||||
|
||||
// stick the manager into our table
|
||||
_pmgrs.put(plobj.getOid(), pmgr);
|
||||
|
||||
// start the place manager up with the newly created place object
|
||||
try {
|
||||
pmgr.startup(plobj);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Error starting place manager [obj=" + plobj +
|
||||
", pmgr=" + pmgr + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
|
||||
// inform the creation observer that the place object was created
|
||||
// and provided to the manager
|
||||
if (observer != null) {
|
||||
try {
|
||||
observer.placeCreated(plobj, pmgr);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Error informing CreationObserver of place " +
|
||||
"[obj=" + plobj + ", pmgr=" + pmgr +
|
||||
", obs=" + observer + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void requestFailed (int oid, ObjectAccessException cause)
|
||||
{
|
||||
// pop a place manager off the queue since it is queued up to
|
||||
// manage the failed place object
|
||||
Tuple<PlaceManager,CreationObserver> tuple = _createq.getNonBlocking();
|
||||
if (tuple == null) {
|
||||
Log.warning("Place creation failed but no manager queued " +
|
||||
"up to hear about it!? [cause=" + cause + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.warning("Failed to create place object [mgr=" + tuple.left +
|
||||
", cause=" + cause + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the place manager when it has been shut down.
|
||||
*/
|
||||
@@ -294,10 +239,6 @@ public class PlaceRegistry
|
||||
/** The distributed object manager with which we operate. */
|
||||
protected RootDObjectManager _omgr;
|
||||
|
||||
/** A queue of place managers waiting for their place objects. */
|
||||
protected Queue<Tuple<PlaceManager,CreationObserver>> _createq =
|
||||
new Queue<Tuple<PlaceManager,CreationObserver>>();
|
||||
|
||||
/** A mapping from place object id to place manager. */
|
||||
protected HashIntMap<PlaceManager> _pmgrs = new HashIntMap<PlaceManager>();
|
||||
}
|
||||
|
||||
@@ -82,14 +82,6 @@ public class ClientDObjectMgr
|
||||
return false;
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public <T extends DObject> void createObject (
|
||||
Class<T> dclass, Subscriber<T> target)
|
||||
{
|
||||
// not presently supported
|
||||
throw new RuntimeException("createObject() not supported");
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public <T extends DObject> void subscribeToObject (
|
||||
int oid, Subscriber<T> target)
|
||||
@@ -125,13 +117,6 @@ public class ClientDObjectMgr
|
||||
_comm.postMessage(new ForwardEventRequest(event));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public void destroyObject (int oid)
|
||||
{
|
||||
// forward an object destroyed event to the server
|
||||
postEvent(new ObjectDestroyedEvent(oid));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public void removedLastSubscriber (DObject obj, boolean deathWish)
|
||||
{
|
||||
|
||||
@@ -39,23 +39,6 @@ public interface DObjectManager
|
||||
*/
|
||||
public boolean isManager (DObject object);
|
||||
|
||||
/**
|
||||
* Creates a distributed object instance of the supplied class and
|
||||
* notifies the specified subscriber when it becomes available. This
|
||||
* is the proper mechanism for constructing a new distributed object
|
||||
* as it is the only way in which it can be properly registered with
|
||||
* the dobj system.
|
||||
*
|
||||
* @param dclass The class object of the derived class of
|
||||
* <code>DObject</code> (or <code>DObject.class</code> itself) that
|
||||
* should be instantiated.
|
||||
* @param target The subscriber to be notified when the object is
|
||||
* created and available, or if there was a problem creating the
|
||||
* object.
|
||||
*/
|
||||
public <T extends DObject> void createObject (
|
||||
Class<T> dclass, Subscriber<T> target);
|
||||
|
||||
/**
|
||||
* Requests that the specified subscriber be subscribed to the object
|
||||
* identified by the supplied object id. That subscriber will be
|
||||
@@ -83,15 +66,6 @@ public interface DObjectManager
|
||||
public <T extends DObject> void unsubscribeFromObject (
|
||||
int oid, Subscriber<T> target);
|
||||
|
||||
/**
|
||||
* Requests that the specified object be destroyed. Once destroyed an
|
||||
* object is removed from the runtime system and may no longer have
|
||||
* events dispatched on it.
|
||||
*
|
||||
* @param oid The object id of the distributed object to be destroyed.
|
||||
*/
|
||||
public void destroyObject (int oid);
|
||||
|
||||
/**
|
||||
* Posts a distributed object event into the system. Instead of
|
||||
* requesting the modification of a distributed object attribute by
|
||||
|
||||
@@ -35,4 +35,22 @@ public interface RootDObjectManager extends DObjectManager
|
||||
* table, returning null if no object exists with that oid.
|
||||
*/
|
||||
public DObject getObject (int oid);
|
||||
|
||||
/**
|
||||
* Registers a distributed object instance of the supplied class with the
|
||||
* system and assigns it an oid. When the call returns the object will be
|
||||
* registered with the system and its oid will have been assigned.
|
||||
*
|
||||
* @return the registered object for the caller's convenience.
|
||||
*/
|
||||
public <T extends DObject> T registerObject (T object);
|
||||
|
||||
/**
|
||||
* Requests that the specified object be destroyed. Once destroyed an
|
||||
* object is removed from the runtime system and may no longer have
|
||||
* events dispatched on it.
|
||||
*
|
||||
* @param oid The object id of the distributed object to be destroyed.
|
||||
*/
|
||||
public void destroyObject (int oid);
|
||||
}
|
||||
|
||||
@@ -116,16 +116,36 @@ public class PeerManager
|
||||
this, PresentsServer.clmgr.getClientFactory()));
|
||||
|
||||
// create our node object
|
||||
@SuppressWarnings("unchecked") Class<NodeObject> clazz =
|
||||
(Class<NodeObject>)getNodeObjectClass();
|
||||
PresentsServer.omgr.createObject(clazz, new Subscriber<NodeObject>() {
|
||||
public void objectAvailable (NodeObject object) {
|
||||
finishInit(object);
|
||||
}
|
||||
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||
log.warning("Failed to create NodeObject: " + cause + ".");
|
||||
_nodeobj = PresentsServer.omgr.registerObject(createNodeObject());
|
||||
|
||||
// register ourselves with the node table
|
||||
_invoker.postUnit(new Invoker.Unit() {
|
||||
public boolean invoke () {
|
||||
NodeRecord record = new NodeRecord(
|
||||
_nodeName, _hostName, _publicHostName, _port);
|
||||
try {
|
||||
_noderepo.updateNode(record);
|
||||
} catch (PersistenceException pe) {
|
||||
log.warning("Failed to register node record " +
|
||||
"[rec=" + record + ", error=" + pe + "].");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// register ourselves as a client observer
|
||||
PresentsServer.clmgr.addClientObserver(this);
|
||||
|
||||
// and start our peer refresh interval (this need not use a runqueue as
|
||||
// all it will do is post an invoker unit)
|
||||
new Interval() {
|
||||
public void expired () {
|
||||
refreshPeers();
|
||||
}
|
||||
}.schedule(5000L, 60*1000L);
|
||||
|
||||
// give derived classes an easy way to get in on the init action
|
||||
didInit();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,38 +221,10 @@ public class PeerManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once our node object is available.
|
||||
* Called after we have finished our initialization.
|
||||
*/
|
||||
protected void finishInit (NodeObject nodeobj)
|
||||
protected void didInit ()
|
||||
{
|
||||
// keep a handle on our node object
|
||||
_nodeobj = nodeobj;
|
||||
|
||||
// register ourselves with the node table
|
||||
_invoker.postUnit(new Invoker.Unit() {
|
||||
public boolean invoke () {
|
||||
NodeRecord record = new NodeRecord(
|
||||
_nodeName, _hostName, _publicHostName, _port);
|
||||
try {
|
||||
_noderepo.updateNode(record);
|
||||
} catch (PersistenceException pe) {
|
||||
log.warning("Failed to register node record " +
|
||||
"[rec=" + record + ", error=" + pe + "].");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// register ourselves as a client observer
|
||||
PresentsServer.clmgr.addClientObserver(this);
|
||||
|
||||
// and start our peer refresh interval (this need not use a runqueue as
|
||||
// all it will do is post an invoker unit)
|
||||
new Interval() {
|
||||
public void expired () {
|
||||
refreshPeers();
|
||||
}
|
||||
}.schedule(5000L, 60*1000L);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,11 +276,12 @@ public class PeerManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class we use when creating our {@link NodeObject}.
|
||||
* Creates the appropriate derived class of {@link NodeObject} which will
|
||||
* be registered with the distributed object system.
|
||||
*/
|
||||
protected Class<? extends NodeObject> getNodeObjectClass ()
|
||||
protected NodeObject createNodeObject ()
|
||||
{
|
||||
return NodeObject.class;
|
||||
return new NodeObject();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -265,11 +265,10 @@ public class ClientManager
|
||||
clr.addResolutionListener(listener);
|
||||
_penders.put(username, clr);
|
||||
|
||||
// request that the appropriate client object be created by the
|
||||
// dobject manager which starts the whole business off
|
||||
@SuppressWarnings("unchecked") Class<ClientObject> cclass =
|
||||
(Class<ClientObject>)clr.getClientObjectClass();
|
||||
PresentsServer.omgr.createObject(cclass, clr);
|
||||
// create and register our client object and give it back to the
|
||||
// client resolver
|
||||
clr.objectAvailable(
|
||||
PresentsServer.omgr.registerObject(clr.createClientObject()));
|
||||
|
||||
} catch (Exception e) {
|
||||
// let the listener know that we're hosed
|
||||
|
||||
@@ -30,7 +30,6 @@ import com.threerings.presents.Log;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
|
||||
/**
|
||||
* Used to resolve client data when a user starts a session (or when some
|
||||
@@ -40,7 +39,6 @@ import com.threerings.presents.dobj.Subscriber;
|
||||
* appropriately.
|
||||
*/
|
||||
public class ClientResolver extends Invoker.Unit
|
||||
implements Subscriber<ClientObject>
|
||||
{
|
||||
/**
|
||||
* Initiailizes this instance.
|
||||
@@ -61,32 +59,24 @@ public class ClientResolver extends Invoker.Unit
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ClientObject} derived class that should be
|
||||
* created to kick off the resolution process.
|
||||
* Creates the {@link ClientObject} derived class that should be created to
|
||||
* kick off the resolution process.
|
||||
*/
|
||||
public Class<? extends ClientObject> getClientObjectClass ()
|
||||
public ClientObject createClientObject ()
|
||||
{
|
||||
return ClientObject.class;
|
||||
return new ClientObject();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
/**
|
||||
* Called once our client object is registered with the distributed object
|
||||
* system.
|
||||
*/
|
||||
public void objectAvailable (ClientObject object)
|
||||
{
|
||||
// we've got our object, so shunt ourselves over to the invoker
|
||||
// thread to perform database loading
|
||||
// we've got our object, so shunt ourselves over to the invoker thread
|
||||
// to perform database loading
|
||||
_clobj = object;
|
||||
PresentsServer.invoker.postUnit(this);
|
||||
|
||||
// we no longer need to be a subscriber of the object now that it
|
||||
// has been created
|
||||
_clobj.removeSubscriber(this);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void requestFailed (int oid, ObjectAccessException cause)
|
||||
{
|
||||
// pass the buck
|
||||
reportFailure(cause);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.LRUHashMap;
|
||||
import com.samskivert.util.StringUtil;
|
||||
@@ -41,7 +39,6 @@ import com.threerings.presents.dobj.EventListener;
|
||||
import com.threerings.presents.dobj.InvocationRequestEvent;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.RootDObjectManager;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
|
||||
/**
|
||||
* The invocation services provide client to server invocations (service
|
||||
@@ -65,7 +62,7 @@ import com.threerings.presents.dobj.Subscriber;
|
||||
* the client.
|
||||
*/
|
||||
public class InvocationManager
|
||||
implements Subscriber<DObject>, EventListener
|
||||
implements EventListener
|
||||
{
|
||||
/** The list of services that are to be provided to clients at boot
|
||||
* time. Don't mess with this list! */
|
||||
@@ -83,9 +80,16 @@ public class InvocationManager
|
||||
_omgr = omgr;
|
||||
|
||||
// create the object on which we'll listen for invocation requests
|
||||
omgr.createObject(DObject.class, this);
|
||||
DObject invobj = omgr.registerObject(new DObject());
|
||||
invobj.addListener(this);
|
||||
_invoid = invobj.getOid();
|
||||
|
||||
// Log.info("Created invocation service object [oid=" + _invoid + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object id of the invocation services object.
|
||||
*/
|
||||
public int getOid ()
|
||||
{
|
||||
return _invoid;
|
||||
@@ -111,13 +115,6 @@ public class InvocationManager
|
||||
InvocationMarshaller marsh = dispatcher.createMarshaller();
|
||||
marsh.init(_invoid, invCode);
|
||||
|
||||
// if we haven't yet finished our own initialization, we need to
|
||||
// throw this dispatcher on a queue so that we can fill in its
|
||||
// invocation oid when we know what it should be
|
||||
if (_invoid == -1) {
|
||||
_lateInitQueue.add(marsh);
|
||||
}
|
||||
|
||||
// register the dispatcher
|
||||
_dispatchers.put(invCode, dispatcher);
|
||||
|
||||
@@ -165,32 +162,6 @@ public class InvocationManager
|
||||
return (dispatcher == null) ? null : dispatcher.getClass();
|
||||
}
|
||||
|
||||
public void objectAvailable (DObject object)
|
||||
{
|
||||
// this must be our invocation object
|
||||
_invoid = object.getOid();
|
||||
|
||||
// add ourselves as a message listener
|
||||
object.addListener(this);
|
||||
|
||||
// let any early registered marshallers know about our invoid
|
||||
while (_lateInitQueue.size() > 0) {
|
||||
InvocationMarshaller marsh = _lateInitQueue.remove(0);
|
||||
marsh.setInvocationOid(_invoid);
|
||||
}
|
||||
|
||||
// Log.info("Created invocation service object [oid=" + _invoid + "].");
|
||||
}
|
||||
|
||||
public void requestFailed (int oid, ObjectAccessException cause)
|
||||
{
|
||||
// if for some reason we were unable to create our invocation
|
||||
// object, we'll end up here
|
||||
Log.warning("Unable to create invocation object " +
|
||||
"[reason=" + cause + "].");
|
||||
_invoid = -1;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void eventReceived (DEvent event)
|
||||
{
|
||||
@@ -314,12 +285,6 @@ public class InvocationManager
|
||||
protected HashIntMap<InvocationDispatcher> _dispatchers =
|
||||
new HashIntMap<InvocationDispatcher>();
|
||||
|
||||
/** Used to keep track of marshallers registered before we had our
|
||||
* invocation object so that we can fill their invocation id in
|
||||
* belatedly. */
|
||||
protected ArrayList<InvocationMarshaller> _lateInitQueue =
|
||||
new ArrayList<InvocationMarshaller>();
|
||||
|
||||
/** The text that is appended to the procedure name when automatically
|
||||
* generating a failure response. */
|
||||
protected static final String FAILED_SUFFIX = "Failed";
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import sun.misc.Perf;
|
||||
|
||||
@@ -39,9 +40,10 @@ import com.samskivert.util.RunQueue;
|
||||
import com.samskivert.util.StringUtil;
|
||||
import com.samskivert.util.Throttle;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.dobj.*;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* The presents distributed object manager implements the {@link
|
||||
* DObjectManager} interface, providing an object manager that runs on the
|
||||
@@ -109,22 +111,14 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
// from interface DObjectManager
|
||||
public boolean isManager (DObject object)
|
||||
{
|
||||
// we are always authoritative in the present implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public <T extends DObject> void createObject (
|
||||
Class<T> dclass, Subscriber<T> target)
|
||||
{
|
||||
// queue up a create object event
|
||||
postEvent(new CreateObjectEvent<T>(dclass, target));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
// from interface DObjectManager
|
||||
public <T extends DObject> void subscribeToObject (
|
||||
int oid, Subscriber<T> target)
|
||||
{
|
||||
@@ -138,7 +132,7 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
// from interface DObjectManager
|
||||
public <T extends DObject> void unsubscribeFromObject (
|
||||
int oid, Subscriber<T> target)
|
||||
{
|
||||
@@ -147,21 +141,14 @@ public class PresentsDObjectMgr
|
||||
oid, target, AccessObjectEvent.UNSUBSCRIBE));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public void destroyObject (int oid)
|
||||
{
|
||||
// queue up an object destroyed event
|
||||
postEvent(new ObjectDestroyedEvent(oid));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
// from interface DObjectManager
|
||||
public void postEvent (DEvent event)
|
||||
{
|
||||
// just append it to the queue
|
||||
_evqueue.append(event);
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
// from interface DObjectManager
|
||||
public void removedLastSubscriber (DObject obj, boolean deathWish)
|
||||
{
|
||||
// destroy the object if it so desires
|
||||
@@ -170,6 +157,31 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
}
|
||||
|
||||
// from interface RootDObjectManager
|
||||
public <T extends DObject> T registerObject (T object)
|
||||
{
|
||||
int oid = getNextOid();
|
||||
|
||||
// initialize this object
|
||||
object.setOid(oid);
|
||||
object.setManager(PresentsDObjectMgr.this);
|
||||
object.setAccessController(_defaultController);
|
||||
|
||||
// insert it into the table
|
||||
_objects.put(oid, object);
|
||||
|
||||
// log.info("Registered object [obj=" + object + "].");
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
// from interface RootDObjectManager
|
||||
public void destroyObject (int oid)
|
||||
{
|
||||
// queue up an object destroyed event
|
||||
postEvent(new ObjectDestroyedEvent(oid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts a self-contained unit of code that should be run on the
|
||||
* distributed object manager thread at the next available
|
||||
@@ -186,13 +198,10 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object in the object table with the specified oid or
|
||||
* null if no object has that oid. Be sure only to call this function
|
||||
* from the dobjmgr thread and not to do anything funny with the
|
||||
* object. If subscription is desired, use
|
||||
* <code>subscribeToObject()</code>.
|
||||
*
|
||||
* @see #subscribeToObject
|
||||
* Returns the object in the object table with the specified oid or null if
|
||||
* no object has that oid. Be sure only to call this function from the
|
||||
* dobjmgr thread and not to do anything funny with the object. If
|
||||
* subscription is desired, use {@link #subscribeToObject}.
|
||||
*/
|
||||
public DObject getObject (int oid)
|
||||
{
|
||||
@@ -227,7 +236,7 @@ public class PresentsDObjectMgr
|
||||
*/
|
||||
public void run ()
|
||||
{
|
||||
Log.info("DOMGR running.");
|
||||
log.info("DOMGR running.");
|
||||
|
||||
// make a note of the thread that's processing events
|
||||
synchronized (this) {
|
||||
@@ -239,7 +248,7 @@ public class PresentsDObjectMgr
|
||||
processUnit(_evqueue.get());
|
||||
}
|
||||
|
||||
Log.info("DOMGR exited.");
|
||||
log.info("DOMGR exited.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,8 +279,8 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Execution unit failed [unit=" + unit + "].");
|
||||
Log.logStackTrace(e);
|
||||
log.log(Level.WARNING,
|
||||
"Execution unit failed [unit=" + unit + "].", e);
|
||||
|
||||
} catch (Error e) {
|
||||
handleFatalError(unit, e);
|
||||
@@ -283,9 +292,9 @@ public class PresentsDObjectMgr
|
||||
|
||||
// report excessively long units
|
||||
if (elapsed > 500000) {
|
||||
Log.warning("Long dobj unit [u=" + StringUtil.safeToString(unit) +
|
||||
" (" + StringUtil.shortClassName(unit) + ")" +
|
||||
", time=" + (elapsed/1000) + "ms].");
|
||||
log.warning("Long dobj unit [u=" + StringUtil.safeToString(unit) +
|
||||
" (" + StringUtil.shortClassName(unit) + ")" +
|
||||
", time=" + (elapsed/1000) + "ms].");
|
||||
}
|
||||
|
||||
// periodically sample and record the time spent processing a unit
|
||||
@@ -326,8 +335,8 @@ public class PresentsDObjectMgr
|
||||
// look up the target object
|
||||
DObject target = _objects.get(event.getTargetOid());
|
||||
if (target == null) {
|
||||
Log.debug("Compound event target no longer exists " +
|
||||
"[event=" + event + "].");
|
||||
log.fine("Compound event target no longer exists " +
|
||||
"[event=" + event + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -335,8 +344,8 @@ public class PresentsDObjectMgr
|
||||
for (int ii = 0; ii < ecount; ii++) {
|
||||
DEvent sevent = (DEvent)events.get(ii);
|
||||
if (!target.checkPermissions(sevent)) {
|
||||
Log.warning("Event failed permissions check " +
|
||||
"[event=" + sevent + ", target=" + target + "].");
|
||||
log.warning("Event failed permissions check " +
|
||||
"[event=" + sevent + ", target=" + target + "].");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -359,15 +368,14 @@ public class PresentsDObjectMgr
|
||||
// look up the target object
|
||||
DObject target = _objects.get(event.getTargetOid());
|
||||
if (target == null) {
|
||||
Log.debug("Event target no longer exists " +
|
||||
"[event=" + event + "].");
|
||||
log.fine("Event target no longer exists [event=" + event + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// check the event's permissions
|
||||
if (!target.checkPermissions(event)) {
|
||||
Log.warning("Event failed permissions check " +
|
||||
"[event=" + event + ", target=" + target + "].");
|
||||
log.warning("Event failed permissions check " +
|
||||
"[event=" + event + ", target=" + target + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,9 +418,8 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Failure processing event [event=" + event +
|
||||
", target=" + target + "].");
|
||||
Log.logStackTrace(e);
|
||||
log.log(Level.WARNING, "Failure processing event [event=" + event +
|
||||
", target=" + target + "].", e);
|
||||
|
||||
} catch (Error e) {
|
||||
handleFatalError(event, e);
|
||||
@@ -433,8 +440,8 @@ public class PresentsDObjectMgr
|
||||
if (_fatalThrottle.throttleOp()) {
|
||||
throw error;
|
||||
}
|
||||
Log.warning("Fatal error caused by '" + causer + "': " + error);
|
||||
Log.logStackTrace(error);
|
||||
log.log(Level.WARNING,
|
||||
"Fatal error caused by '" + causer + "': " + error, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,7 +464,7 @@ public class PresentsDObjectMgr
|
||||
public void dumpUnitProfiles ()
|
||||
{
|
||||
for (Map.Entry<String,UnitProfile> entry : _profiles.entrySet()) {
|
||||
Log.info("P: " + entry.getKey() + " => " + entry.getValue());
|
||||
log.info("P: " + entry.getKey() + " => " + entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +479,7 @@ public class PresentsDObjectMgr
|
||||
{
|
||||
int oid = target.getOid();
|
||||
|
||||
// Log.info("Removing destroyed object from table " +
|
||||
// log.info("Removing destroyed object from table " +
|
||||
// "[oid=" + oid + "].");
|
||||
|
||||
// remove the object from the table
|
||||
@@ -498,10 +505,10 @@ public class PresentsDObjectMgr
|
||||
// post an object removed event to clear the reference
|
||||
postEvent(new ObjectRemovedEvent(
|
||||
ref.reffingOid, ref.field, oid));
|
||||
// Log.info("Forcing removal " + ref + ".");
|
||||
// log.info("Forcing removal " + ref + ".");
|
||||
|
||||
} else {
|
||||
Log.info("Dangling reference from inactive object " +
|
||||
log.info("Dangling reference from inactive object " +
|
||||
ref + ".");
|
||||
}
|
||||
}
|
||||
@@ -534,7 +541,7 @@ public class PresentsDObjectMgr
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to clean up after oid list field " +
|
||||
log.warning("Unable to clean up after oid list field " +
|
||||
"[target=" + target + ", field=" + field + "].");
|
||||
}
|
||||
}
|
||||
@@ -571,13 +578,13 @@ public class PresentsDObjectMgr
|
||||
// object which no longer exists; so we don't complain about non-
|
||||
// existent references if the referree is already destroyed
|
||||
if (ref == null && _objects.containsKey(reffedOid)) {
|
||||
Log.warning("Requested to clear out non-existent reference " +
|
||||
log.warning("Requested to clear out non-existent reference " +
|
||||
"[refferOid=" + reffer.getOid() +
|
||||
", field=" + field +
|
||||
", reffedOid=" + reffedOid + "].");
|
||||
|
||||
// } else {
|
||||
// Log.info("Cleared out reference " + ref + ".");
|
||||
// log.info("Cleared out reference " + ref + ".");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,7 +602,7 @@ public class PresentsDObjectMgr
|
||||
|
||||
// ensure that the target object exists
|
||||
if (!_objects.containsKey(oid)) {
|
||||
Log.info("Rejecting object added event of non-existent object " +
|
||||
log.info("Rejecting object added event of non-existent object " +
|
||||
"[refferOid=" + target.getOid() +
|
||||
", reffedOid=" + oid + "].");
|
||||
return false;
|
||||
@@ -615,7 +622,7 @@ public class PresentsDObjectMgr
|
||||
int rpos = -1;
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
if (ref.equals(refs[i])) {
|
||||
Log.warning("Ignoring request to track existing " +
|
||||
log.warning("Ignoring request to track existing " +
|
||||
"reference " + ref + ".");
|
||||
return true;
|
||||
} else if (refs[i] == null && rpos == -1) {
|
||||
@@ -634,7 +641,7 @@ public class PresentsDObjectMgr
|
||||
// finally add the reference
|
||||
refs[rpos] = ref;
|
||||
|
||||
// Log.info("Tracked reference " + ref + ".");
|
||||
// log.info("Tracked reference " + ref + ".");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -652,7 +659,7 @@ public class PresentsDObjectMgr
|
||||
int toid = target.getOid();
|
||||
int oid = ore.getOid();
|
||||
|
||||
// Log.info("Processing object removed [from=" + toid +
|
||||
// log.info("Processing object removed [from=" + toid +
|
||||
// ", roid=" + toid + "].");
|
||||
|
||||
// get the reference vector for the referenced object
|
||||
@@ -663,7 +670,7 @@ public class PresentsDObjectMgr
|
||||
// generate object removed events for all of its referencees.
|
||||
// so we opt not to log anything in this case
|
||||
|
||||
// Log.info("Object removed without reference to track it " +
|
||||
// log.info("Object removed without reference to track it " +
|
||||
// "[toid=" + toid + ", field=" + field +
|
||||
// ", oid=" + oid + "].");
|
||||
return true;
|
||||
@@ -673,13 +680,13 @@ public class PresentsDObjectMgr
|
||||
for (int i = 0; i < refs.length; i++) {
|
||||
Reference ref = refs[i];
|
||||
if (ref != null && ref.equals(toid, field)) {
|
||||
// Log.info("Removed reference " + refs[i] + ".");
|
||||
// log.info("Removed reference " + refs[i] + ".");
|
||||
refs[i] = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Log.warning("Unable to locate reference for removal " +
|
||||
log.warning("Unable to locate reference for removal " +
|
||||
"[reffingOid=" + toid + ", field=" + field +
|
||||
", reffedOid=" + oid + "].");
|
||||
return true;
|
||||
@@ -711,7 +718,7 @@ public class PresentsDObjectMgr
|
||||
return _nextOid;
|
||||
}
|
||||
|
||||
// documentation inherited from interface PresentsServer.Reporter
|
||||
// from interface PresentsServer.Reporter
|
||||
public void appendReport (
|
||||
StringBuilder report, long now, long sinceLast, boolean reset)
|
||||
{
|
||||
@@ -751,85 +758,12 @@ public class PresentsDObjectMgr
|
||||
try {
|
||||
sub.objectAvailable(obj);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Subscriber choked during object available " +
|
||||
"[obj=" + StringUtil.safeToString(obj) +
|
||||
", sub=" + sub + "].");
|
||||
Log.logStackTrace(e);
|
||||
log.log(Level.WARNING, "Subscriber choked during object " +
|
||||
"available [obj=" + StringUtil.safeToString(obj) +
|
||||
", sub=" + sub + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a distributed object and register it with the
|
||||
* system.
|
||||
*/
|
||||
protected class CreateObjectEvent<T extends DObject> extends DEvent
|
||||
{
|
||||
public CreateObjectEvent (Class<T> clazz, Subscriber<T> target)
|
||||
{
|
||||
super(0); // target the fake object
|
||||
_class = clazz;
|
||||
_target = target;
|
||||
}
|
||||
|
||||
public boolean isPrivate ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
int oid = getNextOid();
|
||||
T obj = null;
|
||||
|
||||
try {
|
||||
// create a new instance of this object
|
||||
obj = _class.newInstance();
|
||||
|
||||
// initialize this object
|
||||
obj.setOid(oid);
|
||||
obj.setManager(PresentsDObjectMgr.this);
|
||||
obj.setAccessController(_defaultController);
|
||||
|
||||
// insert it into the table
|
||||
_objects.put(oid, obj);
|
||||
|
||||
// Log.info("Created object [obj=" + obj + "].");
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Object creation failure " +
|
||||
"[class=" + _class.getName() +
|
||||
", error=" + e + "].");
|
||||
|
||||
// let the subscriber know shit be fucked
|
||||
if (_target != null) {
|
||||
String errmsg = "Object instantiation failed";
|
||||
_target.requestFailed(
|
||||
oid, new ObjectAccessException(errmsg, e));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_target != null) {
|
||||
// add the subscriber to this object's subscriber list
|
||||
obj.addSubscriber(_target);
|
||||
|
||||
// let the target subscriber know that their object is
|
||||
// available
|
||||
informObjectAvailable(_target, obj);
|
||||
}
|
||||
|
||||
// and return false to ensure that this event is not
|
||||
// dispatched to the fake object's subscriber list (even
|
||||
// though it's empty)
|
||||
return false;
|
||||
}
|
||||
|
||||
protected transient Class<T> _class;
|
||||
protected transient Subscriber<T> _target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to make an object available to a subscriber (with or without
|
||||
* the associated subscription).
|
||||
@@ -916,7 +850,7 @@ public class PresentsDObjectMgr
|
||||
_helpers.put(ObjectRemovedEvent.class, method);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to register event helpers " +
|
||||
log.warning("Unable to register event helpers " +
|
||||
"[error=" + e + "].");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,7 @@ import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.TimeBaseCodes;
|
||||
import com.threerings.presents.data.TimeBaseObject;
|
||||
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.RootDObjectManager;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
|
||||
/**
|
||||
* Provides the server-side of the time base services. The time base
|
||||
@@ -65,29 +62,14 @@ public class TimeBaseProvider
|
||||
* client and used to send delta times.
|
||||
*
|
||||
* @param timeBase the name of the time base to create.
|
||||
* @param resl the result listener that will be informed when the time
|
||||
* base object is created or if the creation fails.
|
||||
*
|
||||
* @return the created and registered time base object.
|
||||
*/
|
||||
public static void createTimeBase (
|
||||
final String timeBase, final ResultListener<TimeBaseObject> resl)
|
||||
public static TimeBaseObject createTimeBase (String timeBase)
|
||||
{
|
||||
_omgr.createObject(TimeBaseObject.class,
|
||||
new Subscriber<TimeBaseObject> () {
|
||||
public void objectAvailable (TimeBaseObject object) {
|
||||
// stuff it into our table
|
||||
_timeBases.put(timeBase, object);
|
||||
// and notify the listener
|
||||
resl.requestCompleted(object);
|
||||
}
|
||||
|
||||
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||
Log.warning("Ack. Unable to create time base object " +
|
||||
"[timeBase=" + timeBase +
|
||||
", cause=" + cause + "].");
|
||||
// notify the listener that we're borked
|
||||
resl.requestFailed(cause);
|
||||
}
|
||||
});
|
||||
TimeBaseObject object = _omgr.registerObject(new TimeBaseObject());
|
||||
_timeBases.put(timeBase, object);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user