From 23821aeff680906a904d52f34b5bfab1139a1b64 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Sat, 11 Aug 2001 01:20:38 +0000 Subject: [PATCH] Created a class that makes it easy to run stuff off of the dobjmgr thread and then deal with the results of it back on the dobjmgr thread. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@223 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/presents/util/Invoker.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/java/com/threerings/presents/util/Invoker.java diff --git a/src/java/com/threerings/presents/util/Invoker.java b/src/java/com/threerings/presents/util/Invoker.java new file mode 100644 index 000000000..3a08e9d8e --- /dev/null +++ b/src/java/com/threerings/presents/util/Invoker.java @@ -0,0 +1,128 @@ +// +// $Id: Invoker.java,v 1.1 2001/08/11 01:20:38 mdb Exp $ + +package com.threerings.cocktail.cher.util; + +import com.samskivert.util.LoopingThread; +import com.samskivert.util.Queue; + +import com.threerings.cocktail.cher.Log; +import com.threerings.cocktail.cher.server.CherServer; + +/** + * The invoker is used to invoke self-contained units of code on an + * invoking thread. Each invoker is associated with its own thread and + * that thread is used to invoke all of the units posted to that invoker + * in the order in which they were posted. The invoker also provides a + * convenient mechanism for processing the result of an invocation back on + * the dobjmgr thread. + * + *

The invoker is a useful tool for services that need to block and + * therefore cannot be run on the distributed object thread. For example, + * a user of the Cher system might provide an invoker on which to run + * database queries. + * + *

Bear in mind that each invoker instance runs units on its own + * thread and care must be taken to ensure that code running on separate + * invokers properly synchronizes access to shared information. Where + * possible, complete isolation of the services provided by a particular + * invoker is desirable. + */ +public class Invoker extends LoopingThread +{ + /** + * The unit encapsulates a unit of executable code that will be run on + * the invoker thread. It also provides facilities for additional code + * to be run on the dobjmgr thread once the primary code has completed + * on the invoker thread. + */ + public static abstract class Unit implements Runnable + { + /** + * This method is called on the invoker thread and should be used + * to perform the primary function of the unit. It can return true + * to cause the handleResult method to be + * subsequently invoked on the dobjmgr thread (generally to allow + * the results of the invocation to be acted upon back in the + * context of the distributed object world) or false to indicate + * that no further processing should be performed. + * + *

Note that an invocation unit can do things like post events + * from the invoker thread (which includes modification of + * distributed object fields) and need not jump over to the + * dobjmgr thread to do so. However, it cannot read + * distributed object fields from the invoker thread. Any field + * values needed during the course of the invocation should be + * provided from the dobjmgr thread at the time that the + * invocation unit is created and posted. + * + * @return true if the handleResult method should be + * invoked on the dobjmgr thread, false if not. + */ + public abstract boolean invoke (); + + /** + * Invocation unit implementations can implement this function to + * perform any post-unit-invocation processing back on the dobjmgr + * thread. It will be invoked if invoke returns true. + */ + public void handleResult () + { + // do nothing by default + } + + // we want to be a runnable to make the dobjmgr happy, but we'd + // like for invocation unit implementations to be able to put + // their result handling code into an aptly named method + public void run () + { + handleResult(); + } + } + + /** + * Posts a unit to this invoker for subsequent invocation on the + * invoker's thread. + */ + public void postUnit (Unit unit) + { + // simply append it to the queue + _queue.append(unit); + } + + // documentation inherited + public void iterate () + { + // pop the next item off of the queue + Object unit = _queue.get(); + + // if it's a unit, we invoke it + if (unit instanceof Runnable) { + try { + if (((Unit)unit).invoke()) { + // if it returned true, we post it to the dobjmgr + // thread to invoke the result processing + CherServer.omgr.postUnit((Runnable)unit); + } + + } catch (Exception e) { + Log.warning("Invocation unit failed [unit=" + unit + "]."); + Log.logStackTrace(e); + } + } + + // if it's not a runnable, it was probably just an object posted + // to our queue to wake us up in time to die, so we just ignore it + } + + // documentation inherited + protected void kick () + { + // add a non-runnable to the queue which will be ignored by the + // invoker but will cause it to wake up and go away + _queue.append(new Integer(0)); + } + + /** The invoker's queue of units to be executed. */ + protected Queue _queue; +}