package io.vertx.ext.healthchecks.impl;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.healthchecks.HealthChecks;
import io.vertx.ext.healthchecks.CheckResult;
import io.vertx.ext.healthchecks.Status;
import java.util.Objects;
public class HealthChecksImpl implements HealthChecks {
private final Vertx vertx;
private CompositeProcedure root = new DefaultCompositeProcedure();
public HealthChecksImpl(Vertx vertx) {
this.vertx = Objects.requireNonNull(vertx);
}
@Override
public HealthChecks register(String name, Handler<Promise<Status>> procedure) {
return register(name, 1000L, procedure);
}
@Override
public HealthChecks register(String name, long timeout, Handler<Promise<Status>> procedure) {
Objects.requireNonNull(name);
if (timeout <= 0) {
throw new IllegalArgumentException("The timeout must be strictly positive");
}
if (name.isEmpty()) {
throw new IllegalArgumentException("The name must not be empty");
}
Objects.requireNonNull(procedure);
String[] segments = name.split("/");
CompositeProcedure parent = traverseAndCreate(segments);
String lastSegment = segments[segments.length - 1];
parent.add(lastSegment,
new DefaultProcedure(vertx, lastSegment, timeout, procedure));
return this;
}
private CompositeProcedure traverseAndCreate(String[] segments) {
int i;
CompositeProcedure parent = root;
for (i = 0; i < segments.length - 1; i++) {
Procedure c = parent.get(segments[i]);
if (c == null) {
DefaultCompositeProcedure composite = new DefaultCompositeProcedure();
parent.add(segments[i], composite);
parent = composite;
} else if (c instanceof CompositeProcedure) {
parent = (CompositeProcedure) c;
} else {
throw new IllegalArgumentException("Unable to find the procedure `" + segments[i] + "`, `"
+ segments[i] + "` is not a composite.");
}
}
return parent;
}
@Override
public HealthChecks unregister(String name) {
Objects.requireNonNull(name);
if (name.isEmpty()) {
throw new IllegalArgumentException("The name must not be empty");
}
String[] segments = name.split("/");
CompositeProcedure parent = findLastParent(segments);
if (parent != null) {
String lastSegment = segments[segments.length - 1];
parent.remove(lastSegment);
}
return this;
}
@Override
public HealthChecks invoke(Handler<JsonObject> resultHandler) {
checkStatus(ar -> resultHandler.handle(ar.result().toJson()));
return this;
}
@Override
public HealthChecks invoke(String name, Handler<AsyncResult<JsonObject>> resultHandler) {
checkStatus(name, ar -> resultHandler.handle(ar.map(CheckResult::toJson)));
return this;
}
@Override
public Future<JsonObject> invoke(String name) {
return checkStatus(name).map(CheckResult::toJson);
}
@Override
public Future<CheckResult> checkStatus() {
Promise<CheckResult> promise = ((ContextInternal)vertx.getOrCreateContext()).promise();
checkStatus(promise);
return promise.future();
}
@Override
public void checkStatus(Handler<AsyncResult<CheckResult>> resultHandler) {
Promise<CheckResult> promise = ((ContextInternal)vertx.getOrCreateContext()).promise(resultHandler);
compute(root, promise);
}
@Override
public Future<CheckResult> checkStatus(String name) {
Promise<CheckResult> promise = ((ContextInternal)vertx.getOrCreateContext()).promise();
checkStatus(name, promise);
return promise.future();
}
@Override
public void checkStatus(String name, Handler<AsyncResult<CheckResult>> resultHandler) {
Promise<CheckResult> promise = ((ContextInternal)vertx.getOrCreateContext()).promise(resultHandler);
if (name == null || name.isEmpty() || name.equals("/")) {
checkStatus(promise);
} else {
String[] segments = name.split("/");
Procedure check = root;
for (String segment : segments) {
if (segment.trim().isEmpty()) {
continue;
}
if (check instanceof CompositeProcedure) {
check = ((CompositeProcedure) check).get(segment);
if (check == null) {
promise.fail("Not found");
return;
}
} else {
promise.fail("'" + segment + "' is not a composite");
return;
}
}
if (check == null) {
promise.handle(null);
return;
}
compute(check, promise);
}
}
private CompositeProcedure findLastParent(String[] segments) {
int i;
CompositeProcedure parent = root;
for (i = 0; i < segments.length - 1; i++) {
Procedure c = parent.get(segments[i]);
if (c instanceof CompositeProcedure) {
parent = (CompositeProcedure) c;
} else {
return null;
}
}
return parent;
}
private void compute(Procedure procedure, Promise<CheckResult> resultHandler) {
procedure.check(resultHandler::complete);
}
}