From 915f3db6f11291db935f98d423d12a0ed01a8818 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 19 Jul 2001 07:09:16 +0000 Subject: [PATCH] More work on invocation manager; modified startup sequence so that server can get shit together before bootstrapping the client. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@68 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/presents/client/Client.java | 35 +++--- .../presents/client/ClientDObjectMgr.java | 8 +- .../presents/client/Communicator.java | 28 +---- .../presents/client/InvocationDirector.java | 104 +++++++----------- .../threerings/presents/net/AuthResponse.java | 4 +- .../presents/net/AuthResponseData.java | 12 +- .../presents/net/BootstrapData.java | 26 +++++ .../presents/net/BootstrapNotification.java | 67 +++++++++++ .../presents/net/EventNotification.java | 4 +- .../presents/net/FailureResponse.java | 4 +- .../presents/net/ObjectResponse.java | 4 +- .../presents/server/InvocationManager.java | 62 ++++++++++- .../presents/server/PresentsClient.java | 78 ++++++++++++- .../presents/server/PresentsServer.java | 7 +- .../threerings/presents/util/ClassUtil.java | 57 ++++++++++ 15 files changed, 371 insertions(+), 129 deletions(-) create mode 100644 src/java/com/threerings/presents/net/BootstrapData.java create mode 100644 src/java/com/threerings/presents/net/BootstrapNotification.java create mode 100644 src/java/com/threerings/presents/util/ClassUtil.java diff --git a/src/java/com/threerings/presents/client/Client.java b/src/java/com/threerings/presents/client/Client.java index 5938035df..42abce7d6 100644 --- a/src/java/com/threerings/presents/client/Client.java +++ b/src/java/com/threerings/presents/client/Client.java @@ -1,5 +1,5 @@ // -// $Id: Client.java,v 1.7 2001/07/19 05:56:20 mdb Exp $ +// $Id: Client.java,v 1.8 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.client; @@ -8,6 +8,7 @@ import java.util.List; import com.threerings.cocktail.cher.Log; import com.threerings.cocktail.cher.dobj.DObjectManager; +import com.threerings.cocktail.cher.net.BootstrapData; import com.threerings.cocktail.cher.net.Credentials; /** @@ -142,28 +143,21 @@ public class Client } /** - * Every client has an associated ClientObject instance. - * - * @return the oid of the client object or -1 if we are not currently - * connected to the server. + * Returns the oid of the client object associated with this session. + * It is only valid for the duration of the session. */ public int getClientOid () { - return (_comm != null) ? _comm.getClientOid() : -1; + return _cloid; } /** * Returns the invocation manager associated with this session. This - * reference is only valid for the duration of the session and a new - * reference must be obtained if the client disconnects and reconnects - * to the server. - * - * @return the invocation manager in effect or null if we have no - * established connection to the server. + * reference is only valid for the duration of the session. */ public InvocationManager getInvocationManager () { - return (_comm != null) ? _comm.getInvocationManager() : null; + return _invmgr; } /** @@ -249,6 +243,18 @@ public class Client _comm = null; } + /** + * Called by the omgr when a bootstrap notification arrives. + */ + void gotBootstrap (BootstrapData data) + { + // extract bootstrap information + _cloid = data.clientOid; + + // create our invocation manager + _invmgr = new InvocationManager(this, data.invOid); + } + protected Credentials _creds; protected Invoker _invoker; @@ -261,6 +267,9 @@ public class Client /** The entity that manages our network communications. */ protected Communicator _comm; + protected int _cloid; + protected InvocationManager _invmgr; + // client observer codes static final int CLIENT_DID_LOGON = 0; static final int CLIENT_FAILED_TO_LOGON = 1; diff --git a/src/java/com/threerings/presents/client/ClientDObjectMgr.java b/src/java/com/threerings/presents/client/ClientDObjectMgr.java index 6c9e3c725..de9fed78f 100644 --- a/src/java/com/threerings/presents/client/ClientDObjectMgr.java +++ b/src/java/com/threerings/presents/client/ClientDObjectMgr.java @@ -1,5 +1,5 @@ // -// $Id: ClientDObjectMgr.java,v 1.3 2001/06/13 05:17:54 mdb Exp $ +// $Id: ClientDObjectMgr.java,v 1.4 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.client; @@ -109,7 +109,11 @@ public class ClientDObjectMgr Object obj; while ((obj = _actions.getNonBlocking()) != null) { // do the proper thing depending on the object - if (obj instanceof EventNotification) { + if (obj instanceof BootstrapNotification) { + BootstrapData data = ((BootstrapNotification)obj).getData(); + _client.gotBootstrap(data); + + } else if (obj instanceof EventNotification) { DEvent evt = ((EventNotification)obj).getEvent(); dispatchEvent(evt); diff --git a/src/java/com/threerings/presents/client/Communicator.java b/src/java/com/threerings/presents/client/Communicator.java index fbff0e83a..af2daf813 100644 --- a/src/java/com/threerings/presents/client/Communicator.java +++ b/src/java/com/threerings/presents/client/Communicator.java @@ -1,5 +1,5 @@ // -// $Id: Communicator.java,v 1.8 2001/07/19 05:56:20 mdb Exp $ +// $Id: Communicator.java,v 1.9 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.client; @@ -61,24 +61,6 @@ public class Communicator return _omgr; } - /** - * Returns the oid of the client object associated with this session. - * It is only valid for the duration of the session. - */ - public int getClientOid () - { - return _cloid; - } - - /** - * Returns the invocation manager associated with this session. This - * reference is only valid for the duration of the session. - */ - public InvocationManager getInvocationManager () - { - return _invmgr; - } - /** * Logs on to the server and initiates our full-duplex message * exchange. @@ -171,15 +153,9 @@ public class Communicator { Log.info("Logon succeeded: " + data); - // extract bootstrap information - _cloid = data.clientOid; - // create our distributed object manager _omgr = new ClientDObjectMgr(this, _client); - // create our invocation manager - _invmgr = new InvocationManager(_client, data.invOid); - // create a new writer thread and start it up if (_writer != null) { throw new RuntimeException("Writer already started!?"); @@ -502,6 +478,4 @@ public class Communicator protected DataInputStream _din; protected ClientDObjectMgr _omgr; - protected int _cloid; - protected InvocationManager _invmgr; } diff --git a/src/java/com/threerings/presents/client/InvocationDirector.java b/src/java/com/threerings/presents/client/InvocationDirector.java index 516611bf5..2e3528a2b 100644 --- a/src/java/com/threerings/presents/client/InvocationDirector.java +++ b/src/java/com/threerings/presents/client/InvocationDirector.java @@ -1,5 +1,5 @@ // -// $Id: InvocationDirector.java,v 1.1 2001/07/19 05:56:20 mdb Exp $ +// $Id: InvocationDirector.java,v 1.2 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.client; @@ -9,6 +9,7 @@ import java.util.HashMap; import com.threerings.cocktail.cher.Log; import com.threerings.cocktail.cher.data.*; import com.threerings.cocktail.cher.dobj.*; +import com.threerings.cocktail.cher.util.ClassUtil; import com.threerings.cocktail.cher.util.IntMap; /** @@ -53,28 +54,32 @@ public class InvocationManager /** * Sends an invocation request to the server. If a response target is * supplied, the response will be delivered to that object by calling - * a member function on it whose name is derived from the invocation - * name. For example, if the caller invoked a procedure named - * SwitchLocation, the response would be delivered via a - * call to the handleSwitchLocationResponse method on the - * response target object. The signature of that method would be - * defined by the arguments provided in the response message. + * a member function on it whose name is defined in the response + * generated by the invocation implementation. In general, this is a + * derivative of the invocation procedure name. For example, if the + * caller invoked a procedure named Switch, the response + * may be delivered via a call to the handleSwitchSuccess + * method on the response target object. The signature of that method + * would be defined by the arguments provided in the response message. * - * @param name the name of the invocation. + * @param module the name of the invocation module to use. + * @param procedure the name of the procedure within that module. * @param args the arguments of the invocation. * @param rsptarget the object that will receive the response, or null * if no response is desired. */ - public void invoke (String name, Object[] args, Object rsptarget) + public void invoke (String module, String procedure, Object[] args, + Object rsptarget) { int invid = nextInvocationId(); // we need an args array for a message that can contain the - // invocation name, an invocation id and the invocation arguments - Object[] iargs = new Object[args.length+2]; - System.arraycopy(args, 0, iargs, 2, args.length); - iargs[0] = name; - iargs[1] = new Integer(invid); + // invocation names, an invocation id and the invocation arguments + Object[] iargs = new Object[args.length+3]; + iargs[0] = module; + iargs[1] = procedure; + iargs[2] = new Integer(invid); + System.arraycopy(args, 0, iargs, 3, args.length); // create a message event on the invocation manager object MessageEvent event = new MessageEvent( @@ -83,7 +88,7 @@ public class InvocationManager // if we have a response target, register that for later receipt // of the response if (rsptarget != null) { - _targets.put(invid, new Response(name, rsptarget)); + _targets.put(invid, rsptarget); } // and finally ship off the invocation message @@ -110,9 +115,8 @@ public class InvocationManager return true; } - MessageEvent mevt = (MessageEvent)event; - // and only those of proper name + MessageEvent mevt = (MessageEvent)event; if (!mevt.getName().equals(InvocationObject.MESSAGE_NAME)) { return true; } @@ -120,11 +124,11 @@ public class InvocationManager // we've got an invocation response, so we extract the args and // process it Object[] args = mevt.getArgs(); - int invid = ((Integer)args[0]).intValue(); - String name = (String)args[1]; + String name = (String)args[0]; + int invid = ((Integer)args[1]).intValue(); - Response rsp = (Response)_targets.get(invid); - if (rsp == null) { + Object rsptarg = _targets.get(invid); + if (rsptarg == null) { Log.warning("No target for invocation response " + "[rsp=" + mevt + "]."); return true; @@ -135,53 +139,27 @@ public class InvocationManager System.arraycopy(args, 2, rargs, 0, rargs.length); // and invoke the response method - Method rspmeth = getResponseMethod(name, target, rargs); - if (rspmeth != null) { - try { - rspmeth.invoke(target, rargs); - } catch (Exception e) { - Log.warning("Error invoking response target method " + - "[target=" + target + ", method=" + rspmeth + - ", error=" + e + "]."); - } + String mname = "handle" + name; + Method rspmeth = ClassUtil.getMethod(mname, rsptarg, _methcache); + if (rspmeth == null) { + Log.warning("Unable to resolve response method " + + "[target=" + rsptarg.getClass().getName() + + ", method=" + mname + "]."); + return true; + } + + // and invoke it + try { + rspmeth.invoke(rsptarg, rargs); + } catch (Exception e) { + Log.warning("Error invoking response target method " + + "[target=" + rsptarg + ", method=" + rspmeth + + ", error=" + e + "]."); } return true; } - protected Method getResponseMethod (String name, Object target, - Object[] args) - { - Class tclass = target.getClass(); - String key = tclass.getName() + ":" + name; - Method method = (Method)_methcache.get(key); - - if (method == null) { - String methname = "handle" + name; - method = findMethod(tclass, name); - if (method == null) { - Log.warning("Unable to locate method on response target " + - "[rtclass=" + tclass.getName() + - ", method=" + methname + "]."); - return null; - } - _methcache.put(key, method); - } - - return method; - } - - protected static Method findMethod (Class clazz, String name) - { - Method[] methods = clazz.getMethods(); - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(name)) { - return methods[i]; - } - } - return null; - } - protected synchronized int nextInvocationId () { return _invocationId++; diff --git a/src/java/com/threerings/presents/net/AuthResponse.java b/src/java/com/threerings/presents/net/AuthResponse.java index 439500bda..532399bad 100644 --- a/src/java/com/threerings/presents/net/AuthResponse.java +++ b/src/java/com/threerings/presents/net/AuthResponse.java @@ -1,5 +1,5 @@ // -// $Id: AuthResponse.java,v 1.6 2001/06/11 17:42:20 mdb Exp $ +// $Id: AuthResponse.java,v 1.7 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.net; @@ -30,7 +30,7 @@ public class AuthResponse extends DownstreamMessage } /** - * Constructs a auth response with the supplied credentials. + * Constructs a auth response with the supplied response data. */ public AuthResponse (AuthResponseData data) { diff --git a/src/java/com/threerings/presents/net/AuthResponseData.java b/src/java/com/threerings/presents/net/AuthResponseData.java index 7aab65303..97e6384c8 100644 --- a/src/java/com/threerings/presents/net/AuthResponseData.java +++ b/src/java/com/threerings/presents/net/AuthResponseData.java @@ -1,12 +1,8 @@ // -// $Id: AuthResponseData.java,v 1.5 2001/07/19 05:56:20 mdb Exp $ +// $Id: AuthResponseData.java,v 1.6 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.net; -import java.io.IOException; -import java.io.DataInputStream; -import java.io.DataOutputStream; - import com.threerings.cocktail.cher.dobj.DObject; /** @@ -23,12 +19,6 @@ public class AuthResponseData extends DObject */ public String code; - /** The oid of this client's associated distributed object. */ - public int clientOid; - - /** The oid to which to send invocation requests. */ - public int invOid; - public String toString () { return "[code=" + code + "]"; diff --git a/src/java/com/threerings/presents/net/BootstrapData.java b/src/java/com/threerings/presents/net/BootstrapData.java new file mode 100644 index 000000000..e4deb02cd --- /dev/null +++ b/src/java/com/threerings/presents/net/BootstrapData.java @@ -0,0 +1,26 @@ +// +// $Id: BootstrapData.java,v 1.1 2001/07/19 07:09:16 mdb Exp $ + +package com.threerings.cocktail.cher.net; + +import com.threerings.cocktail.cher.dobj.DObject; + +/** + * An BootstrapData object is communicated back to the client + * after authentication has succeeded and after the server is fully + * prepared to deal with the client. It contains information the client + * will need to interact with the server. + */ +public class BootstrapData extends DObject +{ + /** The oid of this client's associated distributed object. */ + public int clientOid; + + /** The oid to which to send invocation requests. */ + public int invOid; + + public String toString () + { + return "[clientOid=" + clientOid + ", invOid=" + invOid + "]"; + } +} diff --git a/src/java/com/threerings/presents/net/BootstrapNotification.java b/src/java/com/threerings/presents/net/BootstrapNotification.java new file mode 100644 index 000000000..d024032cf --- /dev/null +++ b/src/java/com/threerings/presents/net/BootstrapNotification.java @@ -0,0 +1,67 @@ +// +// $Id: BootstrapNotification.java,v 1.1 2001/07/19 07:09:16 mdb Exp $ + +package com.threerings.cocktail.cher.net; + +import java.io.IOException; +import java.io.DataInputStream; +import java.io.DataOutputStream; + +import com.threerings.cocktail.cher.dobj.io.DObjectFactory; + +/** + * A bootstrap notification is delivered to the client once the server has + * fully initialized itself in preparation for dealing with this client. + * The authentication process completes very early and further information + * need be communicated to the client so that it can fully interact with + * the server. This information is communicated via the bootstrap + * notification. + */ +public class BootstrapNotification extends DownstreamMessage +{ + /** The code for a bootstrap notification. */ + public static final short TYPE = TYPE_BASE + 1; + + /** + * Zero argument constructor used when unserializing an instance. + */ + public BootstrapNotification () + { + super(); + } + + /** + * Constructs an bootstrap notification with the supplied data. + */ + public BootstrapNotification (BootstrapData data) + { + _data = data; + } + + public short getType () + { + return TYPE; + } + + public BootstrapData getData () + { + return _data; + } + + public void writeTo (DataOutputStream out) + throws IOException + { + super.writeTo(out); + DObjectFactory.writeTo(out, _data); + } + + public void readFrom (DataInputStream in) + throws IOException + { + super.readFrom(in); + _data = (BootstrapData)DObjectFactory.readFrom(in); + } + + /** The data associated with this notification. */ + protected BootstrapData _data; +} diff --git a/src/java/com/threerings/presents/net/EventNotification.java b/src/java/com/threerings/presents/net/EventNotification.java index c343970df..c9b3c4786 100644 --- a/src/java/com/threerings/presents/net/EventNotification.java +++ b/src/java/com/threerings/presents/net/EventNotification.java @@ -1,5 +1,5 @@ // -// $Id: EventNotification.java,v 1.7 2001/06/11 17:44:04 mdb Exp $ +// $Id: EventNotification.java,v 1.8 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.net; @@ -13,7 +13,7 @@ import com.threerings.cocktail.cher.io.TypedObjectFactory; public class EventNotification extends DownstreamMessage { /** The code for an event notification. */ - public static final short TYPE = TYPE_BASE + 1; + public static final short TYPE = TYPE_BASE + 2; /** * Zero argument constructor used when unserializing an instance. diff --git a/src/java/com/threerings/presents/net/FailureResponse.java b/src/java/com/threerings/presents/net/FailureResponse.java index f8438bc25..5a6ad1109 100644 --- a/src/java/com/threerings/presents/net/FailureResponse.java +++ b/src/java/com/threerings/presents/net/FailureResponse.java @@ -1,5 +1,5 @@ // -// $Id: FailureResponse.java,v 1.4 2001/06/09 23:39:04 mdb Exp $ +// $Id: FailureResponse.java,v 1.5 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.net; @@ -9,7 +9,7 @@ import java.io.DataOutputStream; public class FailureResponse extends DownstreamMessage { - /** The code for a logoff notification. */ + /** The code for a failure notification. */ public static final short TYPE = TYPE_BASE + 4; /** diff --git a/src/java/com/threerings/presents/net/ObjectResponse.java b/src/java/com/threerings/presents/net/ObjectResponse.java index cd7d1e46b..6e39c0588 100644 --- a/src/java/com/threerings/presents/net/ObjectResponse.java +++ b/src/java/com/threerings/presents/net/ObjectResponse.java @@ -1,5 +1,5 @@ // -// $Id: ObjectResponse.java,v 1.8 2001/06/11 17:42:20 mdb Exp $ +// $Id: ObjectResponse.java,v 1.9 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.net; @@ -13,7 +13,7 @@ import com.threerings.cocktail.cher.dobj.io.DObjectFactory; public class ObjectResponse extends DownstreamMessage { /** The code for an object repsonse. */ - public static final short TYPE = TYPE_BASE + 2; + public static final short TYPE = TYPE_BASE + 3; /** * Zero argument constructor used when unserializing an instance. diff --git a/src/java/com/threerings/presents/server/InvocationManager.java b/src/java/com/threerings/presents/server/InvocationManager.java index 2e2b26d68..15064191e 100644 --- a/src/java/com/threerings/presents/server/InvocationManager.java +++ b/src/java/com/threerings/presents/server/InvocationManager.java @@ -1,10 +1,15 @@ // -// $Id: InvocationManager.java,v 1.1 2001/07/19 05:56:20 mdb Exp $ +// $Id: InvocationManager.java,v 1.2 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.server; +import java.lang.reflect.Method; +import java.util.HashMap; + import com.threerings.cocktail.cher.Log; import com.threerings.cocktail.cher.dobj.*; +import com.threerings.cocktail.cher.data.*; +import com.threerings.cocktail.cher.util.ClassUtil; /** * The invocation services provide client to server invocations (service @@ -22,7 +27,7 @@ import com.threerings.cocktail.cher.dobj.*; * *

The server invocation manager listens for invocation requests from * the client and passes them on to the invocation provider registered for - * the requested invocation type. It also provides a mechanism by which + * the requested invocation module. It also provides a mechanism by which * responses and asynchronous notification invocations can be delivered to * the client. */ @@ -42,6 +47,15 @@ public class InvocationManager return _invoid; } + /** + * Registers the supplied invocation provider instance as the handler + * for all invocation requests for the specified module. + */ + public void registerProvider (String module, Object provider) + { + _providers.put(module, provider); + } + public void objectAvailable (DObject object) { // this must be our invocation object @@ -66,12 +80,54 @@ public class InvocationManager return true; } - MessageEvent mevt = (MessageEvent)event; // make sure the name is proper just for sanities sake + MessageEvent mevt = (MessageEvent)event; + if (!mevt.getName().equals(InvocationObject.MESSAGE_NAME)) { + return true; + } + + // we've got an invocation request, so we process it + Object[] args = mevt.getArgs(); + String module = (String)args[0]; + String procedure = (String)args[1]; + int invid = ((Integer)args[2]).intValue(); + + // locate a provider for this module + Object provider = _providers.get(module); + if (provider == null) { + Log.warning("No provider registered for invocation request " + + "[evt=" + mevt + "]."); + return true; + } + + // prune the method arguments from the full message arguments + Object[] margs = new Object[args.length-3]; + System.arraycopy(args, 3, margs, 0, margs.length); + + // look up the method that will handle this procedure + String mname = "handle" + procedure + "Request"; + Method procmeth = ClassUtil.getMethod(mname, provider, _methcache); + if (procmeth == null) { + Log.warning("Unable to resolve provider procedure " + + "[provider=" + provider.getClass().getName() + + ", method=" + mname + "]."); + return true; + } + + // and invoke it + try { + procmeth.invoke(provider, margs); + } catch (Exception e) { + Log.warning("Error invoking invocation procedure " + + "[provider=" + provider + ", method=" + procmeth + + ", error=" + e + "]."); + } return true; } protected DObjectManager _omgr; protected int _invoid; + protected HashMap _providers = new HashMap(); + protected HashMap _methcache = new HashMap(); } diff --git a/src/java/com/threerings/presents/server/PresentsClient.java b/src/java/com/threerings/presents/server/PresentsClient.java index 933871a15..45e68a9c5 100644 --- a/src/java/com/threerings/presents/server/PresentsClient.java +++ b/src/java/com/threerings/presents/server/PresentsClient.java @@ -1,5 +1,5 @@ // -// $Id: PresentsClient.java,v 1.4 2001/06/11 17:44:04 mdb Exp $ +// $Id: PresentsClient.java,v 1.5 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.server; @@ -7,6 +7,7 @@ import java.io.IOException; import java.util.HashMap; import com.threerings.cocktail.cher.Log; +import com.threerings.cocktail.cher.data.ClientObject; import com.threerings.cocktail.cher.dobj.*; import com.threerings.cocktail.cher.net.*; import com.threerings.cocktail.cher.server.net.*; @@ -36,6 +37,30 @@ public class Client implements Subscriber, MessageHandler _cmgr = cmgr; _username = username; setConnection(conn); + + // create our client object and bootstrap the client once we've + // got it + Subscriber sub = new Subscriber () + { + public void objectAvailable (DObject object) + { + setClientObject((ClientObject)object); + sendBootstrap(); + } + + public void requestFailed (int oid, ObjectAccessException cause) + { + Log.warning("Unable to create client object " + + "[client=" + Client.this + + ", error=" + cause + "]."); + } + + public boolean handleEvent (DEvent event, DObject target) + { + return false; + } + }; + CherServer.omgr.createObject(ClientObject.class, this, false); } /** @@ -68,9 +93,59 @@ public class Client implements Subscriber, MessageHandler // start using the new connection setConnection(conn); + // send off a bootstrap notification immediately because we've + // already got our client object + sendBootstrap(); + Log.info("Session resumed [client=" + this + "]."); } + protected void setClientObject (ClientObject clobj) + { + // keep track of this for later + _clobj = clobj; + } + + /** + * This is called once we have a handle on the client distributed + * object. It sends a bootstrap notification to the client with all + * the information it will need to interact with the server. + */ + protected void sendBootstrap () + { + // create and populate our bootstrap data + BootstrapData data = createBootstrapData(); + populateBootstrapData(data); + + // create a send bootstrap notification + _conn.postMessage(new BootstrapNotification(data)); + } + + /** + * Derived client classes can override this member to create derived + * bootstrap data classes that contain extra bootstrap information, if + * desired. + */ + protected BootstrapData createBootstrapData () + { + return new BootstrapData(); + } + + /** + * Derived client classes can override this member to populate the + * bootstrap data with additional information. They should be sure to + * call super.populateBootstrapData() before doing their + * own populating, however. + */ + protected void populateBootstrapData (BootstrapData data) + { + // give them the client object id + data.clientOid = _clobj.getOid(); + + // give them the invocation oid + data.invOid = CherServer.invmgr.getOid(); + } + /** * Called by the connection manager when this client's connection * fails. This is invoked on the conmgr thread, and should behave @@ -269,6 +344,7 @@ public class Client implements Subscriber, MessageHandler protected ClientManager _cmgr; protected String _username; protected Connection _conn; + protected ClientObject _clobj; protected static HashMap _disps = new HashMap(); diff --git a/src/java/com/threerings/presents/server/PresentsServer.java b/src/java/com/threerings/presents/server/PresentsServer.java index fcbc5c8d7..b55388593 100644 --- a/src/java/com/threerings/presents/server/PresentsServer.java +++ b/src/java/com/threerings/presents/server/PresentsServer.java @@ -1,5 +1,5 @@ // -// $Id: PresentsServer.java,v 1.5 2001/06/09 23:39:04 mdb Exp $ +// $Id: PresentsServer.java,v 1.6 2001/07/19 07:09:16 mdb Exp $ package com.threerings.cocktail.cher.server; @@ -28,6 +28,9 @@ public class CherServer /** The distributed object manager. */ public static DObjectManager omgr; + /** The invocation manager. */ + public static InvocationManager invmgr; + /** * Initializes all of the server services and prepares for operation. */ @@ -42,6 +45,8 @@ public class CherServer clmgr = new ClientManager(conmgr); // create our distributed object manager omgr = new CherDObjectMgr(); + // create our invocation manager + invmgr = new InvocationManager(omgr); // create an object for testing omgr.createObject(TestObject.class, null, false); diff --git a/src/java/com/threerings/presents/util/ClassUtil.java b/src/java/com/threerings/presents/util/ClassUtil.java new file mode 100644 index 000000000..0d6ebe56c --- /dev/null +++ b/src/java/com/threerings/presents/util/ClassUtil.java @@ -0,0 +1,57 @@ +// +// $Id: ClassUtil.java,v 1.1 2001/07/19 07:09:16 mdb Exp $ + +package com.threerings.cocktail.cher.util; + +import java.lang.reflect.Method; +import java.util.HashMap; + +/** + * Class related utility functions. + */ +public class ClassUtil +{ + /** + * Locates and returns teh first method in the supplied class whose + * name is equal to the specified name. If a method is located, it + * will be cached in the supplied cache so that subsequent requests + * will immediately return the method from the cache rather than + * re-reflecting. + * + * @return the method with the specified name or null if no method + * with that name could be found. + */ + public static Method getMethod (String name, Object target, HashMap cache) + { + Class tclass = target.getClass(); + String key = tclass.getName() + ":" + name; + Method method = (Method)cache.get(key); + + if (method == null) { + method = findMethod(tclass, name); + if (method != null) { + cache.put(key, method); + } + } + + return method; + } + + /** + * Locates and returns the first method in the supplied class whose + * name is equal to the specified name. + * + * @return the method with the specified name or null if no method + * with that name could be found. + */ + public static Method findMethod (Class clazz, String name) + { + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(name)) { + return methods[i]; + } + } + return null; + } +}