diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java
index 3ae8dd5c4..3ed20f68e 100644
--- a/src/java/com/threerings/presents/dobj/DObject.java
+++ b/src/java/com/threerings/presents/dobj/DObject.java
@@ -1,5 +1,5 @@
//
-// $Id: DObject.java,v 1.18 2001/08/03 02:11:40 mdb Exp $
+// $Id: DObject.java,v 1.19 2001/08/04 00:39:44 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -129,6 +129,110 @@ public class DObject
}
}
+ /**
+ * At times, an entity on the server may need to ensure that events it
+ * has queued up have made it through the event queue and are applied
+ * to their respective objects before a service may safely be
+ * undertaken again. To make this possible, it can acquire a lock on a
+ * distributed object, generate the events in question and then
+ * release the lock (via a call to releaseLock) which
+ * will queue up a final event, the processing of which will release
+ * the lock. Thus the lock will not be released until all of the
+ * previously generated events have been processed. If the service is
+ * invoked again before that lock is released, the associated call to
+ * acquireLock will fail and the code can respond
+ * accordingly. An object may have any number of outstanding locks as
+ * long as they each have a unique name.
+ *
+ * @param name the name of the lock to acquire.
+ *
+ * @return true if the lock was acquired, false if the lock was not
+ * acquired because it has not yet been released from a previous
+ * acquisition.
+ *
+ * @see #releaseLock
+ */
+ public boolean acquireLock (String name)
+ {
+ // create our lock array if we haven't already. we do all this
+ // jockeying rather than just use something like an ArrayList to
+ // be memory efficient because there may be very many distributed
+ // objects
+ if (_locks == null) {
+ _locks = new String[2];
+ }
+
+ // scan the lock array to see if this lock is already acquired
+ int slot = -1;
+ for (int i = 0; i < _locks.length; i++) {
+ if (_locks[i] == null) {
+ // keep track of this for later
+ slot = i;
+ } else if (name.equals(_locks[i])) {
+ return false;
+ }
+ }
+
+ // if we didnt' find a blank slot in our previous scan, we'll have
+ // to expand the locks array
+ if (slot == -1) {
+ String[] locks = new String[_locks.length*2];
+ System.arraycopy(_locks, 0, locks, 0, _locks.length);
+ slot = _locks.length;
+ }
+
+ // place our lock in the array and let the user know that they
+ // acquired the lock
+ _locks[slot] = name;
+ return true;
+ }
+
+ /**
+ * Queues up an event that when processed will release the lock of the
+ * specified name.
+ *
+ * @see #acquireLock
+ */
+ public void releaseLock (String name)
+ {
+ // queue up a release lock event
+ ReleaseLockEvent event = new ReleaseLockEvent(_oid, name);
+ _mgr.postEvent(event);
+ }
+
+ /**
+ * Don't call this function! It is called by a remove lock event when
+ * that event is processed and shouldn't be called at any other time.
+ * If you mean to release a lock that was acquired with
+ * acquireLock you should be using
+ * releaseLock.
+ *
+ * @see #acquireLock
+ * @see #releaseLock
+ */
+ protected void clearLock (String name)
+ {
+ // track the lock index for reporting purposes
+ int lockidx = -1;
+
+ // scan through and clear the lock in question
+ if (_locks != null) {
+ for (int i = 0; i < _locks.length; i++) {
+ if (name.equals(_locks[i])) {
+ _locks[i] = null;
+ lockidx = i;
+ break;
+ }
+ }
+ }
+
+ // complain if we didn't find the lock
+ if (lockidx == -1) {
+ Log.info("Unable to clear non-existent lock [lock=" + name +
+ ", dobj=" + this + "].");
+ }
+ }
+
/**
* Checks to ensure that the specified subscriber has access to this
* object. This will be called before satisfying a subscription
@@ -304,4 +408,5 @@ public class DObject
protected int _oid;
protected DObjectManager _mgr;
protected ArrayList _subscribers = new ArrayList();
+ protected String[] _locks;
}
diff --git a/src/java/com/threerings/presents/dobj/ReleaseLockEvent.java b/src/java/com/threerings/presents/dobj/ReleaseLockEvent.java
index 92236f249..90f10a3dd 100644
--- a/src/java/com/threerings/presents/dobj/ReleaseLockEvent.java
+++ b/src/java/com/threerings/presents/dobj/ReleaseLockEvent.java
@@ -1,5 +1,5 @@
//
-// $Id: ReleaseLockEvent.java,v 1.1 2001/08/04 00:32:11 mdb Exp $
+// $Id: ReleaseLockEvent.java,v 1.2 2001/08/04 00:39:44 mdb Exp $
package com.threerings.cocktail.cher.dobj;
@@ -11,10 +11,13 @@ import java.lang.reflect.Method;
import com.threerings.cocktail.cher.dobj.io.ValueMarshaller;
/**
- * A release lock event is dispatched at the end of a chain of attribute
- * change events to release a lock that is intended to prevent some
- * application defined activity from happening on the distributed object
- * until those events have been processed.
+ * A release lock event is dispatched at the end of a chain of events to
+ * release a lock that is intended to prevent some application defined
+ * activity from happening until those events have been processed. This is
+ * an entirely cooperative locking system, meaning that the application
+ * will have to explicitly attempt acquisition of the lock to find out if
+ * the lock has yet been released. These locks don't actually prevent any
+ * of the distributed object machinery from functioning.
*
* @see DObjectManager#postEvent
*/
@@ -53,13 +56,13 @@ public class ReleaseLockEvent extends TypedEvent
}
/**
- * Applies this attribute change to the object.
+ * Applies this lock release to the object.
*/
public boolean applyToObject (DObject target)
throws ObjectAccessException
{
- // pass the new value on to the object
- target.setAttribute(_name, _value);
+ // clear this lock from the target object
+ target.clearLock(_name);
return true;
}
@@ -90,5 +93,4 @@ public class ReleaseLockEvent extends TypedEvent
}
protected String _name;
- protected Object _value;
}