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
This commit is contained in:
@@ -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.
|
||||
*
|
||||
* <p> 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.
|
||||
*
|
||||
* <p> 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 <code>handleResult</code> 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.
|
||||
*
|
||||
* <p> 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 <em>read</em>
|
||||
* 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 <code>handleResult</code> 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 <code>invoke</code> 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;
|
||||
}
|
||||
Reference in New Issue
Block a user