diff --git a/src/java/com/threerings/presents/server/PresentsDObjectMgr.java b/src/java/com/threerings/presents/server/PresentsDObjectMgr.java
index 8fc622200..5d99cca95 100644
--- a/src/java/com/threerings/presents/server/PresentsDObjectMgr.java
+++ b/src/java/com/threerings/presents/server/PresentsDObjectMgr.java
@@ -1,5 +1,5 @@
//
-// $Id: PresentsDObjectMgr.java,v 1.12 2001/08/08 00:28:49 mdb Exp $
+// $Id: PresentsDObjectMgr.java,v 1.13 2001/08/08 21:56:47 mdb Exp $
package com.threerings.cocktail.cher.server;
@@ -126,16 +126,22 @@ public class CherDObjectMgr implements DObjectManager
}
try {
- // everything's good so far, apply the event to the object
- boolean notify = event.applyToObject(target);
-
// do any internal management necessary based on this
// event
Method helper = (Method)_helpers.get(event.getClass());
if (helper != null) {
- helper.invoke(this, new Object[] { event, target });
+ // invoke the helper method
+ Object rv =
+ helper.invoke(this, new Object[] { event, target });
+ // if helper returns false, we abort event processing
+ if (!((Boolean)rv).booleanValue()) {
+ continue;
+ }
}
+ // everything's good so far, apply the event to the object
+ boolean notify = event.applyToObject(target);
+
// if the event returns false from applyToObject, this
// means it's a silent event and we shouldn't notify the
// subscribers
@@ -169,8 +175,11 @@ public class CherDObjectMgr implements DObjectManager
/**
* Called as a helper for ObjectDestroyedEvent events. It
* removes the object from the object table.
+ *
+ * @return true if the event should be dispatched, false if it should
+ * be aborted.
*/
- public void objectDestroyed (DEvent event, DObject target)
+ public boolean objectDestroyed (DEvent event, DObject target)
{
int oid = target.getOid();
@@ -240,6 +249,8 @@ public class CherDObjectMgr implements DObjectManager
"[target=" + target + ", field=" + field + "].");
}
}
+
+ return true;
}
/**
@@ -278,12 +289,22 @@ public class CherDObjectMgr implements DObjectManager
/**
* Called as a helper for ObjectAddedEvent events. It
* updates the object/oid list tracking structures.
+ *
+ * @return true if the event should be dispatched, false if it should
+ * be aborted.
*/
- public void objectAdded (DEvent event, DObject target)
+ public boolean objectAdded (DEvent event, DObject target)
{
ObjectAddedEvent oae = (ObjectAddedEvent)event;
int oid = oae.getOid();
- Reference ref = new Reference(target.getOid(), oae.getName(), oid);
+
+ // ensure that the target object exists
+ if (!_objects.contains(oid)) {
+ Log.info("Rejecting object added event of non-existent object " +
+ "[refferOid=" + target.getOid() +
+ ", reffedOid=" + oid + "].");
+ return false;
+ }
// get the reference vector for the referenced object. we use bare
// arrays rather than something like an array list to conserve
@@ -295,12 +316,13 @@ public class CherDObjectMgr implements DObjectManager
}
// determine where to add the reference
+ Reference ref = new Reference(target.getOid(), oae.getName(), oid);
int rpos = -1;
for (int i = 0; i < refs.length; i++) {
if (ref.equals(refs[i])) {
Log.warning("Ignoring request to track existing " +
"reference " + ref + ".");
- return;
+ return true;
} else if (refs[i] == null && rpos == -1) {
rpos = i;
}
@@ -318,13 +340,17 @@ public class CherDObjectMgr implements DObjectManager
refs[rpos] = ref;
// Log.info("Tracked reference " + ref + ".");
+ return true;
}
/**
* Called as a helper for ObjectRemovedEvent events. It
* updates the object/oid list tracking structures.
+ *
+ * @return true if the event should be dispatched, false if it should
+ * be aborted.
*/
- public void objectRemoved (DEvent event, DObject target)
+ public boolean objectRemoved (DEvent event, DObject target)
{
ObjectRemovedEvent ore = (ObjectRemovedEvent)event;
String field = ore.getName();
@@ -342,7 +368,7 @@ public class CherDObjectMgr implements DObjectManager
// Log.warning("Object removed without reference to track it " +
// "[toid=" + toid + ", field=" + field +
// ", oid=" + oid + "].");
- return;
+ return true;
}
// look for the matching reference
@@ -350,13 +376,14 @@ public class CherDObjectMgr implements DObjectManager
if (refs[i].equals(toid, field)) {
// Log.info("Removed reference " + refs[i] + ".");
refs[i] = null;
- return;
+ return true;
}
}
Log.warning("Unable to locate reference for removal " +
"[reffingOid=" + toid + ", field=" + field +
", reffedOid=" + oid + "].");
+ return true;
}
protected synchronized boolean isRunning ()
diff --git a/tests/src/java/com/threerings/presents/server/DestroyedRefTest.java b/tests/src/java/com/threerings/presents/server/DestroyedRefTest.java
new file mode 100644
index 000000000..1789ddf05
--- /dev/null
+++ b/tests/src/java/com/threerings/presents/server/DestroyedRefTest.java
@@ -0,0 +1,77 @@
+//
+// $Id: DestroyedRefTest.java,v 1.1 2001/08/08 21:56:48 mdb Exp $
+
+package com.threerings.cocktail.cher.server.test;
+
+import com.threerings.cocktail.cher.Log;
+import com.threerings.cocktail.cher.dobj.*;
+import com.threerings.cocktail.cher.server.CherServer;
+
+/**
+ * Tests that the dobjmgr will not allow a destroyed object to be added to
+ * an oid list.
+ */
+public class DestroyedRefTest
+ implements Runnable, Subscriber
+{
+ public void run ()
+ {
+ // create two test objects
+ CherServer.omgr.createObject(TestObject.class, this, true);
+ CherServer.omgr.createObject(TestObject.class, this, true);
+ }
+
+ public void objectAvailable (DObject object)
+ {
+ // keep references to our test objects
+ if (_objone == null) {
+ _objone = (TestObject)object;
+
+ } else {
+ _objtwo = (TestObject)object;
+
+ // add object one to object two twice in a row to make sure
+ // repeated adds don't result in the object being listed twice
+ _objtwo.addToList(_objone.getOid());
+ _objtwo.addToList(_objone.getOid());
+
+ // now that we have both objects, try to set up the reference.
+ // first we queue up a destroy event for object two, then we
+ // try to reference it on object one's oid list
+ _objtwo.destroy();
+ _objone.addToList(_objtwo.getOid());
+
+ // finally dispatch an event on which we can trigger our exit
+ _objone.setFoo(1);
+ }
+ }
+
+ public void requestFailed (int oid, ObjectAccessException cause)
+ {
+ Log.warning("Ack. Unable to create object [cause=" + cause + "].");
+ }
+
+ public boolean handleEvent (DEvent event, DObject target)
+ {
+ // when we get the attribute change, we can exit
+ if (event instanceof ObjectDestroyedEvent) {
+ Log.info("The upcoming object added event should be rejected.");
+
+ } else if (event instanceof ObjectAddedEvent &&
+ target == _objtwo) {
+ Log.info("list should contain only one oid: " + _objtwo.list);
+
+ } else if (event instanceof AttributeChangedEvent) {
+ // go bye bye
+ CherServer.shutdown();
+
+ } else {
+ Log.info("Got unexpected event: " + event);
+ }
+
+ return true;
+ }
+
+ protected TestObject _objone;
+ protected TestObject _objtwo;
+}