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; +}