org.apache.james.util.CompletableFutureUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.james.util.CompletableFutureUtil.java

Source

/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you 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 org.apache.james.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import com.google.common.collect.ImmutableList;

public class CompletableFutureUtil {

    public static <T> CompletableFuture<Optional<T>> unwrap(
            CompletableFuture<Optional<CompletableFuture<T>>> base) {
        return base.thenCompose(optional -> optional.map(future -> future.thenApply(Optional::of))
                .orElse(CompletableFuture.completedFuture(Optional.empty())));
    }

    @SuppressWarnings("unchecked")
    public static <T> CompletableFuture<Stream<T>> allOf(Stream<CompletableFuture<T>> futureStream) {
        CompletableFuture<T>[] arrayOfFutures = futureStream.toArray(CompletableFuture[]::new);

        return CompletableFuture.allOf(arrayOfFutures)
                .thenApply(any -> Arrays.stream(arrayOfFutures).map(CompletableFuture::join));
    }

    public static <R, T> CompletableFuture<Stream<R>> chainAll(Stream<T> futureStream,
            Function<T, CompletableFuture<R>> transformationToChain) {
        ImmutableList<T> elements = futureStream.collect(ImmutableList.toImmutableList());
        ArrayList<R> results = new ArrayList<>(elements.size());

        CompletableFuture<Void> futureEmptyStream = CompletableFuture.completedFuture(null);

        BiFunction<CompletableFuture<?>, Supplier<CompletableFuture<R>>, CompletableFuture<?>> accumulator = (
                future, supplier) -> future.thenCompose(any -> supplier.get().thenAccept(results::add));

        BinaryOperator<CompletableFuture<?>> combiner = (f1, f2) -> f1.thenCompose(any -> f2);

        return elements.stream().map(t -> (Supplier<CompletableFuture<R>>) (() -> transformationToChain.apply(t)))
                .reduce(futureEmptyStream, accumulator, combiner).thenApply(any -> results.stream());
    }

    public static <T, U> CompletableFuture<Stream<U>> map(CompletableFuture<Stream<T>> futurStream,
            Function<T, U> action) {
        return futurStream.thenApply(stream -> stream.map(action));
    }

    public static <T> CompletableFuture<Optional<T>> reduce(BinaryOperator<T> binaryOperator,
            CompletableFuture<Stream<T>> futureStream) {
        return futureStream.thenApply(stream -> stream.reduce(binaryOperator));
    }

    public static <T> CompletableFuture<T> reduce(BinaryOperator<T> binaryOperator,
            CompletableFuture<Stream<T>> futureStream, T emptyAccumulator) {
        return futureStream.thenApply(stream -> stream.reduce(binaryOperator).orElse(emptyAccumulator));
    }

    public static <T> Function<Boolean, CompletableFuture<Boolean>> composeIfTrue(
            Supplier<CompletableFuture<T>> composeOperation) {
        return b -> {
            if (b) {
                return composeOperation.get().thenApply(any -> b);
            }
            return CompletableFuture.completedFuture(b);
        };
    }

    public static <T> CompletableFuture<Stream<T>> sorted(CompletableFuture<Stream<T>> futureStream,
            Comparator<T> comparator) {
        return futureStream.thenApply(stream -> stream.sorted(comparator));
    }

    public static <T> CompletableFuture<T> exceptionallyFuture(Throwable throwable) {
        CompletableFuture<T> failedFuture = new CompletableFuture<>();
        failedFuture.completeExceptionally(throwable);
        return failedFuture;
    }
}