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;
+ }
+}