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

graphql.execution.Async Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.execution;

import graphql.Assert;
import graphql.Internal;
import graphql.collect.ImmutableKit;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

@Internal
@SuppressWarnings("FutureReturnValueIgnored")
public class Async {

    @FunctionalInterface
    public interface CFFactory {
        CompletableFuture apply(T input, int index, List previousResults);
    }

    public static  CompletableFuture> each(List> futures) {
        CompletableFuture> overallResult = new CompletableFuture<>();

        @SuppressWarnings("unchecked")
        CompletableFuture[] arrayOfFutures = futures.toArray(new CompletableFuture[0]);
        CompletableFuture
                .allOf(arrayOfFutures)
                .whenComplete((ignored, exception) -> {
                    if (exception != null) {
                        overallResult.completeExceptionally(exception);
                        return;
                    }
                    List results = new ArrayList<>(arrayOfFutures.length);
                    for (CompletableFuture future : arrayOfFutures) {
                        results.add(future.join());
                    }
                    overallResult.complete(results);
                });
        return overallResult;
    }

    public static  CompletableFuture> each(Collection list, BiFunction> cfFactory) {
        List> futures = new ArrayList<>(list.size());
        int index = 0;
        for (T t : list) {
            CompletableFuture cf;
            try {
                cf = cfFactory.apply(t, index++);
                Assert.assertNotNull(cf, () -> "cfFactory must return a non null value");
            } catch (Exception e) {
                cf = new CompletableFuture<>();
                // Async.each makes sure that it is not a CompletionException inside a CompletionException
                cf.completeExceptionally(new CompletionException(e));
            }
            futures.add(cf);
        }
        return each(futures);

    }

    public static  CompletableFuture> eachSequentially(Iterable list, CFFactory cfFactory) {
        CompletableFuture> result = new CompletableFuture<>();
        eachSequentiallyImpl(list.iterator(), cfFactory, 0, new ArrayList<>(), result);
        return result;
    }

    private static  void eachSequentiallyImpl(Iterator iterator, CFFactory cfFactory, int index, List tmpResult, CompletableFuture> overallResult) {
        if (!iterator.hasNext()) {
            overallResult.complete(tmpResult);
            return;
        }
        CompletableFuture cf;
        try {
            cf = cfFactory.apply(iterator.next(), index, tmpResult);
            Assert.assertNotNull(cf, () -> "cfFactory must return a non null value");
        } catch (Exception e) {
            cf = new CompletableFuture<>();
            cf.completeExceptionally(new CompletionException(e));
        }
        cf.whenComplete((cfResult, exception) -> {
            if (exception != null) {
                overallResult.completeExceptionally(exception);
                return;
            }
            tmpResult.add(cfResult);
            eachSequentiallyImpl(iterator, cfFactory, index + 1, tmpResult, overallResult);
        });
    }


    /**
     * Turns an object T into a CompletableFuture if its not already
     *
     * @param t   - the object to check
     * @param  for two
     * @return a CompletableFuture
     */
    public static  CompletableFuture toCompletableFuture(T t) {
        if (t instanceof CompletionStage) {
            //noinspection unchecked
            return ((CompletionStage) t).toCompletableFuture();
        } else {
            return CompletableFuture.completedFuture(t);
        }
    }

    public static  CompletableFuture tryCatch(Supplier> supplier) {
        try {
            return supplier.get();
        } catch (Exception e) {
            CompletableFuture result = new CompletableFuture<>();
            result.completeExceptionally(e);
            return result;
        }
    }

    public static  CompletableFuture exceptionallyCompletedFuture(Throwable exception) {
        CompletableFuture result = new CompletableFuture<>();
        result.completeExceptionally(exception);
        return result;
    }

    public static  CompletableFuture> flatMap(List inputs, Function> mapper) {
        List> collect = ImmutableKit.map(inputs, mapper);
        return Async.each(collect);
    }

    public static  CompletableFuture> map(CompletableFuture> values, Function mapper) {
        return values.thenApply(list -> ImmutableKit.map(list, mapper));
    }

    public static  List> map(List> values, Function mapper) {
        return ImmutableKit.map(values, cf -> cf.thenApply(mapper));
    }

    public static  List> mapCompose(List> values, Function> mapper) {
        return ImmutableKit.map(values, cf -> cf.thenCompose(mapper));
    }

}