The great invocation services rethink of 2002! Rearchitected the remote
method invocation services and converted everything to the new style. Could this be my biggest checkin ever? git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1642 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// $Id: InvocationDispatcher.java,v 1.1 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.InvocationMarshaller;
|
||||
|
||||
/**
|
||||
* Provides the base class via which invocation service requests are
|
||||
* dispatched.
|
||||
*/
|
||||
public abstract class InvocationDispatcher
|
||||
{
|
||||
/** The invocation provider for whom we're dispatching. */
|
||||
public InvocationProvider provider;
|
||||
|
||||
/**
|
||||
* Creates an instance of the appropriate {@link InvocationMarshaller}
|
||||
* derived class for use with this dispatcher.
|
||||
*/
|
||||
public abstract InvocationMarshaller createMarshaller ();
|
||||
|
||||
/**
|
||||
* Dispatches the specified method to our provider.
|
||||
*/
|
||||
public void dispatchRequest (
|
||||
ClientObject source, int methodId, Object[] args)
|
||||
throws InvocationException
|
||||
{
|
||||
Log.warning("Requested to dispatch unknown method " +
|
||||
"[provider=" + provider +
|
||||
", sourceOid=" + source.getOid() +
|
||||
", methodId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// $Id: InvocationException.java,v 1.1 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
/**
|
||||
* Used to report failures when executing service requests.
|
||||
*/
|
||||
public class InvocationException extends Exception
|
||||
{
|
||||
/**
|
||||
* Constructs an invocation exception with the supplied cause code
|
||||
* string.
|
||||
*/
|
||||
public InvocationException (String cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,30 @@
|
||||
//
|
||||
// $Id: InvocationManager.java,v 1.11 2002/04/17 18:20:04 mdb Exp $
|
||||
// $Id: InvocationManager.java,v 1.12 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
import com.threerings.util.StreamableArrayList;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.dobj.*;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.InvocationMarshaller.ListenerMarshaller;
|
||||
import com.threerings.presents.data.InvocationMarshaller;
|
||||
import com.threerings.presents.data.InvocationObject;
|
||||
import com.threerings.presents.util.ClassUtil;
|
||||
|
||||
import com.threerings.presents.dobj.DEvent;
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.EventListener;
|
||||
import com.threerings.presents.dobj.InvocationRequestEvent;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.RootDObjectManager;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
|
||||
/**
|
||||
* The invocation services provide client to server invocations (service
|
||||
@@ -23,11 +34,12 @@ import com.threerings.presents.util.ClassUtil;
|
||||
* invoke code on the client.
|
||||
*
|
||||
* <p> Invocations are like remote procedure calls in that they are named
|
||||
* and take arguments. They are simple in that the arguments can only be
|
||||
* of a small set of supported types (the set of distributed object field
|
||||
* types) and there is no special facility provided for referencing
|
||||
* non-local objects (it is assumed that the distributed object facility
|
||||
* will already be in use for any objects that should be shared).
|
||||
* and take arguments. All arguments must be {@link Streamable} objects,
|
||||
* primitive types, or String objects. All arguments are passed by value
|
||||
* (by serializing and unserializing the arguments); there is no special
|
||||
* facility provided for referencing non-local objects (it is assumed that
|
||||
* the distributed object facility will already be in use for any objects
|
||||
* that should be shared).
|
||||
*
|
||||
* <p> The server invocation manager listens for invocation requests from
|
||||
* the client and passes them on to the invocation provider registered for
|
||||
@@ -36,9 +48,19 @@ import com.threerings.presents.util.ClassUtil;
|
||||
* the client.
|
||||
*/
|
||||
public class InvocationManager
|
||||
implements Subscriber, MessageListener
|
||||
implements Subscriber, EventListener
|
||||
{
|
||||
public InvocationManager (DObjectManager omgr)
|
||||
/** The list of services that are to be provided to clients at boot
|
||||
* time. Don't mess with this list! */
|
||||
public StreamableArrayList bootlist = new StreamableArrayList();
|
||||
|
||||
/**
|
||||
* Constructs an invocation manager which will use the supplied
|
||||
* distributed object manager to operate its invocation
|
||||
* services. Generally only one invocation manager should be
|
||||
* operational in a particular system.
|
||||
*/
|
||||
public InvocationManager (RootDObjectManager omgr)
|
||||
{
|
||||
_omgr = omgr;
|
||||
|
||||
@@ -52,45 +74,42 @@ public class InvocationManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the supplied invocation provider instance as the handler
|
||||
* for all invocation requests for the specified module.
|
||||
*/
|
||||
public void registerProvider (String module, InvocationProvider provider)
|
||||
{
|
||||
_providers.put(module, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers an invocation notification to the specified client. The
|
||||
* <code>module</code> argument selects which
|
||||
* <code>InvocationReceiver</code> will be invoked and the
|
||||
* <code>procedure</code> argument indicates which method will be
|
||||
* invoked on that receiver.
|
||||
* Registers the supplied invocation dispatcher, returning a
|
||||
* marshaller that can be used to send requests to the provider for
|
||||
* whom the dispatcher is proxying.
|
||||
*
|
||||
* <p> The method is constructed as follows: a procedure name of
|
||||
* <code>Tell</code> will result in a method call to
|
||||
* <code>handleTellNotification</code>. The arguments provided with
|
||||
* the notification define the necessary signature of that method,
|
||||
* according to the argument conversion rules defined by the
|
||||
* reflection services (<code>Integer</code> is converted to
|
||||
* <code>int</code>, etc.).
|
||||
* @param dispatcher the dispatcher to be registered.
|
||||
* @param bootstrap if true, the service instance will be added to the
|
||||
* list of invocation service objects provided to the client in the
|
||||
* bootstrap data.
|
||||
*/
|
||||
public void sendNotification (
|
||||
int cloid, String module, String procedure, Object[] args)
|
||||
public InvocationMarshaller registerDispatcher (
|
||||
InvocationDispatcher dispatcher, boolean bootstrap)
|
||||
{
|
||||
// package up the arguments
|
||||
int alength = (args != null) ? args.length : 0;
|
||||
Object[] nargs = new Object[alength + 2];
|
||||
nargs[0] = module;
|
||||
nargs[1] = procedure;
|
||||
if (args != null) {
|
||||
System.arraycopy(args, 0, nargs, 2, alength);
|
||||
// get the next invocation code
|
||||
int invCode = nextInvCode();
|
||||
|
||||
// create the marshaller and initialize it
|
||||
InvocationMarshaller marsh = dispatcher.createMarshaller();
|
||||
marsh.init(_invoid, invCode);
|
||||
|
||||
// if we haven't yet finished our own initialization, we need to
|
||||
// throw this dispatcher on a queue so that we can fill in its
|
||||
// invocation oid when we know what it should be
|
||||
if (_invoid == -1) {
|
||||
_lateInitQueue.add(marsh);
|
||||
}
|
||||
|
||||
// construct a message event and deliver it
|
||||
MessageEvent nevt = new MessageEvent(
|
||||
cloid, InvocationObject.NOTIFICATION_NAME, nargs);
|
||||
PresentsServer.omgr.postEvent(nevt);
|
||||
// register the dispatcher
|
||||
_dispatchers.put(invCode, dispatcher);
|
||||
|
||||
// if it's a bootstrap service, slap it in the list
|
||||
if (bootstrap) {
|
||||
bootlist.add(marsh);
|
||||
}
|
||||
|
||||
// Log.info("Registered service [marsh=" + marsh + "].");
|
||||
return marsh;
|
||||
}
|
||||
|
||||
public void objectAvailable (DObject object)
|
||||
@@ -100,6 +119,15 @@ public class InvocationManager
|
||||
|
||||
// add ourselves as a message listener
|
||||
object.addListener(this);
|
||||
|
||||
// let any early registered marshallers know about our invoid
|
||||
while (_lateInitQueue.size() > 0) {
|
||||
InvocationMarshaller marsh = (InvocationMarshaller)
|
||||
_lateInitQueue.remove(0);
|
||||
marsh.setInvocationOid(_invoid);
|
||||
}
|
||||
|
||||
// Log.info("Created invocation service object [oid=" + _invoid + "].");
|
||||
}
|
||||
|
||||
public void requestFailed (int oid, ObjectAccessException cause)
|
||||
@@ -111,85 +139,118 @@ public class InvocationManager
|
||||
_invoid = -1;
|
||||
}
|
||||
|
||||
public void messageReceived (MessageEvent event)
|
||||
// documentation inherited from interface
|
||||
public void eventReceived (DEvent event)
|
||||
{
|
||||
// make sure the name is proper just for sanity's sake
|
||||
if (!event.getName().equals(InvocationObject.REQUEST_NAME)) {
|
||||
return;
|
||||
}
|
||||
// Log.info("Event received " + event + ".");
|
||||
|
||||
// we've got an invocation request, so we process it
|
||||
Object[] args = event.getArgs();
|
||||
String module = (String)args[0];
|
||||
String procedure = (String)args[1];
|
||||
Integer invid = (Integer)args[2];
|
||||
|
||||
// locate a provider for this module
|
||||
InvocationProvider provider =
|
||||
(InvocationProvider)_providers.get(module);
|
||||
if (provider == null) {
|
||||
Log.warning("No provider registered for invocation request " +
|
||||
"[evt=" + event + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// prune the method arguments from the full message arguments
|
||||
Object[] margs = new Object[args.length-1];
|
||||
int cloid = event.getSourceOid();
|
||||
ClientObject source = (ClientObject)
|
||||
PresentsServer.omgr.getObject(cloid);
|
||||
// make sure the client is still around
|
||||
if (source == null) {
|
||||
Log.warning("Client no longer around for invocation provider " +
|
||||
"request [module=" + module +
|
||||
", proc=" + procedure + ", cloid=" + cloid + "].");
|
||||
return;
|
||||
}
|
||||
margs[0] = source;
|
||||
System.arraycopy(args, 2, margs, 1, args.length-2);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// and invoke it
|
||||
try {
|
||||
procmeth.invoke(provider, margs);
|
||||
|
||||
} catch (InvocationTargetException ite) {
|
||||
Throwable te = ite.getTargetException();
|
||||
if (te instanceof ServiceFailedException) {
|
||||
// automatically generate a <foo>Failed response
|
||||
provider.sendResponse(source, invid.intValue(),
|
||||
procedure + FAILED_SUFFIX,
|
||||
te.getMessage());
|
||||
|
||||
} else {
|
||||
Log.warning("Invocation procedure failed " +
|
||||
"[provider=" + provider +
|
||||
", method=" + procmeth +
|
||||
", args=" + StringUtil.toString(margs) + "].");
|
||||
Log.logStackTrace(te);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Error invoking invocation procedure " +
|
||||
"[provider=" + provider +
|
||||
", method=" + procmeth + "].");
|
||||
Log.logStackTrace(e);
|
||||
if (event instanceof InvocationRequestEvent) {
|
||||
InvocationRequestEvent ire = (InvocationRequestEvent)event;
|
||||
dispatchRequest(ire.getSourceOid(), ire.getInvCode(),
|
||||
ire.getMethodId(), ire.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
protected DObjectManager _omgr;
|
||||
protected int _invoid;
|
||||
protected HashMap _providers = new HashMap();
|
||||
protected HashMap _methcache = new HashMap();
|
||||
/**
|
||||
* Called when we receive an invocation request message. Dispatches
|
||||
* the request to the appropriate invocation provider via the
|
||||
* registered invocation dispatcher.
|
||||
*/
|
||||
protected void dispatchRequest (
|
||||
int clientOid, int invCode, int methodId, Object[] args)
|
||||
{
|
||||
// make sure the client is still around
|
||||
ClientObject source = (ClientObject)_omgr.getObject(clientOid);
|
||||
if (source == null) {
|
||||
Log.warning("Client no longer around for invocation " +
|
||||
"request [clientOid=" + clientOid +
|
||||
", code=" + invCode + ", methId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// look up the dispatcher
|
||||
InvocationDispatcher disp = (InvocationDispatcher)
|
||||
_dispatchers.get(invCode);
|
||||
if (disp == null) {
|
||||
Log.warning("Received invocation request for which we have " +
|
||||
"no registered dispatcher [code=" + invCode +
|
||||
", methId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// scan the args, initializing any listeners and keeping track of
|
||||
// the "primary" listener
|
||||
ListenerMarshaller rlist = null;
|
||||
int acount = args.length;
|
||||
for (int ii = 0; ii < acount; ii++) {
|
||||
Object arg = args[ii];
|
||||
if (arg instanceof ListenerMarshaller) {
|
||||
ListenerMarshaller list = (ListenerMarshaller)arg;
|
||||
list.omgr = _omgr;
|
||||
// keep track of the listener we'll inform if anything
|
||||
// goes horribly awry
|
||||
if (rlist == null) {
|
||||
rlist = list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log.info("Dispatching invreq [caller=" + source.who() +
|
||||
// ", methId=" + methodId +
|
||||
// ", args=" + StringUtil.toString(args) + "].");
|
||||
|
||||
// dispatch the request
|
||||
try {
|
||||
disp.dispatchRequest(source, methodId, args);
|
||||
|
||||
} catch (InvocationException ie) {
|
||||
if (rlist != null) {
|
||||
rlist.requestFailed(ie.getMessage());
|
||||
|
||||
} else {
|
||||
Log.warning("Service request failed but we've got no " +
|
||||
"listener to inform of the failure " +
|
||||
"[clientOid=" + clientOid + ", code=" + invCode +
|
||||
", dispatcher=" + disp + ", methodId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) +
|
||||
", error=" + ie + "].");
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
Log.warning("Dispatcher choked [disp=" + disp +
|
||||
", methId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
Log.logStackTrace(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to generate monotonically increasing provider ids.
|
||||
*/
|
||||
protected synchronized int nextInvCode ()
|
||||
{
|
||||
return _invCode++;
|
||||
}
|
||||
|
||||
/** The distributed object manager with which we're working. */
|
||||
protected RootDObjectManager _omgr;
|
||||
|
||||
/** The object id of the object on which we receive invocation service
|
||||
* requests. */
|
||||
protected int _invoid = -1;
|
||||
|
||||
/** Used to generate monotonically increasing provider ids. */
|
||||
protected int _invCode;
|
||||
|
||||
/** A table of invocation dispatchers each mapped by a unique code. */
|
||||
protected HashIntMap _dispatchers = new HashIntMap();
|
||||
|
||||
/** Used to keep track of marshallers registered before we had our
|
||||
* invocation object so that we can fill their invocation id in
|
||||
* belatedly. */
|
||||
protected ArrayList _lateInitQueue = new ArrayList();
|
||||
|
||||
/** The text that is appended to the procedure name when automatically
|
||||
* generating a failure response. */
|
||||
|
||||
@@ -1,151 +1,11 @@
|
||||
//
|
||||
// $Id: InvocationProvider.java,v 1.7 2002/04/17 18:20:04 mdb Exp $
|
||||
// $Id: InvocationProvider.java,v 1.8 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.InvocationObject;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
|
||||
/**
|
||||
* Invocation providers should extend this class when implementing
|
||||
* invocation services. Because the service procedures are identified by
|
||||
* strings and the methods that are invoked are looked up via reflection,
|
||||
* the derived class doesn't override or implement any particular method.
|
||||
* However, the procedure names are still restricted. For example, a
|
||||
* procedure identified by the name <code>Tell</code> would result in the
|
||||
* invocation of a method named <code>handleTellRequest</code>. The
|
||||
* arguments to that method would be defined by the arguments that
|
||||
* accompanied the <code>Tell</code> invocation request along with the
|
||||
* client object of the client that made the request. Specifically:
|
||||
*
|
||||
* <pre>
|
||||
* // client makes request
|
||||
* Object[] args = new Object[] { "one", new Integer(2) };
|
||||
* invmgr.invoke(MODULE, "Test", args, rsptarget);
|
||||
*
|
||||
* // provider registered for MODULE should look like:
|
||||
* public class TestProvider extends InvocationProvider
|
||||
* {
|
||||
* public void handleTestRequest (ClientObject source, int invid,
|
||||
* String one, int two)
|
||||
* {
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If the arguments do not match, a reflection error will happen when
|
||||
* trying to invoke the method and the whole request will fail.
|
||||
*
|
||||
* <p> Invocation procedures must also package up their response in a
|
||||
* particular way which is through the use of the
|
||||
* <code>sendResponse</code> methods. These take a response identifier
|
||||
* (which determines the name of the method that will be invoked on the
|
||||
* response target object provided in the client) and a variable number of
|
||||
* arguments. If a response was created with the identifier
|
||||
* <code>TellFailed</code>, that would result in the method
|
||||
* <code>handleTellFailed</code> being invoked on the response target
|
||||
* object in the client. Again the arguments much match exactly and follow
|
||||
* the reflection rules for automatic conversion of primitive types
|
||||
* (supply an <code>Integer</code> object for <code>int</code> params,
|
||||
* etc.).
|
||||
*
|
||||
* <p> Note that if an invocation service method throws a {@link
|
||||
* ServiceFailedException}, the invocation manager will automatically
|
||||
* issue a response to the client with the string <code>Failed</code>
|
||||
* appended to the request method. For example, if the client issues a
|
||||
* request for <code>Foo</code> which results in a call to
|
||||
* <code>handleFooRequest</code>, which throws a service failed exception,
|
||||
* the server will automatically issue a failure response named
|
||||
* <code>FooFailed</code> with the single argument being the
|
||||
* <code>reason</code> string provided to the constructor of the service
|
||||
* failed exception. The caller would then implement:
|
||||
*
|
||||
* <pre>
|
||||
* public void handleFooFailed (int invid, String reason)
|
||||
* </pre>
|
||||
*
|
||||
* to handle the failure.
|
||||
* All invocation providers must implement this placeholder interface.
|
||||
*/
|
||||
public class InvocationProvider
|
||||
public interface InvocationProvider
|
||||
{
|
||||
/**
|
||||
* Delivers an invocation response properly configured with the
|
||||
* supplied name and no arguments.
|
||||
*/
|
||||
protected void sendResponse (ClientObject source, int invid, String name)
|
||||
{
|
||||
deliverResponse(source, new Object[] { name, new Integer(invid) });
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers an invocation response properly configured with the
|
||||
* supplied name and single argument.
|
||||
*/
|
||||
protected void sendResponse (ClientObject source, int invid,
|
||||
String name, Object arg)
|
||||
{
|
||||
Object[] args = new Object[] { name, new Integer(invid), arg };
|
||||
deliverResponse(source, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers an invocation response properly configured with the
|
||||
* supplied name and two arguments.
|
||||
*/
|
||||
protected void sendResponse (ClientObject source, int invid,
|
||||
String name, Object arg1, Object arg2)
|
||||
{
|
||||
Object[] args = new Object[] {
|
||||
name, new Integer(invid), arg1, arg2 };
|
||||
deliverResponse(source, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers an invocation response properly configured with the
|
||||
* supplied name and three arguments.
|
||||
*/
|
||||
protected void sendResponse (ClientObject source, int invid,
|
||||
String name, Object arg1, Object arg2,
|
||||
Object arg3)
|
||||
{
|
||||
Object[] args = new Object[] {
|
||||
name, new Integer(invid), arg1, arg2, arg3 };
|
||||
deliverResponse(source, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers an invocation response properly configured with the
|
||||
* supplied name and varying number of arguments.
|
||||
*/
|
||||
protected void sendResponse (ClientObject source, int invid,
|
||||
String name, Object[] args)
|
||||
{
|
||||
Object[] rargs = new Object[args.length+2];
|
||||
rargs[0] = name;
|
||||
rargs[1] = new Integer(invid);
|
||||
System.arraycopy(args, 0, rargs, 2, args.length);
|
||||
deliverResponse(source, rargs);
|
||||
}
|
||||
|
||||
protected void deliverResponse (ClientObject source, Object[] args)
|
||||
{
|
||||
// make sure they didn't go away in the meanwhile
|
||||
if (source.isActive()) {
|
||||
// create the response event
|
||||
MessageEvent mevt = new MessageEvent(
|
||||
source.getOid(), InvocationObject.RESPONSE_NAME, args);
|
||||
// and ship it off
|
||||
PresentsServer.omgr.postEvent(mevt);
|
||||
|
||||
} else {
|
||||
Log.warning("Dropping invrsp due to disappearing client " +
|
||||
"[cloid=" + source.getOid() +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// $Id: InvocationSender.java,v 1.1 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.client.InvocationReceiver.Registration;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.dobj.InvocationNotificationEvent;
|
||||
|
||||
/**
|
||||
* Provides basic functionality used by all invocation sender classes.
|
||||
*/
|
||||
public abstract class InvocationSender
|
||||
{
|
||||
/**
|
||||
* Requests that the specified invocation notification be packaged up
|
||||
* and sent to the supplied target client.
|
||||
*/
|
||||
public static void sendNotification (
|
||||
ClientObject target, String receiverCode, int methodId, Object[] args)
|
||||
{
|
||||
// convert the receiver hash id into the code used on this
|
||||
// specific client
|
||||
Registration rreg = (Registration)target.receivers.get(receiverCode);
|
||||
if (rreg == null) {
|
||||
Log.warning("Unable to locate registered receiver for " +
|
||||
"invocation service notification [target=" + target +
|
||||
", code=" + receiverCode + ", methId=" + methodId +
|
||||
", args=" + StringUtil.toString(args) + "].");
|
||||
|
||||
} else {
|
||||
// Log.info("Sending notification [target=" + target +
|
||||
// ", code=" + receiverCode + ", methodId=" + methodId +
|
||||
// ", args=" + StringUtil.toString(args) + "].");
|
||||
|
||||
// create and dispatch an invocation notification event
|
||||
target.postEvent(
|
||||
new InvocationNotificationEvent(
|
||||
target.getOid(), rreg.receiverId, methodId, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: PresentsClient.java,v 1.34 2002/07/23 05:52:49 mdb Exp $
|
||||
// $Id: PresentsClient.java,v 1.35 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
@@ -324,8 +324,8 @@ public class PresentsClient
|
||||
// give them the client object id
|
||||
data.clientOid = _clobj.getOid();
|
||||
|
||||
// give them the invocation oid
|
||||
data.invOid = PresentsServer.invmgr.getOid();
|
||||
// fill in the list of bootstrap services
|
||||
data.services = PresentsServer.invmgr.bootlist;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: PresentsServer.java,v 1.23 2002/07/25 20:24:02 mdb Exp $
|
||||
// $Id: PresentsServer.java,v 1.24 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
@@ -66,57 +66,57 @@ public class PresentsServer
|
||||
// initialize the time base services
|
||||
TimeBaseProvider.init(invmgr, omgr);
|
||||
|
||||
// register our invocation service providers
|
||||
registerProviders(PresentsConfig.getProviders());
|
||||
// // register our invocation service providers
|
||||
// registerProviders(PresentsConfig.getProviders());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers invocation service providers as parsed from a
|
||||
* configuration file. Each string in the array should contain an
|
||||
* expression of the form:
|
||||
*
|
||||
* <pre>
|
||||
* module = provider fully-qualified class name
|
||||
* </pre>
|
||||
*
|
||||
* A comma separated list of these can be specified in the
|
||||
* configuration file and loaded into a string array easily. These
|
||||
* providers will be instantiated and registered with the invocation
|
||||
* manager.
|
||||
*/
|
||||
protected void registerProviders (String[] providers)
|
||||
{
|
||||
// ignore null arrays to make life easier for the caller
|
||||
if (providers == null) {
|
||||
return;
|
||||
}
|
||||
// /**
|
||||
// * Registers invocation service providers as parsed from a
|
||||
// * configuration file. Each string in the array should contain an
|
||||
// * expression of the form:
|
||||
// *
|
||||
// * <pre>
|
||||
// * module = provider fully-qualified class name
|
||||
// * </pre>
|
||||
// *
|
||||
// * A comma separated list of these can be specified in the
|
||||
// * configuration file and loaded into a string array easily. These
|
||||
// * providers will be instantiated and registered with the invocation
|
||||
// * manager.
|
||||
// */
|
||||
// protected void registerProviders (String[] providers)
|
||||
// {
|
||||
// // ignore null arrays to make life easier for the caller
|
||||
// if (providers == null) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
for (int i = 0; i < providers.length; i++) {
|
||||
int eidx = providers[i].indexOf("=");
|
||||
if (eidx == -1) {
|
||||
Log.warning("Ignoring bogus provider declaration " +
|
||||
"[decl=" + providers[i] + "].");
|
||||
continue;
|
||||
}
|
||||
// for (int i = 0; i < providers.length; i++) {
|
||||
// int eidx = providers[i].indexOf("=");
|
||||
// if (eidx == -1) {
|
||||
// Log.warning("Ignoring bogus provider declaration " +
|
||||
// "[decl=" + providers[i] + "].");
|
||||
// continue;
|
||||
// }
|
||||
|
||||
String module = providers[i].substring(0, eidx).trim();
|
||||
String pname = providers[i].substring(eidx+1).trim();
|
||||
// String module = providers[i].substring(0, eidx).trim();
|
||||
// String pname = providers[i].substring(eidx+1).trim();
|
||||
|
||||
// instantiate the provider class and register it
|
||||
try {
|
||||
Class pclass = Class.forName(pname);
|
||||
InvocationProvider provider = (InvocationProvider)
|
||||
pclass.newInstance();
|
||||
invmgr.registerProvider(module, provider);
|
||||
Log.info("Registered provider [module=" + module +
|
||||
", provider=" + pname + "].");
|
||||
// // instantiate the provider class and register it
|
||||
// try {
|
||||
// Class pclass = Class.forName(pname);
|
||||
// InvocationProvider provider = (InvocationProvider)
|
||||
// pclass.newInstance();
|
||||
// invmgr.registerProvider(module, provider);
|
||||
// Log.info("Registered provider [module=" + module +
|
||||
// ", provider=" + pname + "].");
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to register provider [module=" + module +
|
||||
", provider=" + pname + ", error=" + e + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
// } catch (Exception e) {
|
||||
// Log.warning("Unable to register provider [module=" + module +
|
||||
// ", provider=" + pname + ", error=" + e + "].");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Starts up all of the server services and enters the main server
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// $Id: ServiceFailedException.java,v 1.2 2001/10/11 04:07:53 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
/**
|
||||
* An exception class for use in concert with invocation services when
|
||||
* they need to communicate a failure of some kind and can't use the
|
||||
* return value.
|
||||
*
|
||||
* <p> For example, consider an invitation service:
|
||||
*
|
||||
* <pre>
|
||||
* public class fooManager
|
||||
* {
|
||||
* // returns invitation id, throws ServiceFailedException if
|
||||
* // invitation couldn't be processed
|
||||
* public int invite (...)
|
||||
* throws ServiceFailedException
|
||||
* {
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public class fooProvider
|
||||
* {
|
||||
* public void handleInviteRequest (...)
|
||||
* {
|
||||
* try {
|
||||
* int inviteId = _mgr.invite(...);
|
||||
* sendResponse(..., INVITE_RECEIVED, new Integer(inviteId));
|
||||
*
|
||||
* } catch (ServiceFailedException sfe) {
|
||||
* sendResponse(..., INVITE_FAILED, sfe.getMessage());
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class ServiceFailedException extends Exception
|
||||
{
|
||||
public ServiceFailedException (String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// $Id: TimeBaseDispatcher.java,v 1.1 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.TimeBaseService;
|
||||
import com.threerings.presents.client.TimeBaseService.GotTimeBaseListener;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.InvocationMarshaller;
|
||||
import com.threerings.presents.data.TimeBaseMarshaller;
|
||||
import com.threerings.presents.server.InvocationDispatcher;
|
||||
import com.threerings.presents.server.InvocationException;
|
||||
|
||||
/**
|
||||
* Dispatches requests to the {@link TimeBaseProvider}.
|
||||
*/
|
||||
public class TimeBaseDispatcher extends InvocationDispatcher
|
||||
{
|
||||
/**
|
||||
* Creates a dispatcher that may be registered to dispatch invocation
|
||||
* service requests for the specified provider.
|
||||
*/
|
||||
public TimeBaseDispatcher (TimeBaseProvider provider)
|
||||
{
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public InvocationMarshaller createMarshaller ()
|
||||
{
|
||||
return new TimeBaseMarshaller();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void dispatchRequest (
|
||||
ClientObject source, int methodId, Object[] args)
|
||||
throws InvocationException
|
||||
{
|
||||
switch (methodId) {
|
||||
case TimeBaseMarshaller.GET_TIME_OID:
|
||||
((TimeBaseProvider)provider).getTimeOid(
|
||||
source,
|
||||
(String)args[0], (GotTimeBaseListener)args[1]
|
||||
);
|
||||
return;
|
||||
|
||||
default:
|
||||
super.dispatchRequest(source, methodId, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TimeBaseProvider.java,v 1.1 2002/05/28 23:14:06 mdb Exp $
|
||||
// $Id: TimeBaseProvider.java,v 1.2 2002/08/14 19:07:56 mdb Exp $
|
||||
|
||||
package com.threerings.presents.server;
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.HashMap;
|
||||
import com.samskivert.util.ResultListener;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.client.TimeBaseService.GotTimeBaseListener;
|
||||
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.TimeBaseCodes;
|
||||
import com.threerings.presents.data.TimeBaseObject;
|
||||
@@ -22,8 +24,8 @@ import com.threerings.presents.dobj.Subscriber;
|
||||
* network which are expanded based on a shared base time into full time
|
||||
* stamps.
|
||||
*/
|
||||
public class TimeBaseProvider extends InvocationProvider
|
||||
implements TimeBaseCodes
|
||||
public class TimeBaseProvider
|
||||
implements InvocationProvider, TimeBaseCodes
|
||||
{
|
||||
/**
|
||||
* Registers the time provider with the appropriate managers. Called
|
||||
@@ -35,8 +37,9 @@ public class TimeBaseProvider extends InvocationProvider
|
||||
_invmgr = invmgr;
|
||||
_omgr = omgr;
|
||||
|
||||
// register an invocation provider instance
|
||||
_invmgr.registerProvider(MODULE_NAME, new TimeBaseProvider());
|
||||
// register a provider instance
|
||||
invmgr.registerDispatcher(
|
||||
new TimeBaseDispatcher(new TimeBaseProvider()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,18 +84,17 @@ public class TimeBaseProvider extends InvocationProvider
|
||||
* Processes a request from a client to fetch the oid of the specified
|
||||
* time object.
|
||||
*/
|
||||
public void handleGetTimeOidRequest (
|
||||
ClientObject source, int invid, String timeBase)
|
||||
throws ServiceFailedException
|
||||
public void getTimeOid (
|
||||
ClientObject source, String timeBase, GotTimeBaseListener listener)
|
||||
throws InvocationException
|
||||
{
|
||||
// look up the time base object in question
|
||||
TimeBaseObject time = getTimeBase(timeBase);
|
||||
if (time == null) {
|
||||
throw new ServiceFailedException(NO_SUCH_TIME_BASE);
|
||||
throw new InvocationException(NO_SUCH_TIME_BASE);
|
||||
}
|
||||
// and send the response
|
||||
sendResponse(source, invid, TIME_OID_RESPONSE,
|
||||
new Integer(time.getOid()));
|
||||
listener.gotTimeOid(time.getOid());
|
||||
}
|
||||
|
||||
/** Used to keep track of our time base objects. */
|
||||
|
||||
Reference in New Issue
Block a user