From 567a2ada1016f53d6d9c055cb5c5a34acd8af57c Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 1 Jun 2001 05:01:52 +0000 Subject: [PATCH] More progress on the basic distributed object facilities. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@16 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/presents/dobj/DEvent.java | 14 ++ .../com/threerings/presents/dobj/DObject.java | 127 ++++++++++++++++-- .../presents/dobj/DObjectManager.java | 22 +++ .../presents/dobj/NoSuchObjectException.java | 16 +++ .../presents/dobj/ObjectAccessException.java | 19 +++ .../threerings/presents/dobj/Subscriber.java | 51 +++++++ 6 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 src/java/com/threerings/presents/dobj/DEvent.java create mode 100644 src/java/com/threerings/presents/dobj/DObjectManager.java create mode 100644 src/java/com/threerings/presents/dobj/NoSuchObjectException.java create mode 100644 src/java/com/threerings/presents/dobj/ObjectAccessException.java create mode 100644 src/java/com/threerings/presents/dobj/Subscriber.java 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); +}