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

com.commercetools.sync.commons.utils.CompletableFutureUtils Maven / Gradle / Ivy

package com.commercetools.sync.commons.utils;

import static java.util.stream.Collectors.toList;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;
import javax.annotation.Nonnull;

public final class CompletableFutureUtils {

  /**
   * Creates a Future containing a collection of value results after the mapper function is applied
   * to each value in the supplied collection and completed it. The type of the returned collection
   * is decided by the supplied collector.
   *
   * @param values collection of values to apply a mapper function that would map each to a {@link
   *     java.util.concurrent.CompletionStage}.
   * @param mapper function to map each value to a {@link java.util.concurrent.CompletionStage}
   * @param collector the collector to define the type of the collection returned.
   * @param  The type of the values.
   * @param  The type of the mapped completed values.
   * @param  The type of the collection returned in the future.
   * @return a future containing a collection of completed stage results of the values after the
   *     mapper function was applied to each value in the supplied collection.
   */
  @Nonnull
  public static >
      CompletableFuture mapValuesToFutureOfCompletedValues(
          @Nonnull final Collection values,
          @Nonnull final Function> mapper,
          @Nonnull final Collector collector) {

    return mapValuesToFutureOfCompletedValues(values.stream(), mapper, collector);
  }

  /**
   * Creates a Future containing a collection of value results after the mapper function is applied
   * to each value in the supplied stream and completed it. The type of the returned collection is
   * decided by the supplied collector.
   *
   * @param values stream of values to apply a mapper function that would map each to a {@link
   *     java.util.concurrent.CompletionStage}.
   * @param mapper function to map each value to a {@link java.util.concurrent.CompletionStage}
   * @param collector the collector to define the type of the collection returned.
   * @param  The type of the values.
   * @param  The type of the mapping of the values.
   * @param  The type of the collection returned in the future.
   * @return a future containing a list of completed stage results of the values after the mapper
   *     function was applied to each one.
   */
  @Nonnull
  private static >
      CompletableFuture mapValuesToFutureOfCompletedValues(
          @Nonnull final Stream values,
          @Nonnull final Function> mapper,
          @Nonnull final Collector collector) {

    final List> futureList = mapValuesToFutures(values, mapper, toList());
    return collectionOfFuturesToFutureOfCollection(futureList, collector);
  }

  /**
   * Transforms a collection of {@code CompletionStage} into a {@code CompletionStage} of a
   * collection, that will be completed once all the elements of the given futures are completed. In
   * case multiple stages end exceptionally only one error is kept. The type of the returned
   * collection is decided by the supplied collector.
   *
   * 

Note: Null futures in the collection are filtered out. * * @param futures collection of {@code CompletionStage} * @param collector the collector to define the type of the collection returned. * @param the element obtained from the set of {@code CompletionStage} * @param The type of the collection returned in the future. * @return the {@code CompletableFuture} of a collection of elements */ @Nonnull public static > CompletableFuture collectionOfFuturesToFutureOfCollection( @Nonnull final Collection> futures, @Nonnull final Collector collector) { final List> futureList = futures.stream() .filter(Objects::nonNull) .map(CompletionStage::toCompletableFuture) .collect(toList()); final CompletableFuture[] futuresAsArray = futureList.toArray(new CompletableFuture[futureList.size()]); return CompletableFuture.allOf(futuresAsArray) .thenApply( ignoredResult -> futureList.stream() .map(CompletableFuture::join) .filter(Objects::nonNull) .collect(collector)); } /** * Maps a stream of values to a future collection using the supplied mapper function. The type of * the returned collection is decided by the supplied collector. * * @param values stream of values to apply a mapper function that would map each to a {@link * java.util.concurrent.CompletionStage}. * @param mapper function to map each value to a {@link java.util.concurrent.CompletionStage} * @param collector the collector to define the type of the collection returned. * @param The type of the values. * @param The type of the mapped values. * @param The type of the collection returned. * @return a collection of futures resulting from applying the mapper function on each value. */ @Nonnull private static >> U mapValuesToFutures( @Nonnull final Stream values, @Nonnull final Function> mapper, @Nonnull final Collector, ?, U> collector) { final Stream> stageStream = StreamUtils.filterNullAndMap(values, mapper); return toCompletableFutures(stageStream, collector); } /** * Converts a stream of {@link java.util.concurrent.CompletionStage} of values of type {@code } * into a {@link java.util.Collection} of the type of the supplied {@code collector} of {@link * java.util.concurrent.CompletableFuture} of values of type {@code }. The type of the returned * collection is decided by the supplied collector. * *

Note: Null futures in the stream are filtered out. * * @param values stream of {@link java.util.concurrent.CompletionStage} of values of type {@code * } * @param collector the collector to define the type of the collection returned. * @param the type of the results of the stages. * @param the concrete type of the collection returned. * @return a {@link java.util.List} of {@link java.util.concurrent.CompletableFuture} elements of * type {@code }. */ @Nonnull private static >> S toCompletableFutures( @Nonnull final Stream> values, @Nonnull final Collector, ?, S> collector) { return values .filter(Objects::nonNull) .map(CompletionStage::toCompletableFuture) .collect(collector); } private CompletableFutureUtils() {} }