I love to make vast, sweeping changes. Now the place services incorporate

a place config object which is used to determine the classes of the place
manager and the (newly added) place controller.

Moved PlaceView and PlaceViewUtil into cocktail.party.client from
cocktail.party.util because the controller and the UI (in very abstract
form) are now part of the place services.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@399 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-10-05 23:57:26 +00:00
parent 7636e33a7c
commit 63191ec610
9 changed files with 327 additions and 57 deletions
@@ -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 <code>moveTo</code> 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.
@@ -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
* <code>super.didLeavePlace</code>) 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 <code>super.handleAction</code> 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;
}
@@ -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
{
}
@@ -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;
@@ -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) {
@@ -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.
*
* <p> 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.
*
* <p> 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}. <em>Note:</em>
* 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());
}
}
@@ -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 <code>SUCCESS</code> 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();
}
}
@@ -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 <code>super.didInit()</code>.
*/
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;
@@ -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 + "].");
}
}