io.quarkus.runtime.TemplateHtmlBuilder Maven / Gradle / Ivy
The newest version!
package io.quarkus.runtime;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
import io.quarkus.dev.config.CurrentConfig;
import io.quarkus.runtime.logging.DecorateStackUtil;
import io.quarkus.runtime.util.ExceptionUtil;
public class TemplateHtmlBuilder {
private static String CSS = null;
private static final String SCRIPT_STACKTRACE_MANIPULATION = """
""";
private static final String UTILITIES = """
Change view mode
Copy stacktrace to clipboard
""";
private static final String HTML_TEMPLATE_START_NO_STACK = "" +
"\n" +
"\n" +
"\n" +
" %1$s%2$s \n" +
" \n" +
"";
private static final String HTML_TEMPLATE_START = "" +
"\n" +
"\n" +
"\n" +
" %1$s%2$s \n" +
" \n" +
" \n" +
SCRIPT_STACKTRACE_MANIPULATION +
"\n" +
"\n" +
"\n" +
" \n" +
" ";
private static final String HTML_TEMPLATE_END = "
\n";
private static final String HEADER_TEMPLATE_NO_STACK = "
%1$s
\n" + "%2$s \n" + "\n";
private static final String RESOURCES_START = "
");
}
result.append(UTILITIES);
result.append(String.format(ORIGINAL_STACK_TRACE, original));
result.append(String.format(ERROR_STACK_REVERSED, rootFirst));
result.append(STACKTRACE_DISPLAY_DIV);
throwable.setStackTrace(originalStackTrace);
}
return this;
}
public TemplateHtmlBuilder resourcesStart(String title) {
result.append(String.format(RESOURCES_START, title));
return this;
}
public TemplateHtmlBuilder resourcesEnd() {
result.append(RESOURCES_END);
return this;
}
public TemplateHtmlBuilder noResourcesFound() {
result.append(String.format(RESOURCE_TEMPLATE, "No resources discovered"));
return this;
}
public TemplateHtmlBuilder resourcePath(String title) {
return resourcePath(title, true, false, null);
}
public TemplateHtmlBuilder staticResourcePath(String title) {
return staticResourcePath(title, null);
}
public TemplateHtmlBuilder staticResourcePath(String title, String description) {
return resourcePath(title, false, true, description);
}
public TemplateHtmlBuilder servletMapping(String title) {
return resourcePath(title, false, true, null);
}
private TemplateHtmlBuilder resourcePath(String title, boolean withListStart, boolean withAnchor, String description) {
String content;
if (withAnchor) {
String text = title;
if (title.startsWith("/")) {
title = title.substring(1);
}
if (!title.startsWith("http") && baseUrl != null) {
title = baseUrl + title;
}
if (title.startsWith("http")) {
int firstSlashIndex = title.indexOf("/", title.indexOf("//") + 2);
text = title.substring(firstSlashIndex);
}
content = String.format(ANCHOR_TEMPLATE_ABSOLUTE, title, escapeHtml(text));
} else {
content = escapeHtml(title);
}
if (description != null && !description.isEmpty()) {
content = String.format(DESCRIPTION_TEMPLATE, content, description);
}
result.append(String.format(RESOURCE_TEMPLATE, content));
if (withListStart) {
result.append(LIST_START);
}
return this;
}
public TemplateHtmlBuilder method(String method, String fullPath) {
fullPath = escapeHtml(fullPath);
if (method.equalsIgnoreCase("GET")) {
if (baseUrl != null) {
fullPath = "" + fullPath + "";
} else {
fullPath = "" + fullPath + "";
}
}
result.append(String.format(METHOD_START, escapeHtml(method), fullPath));
return this;
}
public TemplateHtmlBuilder consumes(String consumes) {
result.append(String.format(METHOD_IO, "Consumes", escapeHtml(consumes)));
return this;
}
public TemplateHtmlBuilder produces(String produces) {
result.append(String.format(METHOD_IO, "Produces", escapeHtml(produces)));
return this;
}
public TemplateHtmlBuilder listItem(String content) {
result.append(String.format(LIST_ITEM, escapeHtml(content)));
return this;
}
public TemplateHtmlBuilder methodEnd() {
result.append(METHOD_END);
return this;
}
public TemplateHtmlBuilder resourceStart() {
result.append(LIST_START);
return this;
}
public TemplateHtmlBuilder resourceEnd() {
result.append(LIST_END);
return this;
}
public TemplateHtmlBuilder append(String html) {
result.append(html);
return this;
}
@Override
public String toString() {
return result.append(HTML_TEMPLATE_END).toString();
}
private static String escapeHtml(final String bodyText) {
if (bodyText == null) {
return "";
}
return bodyText
.replace("&", "&")
.replace("<", "<")
.replace(">", ">");
}
public static String adjustRoot(String httpRoot, String basePath) {
//httpRoot can optionally end with a slash
//also some templates want the returned path to start with a / and some don't
//to make this work we check if the basePath starts with a / or not, and make sure we
//return the value that follows the same pattern
if (httpRoot.equals("/")) {
//leave it alone
return basePath;
}
if (basePath.startsWith("/")) {
if (!httpRoot.endsWith("/")) {
return httpRoot + basePath;
}
return httpRoot.substring(0, httpRoot.length() - 1) + basePath;
}
if (httpRoot.endsWith("/")) {
return httpRoot.substring(1) + basePath;
}
return httpRoot.substring(1) + "/" + basePath;
}
public void loadCssFile() {
if (CSS == null) {
ClassLoader classLoader = getClass().getClassLoader();
String cssFilePath = "META-INF/template-html-builder.css";
try (InputStream inputStream = classLoader.getResourceAsStream(cssFilePath)) {
if (inputStream != null) {
// Use a Scanner to read the contents of the CSS file
try (Scanner scanner = new Scanner(inputStream, "UTF-8")) {
StringBuilder stringBuilder = new StringBuilder();
while (scanner.hasNextLine()) {
stringBuilder.append(scanner.nextLine()).append("\n");
}
CSS = stringBuilder.toString();
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
private String buildLink(String name, String url) {
return "" + name + "";
}
}
%1$s
";
private static final String ANCHOR_TEMPLATE_ABSOLUTE = "%2$s";
private static final String DESCRIPTION_TEMPLATE = "%1$s — %2$s";
private static final String RESOURCE_TEMPLATE = "
";
private static final String STACKTRACE_DISPLAY_DIV = "";
private static final String BRSTI = "___begin_relative_stack_trace_item___";
private static final String ERSTI = "___end_relative_stack_trace_item___";
private static final String OPEN_IDE_LINK = "%1$s
\n"; private static final String LIST_START = "- \n";
private static final String METHOD_START = "
- %1$s %2$s\n"
+ "
- \n";
private static final String METHOD_IO = "
- %1$s: %2$s \n"; private static final String LIST_ITEM = "
- %s \n"; private static final String METHOD_END = "
";
private static final String LIST_END = "
";
private static final String ORIGINAL_STACK_TRACE = " actions) {
this(showStack, null, title, subTitle, details, actions, null, Collections.emptyList());
}
public TemplateHtmlBuilder(String title, String subTitle, String details,
List actions) {
this(true, null, title, subTitle, details, actions, null, Collections.emptyList());
}
public TemplateHtmlBuilder(String baseUrl, String title, String subTitle, String details,
List actions) {
this(true, baseUrl, title, subTitle, details, actions, null, Collections.emptyList());
}
public TemplateHtmlBuilder(String title, String subTitle, String details, List actions,
String redirect,
List config) {
this(true, null, title, subTitle, details, actions, redirect, config);
}
public TemplateHtmlBuilder(boolean showStack, String baseUrl, String title, String subTitle, String details,
List actions,
String redirect,
List config) {
this.baseUrl = baseUrl;
StringBuilder actionLinks = new StringBuilder();
if (showStack) {
loadCssFile();
for (ErrorPageAction epa : actions) {
actionLinks.append(buildLink(epa.name(), epa.url()));
}
result = new StringBuilder(String.format(HTML_TEMPLATE_START, escapeHtml(title),
subTitle == null || subTitle.isEmpty() ? "" : " - " + escapeHtml(subTitle), CSS));
result.append(String.format(HEADER_TEMPLATE, escapeHtml(title), escapeHtml(details), actionLinks.toString()));
} else {
result = new StringBuilder(String.format(HTML_TEMPLATE_START_NO_STACK, escapeHtml(title),
subTitle == null || subTitle.isEmpty() ? "" : " - " + escapeHtml(subTitle), CSS));
result.append(
String.format(HEADER_TEMPLATE_NO_STACK, escapeHtml(title), escapeHtml(details), actionLinks.toString()));
}
if (!config.isEmpty()) {
result.append(String.format(CONFIG_EDITOR_HEAD, redirect));
for (CurrentConfig i : config) {
result.append(String.format(CONFIG_EDITOR_ROW, escapeHtml(i.getPropertyName()), escapeHtml(i.getPropertyName()),
escapeHtml(i.getCurrentValue())));
}
result.append(CONFIG_EDITOR_TAIL);
}
}
public TemplateHtmlBuilder decorate(final Throwable throwable, String srcMainJava, List knowClasses) {
String decoratedString = DecorateStackUtil.getDecoratedString(throwable, srcMainJava, knowClasses);
if (decoratedString != null) {
result.append(String.format(DECORATE_DIV, decoratedString));
}
return this;
}
public TemplateHtmlBuilder stack(final Throwable throwable) {
return stack(throwable, List.of());
}
public TemplateHtmlBuilder stack(final Throwable throwable, List knowClasses) {
if (knowClasses != null && throwable != null) {
StackTraceElement[] originalStackTrace = Arrays.copyOf(throwable.getStackTrace(), throwable.getStackTrace().length);
StackTraceElement[] stackTrace = throwable.getStackTrace();
String className = "";
String type = "java"; //default
int lineNumber = 0;
if (!knowClasses.isEmpty()) {
for (int i = 0; i < stackTrace.length; ++i) {
var elem = stackTrace[i];
if (knowClasses.contains(elem.getClassName())) {
className = elem.getClassName();
String filename = elem.getFileName();
if (filename != null) {
int dotindex = filename.lastIndexOf(".");
type = elem.getFileName().substring(dotindex + 1);
}
lineNumber = elem.getLineNumber();
stackTrace[i] = new StackTraceElement(elem.getClassLoaderName(), elem.getModuleName(),
elem.getModuleVersion(),
BRSTI + elem.getClassName()
+ ERSTI,
elem.getMethodName(), elem.getFileName(), elem.getLineNumber());
}
}
}
throwable.setStackTrace(stackTrace);
String original = escapeHtml(ExceptionUtil.generateStackTrace(throwable));
String rootFirst = escapeHtml(ExceptionUtil.rootCauseFirstStackTrace(throwable));
if (original.contains(BRSTI)) {
original = original.replace(BRSTI,
String.format(OPEN_IDE_LINK, className, type, lineNumber));
original = original.replace(ERSTI, "
");
rootFirst = rootFirst.replace(BRSTI,
String.format(OPEN_IDE_LINK, className, type, lineNumber));
rootFirst = rootFirst.replace(ERSTI, "\n" +
"
\n";
private static final String ERROR_STACK_REVERSED = " The stacktrace below is the original. " + "See the stacktrace in reversed order (root-cause first)
" + "%1$s
\n" +
" \n" +
"
\n";
private static final String DECORATE_DIV = "The stacktrace below has been reversed to show the root cause first. " + "See the original stacktrace
" + "%1$s
\n" +
" %s"; private static final String CONFIG_EDITOR_HEAD = "
The following incorrect config values were detected:
" + ""; private StringBuilder result; private String baseUrl; public TemplateHtmlBuilder(String title, String subTitle, String details) { this(true, null, title, subTitle, details, Collections.emptyList(), null, Collections.emptyList()); } public TemplateHtmlBuilder(boolean showStack, String title, String subTitle, String details, List© 2015 - 2025 Weber Informatics LLC | Privacy Policy