Implemented object destruction; wired up some missing stuff; created a

test server to make some testing easier; various other cleanups.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@188 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-08-07 20:38:58 +00:00
parent b3e7f12f08
commit 782e9501d6
15 changed files with 340 additions and 54 deletions
@@ -1,5 +1,5 @@
//
// $Id: ClientDObjectMgr.java,v 1.4 2001/07/19 07:09:16 mdb Exp $
// $Id: ClientDObjectMgr.java,v 1.5 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.client;
@@ -75,6 +75,13 @@ public class ClientDObjectMgr
_comm.postMessage(new ForwardEventRequest(tevent));
}
// 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)
{
@@ -154,8 +161,29 @@ public class ClientDObjectMgr
return;
}
// have the object pass this event on to its subscribers
target.notifySubscribers(event);
try {
// apply the event to the object
boolean notify = event.applyToObject(target);
// if this is an object destroyed event, we need to remove the
// object from our object table
if (event instanceof ObjectDestroyedEvent) {
Log.info("Uncaching destroyed object " +
"[oid=" + target.getOid() + "].");
_ocache.remove(target.getOid());
}
// have the object pass this event on to its subscribers if
// desired
if (notify) {
target.notifySubscribers(event);
}
} catch (Exception e) {
Log.warning("Failure processing event [event=" + event +
", target=" + target + "].");
Log.logStackTrace(e);
}
}
/**
@@ -193,7 +221,19 @@ public class ClientDObjectMgr
*/
protected void notifyFailure (int oid)
{
Log.info("Get failed: " + oid);
// let the penders know that the object is not available
PendingRequest req = (PendingRequest)_penders.remove(oid);
if (req == null) {
Log.warning("Failed to get object, but no one cares?! " +
"[oid=" + oid + "].");
return;
}
for (int i = 0; i < req.targets.size(); i++) {
Subscriber target = (Subscriber)req.targets.get(i);
// and let them know that the object is in
target.requestFailed(oid, null);
}
}
/**
@@ -1,5 +1,5 @@
//
// $Id: Communicator.java,v 1.12 2001/08/03 02:11:20 mdb Exp $
// $Id: Communicator.java,v 1.13 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.client;
@@ -91,6 +91,9 @@ public class Communicator
return;
}
// post a logoff message
postMessage(new LogoffRequest());
// let our reader and writer know that it's time to go
if (_reader != null) {
// if logoff() is being called by the client as part of a
@@ -110,28 +113,12 @@ public class Communicator
if (_writer != null) {
// shutting down the writer thread is simpler because we can
// post a termination message on the queue and be sure that it
// will receive it. we do run the risk that it is in the
// middle of trying to send a message when we close the
// socket, but in theory the send will fail, it will complain
// and then it will cleanly exit. if we were uber paranoid
// about JVMs misbehaving on simultaneous close()/write(), we
// could wait here for the writer thread to exit, but that
// makes me even more nervous because I know that some JVMs
// don't handle Thread.join() properly (hopefully no one is
// still using those JVMs but one can never be sure)
// will receive it. when the writer thread has delivered our
// logoff request and exited, we will complete the logoff
// process by closing our socket and invoking the
// clientDidLogoff callback
_writer.shutdown();
}
// close down our socket
try {
_socket.close();
} catch (IOException cle) {
Log.warning("Error closing failed socket: " + cle);
}
_socket = null;
// let the client observers know that we're logged off
_client.notifyObservers(Client.CLIENT_DID_LOGOFF, null);
}
/**
@@ -226,8 +213,20 @@ public class Communicator
{
// clear out our writer reference
_writer = null;
Log.info("Writer thread exited.");
// now that the writer thread has gone away, we can safely close
// our socket and let the client know that the logoff process has
// completed
try {
_socket.close();
} catch (IOException cle) {
Log.warning("Error closing failed socket: " + cle);
}
_socket = null;
// let the client observers know that we're logged off
_client.notifyObservers(Client.CLIENT_DID_LOGOFF, null);
}
/**
@@ -1,5 +1,5 @@
//
// $Id: DObject.java,v 1.19 2001/08/04 00:39:44 mdb Exp $
// $Id: DObject.java,v 1.20 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -233,6 +233,16 @@ public class DObject
}
}
/**
* Requests that this distributed object be destroyed. It does so by
* queueing up an object destroyed event which the server will
* validate and process.
*/
public void destroy ()
{
_mgr.postEvent(new ObjectDestroyedEvent(_oid));
}
/**
* Checks to ensure that the specified subscriber has access to this
* object. This will be called before satisfying a subscription
@@ -1,5 +1,5 @@
//
// $Id: DObjectManager.java,v 1.7 2001/08/02 04:49:08 mdb Exp $
// $Id: DObjectManager.java,v 1.8 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -59,6 +59,15 @@ public interface DObjectManager
*/
public void unsubscribeFromObject (int oid, Subscriber 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
@@ -0,0 +1,63 @@
//
// $Id: ObjectDestroyedEvent.java,v 1.1 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.dobj;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* An object destroyed event is dispatched when an object has been removed
* from the distributed object system. It can also be constructed to
* request an attribute change on an object and posted to the dobjmgr.
*
* @see DObjectManager#postEvent
*/
public class ObjectDestroyedEvent extends TypedEvent
{
/** The typed object code for this event. */
public static final short TYPE = TYPE_BASE + 7;
/**
* Constructs a new object destroyed event for the specified
* distributed object.
*
* @param targetOid the object id of the object that will be destroyed.
*/
public ObjectDestroyedEvent (int targetOid)
{
super(targetOid);
}
/**
* Constructs a blank instance of this event in preparation for
* unserialization from the network.
*/
public ObjectDestroyedEvent ()
{
}
/**
* Applies this attribute change to the object.
*/
public boolean applyToObject (DObject target)
throws ObjectAccessException
{
// nothing to do in preparation for destruction, the omgr will
// have to recognize this type of event and do the right thing
return true;
}
public short getType ()
{
return TYPE;
}
protected void toString (StringBuffer buf)
{
buf.append("DESTROY:");
super.toString(buf);
}
}
@@ -1,5 +1,5 @@
//
// $Id: DObjectFactory.java,v 1.6 2001/08/03 02:11:40 mdb Exp $
// $Id: DObjectFactory.java,v 1.7 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.dobj.io;
@@ -49,7 +49,7 @@ public class DObjectFactory
Class clazz = Class.forName(in.readUTF());
DObject dobj = (DObject)clazz.newInstance();
dobj.setOid(in.readInt()); // read and set the oid
Log.info("Unmarshalling object: " + dobj);
// Log.info("Unmarshalling object: " + dobj);
// look up the marshaller for that class
Marshaller marsh = getMarshaller(clazz);
@@ -1,5 +1,5 @@
//
// $Id: TypedObjectRegistry.java,v 1.4 2001/08/04 01:05:25 mdb Exp $
// $Id: TypedObjectRegistry.java,v 1.5 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.io;
@@ -64,5 +64,7 @@ public class TypedObjectRegistry
ObjectRemovedEvent.class);
TypedObjectFactory.registerClass(ReleaseLockEvent.TYPE,
ReleaseLockEvent.class);
TypedObjectFactory.registerClass(ObjectDestroyedEvent.TYPE,
ObjectDestroyedEvent.class);
}
}
@@ -1,8 +1,11 @@
//
// $Id: PresentsDObjectMgr.java,v 1.9 2001/07/23 21:12:55 mdb Exp $
// $Id: PresentsDObjectMgr.java,v 1.10 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.server;
import java.lang.reflect.Method;
import java.util.HashMap;
import com.samskivert.util.Queue;
import com.threerings.cocktail.cher.Log;
@@ -61,6 +64,13 @@ public class CherDObjectMgr implements DObjectManager
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
public void postEvent (DEvent event)
{
@@ -121,7 +131,10 @@ public class CherDObjectMgr implements DObjectManager
// do any internal management necessary based on this
// event
// **TBD**
Method helper = (Method)_helpers.get(event.getClass());
if (helper != null) {
helper.invoke(this, new Object[] { event, target });
}
// if the event returns false from applyToObject, this
// means it's a silent event and we shouldn't notify the
@@ -153,6 +166,17 @@ public class CherDObjectMgr implements DObjectManager
_evqueue.append(new ShutdownEvent());
}
/**
* Called as a helper for <code>ObjectDestroyedEvent</code> events. It
* removes the object from the object table.
*/
public void objectDestroyed (DEvent event, DObject target)
{
Log.info("Removing destroyed object from table " +
"[oid=" + target.getOid() + "].");
_objects.remove(target.getOid());
}
protected synchronized boolean isRunning ()
{
return _running;
@@ -170,11 +194,6 @@ public class CherDObjectMgr implements DObjectManager
return _nextOid;
}
protected boolean _running = true;
protected Queue _evqueue = new Queue();
protected IntMap _objects = new IntMap();
protected int _nextOid = 0;
/**
* Used to create a distributed object and register it with the
* system.
@@ -318,4 +337,35 @@ public class CherDObjectMgr implements DObjectManager
return false;
}
}
/**
* Registers our event helper methods.
*/
protected static void registerEventHelpers ()
{
Class[] ptypes = new Class[] { DEvent.class, DObject.class };
Class omgrcl = CherDObjectMgr.class;
Method method;
try {
method = omgrcl.getMethod("objectDestroyed", ptypes);
_helpers.put(ObjectDestroyedEvent.class, method);
} catch (Exception e) {
Log.warning("Unable to register event helpers " +
"[error=" + e + "].");
}
}
protected boolean _running = true;
protected Queue _evqueue = new Queue();
protected IntMap _objects = new IntMap();
protected int _nextOid = 0;
/**
* This table maps event classes to helper methods that perform some
* additional processing for particular events.
*/
protected static HashMap _helpers = new HashMap();
static { registerEventHelpers(); }
}
@@ -1,5 +1,5 @@
//
// $Id: ConnectionManager.java,v 1.7 2001/08/03 02:12:52 mdb Exp $
// $Id: ConnectionManager.java,v 1.8 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.server.net;
@@ -216,7 +216,7 @@ public class ConnectionManager extends LoopingThread
if (socket == null) {
// in theory this shouldn't happen because we got an
// ACCEPT_READY event, but better safe than sorry
Log.info("Psych! Got ACCEPT_READY, but no connection.");
// Log.info("Psych! Got ACCEPT_READY, but no connection.");
return;
}
@@ -1,5 +1,5 @@
//
// $Id: RunningConnection.java,v 1.3 2001/06/02 01:30:37 mdb Exp $
// $Id: RunningConnection.java,v 1.4 2001/08/07 20:38:58 mdb Exp $
package com.threerings.cocktail.cher.server.net;
@@ -33,6 +33,10 @@ public class RunningConnection extends Connection
public String toString ()
{
return "[mode=RUNNING, addr=" + _socket.getInetAddress() + "]";
if (_socket != null) {
return "[mode=RUNNING, addr=" + _socket.getInetAddress() + "]";
} else {
return "[mode=RUNNING, addr=<disconnected>]";
}
}
}