//
// $Id: InvocationProvider.java,v 1.4 2001/08/11 00:05:58 mdb Exp $

package com.threerings.cocktail.cher.server;

import com.threerings.cocktail.cher.dobj.MessageEvent;
import com.threerings.cocktail.cher.data.ClientObject;
import com.threerings.cocktail.cher.data.InvocationObject;

/**
 * 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.).
 */
public class 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)
    {
        // create the response event
        MessageEvent mevt = new MessageEvent(
            source.getOid(), InvocationObject.RESPONSE_NAME, args);
        // and ship it off
        CherServer.omgr.postEvent(mevt);
    }
}

@@ -36,9 +36,9 @@
 v 1.
-4
+5
  200
@@ -50,15 +50,15 @@
 11 0
-0:05:58
+2:02:24
  mdb
@@ -111,16 +111,56 @@
 erver;%0A%0A
+import com.samskivert.util.StringUtil;%0A%0A
 import c
@@ -191,25 +191,11 @@
 her.
-dobj.MessageEvent
+Log
 ;%0Aim
@@ -305,16 +305,71 @@
 nObject;
+%0Aimport com.threerings.cocktail.cher.dobj.MessageEvent;
 %0A%0A/**%0A *
@@ -4601,16 +4601,111 @@
       //
+ make sure they didn't go away in the meanwhile%0A        if (source.isActive()) %7B%0A            //
  create 
@@ -4731,16 +4731,20 @@
         
+    
 MessageE
@@ -4773,16 +4773,20 @@
 eEvent(%0A
+    
         
@@ -4853,16 +4853,20 @@
         
+    
 // and s
@@ -4876,16 +4876,20 @@
  it off%0A
+    
         
@@ -4920,16 +4920,241 @@
 t(mevt);
+%0A%0A        %7D else %7B%0A            Log.warning(%22Dropping invrsp due to disappearing client %22 +%0A                        %22%5Bcloid=%22 + source.getOid() +%0A                        %22, args=%22 + StringUtil.toString(args) + %22%5D.%22);%0A        %7D
 %0A    %7D%0A%7D

Check to be sure that the client is still around before we send the invocation response. (Better to catch it and report it here than have the dobjmgr complain when it tries to dispatch an event on a non-existent object.)