diff --git a/src/java/com/threerings/crowd/client/LocationDirector.java b/src/java/com/threerings/crowd/client/LocationDirector.java
index 9e8669b20..5f32a5b83 100644
--- a/src/java/com/threerings/crowd/client/LocationDirector.java
+++ b/src/java/com/threerings/crowd/client/LocationDirector.java
@@ -1,5 +1,5 @@
//
-// $Id: LocationDirector.java,v 1.9 2001/10/01 22:14:55 mdb Exp $
+// $Id: LocationDirector.java,v 1.10 2001/10/05 23:57:26 mdb Exp $
package com.threerings.cocktail.party.client;
@@ -10,8 +10,7 @@ import com.threerings.cocktail.cher.client.*;
import com.threerings.cocktail.cher.dobj.*;
import com.threerings.cocktail.party.Log;
-import com.threerings.cocktail.party.data.BodyObject;
-import com.threerings.cocktail.party.data.PlaceObject;
+import com.threerings.cocktail.party.data.*;
import com.threerings.cocktail.party.util.PartyContext;
/**
@@ -127,13 +126,27 @@ public class LocationDirector
* effected.
*
* @param placeId the place oid of our new location.
+ * @param config the configuration information for the new place.
*/
- protected void didMoveTo (int placeId)
+ protected void didMoveTo (int placeId, PlaceConfig config)
{
DObjectManager omgr = _ctx.getDObjectManager();
- // unsubscribe from our old place object
+ // do some cleaning up if we were previously in a place
if (_plobj != null) {
+ // let the old controller know that things are going away
+ if (_controller != null) {
+ try {
+ _controller.didLeavePlace(_plobj);
+ } catch (Exception e) {
+ Log.warning("Place controller choked in " +
+ "didLeavePlace [plobj=" + _plobj + "].");
+ Log.logStackTrace(e);
+ }
+ _controller = null;
+ }
+
+ // unsubscribe from our old place object
omgr.unsubscribeFromObject(_plobj.getOid(), this);
_plobj = null;
}
@@ -142,6 +155,18 @@ public class LocationDirector
_previousPlaceId = _placeId;
_placeId = placeId;
+ try {
+ // start up a new place controller to manage the new place
+ Class cclass = config.getControllerClass();
+ _controller = (PlaceController)cclass.newInstance();
+ _controller.init(_ctx, config);
+
+ } catch (Exception e) {
+ Log.warning("Error creating or initializing place controller " +
+ "[config=" + config + "].");
+ Log.logStackTrace(e);
+ }
+
// subscribe to our new place object to complete the move
omgr.subscribeToObject(_placeId, this);
}
@@ -217,10 +242,10 @@ public class LocationDirector
/**
* Called in response to a successful moveTo request.
*/
- public void handleMoveSucceeded (int invid)
+ public void handleMoveSucceeded (int invid, PlaceConfig config)
{
// handle the successful move
- didMoveTo(_pendingPlaceId);
+ didMoveTo(_pendingPlaceId, config);
// and clear out the tracked pending oid
_pendingPlaceId = -1;
@@ -244,6 +269,15 @@ public class LocationDirector
// yay, we have our new place object
_plobj = (PlaceObject)object;
+ // let the place controller know that we're ready to roll
+ try {
+ _controller.willEnterPlace(_plobj);
+ } catch (Exception e) {
+ Log.warning("Controller choked in willEnterPlace " +
+ "[place=" + _plobj + "].");
+ Log.logStackTrace(e);
+ }
+
// let our observers know that all is well on the western front
for (int i = 0; i < _observers.size(); i++) {
LocationObserver obs = (LocationObserver)_observers.get(i);
@@ -265,6 +299,11 @@ public class LocationDirector
// let the kids know shit be fucked
notifyFailure(placeId, "m.unable_to_fetch_place_object");
+ // we need to sort out what to do about the half-initialized place
+ // controller. presently we punt and hope that calling
+ // didLeavePlace() without ever having called willEnterPlace()
+ // does whatever's necessary
+
// try to return to our previous location
recoverFailedMove(placeId);
}
@@ -313,6 +352,9 @@ public class LocationDirector
/** The place object that we currently occupy. */
protected PlaceObject _plobj;
+ /** The place controller in effect for our current place. */
+ protected PlaceController _controller;
+
/**
* The oid of the place for which we have an outstanding moveTo
* request, or -1 if we have no outstanding request.
diff --git a/src/java/com/threerings/crowd/client/PlaceController.java b/src/java/com/threerings/crowd/client/PlaceController.java
new file mode 100644
index 000000000..7cc045a26
--- /dev/null
+++ b/src/java/com/threerings/crowd/client/PlaceController.java
@@ -0,0 +1,104 @@
+//
+// $Id: PlaceController.java,v 1.1 2001/10/05 23:57:26 mdb Exp $
+
+package com.threerings.cocktail.party.client;
+
+import java.awt.event.ActionEvent;
+import com.samskivert.swing.Controller;
+
+import com.threerings.cocktail.party.data.PlaceConfig;
+import com.threerings.cocktail.party.data.PlaceObject;
+import com.threerings.cocktail.party.util.PartyContext;
+
+/**
+ * Controls the user interface that is used to display a place. When the
+ * client moves to a new place, the appropriate place controller is
+ * constructed and requested to create and display the appopriate user
+ * interface for that place.
+ */
+public abstract class PlaceController
+ extends Controller
+{
+ /**
+ * Initializes this place controller with a reference to the context
+ * that they can use to access client services and to the
+ * configuration record for this place. The controller should create
+ * as much of its user interface that it can without having access to
+ * the place object because this will be invoked in parallel with the
+ * fetching of the place object. When the place object is obtained,
+ * the controller will be notified and it can then finish the user
+ * interface configuration and put the user interface into operation.
+ *
+ * @param ctx the client context.
+ * @param config the place configuration for this place.
+ */
+ public void init (PartyContext ctx, PlaceConfig config)
+ {
+ // keep these around
+ _ctx = ctx;
+ _config = config;
+
+ // create our user interface
+ _view = createPlaceView();
+ }
+
+ /**
+ * Creates the user interface that will be used to display this place.
+ * The view instance returned will later be configured with the place
+ * object, once it becomes available.
+ */
+ protected abstract PlaceView createPlaceView ();
+
+ /**
+ * This is called by the location director once the place object has
+ * been fetched. The place controller will dispatch the place object
+ * to the user interface hierarchy via {@link
+ * PlaceViewUtil.dispatchWillEnterPlace}. Derived classes can override
+ * this and perform any other starting up that they need to do
+ */
+ public void willEnterPlace (PlaceObject plobj)
+ {
+ // let the UI hierarchy know that we've got our place
+ if (_view != null ) {
+ PlaceViewUtil.dispatchWillEnterPlace(_view, plobj);
+ }
+ }
+
+ /**
+ * This is called by the location director when we are leaving this
+ * place and need to clean up after ourselves and shutdown. Derived
+ * classes should override this method (being sure to call
+ * super.didLeavePlace) and perform any necessary
+ * cleanup.
+ */
+ public void didLeavePlace (PlaceObject plobj)
+ {
+ // let the UI hierarchy know that we're outta here
+ if (_view != null ) {
+ PlaceViewUtil.dispatchDidLeavePlace(_view, plobj);
+ }
+ }
+
+ /**
+ * Handles basic place controller action events. Derived classes
+ * should be sure to call super.handleAction for events
+ * they don't specifically handle.
+ */
+ public boolean handleAction (ActionEvent action)
+ {
+ return false;
+ }
+
+ /** A reference to the active client context. */
+ protected PartyContext _ctx;
+
+ /** A reference to our place configuration. */
+ protected PlaceConfig _config;
+
+ /** A reference to the place object for which we're controlling a user
+ * interface. */
+ protected PlaceObject _plobj;
+
+ /** A reference to the root user interface component. */
+ protected PlaceView _view;
+}
diff --git a/src/java/com/threerings/crowd/client/PlaceDirector.java b/src/java/com/threerings/crowd/client/PlaceDirector.java
deleted file mode 100644
index 3ac22755c..000000000
--- a/src/java/com/threerings/crowd/client/PlaceDirector.java
+++ /dev/null
@@ -1,8 +0,0 @@
-//
-// $Id: PlaceDirector.java,v 1.1 2001/07/20 20:07:37 mdb Exp $
-
-package com.threerings.cocktail.party.client;
-
-public class PlaceDirector
-{
-}
diff --git a/src/java/com/threerings/crowd/client/PlaceView.java b/src/java/com/threerings/crowd/client/PlaceView.java
index 9a8994063..b1c3b4a91 100644
--- a/src/java/com/threerings/crowd/client/PlaceView.java
+++ b/src/java/com/threerings/crowd/client/PlaceView.java
@@ -1,7 +1,7 @@
//
-// $Id: PlaceView.java,v 1.2 2001/10/04 22:47:48 mdb Exp $
+// $Id: PlaceView.java,v 1.3 2001/10/05 23:57:26 mdb Exp $
-package com.threerings.cocktail.party.util;
+package com.threerings.cocktail.party.client;
import com.threerings.cocktail.party.data.PlaceObject;
diff --git a/src/java/com/threerings/crowd/client/PlaceViewUtil.java b/src/java/com/threerings/crowd/client/PlaceViewUtil.java
index 2f87f0b82..c0786131e 100644
--- a/src/java/com/threerings/crowd/client/PlaceViewUtil.java
+++ b/src/java/com/threerings/crowd/client/PlaceViewUtil.java
@@ -1,9 +1,8 @@
//
-// $Id: PlaceViewUtil.java,v 1.1 2001/10/04 20:02:49 mdb Exp $
+// $Id: PlaceViewUtil.java,v 1.2 2001/10/05 23:57:26 mdb Exp $
-package com.threerings.cocktail.party.util;
+package com.threerings.cocktail.party.client;
-import java.awt.Component;
import java.awt.Container;
import com.threerings.cocktail.party.Log;
@@ -27,7 +26,7 @@ public class PlaceViewUtil
* @param plobj the place object that is about to be entered.
*/
public static void dispatchWillEnterPlace (
- Component root, PlaceObject plobj)
+ Object root, PlaceObject plobj)
{
// dispatch the call on this component if it implements PlaceView
if (root instanceof PlaceView) {
@@ -60,7 +59,7 @@ public class PlaceViewUtil
* @param plobj the place object that is about to be entered.
*/
public static void dispatchDidLeavePlace (
- Component root, PlaceObject plobj)
+ Object root, PlaceObject plobj)
{
// dispatch the call on this component if it implements PlaceView
if (root instanceof PlaceView) {
diff --git a/src/java/com/threerings/crowd/data/PlaceConfig.java b/src/java/com/threerings/crowd/data/PlaceConfig.java
new file mode 100644
index 000000000..b46c4c483
--- /dev/null
+++ b/src/java/com/threerings/crowd/data/PlaceConfig.java
@@ -0,0 +1,94 @@
+//
+// $Id: PlaceConfig.java,v 1.1 2001/10/05 23:57:26 mdb Exp $
+
+package com.threerings.cocktail.party.data;
+
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
+import com.threerings.cocktail.cher.io.Streamable;
+
+/**
+ * The place config class encapsulates the configuration information for a
+ * particular type of place. The hierarchy of place config objects mimics
+ * the hierarchy of place managers and controllers. Both the place manager
+ * and place controller are provided with the place config object when the
+ * place is created.
+ *
+ *
The place config object is also the mechanism used to instantiate + * the appropriate place manager and controller. Every place must have an + * associated place config derived class that overrides {@link + * #getControllerClass} and {@link #getManagerClassName}, returning the + * appropriate place controller and manager class for that place. + * + *
A place that has specific configuration needs would extend this
+ * class (or an appropriate subclass) adding it's configuration
+ * information and overriding {@link #writeTo} and {@link #readFrom} to
+ * provide code to serialize and unserialize the additional fields.
+ */
+public abstract class PlaceConfig implements Streamable
+{
+ /** The oid of the place object for which we represent the
+ * configuration information. */
+ public int placeOid;
+
+ /**
+ * Returns the class that should be used to create a controller for
+ * this place. The controller class must derive from {@link
+ * com.threerings.cocktail.party.client.PlaceController}.
+ */
+ public abstract Class getControllerClass ();
+
+ /**
+ * Returns the name of the class that should be used to create a
+ * manager for this place. The manager class must derive from {@link
+ * com.threerings.cocktail.party.server.PlaceManager}. Note:
+ * this method differs from {@link #getControllerClass} because we
+ * want to avoid compile time linkage of the place config object
+ * (which is used on the client) to server code. This allows a code
+ * optimizer (DashO Pro, for example) to remove the server code from
+ * the client, knowing that it is never used.
+ */
+ public abstract String getManagerClassName ();
+
+ // documentation inherited
+ public void writeTo (DataOutputStream out)
+ throws IOException
+ {
+ out.writeInt(placeOid);
+ }
+
+ // documentation inherited
+ public void readFrom (DataInputStream in)
+ throws IOException
+ {
+ placeOid = in.readInt();
+ }
+
+ /**
+ * Generates a string representation of this object by calling the
+ * overridable {@link #toString(StringBuffer)} which builds up the
+ * string in a manner friendly to derived classes.
+ */
+ public String toString ()
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append("[");
+ toString(buf);
+ buf.append("]");
+ return buf.toString();
+ }
+
+ /**
+ * An extensible mechanism for generating a string representation of
+ * this object. Derived classes should override this method, calling
+ * super and then appending their own data to the supplied string
+ * buffer. The regular {@link #toString} function will call this
+ * derived function to generate its string.
+ */
+ protected void toString (StringBuffer buf)
+ {
+ buf.append("type=").append(getClass().getName());
+ }
+}
diff --git a/src/java/com/threerings/crowd/server/LocationProvider.java b/src/java/com/threerings/crowd/server/LocationProvider.java
index 54749b6ff..dc152b7f1 100644
--- a/src/java/com/threerings/crowd/server/LocationProvider.java
+++ b/src/java/com/threerings/crowd/server/LocationProvider.java
@@ -1,10 +1,11 @@
//
-// $Id: LocationProvider.java,v 1.8 2001/10/01 22:14:55 mdb Exp $
+// $Id: LocationProvider.java,v 1.9 2001/10/05 23:57:26 mdb Exp $
package com.threerings.cocktail.party.server;
import com.threerings.cocktail.cher.dobj.DObject;
import com.threerings.cocktail.cher.server.InvocationProvider;
+import com.threerings.cocktail.cher.server.ServiceFailedException;
import com.threerings.cocktail.party.Log;
import com.threerings.cocktail.party.client.LocationCodes;
@@ -23,14 +24,15 @@ public class LocationProvider
public void handleMoveToRequest (BodyObject source, int invid,
int placeId)
{
- // try to do the actual move
- String rcode = moveTo(source, placeId);
+ try {
+ // do the move
+ PlaceConfig config = moveTo(source, placeId);
+ // and send the response
+ sendResponse(source, invid, MOVE_SUCCEEDED_RESPONSE, config);
- // send the response
- if (rcode.equals(SUCCESS)) {
- sendResponse(source, invid, MOVE_SUCCEEDED_RESPONSE);
- } else {
- sendResponse(source, invid, MOVE_FAILED_RESPONSE, rcode);
+ } catch (ServiceFailedException sfe) {
+ sendResponse(source, invid, MOVE_FAILED_RESPONSE,
+ sfe.getMessage());
}
}
@@ -38,10 +40,14 @@ public class LocationProvider
* Moves the specified body from whatever location they currently
* occupy to the location identified by the supplied place id.
*
- * @return the string SUCCESS if the move was successful
- * or a reason code for failure if not.
+ * @return the config object for the new location.
+ *
+ * @exception ServiceFaildException thrown if the move was not
+ * successful for some reason (which will be communicated as an error
+ * code in the exception's message data).
*/
- public static String moveTo (BodyObject source, int placeId)
+ public static PlaceConfig moveTo (BodyObject source, int placeId)
+ throws ServiceFailedException
{
int bodoid = source.getOid();
@@ -50,7 +56,7 @@ public class LocationProvider
if (pmgr == null) {
Log.info("Requested to move to non-existent place " +
"[source=" + source + ", place=" + placeId + "].");
- return NO_SUCH_PLACE;
+ throw new ServiceFailedException(NO_SUCH_PLACE);
}
// acquire a lock on the body object to ensure that rapid fire
@@ -58,13 +64,13 @@ public class LocationProvider
if (!source.acquireLock("moveToLock")) {
// if we're still locked, a previous moveTo request hasn't
// been fully processed
- return MOVE_IN_PROGRESS;
+ throw new ServiceFailedException(MOVE_IN_PROGRESS);
}
// make sure they're not already in the location they're asking to
// move to
if (source.location == placeId) {
- return ALREADY_THERE;
+ throw new ServiceFailedException(ALREADY_THERE);
}
// find out if they were previously in some other location
@@ -112,6 +118,6 @@ public class LocationProvider
// once all these events are processed
source.releaseLock("moveToLock");
- return SUCCESS;
+ return pmgr.getConfig();
}
}
diff --git a/src/java/com/threerings/crowd/server/PlaceManager.java b/src/java/com/threerings/crowd/server/PlaceManager.java
index f4d7ebacd..3fd02a2ce 100644
--- a/src/java/com/threerings/crowd/server/PlaceManager.java
+++ b/src/java/com/threerings/crowd/server/PlaceManager.java
@@ -1,5 +1,5 @@
//
-// $Id: PlaceManager.java,v 1.13 2001/10/02 02:07:50 mdb Exp $
+// $Id: PlaceManager.java,v 1.14 2001/10/05 23:57:26 mdb Exp $
package com.threerings.cocktail.party.server;
@@ -33,11 +33,19 @@ import com.threerings.cocktail.party.data.*;
public class PlaceManager implements Subscriber
{
/**
- * Called by the place registry after creating this place manager.
+ * Returns a reference to our place configuration object.
*/
- public void setPlaceRegistry (PlaceRegistry registry)
+ public PlaceConfig getConfig ()
{
- _registry = registry;
+ return _config;
+ }
+
+ /**
+ * Returns the place object managed by this place manager.
+ */
+ public PlaceObject getPlaceObject ()
+ {
+ return _plobj;
}
/**
@@ -58,6 +66,29 @@ public class PlaceManager implements Subscriber
return PlaceObject.class;
}
+ /**
+ * Called by the place registry after creating this place manager.
+ */
+ public void init (PlaceRegistry registry, PlaceConfig config)
+ {
+ _registry = registry;
+ _config = config;
+
+ // let derived classes do initialization stuff
+ didInit();
+ }
+
+ /**
+ * Called after this place manager has been initialized with its
+ * configuration information but before it has been started up with
+ * its place object reference. Derived classes can override this
+ * function and perform any basic initialization that they desire.
+ * They should of course be sure to call super.didInit().
+ */
+ protected void didInit ()
+ {
+ }
+
/**
* Called by the place manager after the place object has been
* successfully created.
@@ -194,14 +225,6 @@ public class PlaceManager implements Subscriber
_msghandlers.put(name, handler);
}
- /**
- * Returns the place object managed by this place manager.
- */
- public PlaceObject getPlaceObject ()
- {
- return _plobj;
- }
-
// nothing doing
public void objectAvailable (DObject object)
{
@@ -269,6 +292,7 @@ public class PlaceManager implements Subscriber
protected void toString (StringBuffer buf)
{
buf.append("place=").append(_plobj);
+ buf.append(", config=").append(_config);
}
/**
@@ -291,6 +315,9 @@ public class PlaceManager implements Subscriber
/** A reference to the place object that we manage. */
protected PlaceObject _plobj;
+ /** A reference to the configuration for our place. */
+ protected PlaceConfig _config;
+
/** A reference to the place registry with which we're registered. */
protected PlaceRegistry _registry;
diff --git a/src/java/com/threerings/crowd/server/PlaceRegistry.java b/src/java/com/threerings/crowd/server/PlaceRegistry.java
index 165903755..dd49e04a5 100644
--- a/src/java/com/threerings/crowd/server/PlaceRegistry.java
+++ b/src/java/com/threerings/crowd/server/PlaceRegistry.java
@@ -1,5 +1,5 @@
//
-// $Id: PlaceRegistry.java,v 1.9 2001/10/02 02:07:50 mdb Exp $
+// $Id: PlaceRegistry.java,v 1.10 2001/10/05 23:57:26 mdb Exp $
package com.threerings.cocktail.party.server;
@@ -12,6 +12,7 @@ import com.samskivert.util.Queue;
import com.threerings.cocktail.cher.dobj.*;
import com.threerings.cocktail.party.Log;
+import com.threerings.cocktail.party.data.PlaceConfig;
import com.threerings.cocktail.party.data.PlaceObject;
/**
@@ -36,8 +37,10 @@ public class PlaceRegistry implements Subscriber
* creation of the object and informing the manager when it is
* created.
*
- * @param pmgrClass the {@link PlaceManager} derived class that should
- * be instantiated to manage the place.
+ * @param config the configuration object for the place to be
+ * created. The {@link PlaceManager} derived class that should be
+ * instantiated to manage the place will be determined from the config
+ * object.
*
* @return a reference to the place manager that will manage the new
* place object.
@@ -45,14 +48,16 @@ public class PlaceRegistry implements Subscriber
* @exception InstantiationException thrown if an error occurs trying
* to instantiate and initialize the place manager.
*/
- public PlaceManager createPlace (Class pmgrClass)
+ public PlaceManager createPlace (PlaceConfig config)
throws InstantiationException
{
try {
+ // load up the manager class
+ Class pmgrClass = Class.forName(config.getManagerClassName());
// create a place manager for this place
PlaceManager pmgr = (PlaceManager)pmgrClass.newInstance();
- // let the pmgr know about us
- pmgr.setPlaceRegistry(this);
+ // let the pmgr know about us and its configuration
+ pmgr.init(this, config);
// stick the manager on the creation queue because we know
// we'll get our calls to objectAvailable()/requestFailed() in
@@ -65,9 +70,10 @@ public class PlaceRegistry implements Subscriber
return pmgr;
- } catch (IllegalAccessException iae) {
+ } catch (Exception e) {
+ Log.logStackTrace(e);
throw new InstantiationException(
- "Error instantiating place manager: " + iae);
+ "Error creating place manager [config=" + config + "].");
}
}