All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.runtime.TemplateHtmlBuilder Maven / Gradle / Ivy

There is a newer version: 3.17.5
Show 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 = "\n";

    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" + " \n" + " \n" + " \n" + " quarkus_logo_horizontal_rgb_1280px_reverse\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
"; private static final String HTML_TEMPLATE_END = "
\n" + "\n"; private static final String HEADER_TEMPLATE = "
\n" + "
%1$s
\n" + "
" + "" + "" + "
\n" + "
\n" + "

%2$s

\n" + "
%3$s
\n" + "
\n" + "
\n" + "
\n"; private static final String HEADER_TEMPLATE_NO_STACK = "

%1$s

\n" + "%2$s \n" + "
\n"; private static final String RESOURCES_START = "
%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 = "

%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 = "
    \n" + "
  • "; private static final String LIST_END = "
\n"; private static final String RESOURCES_END = "
"; 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 = "
"; private static final String ERROR_STACK = "
\n" + "

The stacktrace below is the original. " + "See the stacktrace in reversed order (root-cause first)

" + "
%1$s
\n" +
            "    
\n"; private static final String ERROR_STACK_REVERSED = "
\n" + "

The stacktrace below has been reversed to show the root cause first. " + "See the original stacktrace

" + "
%1$s
\n" + "
\n"; private static final String DECORATE_DIV = "
%s
"; private static final String CONFIG_EDITOR_HEAD = "

The following incorrect config values were detected:

" + "
" + "\n"; private static final String CONFIG_EDITOR_ROW = "%s\n\n" + " \n"; private static final String CONFIG_UPDATE_BUTTON = ""; private static final String CONFIG_EDITOR_TAIL = " \n" + "" + CONFIG_UPDATE_BUTTON + "
"; 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 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, "
"); } result.append(String.format(ERROR_STACK, 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 + ""; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy