diff --git a/src/java/com/threerings/presents/dobj/DEvent.java b/src/java/com/threerings/presents/dobj/DEvent.java new file mode 100644 index 000000000..7a866281e --- /dev/null +++ b/src/java/com/threerings/presents/dobj/DEvent.java @@ -0,0 +1,14 @@ +// +// $Id: DEvent.java,v 1.1 2001/06/01 05:01:52 mdb Exp $ + +package com.threerings.cocktail.cher.dobj; + +/** + * A distributed object event is dispatched whenever any modification is + * made to a distributed object. It can also be dispatched purely for + * notification purposes, without making any modifications to the object + * that defines the delivery group (the object's subscribers). + */ +public class DEvent +{ +} diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java index 3b1e55025..4a0159fba 100644 --- a/src/java/com/threerings/presents/dobj/DObject.java +++ b/src/java/com/threerings/presents/dobj/DObject.java @@ -1,23 +1,130 @@ // -// $Id: DObject.java,v 1.4 2001/05/30 23:58:31 mdb Exp $ +// $Id: DObject.java,v 1.5 2001/06/01 05:01:52 mdb Exp $ package com.threerings.cocktail.cher.dobj; -import java.io.IOException; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.util.ArrayList; +/** + * The distributed object forms the foundation of the cocktail system. All + * information shared among users of the system is done via distributed + * objects. A distributed object has a set of subscribers. These + * subscribers have access to the object or a proxy of the object and + * therefore have access to the data stored in the object's members at all + * times. + * + *
When there is any change to that data, initiated by one of the + * subscribers, an event is generated which is dispatched to all + * subscribers of the object, notifying them of that change and affecting + * that change to the copy of the object maintained at each client. In + * this way, both a respository of shared information and a mechanism for + * asynchronous notification are made available as a fundamental + * application building blocks. + * + *
To define what information is shared, an application creates a
+ * distributed object declaration which is much like a class declaration
+ * except that it is transformed into a proper derived class of
+ * DObject by a script. A declaration looks something like
+ * this:
+ *
+ *
+ * public dclass RoomObject
+ * {
+ * public String description;
+ * public int[] occupants;
+ * }
+ *
+ *
+ * which is converted into an actual Java class that looks like this:
+ *
+ *
+ * public class RoomObject extends DObject
+ * {
+ * public String getDescription ()
+ * {
+ * // ...
+ * }
+ *
+ * public void setDescription (String description)
+ * {
+ * // ...
+ * }
+ *
+ * public int[] getOccupants ()
+ * {
+ * // ...
+ * }
+ *
+ * public void setOccupants (int[] occupants)
+ * {
+ * // ...
+ * }
+ *
+ * public void setOccupantsAt (int index, int value)
+ * {
+ * // ...
+ * }
+ * }
+ *
+ *
+ * These method calls on the actual distributed object will result in the
+ * proper attribute change events being generated and dispatched.
+ */
public class DObject
{
- public void writeTo (DataOutputStream out)
- throws IOException
+ /**
+ * Constructs a new distributed object with the supplied object id.
+ * This should not be called directly, rather objects should be
+ * created via the distributed object manager.
+ *
+ * @see DObjectManager.createObject
+ */
+ public DObject (int oid)
{
- // nothing doing!
+ _oid = oid;
+ _subscribers = new ArrayList();
}
- public void readFrom (DataInputStream in)
- throws IOException
+ /**
+ * Returns the object id of this object. All objects in the system
+ * have a unique object id.
+ */
+ public int getOid ()
{
- // nothing doing!
+ return _oid;
}
+
+ /**
+ * Adds the supplied subscriber to the subscriber list for this
+ * object. This is done automatically when an object is requested for
+ * subscription by the distributed object manager, thus this function
+ * should not be called directly except in circumstances where one
+ * subscriber has already obtained a subscription to an object and
+ * wishes to include a subordinate subscriber in on the fun.
+ *
+ * If the specified subscriber is already subscribed to this
+ * object, they will not be added to the list a second time.
+ */
+ public void addSubscriber (Subscriber subscriber)
+ {
+ if (!_subscribers.contains(subscriber)) {
+ _subscribers.add(subscriber);
+ }
+ }
+
+ /**
+ * Removes the specified subscriber from the subscriber list for this
+ * object. This is done automatically when a subscriber returns false
+ * from handleEvent, but can also be done directly
+ * through a call to removeSubscriber. If the specified
+ * subscriber is not currently on the list of subscribers for this
+ * object, nothing happens.
+ */
+ public void removeSubscriber (Subscriber subscriber)
+ {
+ _subscribers.remove(subscriber);
+ }
+
+ protected int _oid;
+ protected ArrayList _subscribers;
}
diff --git a/src/java/com/threerings/presents/dobj/DObjectManager.java b/src/java/com/threerings/presents/dobj/DObjectManager.java
new file mode 100644
index 000000000..c2aea7a39
--- /dev/null
+++ b/src/java/com/threerings/presents/dobj/DObjectManager.java
@@ -0,0 +1,22 @@
+//
+// $Id: DObjectManager.java,v 1.1 2001/06/01 05:01:52 mdb Exp $
+
+package com.threerings.cocktail.cher.dobj;
+
+/**
+ * The distributed object manager is responsible for managing the creation
+ * and destruction of distributed objects and propagating dobj events to
+ * the appropriate subscribers. On the client, objects are managed as
+ * proxies to the real objects managed by the server, so attribute change
+ * requests are forwarded to the server and events coming down from the
+ * server are delivered to the local subscribers. On the server, the
+ * objects are managed directly.
+ */
+public interface DObjectManager
+{
+ public void createObject (Class dclass, Subscriber sub);
+
+ public void subscribeToObject (int oid, Subscriber sub);
+
+ public void fetchObject (int oid, Subscriber sub);
+}
diff --git a/src/java/com/threerings/presents/dobj/NoSuchObjectException.java b/src/java/com/threerings/presents/dobj/NoSuchObjectException.java
new file mode 100644
index 000000000..3f0dc08f6
--- /dev/null
+++ b/src/java/com/threerings/presents/dobj/NoSuchObjectException.java
@@ -0,0 +1,16 @@
+//
+// $Id: NoSuchObjectException.java,v 1.1 2001/06/01 05:01:52 mdb Exp $
+
+package com.threerings.cocktail.cher.dobj;
+
+/**
+ * A no such object exception is delivered when a subscriber requests
+ * access to an object that does not exist.
+ */
+public class NoSuchObjectException extends ObjectAccessException
+{
+ public NoSuchObjectException (int oid)
+ {
+ super("m.no_such_object\t" + oid);
+ }
+}
diff --git a/src/java/com/threerings/presents/dobj/ObjectAccessException.java b/src/java/com/threerings/presents/dobj/ObjectAccessException.java
new file mode 100644
index 000000000..36b1156f6
--- /dev/null
+++ b/src/java/com/threerings/presents/dobj/ObjectAccessException.java
@@ -0,0 +1,19 @@
+//
+// $Id: ObjectAccessException.java,v 1.1 2001/06/01 05:01:52 mdb Exp $
+
+package com.threerings.cocktail.cher.dobj;
+
+/**
+ * An object access exception is delivered when an object is not
+ * accessible to a requesting subscriber for some reason or other. For
+ * some access exceptions, special derived classes exist to communicate
+ * the error. For others, a message string explaining the access failure
+ * is provided.
+ */
+public class ObjectAccessException extends Exception
+{
+ public ObjectAccessException (String message)
+ {
+ super(message);
+ }
+}
diff --git a/src/java/com/threerings/presents/dobj/Subscriber.java b/src/java/com/threerings/presents/dobj/Subscriber.java
new file mode 100644
index 000000000..eb95c6e2b
--- /dev/null
+++ b/src/java/com/threerings/presents/dobj/Subscriber.java
@@ -0,0 +1,51 @@
+//
+// $Id: Subscriber.java,v 1.1 2001/06/01 05:01:52 mdb Exp $
+
+package com.threerings.cocktail.cher.dobj;
+
+/**
+ * A subscriber is an entity that has access to a distributed object. The
+ * process of obtaining access to a distributed object is an asynchronous
+ * one, and changes made to an object are delivered asynchronously. By
+ * registering as a subscriber to an object, an entity can react to
+ * changes made to an object and ensure that their object is kept up to
+ * date.
+ */
+public interface Subscriber
+{
+ /**
+ * Called when a subscription request has succeeded and the object is
+ * available. If the object was requested for subscription, the
+ * subscriber will subsequently receive notifications via
+ * handleEvent. If the object was requested as a one-time
+ * read-only copy, these updates will not occur and the subscriber
+ * should not attempt to modify the object.
+ *
+ * @see DObjectManager.subscribeToObject
+ * @see DObjectManager.fetchObject
+ */
+ public void objectAvailable (DObject object);
+
+ /**
+ * Called when a subscription request has failed. The nature of the
+ * failure will be communicated via the supplied
+ * ObjectAccessException.
+ *
+ * @see DObjectManager.subscribeToObject
+ * @see DObjectManager.fetchObject
+ */
+ public void subscriptionFailed (ObjectAccessException cause);
+
+ /**
+ * Called when an event has been dispatched on an object. The event
+ * will be of the derived class that corresponds to the kind of event
+ * that occurred on the object. handleEvent will be
+ * called after the event has been applied to the object. So
+ * fetching an attribute upon receiving an attribute changed event
+ * will provide the new value for the attribute.
+ *
+ * @param event The event dispatched on the object.
+ * @param target The object on which the event was dispatched.
+ */
+ public void handleEvent (DEvent event, DObject target);
+}