All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hprose.util.concurrent.Promise Maven / Gradle / Ivy

Go to download

Hprose is a High Performance Remote Object Service Engine. It is a modern, lightweight, cross-language, cross-platform, object-oriented, high performance, remote dynamic communication middleware. It is not only easy to use, but powerful. You just need a little time to learn, then you can use it to easily construct cross language cross platform distributed application system. Hprose supports many programming languages, for example: * AAuto Quicker * ActionScript * ASP * C++ * Dart * Delphi/Free Pascal * dotNET(C#, Visual Basic...) * Golang * Java * JavaScript * Node.js * Objective-C * Perl * PHP * Python * Ruby * ... Through Hprose, You can conveniently and efficiently intercommunicate between those programming languages. This project is the implementation of Hprose for Java.

There is a newer version: 2.0.38
Show newest version
/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * Promise.java                                           *
 *                                                        *
 * Promise class for Java.                                *
 *                                                        *
 * LastModified: Jun 19, 2016                             *
 * Author: Ma Bingyao                   *
 *                                                        *
\**********************************************************/
package hprose.util.concurrent;

import hprose.util.JdkVersion;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public final class Promise implements Resolver, Rejector, Thenable {
    private final static ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
    static {
        Threads.registerShutdownHandler(new Runnable() {
            public void run() {
                timer.shutdown();
            }
        });
    }

    private final ConcurrentLinkedQueue> subscribers = new ConcurrentLinkedQueue>();
    private volatile State state = State.PENDING;
    private volatile Object value;
    private volatile Throwable reason;

    public Promise() {}

    public Promise(final Callable computation) {
        timer.execute(new Runnable() {
            public void run() {
                try {
                    Promise.this.resolve(computation.call());
                }
                catch (Throwable e) {
                    Promise.this.reject(e);
                }
            }
        });
    }

    public Promise(Executor executor) {
        executor.exec((Resolver)this, (Rejector)this);
    }

    public final static  Promise value(T value) {
        Promise promise = new Promise();
        promise.resolve(value);
        return promise;
    }

    public final static  Promise value(Promise value) {
        Promise promise = new Promise();
        promise.resolve(value);
        return promise;
    }

    public final static  Promise error(Throwable reason) {
        Promise promise = new Promise();
        promise.reject(reason);
        return promise;
    }

    public final static  Promise delayed(long duration, TimeUnit timeunit, final Callable computation) {
        final Promise promise = new Promise();
        timer.schedule(new Runnable() {
            public void run() {
                try {
                    promise.resolve(computation.call());
                }
                catch (Throwable e) {
                    promise.reject(e);
                }
            }
        }, duration, timeunit);
        return promise;
    }

    public final static  Promise delayed(long duration, TimeUnit timeunit, final T value) {
        final Promise promise = new Promise();
        timer.schedule(new Runnable() {
            public void run() {
                promise.resolve(value);
            }
        }, duration, timeunit);
        return promise;
    }

    public final static  Promise delayed(long duration, TimeUnit timeunit, final Promise value) {
        final Promise promise = new Promise();
        timer.schedule(new Runnable() {
            public void run() {
                promise.resolve(value);
            }
        }, duration, timeunit);
        return promise;
    }

    public final static  Promise delayed(long duration, Callable computation) {
        return delayed(duration, TimeUnit.MILLISECONDS, computation);
    }

    public final static  Promise delayed(long duration, T value) {
        return delayed(duration, TimeUnit.MILLISECONDS, value);
    }

    public final static  Promise delayed(long duration, Promise value) {
        return delayed(duration, TimeUnit.MILLISECONDS, value);
    }

    public final static  Promise sync(Callable computation) {
        try {
            return value(computation.call());
        }
        catch (Throwable e) {
            return error(e);
        }
    }

    public final static boolean isThenable(Object value) {
        return value instanceof Thenable;
    }

    public final static boolean isPromise(Object value) {
        return value instanceof Promise;
    }

    public final static Promise toPromise(Object value) {
        return isPromise(value) ? (Promise)value : value(value);
    }

    @SuppressWarnings("unchecked")
    private static  void allHandler(final Promise promise, final AtomicInteger count, final T[] result, Object element, final int i) {
        ((Promise)toPromise(element)).then(
            new Action() {
                public void call(T value) throws Throwable {
                    result[i] = value;
                    if (count.decrementAndGet() == 0) {
                        promise.resolve(result);
                    }
                }
            },
            new Action() {
                public void call(Throwable e) throws Throwable {
                    promise.reject(e);
                }
            }
        );
    }

    @SuppressWarnings("unchecked")
    public final static  Promise all(Object[] array, Class type) {
        int n = array.length;
        T[] result = (type == Object.class) ?
                (T[])(new Object[n]) :
                (T[])Array.newInstance(type, n);
        if (n == 0) return (Promise)value(result);
        AtomicInteger count = new AtomicInteger(n);
        Promise promise = new Promise();
        for (int i = 0; i < n; ++i) {
            allHandler(promise, count, result, array[i], i);
        }
        return promise;
    }

    public final static Promise all(Object[] array) {
        return all(array, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise all(Promise promise, final Class type) {
        return (Promise)promise.then(new Func() {
            public Object call(Object array) throws Throwable {
                return all((Object[])array, type);
            }
        });
    }

    public final static Promise all(Promise promise) {
        return all(promise, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final  Promise all(Class type) {
        return all((Promise)this, type);
    }

    @SuppressWarnings("unchecked")
    public final Promise all() {
        return all((Promise)this);
    }

    public final static Promise join(Object...args) {
        return all(args);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise race(Object[] array, Class type) {
        Promise promise = new Promise();
        for (int i = 0, n = array.length; i < n; ++i) {
            ((Promise)toPromise(array[i])).fill(promise);
        }
        return promise;
    }

    public final static Promise race(Object[] array) {
        return race(array, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise race(Promise promise, final Class type) {
        return (Promise)promise.then(new Func, Object[]>() {
            public Promise call(Object[] array) throws Throwable {
                return race(array, type);
            }
        });
    }

    public final static Promise race(Promise promise) {
        return race(promise, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final  Promise race(Class type) {
        return race((Promise)this, type);
    }

    @SuppressWarnings("unchecked")
    public final Promise race() {
        return race((Promise)this);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise any(Object[] array, Class type) {
        int n = array.length;
        if (n == 0) {
            return (Promise)Promise.error(new IllegalArgumentException("any(): array must not be empty"));
        }
        final RuntimeException reason = new RuntimeException("any(): all promises failed");
        final Promise promise = new Promise();
        final AtomicInteger count = new AtomicInteger(n);
        for (int i = 0; i < n; ++i) {
            ((Promise)toPromise(array[i])).then(
                new Action() {
                    public void call(T value) throws Throwable {
                        promise.resolve(value);
                    }
                },
                new Action() {
                    public void call(Throwable e) throws Throwable {
                        if (JdkVersion.majorJavaVersion  >= JdkVersion.JAVA_17) {
                            reason.addSuppressed(e);
                        }
                        if (count.decrementAndGet() == 0) {
                            promise.reject(reason);
                        }
                    }
                }
            );
        }
        return promise;
    }

    public final static Promise any(Object[] array) {
        return any(array, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise any(Promise promise, final Class type) {
        return (Promise)promise.then(new Func, Object[]>() {
            public Promise call(Object[] array) throws Throwable {
                return any(array, type);
            }
        });
    }

    public final static Promise any(Promise promise) {
        return any(promise, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final  Promise any(Class type) {
        return any((Promise)this, type);
    }

    @SuppressWarnings("unchecked")
    public final Promise any() {
        return any((Promise)this);
    }

    public final static Promise run(Action handler, Object...args) {
        return all(args).then(handler);
    }

    public final static Promise run(Func handler, Object...args) {
        return all(args).then(handler);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise forEach(final Action callback, Object...args) {
        return all(args).then(new Action() {
            public void call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    callback.call((V)array[i]);
                }
            }
        });
    }

    @SuppressWarnings("unchecked")
    private static  Action getForEachHandler(final Handler callback) {
        return new Action() {
            public void call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    callback.call((V)array[i], i);
                }
            }
        };
    }

    public final static  Promise forEach(Object[] array, Handler callback) {
        return all(array).then(getForEachHandler(callback));
    }

    public final static  Promise forEach(Promise array, Handler callback) {
        return all(array).then(getForEachHandler(callback));
    }

    public final Promise forEach(Handler callback) {
        return this.all().then(getForEachHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise every(final Func callback, Object...args) {
        return (Promise) all(args).then(new Func() {
            public Boolean call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    if (!callback.call((V)array[i])) return false;
                }
                return true;
            }
        });
    }

    @SuppressWarnings("unchecked")
    private static  Func getEveryHandler(final Handler callback) {
        return new Func() {
            public Boolean call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    if (!callback.call((V)array[i], i)) return false;
                }
                return true;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise every(Object[] array, Handler callback) {
        return (Promise) all(array).then(getEveryHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise every(Promise array, Handler callback) {
        return (Promise) all(array).then(getEveryHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final  Promise every(Handler callback) {
        return (Promise) this.all().then(getEveryHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise some(final Func callback, Object...args) {
        return (Promise) all(args).then(new Func() {
            public Boolean call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    if (callback.call((V)array[i])) return true;
                }
                return false;
            }
        });
    }

    @SuppressWarnings("unchecked")
    private static  Func getSomeHandler(final Handler callback) {
        return new Func() {
            public Boolean call(Object[] array) throws Throwable {
                for (int i = 0, n = array.length; i < n; ++i) {
                    if (callback.call((V)array[i], i)) return true;
                }
                return false;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise some(Object[] array, Handler callback) {
        return (Promise)all(array).then(getSomeHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise some(Promise array, Handler callback) {
        return (Promise)all(array).then(getSomeHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final  Promise some(Handler callback) {
        return (Promise)this.all().then(getSomeHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise filter(final Func callback, Object...args) {
        return (Promise) all(args).then(new Func() {
            public Object[] call(Object[] array) throws Throwable {
                int n = array.length;
                ArrayList result = new ArrayList(n);
                for (int i = 0; i < n; ++i) {
                    if (callback.call((V)array[i])) result.add(array[i]);
                }
                return result.toArray();
            }
        });
    }

    @SuppressWarnings("unchecked")
    private static  Func getFilterHandler(final Handler callback, final Class type) {
        return new Func() {
            public T[] call(T[] array) throws Throwable {
                int n = array.length;
                ArrayList result = new ArrayList(n);
                for (int i = 0; i < n; ++i) {
                    if (callback.call((V)array[i], i)) result.add(array[i]);
                }
                return result.toArray((type == Object.class) ?
                (T[])(new Object[result.size()]) :
                (T[])Array.newInstance(type, result.size()));
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise filter(Object[] array, Handler callback, Class type) {
        return (Promise)all(array, type).then(getFilterHandler(callback, type));
    }

    public final static  Promise filter(Object[] array, Handler callback) {
        return filter(array, callback, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise filter(Promise array, Handler callback, Class type) {
        return (Promise)all(array, type).then(getFilterHandler(callback, type));
    }

    public final static  Promise filter(Promise array, Handler callback) {
        return filter(array, callback, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final  Promise filter(Handler callback, Class type) {
        return (Promise)this.all(type).then(getFilterHandler(callback, type));
    }

    public final  Promise filter(Handler callback) {
        return filter(callback, Object.class);
    }

    @SuppressWarnings("unchecked")
    public final static  Promise map(final Func callback, Object...args) {
        return (Promise)all(args).then(new Func() {
            public Object[] call(Object[] array) throws Throwable {
                int n = array.length;
                Object[] result = new Object[n];
                for (int i = 0; i < n; ++i) {
                    result[i] = callback.call((V)array[i]);
                }
                return result;
            }
        });
    }

    @SuppressWarnings("unchecked")
    private static  Func getMapHandler(final Handler callback, final Class type) {
        return new Func() {
            public T[] call(Object[] array) throws Throwable {
                int n = array.length;
                T[] result = (type == Object.class) ?
                (T[])(new Object[n]) :
                (T[])Array.newInstance(type, n);
                for (int i = 0; i < n; ++i) {
                    result[i] = callback.call((V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static  Func getMapHandler(final Handler callback) {
        return new Func() {
            public Object[] call(Object[] array) throws Throwable {
                int n = array.length;
                Object[] result = new Object[n];
                for (int i = 0; i < n; ++i) {
                    result[i] = callback.call((V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise map(Object[] array, Handler callback, Class type) {
        return (Promise)all(array).then(getMapHandler(callback, type));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise map(Object[] array, Handler callback) {
        return (Promise)all(array).then(getMapHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise map(Promise array, Handler callback, Class type) {
        return (Promise)all(array).then(getMapHandler(callback, type));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise map(Promise array, Handler callback) {
        return (Promise)all(array).then(getMapHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final  Promise map(Handler callback, Class type) {
        return (Promise)this.all().then(getMapHandler(callback, type));
    }

    @SuppressWarnings("unchecked")
    public final  Promise map(Handler callback) {
        return (Promise)this.all().then(getMapHandler(callback));
    }


    @SuppressWarnings("unchecked")
    private static  Func getReduceHandler(final Reducer callback) {
        return new Func() {
            public V call(Object[] array) throws Throwable {
                int n = array.length;
                if (n == 0) return null;
                V result = (V)array[0];
                for (int i = 1; i < n; ++i) {
                    result = callback.call(result, (V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduce(Object[] array, Reducer callback) {
        return (Promise)all(array).then(getReduceHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduce(Promise array, Reducer callback) {
        return (Promise)all(array).then(getReduceHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final  Promise reduce(Reducer callback) {
        return (Promise)this.all().then(getReduceHandler(callback));
    }

    @SuppressWarnings("unchecked")
    private static  Func getReduceHandler(final Reducer callback, final R initialValue) {
        return new Func() {
            public R call(Object[] array) throws Throwable {
                int n = array.length;
                if (n == 0) return initialValue;
                R result = initialValue;
                for (int i = 0; i < n; ++i) {
                    result = callback.call(result, (V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduce(Object[] array, Reducer callback, R initialValue) {
        return (Promise)all(array).then(getReduceHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduce(Promise array, Reducer callback, R initialValue) {
        return (Promise)all(array).then(getReduceHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    public final  Promise reduce(Reducer callback, R initialValue) {
        return (Promise)this.all().then(getReduceHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    private static  Func getReduceRightHandler(final Reducer callback) {
        return new Func() {
            public V call(Object[] array) throws Throwable {
                int n = array.length;
                if (n == 0) return null;
                V result = (V)array[n - 1];
                for (int i = n - 2; i >= 0; --i) {
                    result = callback.call(result, (V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduceRight(Object[] array, Reducer callback) {
        return (Promise)all(array).then(getReduceRightHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduceRight(Promise array, Reducer callback) {
        return (Promise)all(array).then(getReduceRightHandler(callback));
    }

    @SuppressWarnings("unchecked")
    public final  Promise reduceRight(Reducer callback) {
        return (Promise)this.all().then(getReduceRightHandler(callback));
    }

    @SuppressWarnings("unchecked")
    private static  Func getReduceRightHandler(final Reducer callback, final R initialValue) {
        return new Func() {
            public R call(Object[] array) throws Throwable {
                int n = array.length;
                if (n == 0) return initialValue;
                R result = initialValue;
                for (int i = n - 1; i >= 0; --i) {
                    result = callback.call(result, (V)array[i], i);
                }
                return result;
            }
        };
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduceRight(Object[] array, Reducer callback, R initialValue) {
        return (Promise)all(array).then(getReduceRightHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    public final static  Promise reduceRight(Promise array, Reducer callback, R initialValue) {
        return (Promise)all(array).then(getReduceRightHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    public final  Promise reduceRight(Reducer callback, R initialValue) {
        return (Promise)this.all().then(getReduceRightHandler(callback, initialValue));
    }

    @SuppressWarnings("unchecked")
    private  void call(final Callback callback, final Promise next, final V x) {
        try {
            if (callback instanceof Action) {
                ((Action)callback).call(x);
                next.resolve((U)null);
            }
            else {
                next.resolve(((Func)callback).call(x));
            }
        }
        catch (Throwable e) {
            next.reject(e);
        }
    }

    private void reject(final Callback onreject, final Promise next, final Throwable e) {
        if (onreject != null) {
            call(onreject, next, e);
        }
        else {
            next.reject(e);
        }
    }

    @SuppressWarnings("unchecked")
    private  void resolve(final Callback onfulfill, final Callback onreject, final Promise next, final Object x) {
        if (x instanceof Promise) {
            if (x == this) {
                reject(onreject, next, new TypeException("Self resolution"));
                return;
            }
            Action resolveFunction = new Action() {
                public void call(Object y) throws Throwable {
                    resolve(onfulfill, onreject, next, y);
                }
            };
            Action rejectFunction = new Action() {
                public void call(Throwable e) throws Throwable {
                    reject(onreject, next, e);
                }
            };
            ((Promise)x).then(resolveFunction, rejectFunction);
        }
        else if (x instanceof Thenable) {
            final AtomicBoolean notrun = new AtomicBoolean(true);
            Action resolveFunction = new Action() {
                public void call(Object y) throws Throwable {
                    if (notrun.compareAndSet(true, false)) {
                        resolve(onfulfill, onreject, next, y);
                    }
                }
            };
            Action rejectFunction = new Action() {
                public void call(Throwable e) throws Throwable {
                    if (notrun.compareAndSet(true, false)) {
                        reject(onreject, next, e);
                    }
                }
            };
            try {
                ((Thenable)x).then(resolveFunction, rejectFunction);
            }
            catch (Throwable e) {
                if (notrun.compareAndSet(true, false)) {
                    reject(onreject, next, e);
                }
            }
        }
        else {
            if (onfulfill != null) {
                call(onfulfill, next, (V)x);
            }
            else {
                next.resolve((U)x);
            }
        }
    }

    public final void resolve(V value) {
        if (state == State.PENDING) {
            state = State.FULFILLED;
            this.value = value;
            while (!subscribers.isEmpty()) {
                Subscriber subscriber = subscribers.poll();
                resolve(subscriber.onfulfill, subscriber.onreject, subscriber.next, value);
            }
        }
    }

    public final void resolve(Promise value) {
        value.fill(this);
    }

    public final void reject(Throwable e) {
        if (state == State.PENDING) {
            state = State.REJECTED;
            this.reason = e;
            while (!subscribers.isEmpty()) {
                Subscriber subscriber = subscribers.poll();
                if (subscriber.onreject != null) {
                    call(subscriber.onreject, subscriber.next, e);
                }
                else {
                    subscriber.next.reject(e);
                }
            }
        }
    }

    public final Promise then(Action onfulfill) {
        return then((Callback)onfulfill, null);
    }

    public final  Promise then(Func onfulfill) {
        return (Promise)then((Callback)onfulfill, null);
    }

    public final Promise then(Action onfulfill, Action onreject) {
        return then((Callback)onfulfill, (Callback)onreject);
    }

    public final  Promise then(Action onfulfill, Func onreject) {
        return (Promise)then((Callback)onfulfill, (Callback)onreject);
    }

    public final  Promise then(Func onfulfill, Action onreject) {
        return (Promise)then((Callback)onfulfill, (Callback)onreject);
    }

    public final  Promise then(Func onfulfill, Func onreject) {
        return (Promise)then((Callback)onfulfill, (Callback)onreject);
    }

    public final Promise then(Callback onfulfill, Callback onreject) {
        if ((onfulfill != null) || (onreject != null)) {
            Promise next = new Promise();
            if (state == State.FULFILLED) {
                resolve(onfulfill, onreject, next, value);
            }
            else if (state == State.REJECTED) {
                if (onreject != null) {
                    call(onreject, next, reason);
                }
                else {
                    next.reject(reason);
                }
            }
            else {
                subscribers.offer(new Subscriber(onfulfill, onreject, next));
            }
            return next;
        }
        return this;
    }

    public final void done(Action onfulfill) {
        done((Callback)onfulfill, null);
    }

    public final void done(Func onfulfill) {
        done((Callback)onfulfill, null);
    }

    public final void done(Action onfulfill, Action onreject) {
        done((Callback)onfulfill, (Callback)onreject);
    }

    public final void done(Action onfulfill, Func onreject) {
        done((Callback)onfulfill, (Callback)onreject);
    }

    public final void done(Func onfulfill, Action onreject) {
        done((Callback)onfulfill, (Callback)onreject);
    }

    public final void done(Func onfulfill, Func onreject) {
        done((Callback)onfulfill, (Callback)onreject);
    }

    private void done(Callback onfulfill, Callback onreject) {
        then(onfulfill, onreject).then((Callback)null, new Action() {
            public void call(final Throwable e) {
                timer.execute(new Runnable() {
                    public void run() {
                        throw new RuntimeException(e);
                    }
                });
            }
        });
    }

    public final State getState() {
        return state;
    }

    public final Object getValue() {
        return value;
    }

    public final Throwable getReason() {
        return reason;
    }

    public final Promise catchError(final Action onreject) {
        return then((Callback)null, onreject);
    }

    public final  Promise catchError(final Func onreject) {
        return then((Callback)null, onreject);
    }

    public final Promise catchError(final Action onreject, final Func test) {
        return catchError((Callback)onreject, test);
    }

    public final  Promise catchError(final Func onreject, final Func test) {
        return (Promise)catchError((Callback)onreject, test);
    }

    private Promise catchError(final Callback onreject, final Func test) {
        if (test != null) {
            return then((Callback)null, new Func, Throwable>() {
                public Promise call(Throwable e) throws Throwable {
                    if (test.call(e)) {
                        return then(null, onreject);
                    }
                    throw e;
                }
            });
        }
        return then(null, onreject);
    }

    public final void fail(final Action onreject) {
        done((Callback)null, onreject);
    }

    public final void fail(final Func onreject) {
        done((Callback)null, onreject);
    }

    @SuppressWarnings("unchecked")
    public final Promise whenComplete(final Callable action) {
        return (Promise)then(
            new Func() {
                public Object call(final V value) throws Throwable {
                    Object f = action.call();
                    if (f == null || !isThenable(f)) return value;
                    return ((Promise)toPromise(f)).then(new Func() {
                        public V call(Object __) throws Throwable {
                            return value;
                        }
                    });
                }
            },
            new Func() {
                public Object call(final Throwable e) throws Throwable {
                    Object f = action.call();
                    if (f == null || !isThenable(f)) throw e;
                    return ((Promise)toPromise(f)).then(new Func() {
                        public V call(Object __) throws Throwable {
                            throw e;
                        }
                    });
                }
            }
        );
    }

    @SuppressWarnings("unchecked")
    public final Promise whenComplete(final Runnable action) {
        return (Promise)then(
            new Func() {
                public Object call(final V value) throws Throwable {
                    action.run();
                    return value;
                }
            },
            new Func() {
                public Object call(final Throwable e) throws Throwable {
                    action.run();
                    throw e;
                }
            }
        );
    }

    @SuppressWarnings("unchecked")
    public final Promise complete(Action oncomplete) {
        return then((Callback)oncomplete, (Callback)oncomplete);
    }

    @SuppressWarnings("unchecked")
    public final Promise complete(Func oncomplete) {
        return then((Callback)oncomplete, (Callback)oncomplete);
    }

    @SuppressWarnings("unchecked")
    public final void always(Action oncomplete) {
        done((Callback)oncomplete, (Callback)oncomplete);
    }

    @SuppressWarnings("unchecked")
    public final void always(Func oncomplete) {
        done((Callback)oncomplete, (Callback)oncomplete);
    }

    public final void fill(final Promise promise) {
        then(
            new Action() {
                public void call(V value) throws Throwable {
                    promise.resolve(value);
                }
            },
            new Action() {
                public void call(Throwable e) throws Throwable {
                    promise.reject(e);
                }
            }
        );
    }

    public final Promise timeout(long duration, TimeUnit timeunit, final Throwable reason) {
        final Promise promise = new Promise();
        final Future timeoutID = timer.schedule(new Runnable() {
            public void run() {
                if (reason == null) {
                    promise.reject(new TimeoutException("timeout"));
                }
                else {
                    promise.reject(reason);
                }
            }
        }, duration, timeunit);
        whenComplete(new Runnable() {
            public void run() {
                timeoutID.cancel(true);
            }
        }).fill(promise);
        return promise;
    }

    public final Promise timeout(long duration, Throwable reason) {
        return timeout(duration, TimeUnit.MILLISECONDS, reason);
    }

    public final Promise timeout(long duration) {
        return timeout(duration, TimeUnit.MILLISECONDS, null);
    }

    public final Promise delay(final long duration, final TimeUnit timeunit) {
        final Promise promise = new Promise();
        then(new Action() {
                public void call(final V value) throws Throwable {
                    timer.schedule(new Runnable() {
                        public void run() {
                            promise.resolve(value);
                        }
                    }, duration, timeunit);
                }
            },
            new Action() {
                public void call(Throwable e) throws Throwable {
                    promise.reject(e);
                }
            }
        );
        return promise;
    }

    public final Promise delay(long duration) {
        return delay(duration, TimeUnit.MILLISECONDS);
    }

    @SuppressWarnings("unchecked")
    public final Promise tap(final Action onfulfilledSideEffect) {
        return then(new Func() {
            public V call(V value) throws Throwable {
                onfulfilledSideEffect.call(value);
                return value;
            }
        });
    }

    public final Future toFuture() {
        return new PromiseFuture(this);
    }
}