org.excalibur.core.util.concurrent.Futures2.java Source code

Java tutorial

Introduction

Here is the source code for org.excalibur.core.util.concurrent.Futures2.java

Source

/**
 *     Copyright (C) 2013-2014  the original author or authors.
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License,
 *     any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
package org.excalibur.core.util.concurrent;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.annotation.Nullable;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.Uninterruptibles;

@SuppressWarnings("unchecked")
public final class Futures2 {
    private Futures2() {
        throw new UnsupportedOperationException();
    }

    public <V> ListenableFuture<V> invokeAll(Future<V> future) {
        if (future instanceof ListenableFuture) {
            return (ListenableFuture<V>) future;
        }

        return null;
    }

    public static <V> ListenableFuture<V> addCallback(ListenableFuture<V> future, FutureCallback<V> callback) {
        return addCallbacks(future, new FutureCallback[] { callback });
    }

    public static <V> ListenableFuture<V> addCallbacks(ListenableFuture<V> future, FutureCallback<V>[] callbacks) {
        if (future != null && callbacks != null) {
            for (FutureCallback<V> callback : callbacks) {
                if (callback != null) {
                    Futures.addCallback(future, callback);
                }
            }
        }

        return future;
    }

    /**
     * Registers separate success and failure callbacks to be run when the {@code Future}'s computation is
     * {@linkplain java.util.concurrent.Future#isDone() complete} or, if the computation is already complete, immediately.
     * 
     * @param futures
     * @param callback
     * @param <V>
     * @return The same input.
     */
    public static <V> List<ListenableFuture<V>> addCallback(List<ListenableFuture<V>> futures,
            FutureCallback<V> callback) {
        return addCallbacks(futures, new FutureCallback[] { callback });
    }

    public static <V> List<ListenableFuture<V>> addCallbacks(List<ListenableFuture<V>> futures,
            FutureCallback<V>[] callbacks) {
        if (futures != null && callbacks != null) {
            for (ListenableFuture<V> future : futures) {
                addCallbacks(future, callbacks);
            }
        }

        return futures;
    }

    public static <V> List<ListenableFuture<V>> invokeAll(Iterable<Callable<V>> tasks,
            ListeningExecutorService executor) {
        List<ListenableFuture<V>> futures = Lists.newArrayList();

        for (Callable<V> task : tasks) {
            ListenableFuture<V> future = executor.submit(task);
            futures.add(future);
        }

        return futures;
    }

    public static <V> List<ListenableFuture<V>> invokeAll(Iterable<Callable<V>> tasks,
            ListeningExecutorService executor, FutureCallback<V>[] callbacks) {
        List<ListenableFuture<V>> futures = Lists.newArrayList();

        for (Callable<V> task : tasks) {
            ListenableFuture<V> future = executor.submit(task);
            futures.add(addCallbacks(future, callbacks));
        }

        return futures;
    }

    public static <V> List<V> invokeAllAndShutdownWhenFinish(List<Callable<V>> tasks,
            ListeningExecutorService executor) {
        return invokeAllAndShutdownWhenFinish(tasks, executor, new FutureCallback[0]);
    }

    public static <V> List<V> invokeAllAndShutdownWhenFinish(List<Callable<V>> tasks,
            ListeningExecutorService executor, FutureCallback<V>[] callbacks) {
        final List<V> results = Lists.newArrayList();
        final CountDownLatch endSignal = new CountDownLatch(tasks.size());

        FutureCallback<V> endSignalCallback = new FutureCallback<V>() {
            @Override
            public void onSuccess(@Nullable V result) {
                endSignal.countDown();
                results.add(result);
            }

            @Override
            public void onFailure(Throwable t) {
                endSignal.countDown();
            }
        };

        List<FutureCallback<V>> l = Lists.newArrayList(callbacks);
        l.add(endSignalCallback);

        invokeAll(tasks, executor, l.toArray(new FutureCallback[l.size()]));

        try {
            endSignal.await();
            executor.shutdownNow();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return results;
    }

    public static void invokeAllAndShutdownWhenFinish(List<Callable<Boolean>> tasks, String threadName) {
        ListeningExecutorService executor = DynamicExecutors.newListeningDynamicScalingThreadPool(threadName);

        invokeAllAndShutdownWhenFinish(tasks, executor);
    }

    public static <V> List<V> invokeAll(List<Callable<V>> tasks) {
        return invokeAllAndShutdownWhenFinish(tasks,
                MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()));
    }

    /**
     * Returns the result of calling {@link Future#get()} uninterruptibly on a task known not to throw a checked exception. This makes {@code Future}
     * more suitable for lightweight, fast-running tasks that, barring bugs in the code, will not fail. This gives it exception-handling behavior
     * similar to that of {@code ForkJoinTask.join}.
     * 
     * <p>
     * Exceptions from {@code Future.get} are treated as follows:
     * <ul>
     * <li>Any {@link ExecutionException} has its <i>cause</i> wrapped in an {@link UncheckedExecutionException} (if the cause is an {@code Exception}
     * ) or {@link ExecutionError} (if the cause is an {@code Error}).
     * <li>Any {@link InterruptedException} causes a retry of the {@code get} call. The interrupt is restored before {@code getUnchecked} returns.
     * <li>Any {@link CancellationException} is propagated untouched. So is any other {@link RuntimeException} ({@code get} implementations are
     * discouraged from throwing such exceptions).
     * </ul>
     * 
     * <p>
     * The overall principle is to eliminate all checked exceptions: to loop to avoid {@code InterruptedException}, to pass through
     * {@code CancellationException}, and to wrap any exception from the underlying computation in an {@code UncheckedExecutionException} or
     * {@code ExecutionError}.
     * 
     * <p>
     * For an uninterruptible {@code get} that preserves other exceptions, see {@link Uninterruptibles#getUninterruptibly(Future)}.
     * 
     * @throws UncheckedExecutionException
     *             if {@code get} throws an {@code ExecutionException} with an {@code Exception} as its cause
     * @throws ExecutionError
     *             if {@code get} throws an {@code ExecutionException} with an {@code Error} as its cause
     * @throws CancellationException
     *             if {@code get} throws a {@code CancellationException}
     */
    public static <V> List<V> getUnchecked(List<Future<V>> futures) {
        List<V> results = Lists.newArrayList();

        for (Future<V> future : futures) {
            results.add(Futures.getUnchecked(future));
        }

        return results;
    }

    public static class FutureCallbackList<V> implements FutureCallback<V> {
        private final List<V> successfulResults_ = Lists.newCopyOnWriteArrayList();
        private final List<Throwable> errors_ = Lists.newCopyOnWriteArrayList();

        @Override
        public void onSuccess(@Nullable V result) {
            successfulResults_.add(result);
        }

        @Override
        public void onFailure(Throwable t) {
            errors_.add(t);
        }

        public List<V> getResults() {
            return successfulResults_;
        }

        public List<Throwable> getErrors() {
            return errors_;
        }
    }

}