package io.vertx.core.impl;
import io.vertx.core.AsyncResult;
import io.vertx.core.Closeable;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.impl.logging.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class CloseHooks {
private final Logger log;
private boolean closeHooksRun;
private Map<Closeable, CloseHooks> closeHooks;
CloseHooks(Logger log) {
this.log = log;
this.closeHooks = new WeakHashMap<>();
}
public synchronized void add(Closeable hook) {
if (closeHooks == null) {
throw new IllegalStateException();
}
if (hook instanceof CloseFuture) {
CloseFuture fut = (CloseFuture) hook;
fut.onComplete(ar -> remove(fut));
}
closeHooks.put(hook, this);
}
public synchronized void remove(Closeable hook) {
if (closeHooks != null) {
closeHooks.remove(hook);
}
}
void run(Handler<AsyncResult<Void>> completionHandler) {
Map<Closeable, CloseHooks> copy;
synchronized (this) {
if (closeHooksRun) {
throw new IllegalStateException("Close hooks already run");
}
closeHooksRun = true;
copy = closeHooks;
closeHooks = null;
}
List<Closeable> list = new ArrayList<>(copy.keySet());
int num = list.size();
if (num > 0) {
AtomicInteger count = new AtomicInteger();
for (Closeable hook : list) {
Promise<Void> promise = Promise.promise();
promise.future().onComplete(ar -> {
if (count.incrementAndGet() == num) {
completionHandler.handle(Future.succeededFuture());
}
});
try {
hook.close(promise);
} catch (Throwable t) {
log.warn("Failed to run close hook", t);
promise.tryFail(t);
}
}
} else {
completionHandler.handle(Future.succeededFuture());
}
}
}