package io.futuristic; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * @autor: julio */ final class FuturePool<T> { //Sets to store the futures that are being listened and completed private final Set<Future<T>> listenedFutures = Collections.newSetFromMap(new ConcurrentHashMap<>()); private final Set<Future<T>> completedFutures = Collections.newSetFromMap(new ConcurrentHashMap<>()); //Futures that will get triggered once any or all listened futures are finished private final FutureWithTrigger<Set<T>> allFinishedFuture = new FutureWithTrigger<>(); private final FutureWithTrigger<T> firstFinishedFuture = new FutureWithTrigger<>(); //Atomic structures to detect wether the first of the last Future is the one finishing private final AtomicInteger successCompletedCount = new AtomicInteger(0); private final AtomicBoolean isLastCompleted = new AtomicBoolean(true); //Structure to store the results private final Set<T> results = Collections.newSetFromMap(new ConcurrentHashMap<>()); FuturePool() { } public Future<T> listen(Future<T> future){ listenedFutures.add(future); return future.consume(v -> registerCompleted(future, v, null) ).trap(Exception.class, e -> { registerCompleted(future, null, e); throw e; }); } public Future<Set<T>> all() { return allFinishedFuture.getFuture(); } public Future<T> first() { return firstFinishedFuture.getFuture(); } private void registerCompleted(Future<T> future, T result, Exception error) { int currentSuccessCompletedCount = successCompletedCount.incrementAndGet(); //Save the result if the future completed successfully if(error == null && result != null){ results.add(result); } //First finished? if(currentSuccessCompletedCount == 1) { if(error == null){ firstFinishedFuture.getTrigger().completed(result); } else { firstFinishedFuture.getTrigger().failed(error); } } //All finished? completedFutures.add(future); if(completedFutures.equals(listenedFutures) && this.isLastCompleted.getAndSet(false)) { this.allFinishedFuture.getTrigger().completed(results); } } }