// Generated by delombok at Sun Sep 08 08:37:39 UTC 2019
package org.testcontainers.lifecycle;
import java.util.
Collection;
import java.util.
HashMap;
import java.util.
Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.
AtomicLong;
import java.util.stream.
Stream;
public final class
Startables {
private static final
Executor EXECUTOR =
Executors.
newCachedThreadPool(new
ThreadFactory() {
private final
AtomicLong COUNTER = new
AtomicLong(0);
@
Override
public
Thread newThread(
Runnable r) {
Thread thread = new
Thread(
r, "testcontainers-lifecycle-" +
COUNTER.
getAndIncrement());
thread.
setDaemon(true);
return
thread;
}
});
/**
* @see #deepStart(Stream)
*/
public static
CompletableFuture<
Void>
deepStart(
Collection<
Startable>
startables) {
return
deepStart(
startables.
stream());
}
/**
* Start every {@link Startable} recursively and asynchronously and join on the result.
*
* Performance note:
* The method uses and returns {@link CompletableFuture}s to resolve as many {@link Startable}s at once as possible.
* This way, for the following graph:
* / b \
* a e
* c /
* d /
* "a", "c" and "d" will resolve in parallel, then "b".
*
* If we would call blocking {@link Startable#start()}, "e" would wait for "b", "b" for "a", and only then "c", and then "d".
* But, since "c" and "d" are independent from "a", there is no point in waiting for "a" to be resolved first.
*
* @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies.
* @return a {@link CompletableFuture} that resolves once all {@link Startable}s have started.
*/
public static
CompletableFuture<
Void>
deepStart(
Stream<
Startable>
startables) {
return
deepStart(new
HashMap<>(),
startables);
}
/**
* @param started an intermediate storage for already started {@link Startable}s to prevent multiple starts.
* @param startables a {@link Stream} of {@link Startable}s to start and scan for transitive dependencies.
*/
private static
CompletableFuture<
Void>
deepStart(
Map<
Startable,
CompletableFuture<
Void>>
started,
Stream<
Startable>
startables) {
CompletableFuture[]
futures =
// avoid a recursive update in `computeIfAbsent`
startables.
map(
it -> {
Map<
Startable,
CompletableFuture<
Void>>
subStarted = new
HashMap<>(
started);
CompletableFuture<
Void>
future =
started.
computeIfAbsent(
it,
startable -> {
return
deepStart(
subStarted,
startable.
getDependencies().
stream()).
thenRunAsync(
startable::start,
EXECUTOR);
});
started.
putAll(
subStarted);
return
future;
}).
toArray(
CompletableFuture[]::new);
return
CompletableFuture.
allOf(
futures);
}
@java.lang.
SuppressWarnings("all")
private
Startables() {
throw new java.lang.
UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}