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
This commit is contained in:
@@ -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;
|
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.Log;
|
||||||
import com.threerings.cocktail.cher.dobj.DObjectManager;
|
import com.threerings.cocktail.cher.dobj.DObjectManager;
|
||||||
|
import com.threerings.cocktail.cher.net.BootstrapData;
|
||||||
import com.threerings.cocktail.cher.net.Credentials;
|
import com.threerings.cocktail.cher.net.Credentials;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,28 +143,21 @@ public class Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every client has an associated <code>ClientObject</code> instance.
|
* Returns the oid of the client object associated with this session.
|
||||||
*
|
* It is only valid for the duration of the session.
|
||||||
* @return the oid of the client object or -1 if we are not currently
|
|
||||||
* connected to the server.
|
|
||||||
*/
|
*/
|
||||||
public int getClientOid ()
|
public int getClientOid ()
|
||||||
{
|
{
|
||||||
return (_comm != null) ? _comm.getClientOid() : -1;
|
return _cloid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the invocation manager associated with this session. This
|
* Returns the invocation manager associated with this session. This
|
||||||
* reference is only valid for the duration of the session and a new
|
* reference is only valid for the duration of the session.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
public InvocationManager getInvocationManager ()
|
public InvocationManager getInvocationManager ()
|
||||||
{
|
{
|
||||||
return (_comm != null) ? _comm.getInvocationManager() : null;
|
return _invmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,6 +243,18 @@ public class Client
|
|||||||
_comm = null;
|
_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 Credentials _creds;
|
||||||
protected Invoker _invoker;
|
protected Invoker _invoker;
|
||||||
|
|
||||||
@@ -261,6 +267,9 @@ public class Client
|
|||||||
/** The entity that manages our network communications. */
|
/** The entity that manages our network communications. */
|
||||||
protected Communicator _comm;
|
protected Communicator _comm;
|
||||||
|
|
||||||
|
protected int _cloid;
|
||||||
|
protected InvocationManager _invmgr;
|
||||||
|
|
||||||
// client observer codes
|
// client observer codes
|
||||||
static final int CLIENT_DID_LOGON = 0;
|
static final int CLIENT_DID_LOGON = 0;
|
||||||
static final int CLIENT_FAILED_TO_LOGON = 1;
|
static final int CLIENT_FAILED_TO_LOGON = 1;
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.client;
|
||||||
|
|
||||||
@@ -109,7 +109,11 @@ public class ClientDObjectMgr
|
|||||||
Object obj;
|
Object obj;
|
||||||
while ((obj = _actions.getNonBlocking()) != null) {
|
while ((obj = _actions.getNonBlocking()) != null) {
|
||||||
// do the proper thing depending on the object
|
// 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();
|
DEvent evt = ((EventNotification)obj).getEvent();
|
||||||
dispatchEvent(evt);
|
dispatchEvent(evt);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.client;
|
||||||
|
|
||||||
@@ -61,24 +61,6 @@ public class Communicator
|
|||||||
return _omgr;
|
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
|
* Logs on to the server and initiates our full-duplex message
|
||||||
* exchange.
|
* exchange.
|
||||||
@@ -171,15 +153,9 @@ public class Communicator
|
|||||||
{
|
{
|
||||||
Log.info("Logon succeeded: " + data);
|
Log.info("Logon succeeded: " + data);
|
||||||
|
|
||||||
// extract bootstrap information
|
|
||||||
_cloid = data.clientOid;
|
|
||||||
|
|
||||||
// create our distributed object manager
|
// create our distributed object manager
|
||||||
_omgr = new ClientDObjectMgr(this, _client);
|
_omgr = new ClientDObjectMgr(this, _client);
|
||||||
|
|
||||||
// create our invocation manager
|
|
||||||
_invmgr = new InvocationManager(_client, data.invOid);
|
|
||||||
|
|
||||||
// create a new writer thread and start it up
|
// create a new writer thread and start it up
|
||||||
if (_writer != null) {
|
if (_writer != null) {
|
||||||
throw new RuntimeException("Writer already started!?");
|
throw new RuntimeException("Writer already started!?");
|
||||||
@@ -502,6 +478,4 @@ public class Communicator
|
|||||||
protected DataInputStream _din;
|
protected DataInputStream _din;
|
||||||
|
|
||||||
protected ClientDObjectMgr _omgr;
|
protected ClientDObjectMgr _omgr;
|
||||||
protected int _cloid;
|
|
||||||
protected InvocationManager _invmgr;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
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.Log;
|
||||||
import com.threerings.cocktail.cher.data.*;
|
import com.threerings.cocktail.cher.data.*;
|
||||||
import com.threerings.cocktail.cher.dobj.*;
|
import com.threerings.cocktail.cher.dobj.*;
|
||||||
|
import com.threerings.cocktail.cher.util.ClassUtil;
|
||||||
import com.threerings.cocktail.cher.util.IntMap;
|
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
|
* Sends an invocation request to the server. If a response target is
|
||||||
* supplied, the response will be delivered to that object by calling
|
* supplied, the response will be delivered to that object by calling
|
||||||
* a member function on it whose name is derived from the invocation
|
* a member function on it whose name is defined in the response
|
||||||
* name. For example, if the caller invoked a procedure named
|
* generated by the invocation implementation. In general, this is a
|
||||||
* <code>SwitchLocation</code>, the response would be delivered via a
|
* derivative of the invocation procedure name. For example, if the
|
||||||
* call to the <code>handleSwitchLocationResponse</code> method on the
|
* caller invoked a procedure named <code>Switch</code>, the response
|
||||||
* response target object. The signature of that method would be
|
* may be delivered via a call to the <code>handleSwitchSuccess</code>
|
||||||
* defined by the arguments provided in the response message.
|
* 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 args the arguments of the invocation.
|
||||||
* @param rsptarget the object that will receive the response, or null
|
* @param rsptarget the object that will receive the response, or null
|
||||||
* if no response is desired.
|
* 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();
|
int invid = nextInvocationId();
|
||||||
|
|
||||||
// we need an args array for a message that can contain the
|
// we need an args array for a message that can contain the
|
||||||
// invocation name, an invocation id and the invocation arguments
|
// invocation names, an invocation id and the invocation arguments
|
||||||
Object[] iargs = new Object[args.length+2];
|
Object[] iargs = new Object[args.length+3];
|
||||||
System.arraycopy(args, 0, iargs, 2, args.length);
|
iargs[0] = module;
|
||||||
iargs[0] = name;
|
iargs[1] = procedure;
|
||||||
iargs[1] = new Integer(invid);
|
iargs[2] = new Integer(invid);
|
||||||
|
System.arraycopy(args, 0, iargs, 3, args.length);
|
||||||
|
|
||||||
// create a message event on the invocation manager object
|
// create a message event on the invocation manager object
|
||||||
MessageEvent event = new MessageEvent(
|
MessageEvent event = new MessageEvent(
|
||||||
@@ -83,7 +88,7 @@ public class InvocationManager
|
|||||||
// if we have a response target, register that for later receipt
|
// if we have a response target, register that for later receipt
|
||||||
// of the response
|
// of the response
|
||||||
if (rsptarget != null) {
|
if (rsptarget != null) {
|
||||||
_targets.put(invid, new Response(name, rsptarget));
|
_targets.put(invid, rsptarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// and finally ship off the invocation message
|
// and finally ship off the invocation message
|
||||||
@@ -110,9 +115,8 @@ public class InvocationManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEvent mevt = (MessageEvent)event;
|
|
||||||
|
|
||||||
// and only those of proper name
|
// and only those of proper name
|
||||||
|
MessageEvent mevt = (MessageEvent)event;
|
||||||
if (!mevt.getName().equals(InvocationObject.MESSAGE_NAME)) {
|
if (!mevt.getName().equals(InvocationObject.MESSAGE_NAME)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -120,11 +124,11 @@ public class InvocationManager
|
|||||||
// we've got an invocation response, so we extract the args and
|
// we've got an invocation response, so we extract the args and
|
||||||
// process it
|
// process it
|
||||||
Object[] args = mevt.getArgs();
|
Object[] args = mevt.getArgs();
|
||||||
int invid = ((Integer)args[0]).intValue();
|
String name = (String)args[0];
|
||||||
String name = (String)args[1];
|
int invid = ((Integer)args[1]).intValue();
|
||||||
|
|
||||||
Response rsp = (Response)_targets.get(invid);
|
Object rsptarg = _targets.get(invid);
|
||||||
if (rsp == null) {
|
if (rsptarg == null) {
|
||||||
Log.warning("No target for invocation response " +
|
Log.warning("No target for invocation response " +
|
||||||
"[rsp=" + mevt + "].");
|
"[rsp=" + mevt + "].");
|
||||||
return true;
|
return true;
|
||||||
@@ -135,53 +139,27 @@ public class InvocationManager
|
|||||||
System.arraycopy(args, 2, rargs, 0, rargs.length);
|
System.arraycopy(args, 2, rargs, 0, rargs.length);
|
||||||
|
|
||||||
// and invoke the response method
|
// and invoke the response method
|
||||||
Method rspmeth = getResponseMethod(name, target, rargs);
|
String mname = "handle" + name;
|
||||||
if (rspmeth != null) {
|
Method rspmeth = ClassUtil.getMethod(mname, rsptarg, _methcache);
|
||||||
try {
|
if (rspmeth == null) {
|
||||||
rspmeth.invoke(target, rargs);
|
Log.warning("Unable to resolve response method " +
|
||||||
} catch (Exception e) {
|
"[target=" + rsptarg.getClass().getName() +
|
||||||
Log.warning("Error invoking response target method " +
|
", method=" + mname + "].");
|
||||||
"[target=" + target + ", method=" + rspmeth +
|
return true;
|
||||||
", error=" + e + "].");
|
}
|
||||||
}
|
|
||||||
|
// 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;
|
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 ()
|
protected synchronized int nextInvocationId ()
|
||||||
{
|
{
|
||||||
return _invocationId++;
|
return _invocationId++;
|
||||||
|
|||||||
@@ -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;
|
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)
|
public AuthResponse (AuthResponseData data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
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;
|
import com.threerings.cocktail.cher.dobj.DObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,12 +19,6 @@ public class AuthResponseData extends DObject
|
|||||||
*/
|
*/
|
||||||
public String code;
|
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 ()
|
public String toString ()
|
||||||
{
|
{
|
||||||
return "[code=" + code + "]";
|
return "[code=" + code + "]";
|
||||||
|
|||||||
@@ -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 <code>BootstrapData</code> 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 + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
package com.threerings.cocktail.cher.net;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ import com.threerings.cocktail.cher.io.TypedObjectFactory;
|
|||||||
public class EventNotification extends DownstreamMessage
|
public class EventNotification extends DownstreamMessage
|
||||||
{
|
{
|
||||||
/** The code for an event notification. */
|
/** 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.
|
* Zero argument constructor used when unserializing an instance.
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.net;
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ import java.io.DataOutputStream;
|
|||||||
|
|
||||||
public class FailureResponse extends DownstreamMessage
|
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;
|
public static final short TYPE = TYPE_BASE + 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.net;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ import com.threerings.cocktail.cher.dobj.io.DObjectFactory;
|
|||||||
public class ObjectResponse extends DownstreamMessage
|
public class ObjectResponse extends DownstreamMessage
|
||||||
{
|
{
|
||||||
/** The code for an object repsonse. */
|
/** 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.
|
* Zero argument constructor used when unserializing an instance.
|
||||||
|
|||||||
@@ -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;
|
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.Log;
|
||||||
import com.threerings.cocktail.cher.dobj.*;
|
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
|
* The invocation services provide client to server invocations (service
|
||||||
@@ -22,7 +27,7 @@ import com.threerings.cocktail.cher.dobj.*;
|
|||||||
*
|
*
|
||||||
* <p> The server invocation manager listens for invocation requests from
|
* <p> The server invocation manager listens for invocation requests from
|
||||||
* the client and passes them on to the invocation provider registered for
|
* 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
|
* responses and asynchronous notification invocations can be delivered to
|
||||||
* the client.
|
* the client.
|
||||||
*/
|
*/
|
||||||
@@ -42,6 +47,15 @@ public class InvocationManager
|
|||||||
return _invoid;
|
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)
|
public void objectAvailable (DObject object)
|
||||||
{
|
{
|
||||||
// this must be our invocation object
|
// this must be our invocation object
|
||||||
@@ -66,12 +80,54 @@ public class InvocationManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEvent mevt = (MessageEvent)event;
|
|
||||||
// make sure the name is proper just for sanities sake
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DObjectManager _omgr;
|
protected DObjectManager _omgr;
|
||||||
protected int _invoid;
|
protected int _invoid;
|
||||||
|
protected HashMap _providers = new HashMap();
|
||||||
|
protected HashMap _methcache = new HashMap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.server;
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import com.threerings.cocktail.cher.Log;
|
import com.threerings.cocktail.cher.Log;
|
||||||
|
import com.threerings.cocktail.cher.data.ClientObject;
|
||||||
import com.threerings.cocktail.cher.dobj.*;
|
import com.threerings.cocktail.cher.dobj.*;
|
||||||
import com.threerings.cocktail.cher.net.*;
|
import com.threerings.cocktail.cher.net.*;
|
||||||
import com.threerings.cocktail.cher.server.net.*;
|
import com.threerings.cocktail.cher.server.net.*;
|
||||||
@@ -36,6 +37,30 @@ public class Client implements Subscriber, MessageHandler
|
|||||||
_cmgr = cmgr;
|
_cmgr = cmgr;
|
||||||
_username = username;
|
_username = username;
|
||||||
setConnection(conn);
|
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
|
// start using the new connection
|
||||||
setConnection(conn);
|
setConnection(conn);
|
||||||
|
|
||||||
|
// send off a bootstrap notification immediately because we've
|
||||||
|
// already got our client object
|
||||||
|
sendBootstrap();
|
||||||
|
|
||||||
Log.info("Session resumed [client=" + this + "].");
|
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 <code>super.populateBootstrapData()</code> 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
|
* Called by the connection manager when this client's connection
|
||||||
* fails. This is invoked on the conmgr thread, and should behave
|
* 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 ClientManager _cmgr;
|
||||||
protected String _username;
|
protected String _username;
|
||||||
protected Connection _conn;
|
protected Connection _conn;
|
||||||
|
protected ClientObject _clobj;
|
||||||
|
|
||||||
protected static HashMap _disps = new HashMap();
|
protected static HashMap _disps = new HashMap();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
package com.threerings.cocktail.cher.server;
|
||||||
|
|
||||||
@@ -28,6 +28,9 @@ public class CherServer
|
|||||||
/** The distributed object manager. */
|
/** The distributed object manager. */
|
||||||
public static DObjectManager omgr;
|
public static DObjectManager omgr;
|
||||||
|
|
||||||
|
/** The invocation manager. */
|
||||||
|
public static InvocationManager invmgr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes all of the server services and prepares for operation.
|
* Initializes all of the server services and prepares for operation.
|
||||||
*/
|
*/
|
||||||
@@ -42,6 +45,8 @@ public class CherServer
|
|||||||
clmgr = new ClientManager(conmgr);
|
clmgr = new ClientManager(conmgr);
|
||||||
// create our distributed object manager
|
// create our distributed object manager
|
||||||
omgr = new CherDObjectMgr();
|
omgr = new CherDObjectMgr();
|
||||||
|
// create our invocation manager
|
||||||
|
invmgr = new InvocationManager(omgr);
|
||||||
|
|
||||||
// create an object for testing
|
// create an object for testing
|
||||||
omgr.createObject(TestObject.class, null, false);
|
omgr.createObject(TestObject.class, null, false);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user