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

com.landawn.abacus.util.ContinuableFuture Maven / Gradle / Ivy

There is a newer version: 1.10.1
Show newest version
/*
 * Copyright (C) 2016 HaiYang Li
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.landawn.abacus.util;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.Tuple.Tuple4;

/**
 * 
 * @since 0.8
 * 
 * @author Haiyang Li
 * 
 * @see https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ContinuableFuture.html
 */
public class ContinuableFuture implements Future {
    private static final Logger logger = LoggerFactory.getLogger(ContinuableFuture.class);

    private static final ExecutorService DEFAULT_EXECUTOR = new ThreadPoolExecutor(8, 64, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());

    static {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                logger.warn("Starting to shutdown task in ContinuableFuture");

                try {
                    DEFAULT_EXECUTOR.shutdown();

                    while (DEFAULT_EXECUTOR.isTerminated() == false) {
                        N.sleepUninterruptibly(100);
                    }
                } finally {
                    logger.warn("Completed to shutdown task in ContinuableFuture");
                }
            }
        });
    }

    final Future future;
    final List> upFutures;
    final Executor asyncExecutor;

    ContinuableFuture(final Future future) {
        this(future, null, null);
    }

    ContinuableFuture(final Future future, final List> upFutures, final Executor asyncExecutor) {
        this.future = future;
        this.upFutures = upFutures;
        this.asyncExecutor = asyncExecutor == null ? DEFAULT_EXECUTOR : asyncExecutor;
    }

    public static  ContinuableFuture run(final Try.Runnable action) {
        return run(action, DEFAULT_EXECUTOR);
    }

    public static  ContinuableFuture run(final Try.Runnable action, final Executor executor) {
        final FutureTask futureTask = new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                action.run();
                return null;
            }
        });

        executor.execute(futureTask);

        return new ContinuableFuture<>(futureTask, null, executor);
    }

    public static  ContinuableFuture call(final Try.Callable action) {
        return call(action, DEFAULT_EXECUTOR);
    }

    public static  ContinuableFuture call(final Try.Callable action, final Executor executor) {
        final FutureTask futureTask = new FutureTask<>(new Callable() {
            @Override
            public T call() throws Exception {
                return action.call();
            }
        });

        executor.execute(futureTask);

        return new ContinuableFuture<>(futureTask, null, executor);
    }

    /**
     * 
     * @param result
     * @param asyncExecutor
     * @return a ContinuableFuture which is already done by passing the result to it directly.
     */
    public static  ContinuableFuture completed(final T result) {
        return new ContinuableFuture<>(new Future() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return false;
            }

            @Override
            public boolean isCancelled() {
                return false;
            }

            @Override
            public boolean isDone() {
                return true;
            }

            @Override
            public T get() {
                return result;
            }

            @Override
            public T get(final long timeout, final TimeUnit unit) {
                return result;
            }
        }, null, DEFAULT_EXECUTOR);
    }

    public static  ContinuableFuture wrap(Future future) {
        return new ContinuableFuture(future);
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return future.cancel(mayInterruptIfRunning);
    }

    @Override
    public boolean isCancelled() {
        return future.isCancelled();
    }

    /**
     * Cancel this future and all the previous stage future recursively.
     * 
     * @param mayInterruptIfRunning
     * @return
     */
    public boolean cancelAll(boolean mayInterruptIfRunning) {
        boolean res = true;

        if (N.notNullOrEmpty(upFutures)) {
            for (ContinuableFuture preFuture : upFutures) {
                res = res & preFuture.cancelAll(mayInterruptIfRunning);
            }
        }

        return cancel(mayInterruptIfRunning) && res;
    }

    /**
     * Returns true if this future and all previous stage futures have been recursively cancelled, otherwise false is returned.
     * 
     * @return
     */
    public boolean isAllCancelled() {
        boolean res = true;

        if (N.notNullOrEmpty(upFutures)) {
            for (ContinuableFuture preFuture : upFutures) {
                res = res & preFuture.isAllCancelled();
            }
        }

        return isCancelled() && res;
    }

    @Override
    public boolean isDone() {
        return future.isDone();
    }

    @Override
    public T get() throws InterruptedException, ExecutionException {
        return future.get();
    }

    @Override
    public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return future.get(timeout, unit);
    }

    public Result gett() {
        try {
            return Result.of(get(), null);
        } catch (Exception e) {
            return Result.of(null, e);
        }
    }

    public Result gett(final long timeout, final TimeUnit unit) {
        try {
            return Result.of(get(timeout, unit), null);
        } catch (Exception e) {
            return Result.of(null, e);
        }
    }

    public T getNow(T defaultValue) {
        if (isDone()) {
            try {
                return get();
            } catch (InterruptedException | ExecutionException e) {
                throw N.toRuntimeException(e);
            }
        }

        return defaultValue;
    }

    public  U getThenApply(final Try.Function action) throws InterruptedException, ExecutionException, E {
        return action.apply(get());
    }

    public  U getThenApply(final long timeout, final TimeUnit unit, final Try.Function action)
            throws InterruptedException, ExecutionException, TimeoutException, E {
        return action.apply(get(timeout, unit));
    }

    public  U getThenApply(final Try.BiFunction action) throws E {
        final Result result = gett();
        return action.apply(result.orElse(null), result.getExceptionIfPresent());
    }

    public  U getThenApply(final long timeout, final TimeUnit unit, final Try.BiFunction action)
            throws E {
        final Result result = gett(timeout, unit);
        return action.apply(result.orElse(null), result.getExceptionIfPresent());
    }

    public  void getThenAccept(final Try.Consumer action) throws InterruptedException, ExecutionException, E {
        action.accept(get());
    }

    public  void getThenAccept(final long timeout, final TimeUnit unit, final Try.Consumer action)
            throws InterruptedException, ExecutionException, TimeoutException, E {
        action.accept(get(timeout, unit));
    }

    public  void getThenAccept(final Try.BiConsumer action) throws E {
        final Result result = gett();
        action.accept(result.orElse(null), result.getExceptionIfPresent());
    }

    public  void getThenAccept(final long timeout, final TimeUnit unit, final Try.BiConsumer action)
            throws E {
        final Result result = gett(timeout, unit);
        action.accept(result.orElse(null), result.getExceptionIfPresent());
    }

    //    public void complete() throws InterruptedException, ExecutionException {
    //        get();
    //    }
    //
    //    public void complete(Consumer action) {
    //        try {
    //            action.accept(get());
    //        } catch (InterruptedException | ExecutionException e) {
    //            throw N.toRuntimeException(e);
    //        }
    //    }
    //
    //    public void complete(BiConsumer action) {
    //        final Result result = gett();
    //        action.accept(result.orElse(null), result.getExceptionIfPresent());
    //    }

    public  ContinuableFuture map(final Try.Function func) {
        return new ContinuableFuture(new Future() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return ContinuableFuture.this.cancel(mayInterruptIfRunning);
            }

            @Override
            public boolean isCancelled() {
                return ContinuableFuture.this.isCancelled();
            }

            @Override
            public boolean isDone() {
                return ContinuableFuture.this.isDone();
            }

            @Override
            public U get() throws InterruptedException, ExecutionException {
                try {
                    return func.apply(ContinuableFuture.this.get());
                } catch (InterruptedException | ExecutionException e) {
                    throw e;
                } catch (Exception e) {
                    throw N.toRuntimeException(e);
                }
            }

            @Override
            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                try {
                    return func.apply(ContinuableFuture.this.get(timeout, unit));
                } catch (InterruptedException | ExecutionException | TimeoutException e) {
                    throw e;
                } catch (Exception e) {
                    throw N.toRuntimeException(e);
                }
            }
        }, null, asyncExecutor) {
            @Override
            public boolean cancelAll(boolean mayInterruptIfRunning) {
                return ContinuableFuture.this.cancelAll(mayInterruptIfRunning);
            }

            @Override
            public boolean isAllCancelled() {
                return ContinuableFuture.this.isAllCancelled();
            }
        };
    }

    //    public  ContinuableFuture thenApply(final BiFunction action) {
    //        return new ContinuableFuture(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone();
    //            }
    //
    //            @Override
    //            public U get() throws InterruptedException, ExecutionException {
    //                final Result result = gett();
    //                return action.apply(result.orElse(null), result.getExceptionIfPresent());
    //            }
    //
    //            @Override
    //            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                final Result result = gett(timeout, unit);
    //                return action.apply(result.orElse(null), result.getExceptionIfPresent());
    //            }
    //        }, null, asyncExecutor) {
    //            @Override
    //            public boolean cancelAll(boolean mayInterruptIfRunning) {
    //                return super.cancelAll(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isAllCancelled() {
    //                return super.isAllCancelled();
    //            }
    //        };
    //    }

    //    public  ContinuableFuture thenAccept(final Consumer action) {
    //        return thenApply(new Function() {
    //            @Override
    //            public Void apply(T t) {
    //                action.accept(t);
    //                return null;
    //            }
    //        });
    //    }
    //
    //    public  ContinuableFuture thenAccept(final BiConsumer action) {
    //        return thenApply(new BiFunction() {
    //            @Override
    //            public Void apply(T t, ? super Exception e) {
    //                action.accept(t, e);
    //                return null;
    //            }
    //        });
    //    }
    //
    //    public  ContinuableFuture thenCombine(final ContinuableFuture other, final BiFunction action) {
    //        return new ContinuableFuture(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning) && other.future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled() || other.future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone() && other.future.isDone();
    //            }
    //
    //            @Override
    //            public R get() throws InterruptedException, ExecutionException {
    //                return action.apply(future.get(), other.future.get());
    //            }
    //
    //            @Override
    //            public R get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                final long timeoutInMillis = unit.toMillis(timeout);
    //                final long now = N.currentMillis();
    //                final long endTime = timeoutInMillis > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + timeoutInMillis;
    //
    //                final T result = future.get(timeout, unit);
    //                final U otherResult = other.future.get(N.max(0, endTime - N.currentMillis()), TimeUnit.MILLISECONDS);
    //
    //                return action.apply(result, otherResult);
    //            }
    //        }, null, asyncExecutor) {
    //            @Override
    //            public boolean cancelAll(boolean mayInterruptIfRunning) {
    //                return super.cancelAll(mayInterruptIfRunning) && other.cancelAll(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isAllCancelled() {
    //                return super.isAllCancelled() && other.isAllCancelled();
    //            }
    //        };
    //    }
    //
    //    public  ContinuableFuture thenCombine(final ContinuableFuture other, final Function, R> action) {
    //        return new ContinuableFuture(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning) && other.future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled() || other.future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone() && other.future.isDone();
    //            }
    //
    //            @Override
    //            public R get() throws InterruptedException, ExecutionException {
    //                final Result result = gett();
    //                final Pair result2 = other.gett();
    //
    //                return action.apply(Tuple.of(result.orElse(null), result.getExceptionIfPresent(), (U) result2.orElse(null), result2.getExceptionIfPresent()));
    //            }
    //
    //            @Override
    //            public R get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                final long timeoutInMillis = unit.toMillis(timeout);
    //                final long now = N.currentMillis();
    //                final long endTime = timeoutInMillis > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + timeoutInMillis;
    //
    //                final Result result = ContinuableFuture.this.gett(timeout, unit);
    //                final Pair result2 = other.gett(N.max(0, endTime - N.currentMillis()), TimeUnit.MILLISECONDS);
    //
    //                return action.apply(Tuple.of(result.orElse(null), result.getExceptionIfPresent(), (U) result2.orElse(null), result2.getExceptionIfPresent()));
    //            }
    //        }, null, asyncExecutor) {
    //            @Override
    //            public boolean cancelAll(boolean mayInterruptIfRunning) {
    //                return super.cancelAll(mayInterruptIfRunning) && other.cancelAll(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isAllCancelled() {
    //                return super.isAllCancelled() && other.isAllCancelled();
    //            }
    //        };
    //    }
    //
    //    public  ContinuableFuture thenAcceptBoth(final ContinuableFuture other, final BiConsumer action) {
    //        return thenCombine(other, new BiFunction() {
    //            @Override
    //            public Void apply(T t, U u) {
    //                action.accept(t, u);
    //                return null;
    //            }
    //        });
    //    }
    //
    //    public  ContinuableFuture thenAcceptBoth(final ContinuableFuture other, final Consumer> action) {
    //        return thenCombine(other, new Function, Void>() {
    //            @Override
    //            public Void apply(Tuple4 t) {
    //                action.accept(t);
    //                return null;
    //            }
    //        });
    //    }

    public  ContinuableFuture thenRun(final Try.Runnable action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                get();
                action.run();
                return null;
            }
        });
    }

    public  ContinuableFuture thenRun(final Try.Consumer action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                action.accept(get());
                return null;
            }
        });
    }

    public  ContinuableFuture thenRun(final Try.BiConsumer action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                final Result result = gett();
                action.accept(result.orElse(null), result.getExceptionIfPresent());
                return null;
            }
        });
    }

    public  ContinuableFuture thenCall(final Try.Callable action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                get();
                return action.call();
            }
        });
    }

    public  ContinuableFuture thenCall(final Try.Function action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                return action.apply(get());
            }
        });
    }

    public  ContinuableFuture thenCall(final Try.BiFunction action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final Result result = gett();
                return action.apply(result.orElse(null), result.getExceptionIfPresent());
            }
        });
    }

    public  ContinuableFuture runAfterBoth(final ContinuableFuture other, final Try.Runnable action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                get();
                other.get();
                action.run();
                return null;
            }
        }, other);
    }

    public  ContinuableFuture runAfterBoth(final ContinuableFuture other,
            final Try.BiConsumer action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                action.accept(get(), other.get());
                return null;
            }
        }, other);
    }

    public  ContinuableFuture runAfterBoth(final ContinuableFuture other,
            final Try.Consumer, E> action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                final Result result = gett();
                final Result result2 = other.gett();

                action.accept(Tuple.of(result.orElse(null), result.getExceptionIfPresent(), result2.orElse(null), result2.getExceptionIfPresent()));
                return null;
            }
        }, other);
    }

    public  ContinuableFuture callAfterBoth(final ContinuableFuture other, final Try.Callable action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                get();
                other.get();
                return action.call();
            }
        }, other);
    }

    public  ContinuableFuture callAfterBoth(final ContinuableFuture other,
            final Try.BiFunction action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                return action.apply(get(), other.get());
            }
        }, other);
    }

    public  ContinuableFuture callAfterBoth(final ContinuableFuture other,
            final Try.Function, R, E> action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final Result result = gett();
                final Result result2 = other.gett();

                return action.apply(Tuple.of(result.orElse(null), result.getExceptionIfPresent(), result2.orElse(null), result2.getExceptionIfPresent()));
            }
        }, other);
    }

    public  ContinuableFuture runAfterEither(final ContinuableFuture other, final Try.Runnable action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                Futures.anyOf(N.asList(ContinuableFuture.this, other)).get();

                action.run();
                return null;
            }
        }, other);
    }

    public  ContinuableFuture runAfterEither(final ContinuableFuture other, final Try.Consumer action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                final T result = Futures.anyOf(N.asList(ContinuableFuture.this, other)).get();

                action.accept(result);
                return null;
            }
        }, other);
    }

    public  ContinuableFuture runAfterEither(final ContinuableFuture other,
            final Try.BiConsumer action) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                final Result result = Futures.anyOf(N.asList(ContinuableFuture.this, other)).gett();

                action.accept(result.orElse(null), result.getExceptionIfPresent());
                return null;
            }
        }, other);
    }

    public  ContinuableFuture callAfterEither(final ContinuableFuture other, final Try.Callable action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                Futures.anyOf(N.asList(ContinuableFuture.this, other)).get();

                return action.call();
            }
        }, other);
    }

    public  ContinuableFuture callAfterEither(final ContinuableFuture other,
            final Try.Function action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final T result = Futures.anyOf(N.asList(ContinuableFuture.this, other)).get();

                return action.apply(result);
            }
        }, other);
    }

    public  ContinuableFuture callAfterEither(final ContinuableFuture other,
            final Try.BiFunction action) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final Result result = Futures.anyOf(N.asList(ContinuableFuture.this, other)).gett();

                return action.apply(result.orElse(null), result.getExceptionIfPresent());
            }
        }, other);
    }

    //    /**
    //     * Returns a new ContinuableFuture that, when either this or the
    //     * other given ContinuableFuture complete normally. If both of the given
    //     * ContinuableFutures complete exceptionally, then the returned
    //     * ContinuableFuture also does so.
    //     * 
    //     * @param other
    //     * @param action
    //     * @return
    //     */
    //    public  ContinuableFuture applyToEither(final ContinuableFuture other, final Function action) {
    //        return Futures.anyOf(N.asList(this, other)).thenApply(action);
    //    }
    //
    //    /**
    //     * Returns a new ContinuableFuture that, when either this or the
    //     * other given ContinuableFuture complete normally. If both of the given
    //     * ContinuableFutures complete exceptionally, then the returned
    //     * ContinuableFuture also does so.
    //     * 
    //     * @param other
    //     * @param action
    //     * @return
    //     */
    //    public ContinuableFuture acceptEither(final ContinuableFuture other, final Consumer action) {
    //        return Futures.anyOf(N.asList(this, other)).thenAccept(action);
    //    }

    //    /**
    //     * Returns a new ContinuableFuture that, when this ContinuableFuture completes
    //     * exceptionally, is executed with this ContinuableFuture's exception as the
    //     * argument to the supplied function. Otherwise, if this ContinuableFuture
    //     * completes normally, then the returned ContinuableFuture also completes
    //     * normally with the same value.
    //     * 
    //     * @param action
    //     * @return
    //     */
    //    public ContinuableFuture exceptionally(final Function action) {
    //        return new ContinuableFuture(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone();
    //            }
    //
    //            @Override
    //            public T get() throws InterruptedException, ExecutionException {
    //                try {
    //                    return future.get();
    //                } catch (Exception e) {
    //                    return action.apply(e);
    //                }
    //            }
    //
    //            @Override
    //            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                try {
    //                    return future.get(timeout, unit);
    //                } catch (Exception e) {
    //                    return action.apply(e);
    //                }
    //            }
    //        }, null, asyncExecutor) {
    //            @Override
    //            public boolean cancelAll(boolean mayInterruptIfRunning) {
    //                return super.cancelAll(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isAllCancelled() {
    //                return super.isAllCancelled();
    //            }
    //        };
    //    }

    //    public ContinuableFuture whenComplete(final BiConsumer action) {
    //        return new ContinuableFuture<>(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone();
    //            }
    //
    //            @Override
    //            public T get() throws InterruptedException, ExecutionException {
    //                final Result result = gett();
    //
    //                if (result.right != null) {
    //                    try {
    //                        action.accept(result.orElse(null), result.getExceptionIfPresent());
    //                    } catch (Exception e) {
    //                        // ignore.
    //                    }
    //
    //                    if (result.right instanceof InterruptedException) {
    //                        throw ((InterruptedException) result.right);
    //                    } else if (result.right instanceof ExecutionException) {
    //                        throw ((ExecutionException) result.right);
    //                    } else {
    //                        throw N.toRuntimeException(result.right);
    //                    }
    //                } else {
    //                    action.accept(result.orElse(null), result.getExceptionIfPresent());
    //                    return result.left;
    //                }
    //            }
    //
    //            @Override
    //            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                final Result result = gett(timeout, unit);
    //
    //                if (result.right != null) {
    //                    try {
    //                        action.accept(result.orElse(null), result.getExceptionIfPresent());
    //                    } catch (Exception e) {
    //                        // ignore.
    //                    }
    //
    //                    if (result.right instanceof InterruptedException) {
    //                        throw ((InterruptedException) result.right);
    //                    } else if (result.right instanceof ExecutionException) {
    //                        throw ((ExecutionException) result.right);
    //                    } else {
    //                        throw N.toRuntimeException(result.right);
    //                    }
    //                } else {
    //                    action.accept(result.orElse(null), result.getExceptionIfPresent());
    //                    return result.left;
    //                }
    //            }
    //        }, asyncExecutor);
    //    }
    //
    //    public  ContinuableFuture handle(final BiFunction action) {
    //        return new ContinuableFuture<>(new Future() {
    //            @Override
    //            public boolean cancel(boolean mayInterruptIfRunning) {
    //                return future.cancel(mayInterruptIfRunning);
    //            }
    //
    //            @Override
    //            public boolean isCancelled() {
    //                return future.isCancelled();
    //            }
    //
    //            @Override
    //            public boolean isDone() {
    //                return future.isDone();
    //            }
    //
    //            @Override
    //            public U get() throws InterruptedException, ExecutionException {
    //                final Result result = gett();
    //                return action.apply(result.orElse(null), result.getExceptionIfPresent());
    //            }
    //
    //            @Override
    //            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    //                final Result result = gett(timeout, unit);
    //                return action.apply(result.orElse(null), result.getExceptionIfPresent());
    //            }
    //        }, asyncExecutor);
    //    }

    private  ContinuableFuture execute(final Callable command) {
        return execute(command, null);
    }

    private  ContinuableFuture execute(final Callable command, final ContinuableFuture other) {
        return execute(new FutureTask<>(command), other);
    }

    private  ContinuableFuture execute(final FutureTask futureTask, final ContinuableFuture other) {
        asyncExecutor.execute(futureTask);

        @SuppressWarnings("rawtypes")
        final List> upFutures = other == null ? (List) Arrays.asList(this) : Arrays.asList(this, other);
        return new ContinuableFuture<>(futureTask, upFutures, asyncExecutor);
    }

    public ContinuableFuture thenDelay(long delay, TimeUnit unit) {
        if (delay <= 0) {
            return this;
        }

        return with(asyncExecutor, delay, unit);
    }

    public ContinuableFuture thenUse(Executor executor) {
        return with(executor, 0, TimeUnit.MILLISECONDS);
    }

    @Deprecated
    ContinuableFuture with(final Executor executor, final long delay, final TimeUnit unit) {
        N.checkArgNotNull(executor);

        return new ContinuableFuture(new Future() {
            private final long delayInMillis = unit.toMillis(delay);
            private final long startTime = System.currentTimeMillis();
            private volatile boolean isDelayed = false;

            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                return future.cancel(mayInterruptIfRunning);
            }

            @Override
            public boolean isCancelled() {
                return future.isCancelled();
            }

            @Override
            public boolean isDone() {
                boolean isDone = future.isDone();

                if (isDone) {
                    delay();
                }

                return isDone;
            }

            @Override
            public T get() throws InterruptedException, ExecutionException {
                delay();

                return future.get();
            }

            @Override
            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                delay();

                return future.get(timeout, unit);
            }

            private void delay() {
                if (isDelayed == false) {
                    isDelayed = true;

                    N.sleepUninterruptibly(delayInMillis - (System.currentTimeMillis() - startTime));
                }
            }
        }, null, executor) {
            @Override
            public boolean cancelAll(boolean mayInterruptIfRunning) {
                return super.cancelAll(mayInterruptIfRunning);
            }

            @Override
            public boolean isAllCancelled() {
                return super.isAllCancelled();
            }
        };
    }
}