From 68a895fad4e60f38f1a026051cb41cdec23e7480 Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Tue, 27 Sep 2011 04:58:08 +0000 Subject: [PATCH] Revert Resulting. Oops. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6702 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../java/com/threerings/util/Resulting.java | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/main/java/com/threerings/util/Resulting.java diff --git a/src/main/java/com/threerings/util/Resulting.java b/src/main/java/com/threerings/util/Resulting.java new file mode 100644 index 000000000..ff192eff5 --- /dev/null +++ b/src/main/java/com/threerings/util/Resulting.java @@ -0,0 +1,289 @@ +// +// $Id$ + +package com.threerings.util; + +import com.google.common.base.Function; +import com.google.common.base.Objects; + +import com.samskivert.util.ArrayUtil; +import com.samskivert.util.IntResultListener; +import com.samskivert.util.Invoker; +import com.samskivert.util.Logger; +import com.samskivert.util.ResultListener; + +import com.threerings.presents.client.InvocationService; +import com.threerings.presents.data.InvocationCodes; +import com.threerings.presents.server.InvocationException; + +import static com.threerings.NaryaLog.log; + +/** + * A chainable ResultListener, InvocationListener, and Invoker.Unit all in one. + * + * TODO: add some examples of different usages. + */ +public class Resulting extends Invoker.Unit + implements ResultListener, + InvocationService.ConfirmListener, InvocationService.ResultListener +{ + /** A handy Object->Void function for when you wish to chain to a ResultListener. */ + public static final Function TO_VOID = + new Function() { + public Void apply (Object o) { + return null; + } + }; + + public Resulting (String name) + { + super(name); + } + + public Resulting (String name, Resulting chain) + { + this(name, (ResultListener)chain); + } + + public Resulting (Resulting chain) + { + this(chain.toString(), chain); + } + + public Resulting (String name, ResultListener chain) + { + this(name); + _chain = chain; + } + + public Resulting (ResultListener chain) + { + this(chain.toString(), chain); + } + + public Resulting (String name, InvocationService.InvocationListener chain) + { + this(name); + _invChain = chain; + } + + public Resulting (InvocationService.InvocationListener chain) + { + this(chain.toString(), chain); + } + + public Resulting ( + String name, final ResultListener chain, final Function xform) + { + this(name, new ResultListener() { + public void requestCompleted (T result) { + chain.requestCompleted(xform.apply(result)); + } + public void requestFailed (Exception cause) { + chain.requestFailed(cause); + } + }); + } + + public Resulting (ResultListener chain, Function xform) + { + this(chain.toString(), chain, xform); + } + + public Resulting (String name, Logger log, Object... logArgs) + { + this(name); + _log = log; + _logArgs = logArgs; + } + + /** + * Construct your Resulting, overriding what you need to, + * then call this to adapt it. + */ + public final IntResultListener asIntResultListener () + { + return new IntResultListener() { + public void requestCompleted (int result) { + // call the invocation method and it will do the unsafe cast for us. + Resulting.this.requestProcessed((Object)result); + } + public void requestFailed (Exception cause) { + Resulting.this.requestFailed(cause); + } + }; + } + +// TODO: Maybe we don't extend Invoker.Unit +// public Invoker.Unit asUnit (Callable callable) +// { +// } +// +// public Invoker.Unit asUnit () +// { +// } +// + /** + * Override this if you are using a Resulting as an Invoker unit. + */ + public T invokePersist () + throws Exception + { + // please to be overriding + return null; + } + + @Override + public final boolean invoke () + { + try { + _result = invokePersist(); + + } catch (StopException se) { + return false; + + } catch (Exception e) { + _error = e; + } + return true; + } + + /** + * Call this from your invokePersist() to suppress returning to the dobj thread. + * @throws StopException every time. + */ + protected final T stop () + throws StopException + { + throw STOP.get(); + } + + @Override + public final void handleResult () + { + if (_error != null) { + requestFailed(_error); + } else { + requestCompleted(_result); + } + } + + // from InvocationService.InvocationListener + public final void requestFailed (String error) + { + requestFailed(INV_EX.get().setMessage(error)); + } + + // from InvocationService.ConfirmListener + public final void requestProcessed () + { + requestCompleted(null); + } + + // from InvocationService.ResultListener + public final void requestProcessed (Object result) + { + @SuppressWarnings("unchecked") T casted = (T)result; + requestCompleted(casted); + } + + /** + * Override this to handle a request failed in your own way. + */ + public void requestFailed (Exception cause) + { + if (_chain != null) { + _chain.requestFailed(cause); + + } else if (_invChain != null) { + _invChain.requestFailed((cause instanceof InvocationException) + ? cause.getMessage() + : InvocationCodes.INTERNAL_ERROR); + + } else { + Object[] logArgs = Objects.firstNonNull(_logArgs, ArrayUtil.EMPTY_OBJECT); + Object[] args; + if (cause instanceof InvocationException) { + args = new Object[logArgs.length + 4]; + args[args.length - 2] = "error"; + args[args.length - 1] = cause.getMessage(); + + } else { + args = new Object[logArgs.length + 3]; + args[args.length - 1] = cause; + } + args[0] = "Resulting"; + args[1] = this; + System.arraycopy(logArgs, 0, args, 2, logArgs.length); + Objects.firstNonNull(_log, log).warning("Request failed", args); + } + } + + /** + * Override this to handle a request completion in your own way. + */ + public void requestCompleted (T result) + { + if (_chain != null) { + _chain.requestCompleted(result); + + } else if (_invChain instanceof InvocationService.ResultListener) { + ((InvocationService.ResultListener)_invChain).requestProcessed(result); + + } else if (_invChain instanceof InvocationService.ConfirmListener) { + ((InvocationService.ConfirmListener)_invChain).requestProcessed(); + } + } + + /** Our invocation chain, if any. */ + protected InvocationService.InvocationListener _invChain; + + protected ResultListener _chain; + + protected Logger _log; + + protected Object[] _logArgs; + + protected T _result; + + protected Exception _error; + + protected static final ThreadLocal INV_EX = + new ThreadLocal() { + @Override protected ReusableInvocationException initialValue () { + return new ReusableInvocationException(); + } + }; + + protected static class ReusableInvocationException extends InvocationException + { + public ReusableInvocationException () + { + super(""); + } + + public ReusableInvocationException setMessage (String msg) + { + _msg = msg; + return this; + } + + @Override public String getMessage () + { + return _msg; + } + + protected String _msg; + } + + protected static final ThreadLocal STOP = + new ThreadLocal() { + @Override protected StopException initialValue () { + return new StopException(); + } + }; + + protected static class StopException extends RuntimeException + { + } +}