
net.yudichev.jiotty.common.lang.CompletableFutures Maven / Gradle / Ivy
package net.yudichev.jiotty.common.lang;
import com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collector;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
import static net.yudichev.jiotty.common.lang.DelayedExecutors.delayedExecutor;
@SuppressWarnings("WeakerAccess") // it's a library
public final class CompletableFutures {
private CompletableFutures() {
}
public static CompletableFuture completable(Future extends T> future) {
return CompletableFuture.supplyAsync(() -> {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
});
}
@SuppressWarnings("ZeroLengthArrayAllocation") // this is what we need
public static CompletableFuture allOf(ImmutableList> futures) {
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
}
public static CompletableFuture completedFuture() {
return CompletableFuture.completedFuture(null);
}
public static CompletableFuture delay(long millis) {
return CompletableFuture.runAsync(() -> {}, delayedExecutor(millis));
}
public static CompletableFuture failure(String message) {
return failure(new RuntimeException(message));
}
public static CompletableFuture failure(Throwable exception) {
CompletableFuture future = new CompletableFuture<>();
future.completeExceptionally(exception);
return future;
}
public static Collector, ?, CompletableFuture>> toFutureOfList() {
return Collector.of(
ImmutableList::>builder,
ImmutableList.Builder::add,
(builder1, builder2) ->
ImmutableList.>builder()
.addAll(builder1.build())
.addAll(builder2.build()),
builder -> {
ImmutableList> listOfFutures = builder.build();
//noinspection ZeroLengthArrayAllocation
return CompletableFuture.allOf(listOfFutures.toArray(new CompletableFuture[0]))
.thenApply(ignored -> unmodifiableList(listOfFutures.stream()
.map(CompletableFuture::join)
// cannot use ImmutableList here, void futures typically return nulls
.collect(toList())));
}
);
}
public static Collector>> toFutureOfListChaining(Function> operation) {
Object builderMutex = new Object();
return Collector., CompletableFuture>>of(
() -> new FutureChainBuilder<>(operation, builderMutex),
FutureChainBuilder::accept,
FutureChainBuilder::combinedWith,
FutureChainBuilder::build
);
}
public static BiConsumer logErrorOnFailure(Logger logger, String errorMessageTemplate, Object... params) {
return (aVoid, e) -> {
if (e != null) {
logger.error(String.format(errorMessageTemplate, params), e);
}
};
}
private static class FutureChainBuilder {
private final Function> operation;
private final Object mutex;
private CompletableFuture> future;
FutureChainBuilder(Function> operation, Object mutex) {
this.operation = checkNotNull(operation);
this.mutex = checkNotNull(mutex);
}
public FutureChainBuilder combinedWith(FutureChainBuilder another) {
if (future == null) {
return another;
} else if (another.future == null) {
return this;
} else {
FutureChainBuilder combinedBuilder = new FutureChainBuilder<>(operation, mutex);
combinedBuilder.future = future.thenCompose(list1 -> another.future.thenApply(list2 -> {
synchronized (mutex) {
list1.addAll(list2);
return list1;
}
}));
return combinedBuilder;
}
}
public void accept(T input) {
if (future == null) {
future = operation.apply(input)
.thenApply(result -> {
List list = new ArrayList<>();
list.add(result);
return list;
});
} else {
future = future.thenCompose(list ->
operation.apply(input)
.thenApply(result -> {
synchronized (mutex) {
list.add(result);
return list;
}
}));
}
}
public CompletableFuture> build() {
return future == null ? CompletableFuture.completedFuture(emptyList()) : future;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy