package io.vertx.config.spi.utils;
import io.vertx.config.spi.ConfigProcessor;
import io.vertx.core.*;
import io.vertx.core.impl.launcher.commands.FileSelector;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.RejectedExecutionException;
public class FileSet {
private final static Logger LOGGER = LoggerFactory.getLogger(FileSet.class);
private final String pattern;
private final ConfigProcessor processor;
private final File root;
private final Vertx vertx;
private final Boolean rawData;
public FileSet(Vertx vertx, File root, JsonObject set) {
this.vertx = vertx;
this.root = root;
this.pattern = set.getString("pattern");
if (this.pattern == null) {
throw new IllegalArgumentException("Each file set needs to contain a `pattern`");
}
this.rawData = set.getBoolean("raw-data", false);
String format = set.getString("format", "json");
this.processor = Processors.get(format);
if (this.processor == null) {
throw new IllegalArgumentException("Unknown configuration format `" + format + "`, supported types are " +
Processors.getSupportedFormats());
}
}
private boolean matches(String path) {
return FileSelector.match(pattern, path, false);
}
public void buildConfiguration(List<File> files, Handler<AsyncResult<JsonObject>> handler) {
List<Future> futures = new ArrayList<>();
files.stream()
.map(file -> {
String relative = null;
if (file.getAbsolutePath().startsWith(root.getAbsolutePath())) {
relative = file.getAbsolutePath().substring(root.getAbsolutePath().length() + 1);
}
if (relative == null) {
LOGGER.warn("The file `" + file.getAbsolutePath() + "` is not in '" + root
.getAbsolutePath() + "'");
}
return relative;
})
.filter(Objects::nonNull)
.filter(this::matches)
.map(s -> new File(root, s))
.forEach(file -> {
Promise<JsonObject> promise = Promise.promise();
futures.add(promise.future());
try {
vertx.fileSystem().readFile(file.getAbsolutePath(),
buffer -> {
if (buffer.failed()) {
promise.fail(buffer.cause());
} else {
processor.process(vertx, new JsonObject().put("raw-data", rawData), buffer.result(), promise);
}
});
} catch (RejectedExecutionException e) {
promise.fail(e);
}
});
CompositeFuture.all(futures).setHandler(ar -> {
if (ar.failed()) {
handler.handle(Future.failedFuture(ar.cause()));
} else {
JsonObject result = new JsonObject();
futures.stream()
.map(future -> (JsonObject) future.result())
.forEach(result::mergeIn);
handler.handle(Future.succeededFuture(result));
}
});
}
public static List<File> traverse(File root) {
List<File> files = new ArrayList<>();
if (!root.isDirectory()) {
return files;
} else {
File[] children = root.listFiles();
if (children == null) {
return files;
} else {
for (File file : children) {
if (file.isDirectory()) {
files.addAll(traverse(file));
} else {
files.add(file);
}
}
}
return files;
}
}
}