// // $Id$ // // Narya library - tools for developing networked games // Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved // http://www.threerings.net/code/narya/ // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package com.threerings.presents.server; import java.util.Map; import com.google.common.collect.Maps; import com.google.inject.Inject; import com.google.inject.Singleton; import com.samskivert.util.IntMaps; import com.samskivert.util.IntMap; import com.samskivert.util.LRUHashMap; import com.samskivert.util.StringUtil; import com.threerings.io.Streamable; import com.threerings.util.StreamableArrayList; import com.threerings.presents.data.ClientObject; import com.threerings.presents.data.InvocationMarshaller.ListenerMarshaller; import com.threerings.presents.data.InvocationMarshaller; 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.ObjectAccessException; import com.threerings.presents.net.Transport; import static com.threerings.presents.Log.log; /** * The invocation services provide client to server invocations (service requests) and server to * client invocations (responses and notifications). Via this mechanism, the client can make * requests of the server, be notified of its response and the server can asynchronously invoke * code on the client. * *
Invocations are like remote procedure calls in that they are named 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). * *
The server invocation manager listens for invocation requests from the client and passes
* them on to the invocation provider registered for the requested invocation module. It also
* provides a mechanism by which responses and asynchronous notification invocations can be
* delivered to the client.
*/
@Singleton
public class InvocationManager
implements EventListener
{
/**
* 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.
*/
@Inject public InvocationManager (PresentsDObjectMgr omgr)
{
_omgr = omgr;
_omgr._invmgr = this;
// create the object on which we'll listen for invocation requests
DObject invobj = _omgr.registerObject(new DObject());
invobj.addListener(this);
_invoid = invobj.getOid();
// log.info("Created invocation service object [oid=" + _invoid + "].");
}
/**
* Returns the object id of the invocation services object.
*/
public int getOid ()
{
return _invoid;
}
/**
* Registers the supplied invocation dispatcher, returning a marshaller that can be used to
* send requests to the provider for whom the dispatcher is proxying.
*
* @param dispatcher the dispatcher to be registered.
*/
public InvocationMarshaller registerDispatcher (InvocationDispatcher dispatcher)
{
return registerDispatcher(dispatcher, null);
}
/**
* @Deprecated use {@link #registerDispatcher(InvocationDispatcher)}.
*/
public InvocationMarshaller registerDispatcher (
InvocationDispatcher dispatcher, boolean bootstrap)
{
return registerDispatcher(dispatcher, null);
}
/**
* Registers the supplied invocation dispatcher, returning a marshaller that can be used to
* send requests to the provider for whom the dispatcher is proxying.
*
* @param dispatcher the dispatcher to be registered.
* @param group the bootstrap group in which this marshaller is to be registered, or null if it
* is not a bootstrap service. Do not: register a dispatcher with multiple boot
* groups. You must collect shared dispatchers into as fine grained a set of groups as
* necessary and have different types of clients specify the list of groups they need.
*/
public InvocationMarshaller registerDispatcher (InvocationDispatcher dispatcher, String group)
{
// get the next invocation code
int invCode = nextInvCode();
// create the marshaller and initialize it
InvocationMarshaller marsh = dispatcher.createMarshaller();
marsh.init(_invoid, invCode);
// register the dispatcher
_dispatchers.put(invCode, dispatcher);
// if it's a bootstrap service, slap it in the list
if (group != null) {
StreamableArrayList