package de.invesdwin.util.concurrent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.concurrent.Immutable;
import de.invesdwin.util.assertions.Assertions;
import de.invesdwin.util.error.Throwables;
import de.invesdwin.util.time.duration.Duration;
import de.invesdwin.util.time.fdate.FDate;
import de.invesdwin.util.time.fdate.FTimeUnit;
@Immutable
public final class Futures {
private Futures() {}
public static <T> T get(final Future<T> future) throws InterruptedException {
try {
return future.get();
} catch (final ExecutionException e) {
final InterruptedException iCause = Throwables.getCauseByType(e, InterruptedException.class);
if (iCause != null) {
throw iCause;
} else {
throw new RuntimeException(e);
}
}
}
@SafeVarargs
public static <T> List<T> get(final Future<T>... futures) throws InterruptedException {
return get(Arrays.asList(futures));
}
public static <T> List<T> get(final List<Future<T>> futures) throws InterruptedException {
final List<T> resultate = new ArrayList<T>(futures.size());
for (final Future<T> future : futures) {
resultate.add(get(future));
}
return resultate;
}
public static void submitAndWait(final ExecutorService executor, final Runnable task) throws InterruptedException {
final Future<?> future = executor.submit(task);
wait(future);
}
public static void submitAndWait(final ExecutorService executor, final List<? extends Runnable> tasks)
throws InterruptedException {
final List<Future<?>> futures = new ArrayList<Future<?>>(tasks.size());
for (final Runnable task : tasks) {
futures.add(executor.submit(task));
}
wait(futures);
}
/**
* Returns with the first exception and aborts remaining tasks. This is useful for caller runs or similar throttled
* executors.
*/
public static void submitAndWaitFailFast(final ExecutorService executor, final List<? extends Runnable> tasks)
throws InterruptedException {
final List<Future<?>> futures = new CopyOnWriteArrayList<Future<?>>();
FDate lastFailFastCheck = FDate.MIN_DATE;
for (final Runnable task : tasks) {
futures.add(executor.submit(task));
if (new Duration(lastFailFastCheck, new FDate()).isGreaterThan(5, FTimeUnit.SECONDS)) {
//failfast on exceptions
for (final Future<?> future : futures) {
if (future.isDone()) {
futures.remove(future);
try {
Assertions.assertThat(get(future)).isNull();
} catch (final Throwable t) {
for (final Future<?> f : futures) {
f.cancel(true);
}
throw Throwables.propagate(t);
}
}
}
lastFailFastCheck = new FDate();
}
}
wait(futures);
}
public static <T> T submitAndGet(final ExecutorService executor, final Callable<T> task)
throws InterruptedException {
final Future<T> future = executor.submit(task);
return get(future);
}
public static <T> List<T> submitAndGet(final ExecutorService executor, final List<? extends Callable<T>> tasks)
throws InterruptedException {
final List<Future<T>> futures = executor.invokeAll(tasks);
return get(futures);
}
public static void wait(final Future<?>... futures) throws InterruptedException {
wait(Arrays.asList(futures));
}
public static void wait(final List<Future<?>> futures) throws InterruptedException {
for (final Future<?> future : futures) {
wait(future);
}
}
public static void wait(final Future<?> future) throws InterruptedException {
Assertions.assertThat(get(future)).isNull();
}
}