Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.quarkus.vertx.http.deployment.devmode.console.DevConsole Maven / Gradle / Ivy
package io.quarkus.vertx.http.deployment.devmode.console;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.function.BiFunction;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.quarkus.builder.Version;
import io.quarkus.devconsole.runtime.spi.FlashScopeUtil;
import io.quarkus.maven.dependency.GACTV;
import io.quarkus.qute.Engine;
import io.quarkus.qute.Template;
import io.quarkus.qute.TemplateInstance;
import io.smallrye.common.classloader.ClassPathUtils;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpHeaders;
import io.vertx.ext.web.RoutingContext;
/**
* This is a Handler running in the Dev Vert.x instance (which is loaded by the Augmentation ClassLoader)
* and has access to build time stuff
*/
public class DevConsole implements Handler {
private static final Logger log = Logger.getLogger(DevConsole.class);
private static final String HTML_CONTENT_TYPE = "text/html; charset=UTF-8";
static final ThreadLocal currentExtension = new ThreadLocal<>();
private static final Comparator> EXTENSION_COMPARATOR = Comparator
.comparing(m -> ((String) m.get("name")));
final Engine engine;
final Map> extensions = new HashMap<>();
final Map globalData = new HashMap<>();
final Config config = ConfigProvider.getConfig();
final String devRootAppend;
DevConsole(Engine engine, String httpRootPath, String frameworkRootPath) {
this.engine = engine;
// Both of these paths will end in slash
this.globalData.put("httpRootPath", httpRootPath);
this.globalData.put("frameworkRootPath", frameworkRootPath);
// This includes the dev segment, but does not include a trailing slash (for append)
this.devRootAppend = frameworkRootPath + "dev-v1";
this.globalData.put("devRootAppend", devRootAppend);
this.globalData.put("quarkusVersion", Version.getVersion());
this.globalData.put("applicationName", config.getOptionalValue("quarkus.application.name", String.class).orElse(""));
this.globalData.put("applicationVersion",
config.getOptionalValue("quarkus.application.version", String.class).orElse(""));
}
private void initLazyState() {
if (extensions.isEmpty()) {
synchronized (extensions) {
if (extensions.isEmpty()) {
try {
final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
ClassPathUtils.consumeAsPaths("/META-INF/quarkus-extension.yaml", p -> {
try {
final String desc;
try (Scanner scanner = new Scanner(Files.newBufferedReader(p, StandardCharsets.UTF_8))) {
scanner.useDelimiter("\\A");
desc = scanner.hasNext() ? scanner.next() : null;
}
if (desc == null) {
// should be an exception?
return;
}
final Map metadata = yaml.load(desc);
extensions.put(getExtensionNamespace(metadata), metadata);
} catch (IOException | RuntimeException e) {
// don't abort, just log, to prevent a single extension from breaking entire dev ui
log.error("Failed to process extension descriptor " + p.toUri(), e);
}
});
this.globalData.put("configKeyMap", getConfigKeyMap());
} catch (IOException x) {
throw new RuntimeException(x);
}
}
}
}
}
@Override
public void handle(RoutingContext ctx) {
initLazyState();
// Redirect /q/dev-v1 to /q/dev-v1/
if (ctx.normalizedPath().length() == devRootAppend.length()) {
ctx.response().setStatusCode(302);
ctx.response().headers().set(HttpHeaders.LOCATION, devRootAppend + "/");
ctx.response().end();
return;
}
String path = ctx.normalizedPath().substring(ctx.mountPoint().length() + 1);
if (path.isEmpty() || path.equals("/")) {
sendMainPage(ctx);
} else {
int nsIndex = path.indexOf("/");
if (nsIndex == -1) {
ctx.response().setStatusCode(404).end();
return;
}
String namespace = path.substring(0, nsIndex);
currentExtension.set(namespace);
Template devTemplate = engine.getTemplate(path);
if (devTemplate != null) {
String extName = getExtensionName(namespace);
ctx.response().setStatusCode(200).headers().set(HttpHeaderNames.CONTENT_TYPE, HTML_CONTENT_TYPE);
TemplateInstance devTemplateInstance = devTemplate
.data("currentExtensionName", extName)
.data("query-string", ctx.request().query())
.data("flash", FlashScopeUtil.getFlash(ctx))
.data("currentRequest", ctx.request());
renderTemplate(ctx, devTemplateInstance);
} else {
ctx.next();
}
}
}
private Map> getConfigKeyMap() {
Map> ckm = new TreeMap<>();
Collection> values = this.extensions.values();
for (Map extension : values) {
if (extension.containsKey("metadata")) {
Map metadata = (Map) extension.get("metadata");
if (metadata.containsKey("config")) {
List configKeys = (List) metadata.get("config");
String name = (String) extension.get("name");
ckm.put(name, configKeys);
}
}
}
return ckm;
}
private String getExtensionName(String namespace) {
Map map = extensions.get(namespace);
if (map == null)
return null;
return (String) map.get("name");
}
protected void renderTemplate(RoutingContext event, TemplateInstance template) {
// Add some global variables
for (Map.Entry global : globalData.entrySet()) {
template.data(global.getKey(), global.getValue());
}
template.renderAsync().handle(new BiFunction() {
@Override
public Object apply(String s, Throwable throwable) {
if (throwable != null) {
event.fail(throwable);
} else {
event.response().end(s);
}
return null;
}
});
}
private void sendMainPage(RoutingContext event) {
final Template devTemplate = engine.getTemplate("index");
if (devTemplate == null) {
throw new RuntimeException("Failed to locate the `index` template");
}
List> actionableExtensions = new ArrayList<>();
List> nonActionableExtensions = new ArrayList<>();
for (Entry> entry : this.extensions.entrySet()) {
final String namespace = entry.getKey();
final Map loaded = entry.getValue();
@SuppressWarnings("unchecked")
final Map metadata = (Map) loaded.get("metadata");
currentExtension.set(namespace); // needed because the template of the extension is going to be read
Template simpleTemplate = engine.getTemplate(namespace + "/embedded.html");
boolean hasConsoleEntry = simpleTemplate != null;
boolean hasGuide = metadata.containsKey("guide");
boolean hasConfig = metadata.containsKey("config");
boolean isUnlisted = metadata.containsKey("unlisted")
&& (metadata.get("unlisted").equals(true) || metadata.get("unlisted").equals("true"));
loaded.put("hasConsoleEntry", hasConsoleEntry);
loaded.put("hasGuide", hasGuide);
if (!isUnlisted || hasConsoleEntry || hasGuide || hasConfig) {
if (hasConsoleEntry) {
Map data = new HashMap<>();
data.putAll(globalData);
data.put("urlbase", namespace);
String result = simpleTemplate.render(data);
loaded.put("_dev", result);
actionableExtensions.add(loaded);
} else {
nonActionableExtensions.add(loaded);
}
}
}
actionableExtensions.sort(EXTENSION_COMPARATOR);
nonActionableExtensions.sort(EXTENSION_COMPARATOR);
TemplateInstance instance = devTemplate.data("actionableExtensions", actionableExtensions)
.data("nonActionableExtensions", nonActionableExtensions).data("flash", FlashScopeUtil.getFlash(event));
event.response().setStatusCode(200).headers().set(HttpHeaderNames.CONTENT_TYPE, HTML_CONTENT_TYPE);
renderTemplate(event, instance);
}
private static String getExtensionNamespace(Map metadata) {
final String groupId;
final String artifactId;
final String artifact = (String) metadata.get("artifact");
if (artifact == null) {
// trying quarkus 1.x format
groupId = (String) metadata.get("group-id");
artifactId = (String) metadata.get("artifact-id");
if (artifactId == null || groupId == null) {
throw new RuntimeException(
"Failed to locate 'artifact' or 'group-id' and 'artifact-id' among metadata keys " + metadata.keySet());
}
} else {
final GACTV coords = GACTV.fromString(artifact);
groupId = coords.getGroupId();
artifactId = coords.getArtifactId();
}
return groupId + "." + artifactId;
}
}