diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java index d8fd13fdd7c..af28135e673 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,19 +23,50 @@ package jdk.test.failurehandler; +import java.io.FileWriter; +import java.io.IOException; import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Objects; public class HtmlPage implements AutoCloseable { + static final String STYLE_SHEET_FILENAME = "failure-handler-style.css"; + static final String SCRIPT_FILENAME = "failure-handler-script.js"; + private final PrintWriter writer; private final HtmlSection rootSection; - public HtmlPage(PrintWriter writer) { - Objects.requireNonNull(writer, "writer cannot be null"); - this.writer = writer; + /** + * Constructs a {@code HtmlPage} + * + * @param dir The directory into which the HTML file and related resources will be created + * @param htmlFileName The HTML file name + * @param append if {@code true} then the content will be appended to the file represented + * by the {@code htmlFileName}, else the {@code htmlFileName} will be overwritten + * with the new content + * @throws IllegalArgumentException if {@code dir} is not a directory or if the + * {@code htmlFileName} is {@linkplain String#isBlank() blank} + * @throws IOException if there is an error constructing file resource(s) for this HTML page + */ + public HtmlPage(final Path dir, final String htmlFileName, final boolean append) + throws IOException { + Objects.requireNonNull(dir, "directory cannot be null"); + Objects.requireNonNull(htmlFileName, "HTML file name cannot be null"); + if (!Files.isDirectory(dir)) { + throw new IllegalArgumentException(dir + " is not a directory"); + } + if (htmlFileName.isBlank()) { + throw new IllegalArgumentException("HTML file name cannot be blank"); + } + final FileWriter fileWriter = new FileWriter(dir.resolve(htmlFileName).toFile(), append); + this.writer = new PrintWriter(fileWriter, true); + createScriptFile(dir); + createStyleSheetFile(dir); rootSection = new HtmlSection(writer); } + @Override public void close() { writer.close(); @@ -44,4 +75,71 @@ public class HtmlPage implements AutoCloseable { public HtmlSection getRootSection() { return rootSection; } + + private static void createStyleSheetFile(final Path destDir) throws IOException { + final Path styleSheet = destDir.resolve(STYLE_SHEET_FILENAME); + if (Files.exists(styleSheet)) { + return; + } + final String content = """ + div { display:none;} + """; + Files.writeString(styleSheet, content); + } + + private static void createScriptFile(final Path destDir) throws IOException { + final Path script = destDir.resolve(SCRIPT_FILENAME); + if (Files.exists(script)) { + return; + } + final String content = """ + function doShow(e) { + while (e != null) { + if (e.tagName == 'DIV') { + e.style.display = 'block'; + } + e = e.parentNode; + } + } + + function showHandler(event) { + elementId = this.dataset.show; + elementToShow = document.getElementById(elementId); + doShow(elementToShow); + } + + function toggleHandler(event) { + toggleElementId = this.dataset.toggle; + elementToToggle = document.getElementById(toggleElementId); + d = elementToToggle.style.display; + if (d == 'block') { + elementToToggle.style.display = 'none'; + } else { + doShow(elementToToggle); + } + } + + function bodyLoadHandler() { + const index = location.href.indexOf("#"); + if (index != -1) { + doShow(document.getElementById(location.href.substring(index + 1))); + } + // elements that require the "toggleHandler" function to be registered + // as an event handler for the onclick event + const requiringToggleHandler = document.querySelectorAll("[data-toggle]"); + for (const e of requiringToggleHandler) { + e.addEventListener("click", toggleHandler); + } + // elements that require the "showHandler" function to be registered + // as an event handler for the onclick event + const requiringShowHandler = document.querySelectorAll("[data-show]"); + for (const e of requiringShowHandler) { + e.addEventListener("click", showHandler); + } + } + // register a onload event handler + window.addEventListener("DOMContentLoaded", bodyLoadHandler); + """; + Files.writeString(script, content); + } } diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java index 141caf450bd..53ffab95a1e 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,41 +57,15 @@ public class HtmlSection { if (rootSection == null) { this.rootSection = this; this.pw.println(""); - this.pw.println("\n" - + "\n" - + "\n" - + ""); - this.pw.println("
"); + this.pw.println(""); + this.pw.println( + ""); + this.pw.println( + ""); + this.pw.println(""); + + this.pw.println(""); } else { this.rootSection = rootSection; this.pw.print("",
+ pw.printf("- %2$s
",
id, name);
}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java
index 96c5f4f2858..e63e55888d7 100644
--- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -105,9 +105,7 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer {
private void gatherCoreInfo(Path workDir, String name, Path core, PrintWriter log,
CoreInfoGatherer gatherer) {
- File output = workDir.resolve(CORES_OUTPUT).toFile();
- try (HtmlPage html = new HtmlPage(new PrintWriter(
- new FileWriter(output, true), true))) {
+ try (HtmlPage html = new HtmlPage(workDir, CORES_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherCoreInfo(html.getRootSection(), core);
@@ -121,9 +119,7 @@ public class GatherDiagnosticInfoObserver implements Harness.Observer {
private void gatherEnvInfo(Path workDir, String name, PrintWriter log,
EnvironmentInfoGatherer gatherer) {
- File output = workDir.resolve(ENVIRONMENT_OUTPUT).toFile();
- try (HtmlPage html = new HtmlPage(new PrintWriter(
- new FileWriter(output, true), true))) {
+ try (HtmlPage html = new HtmlPage(workDir, ENVIRONMENT_OUTPUT, true)) {
try (ElapsedTimePrinter timePrinter
= new ElapsedTimePrinter(new Stopwatch(), name, log)) {
gatherer.gatherEnvironmentInfo(html.getRootSection());
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java
index 63ed7e5f2c7..c1f1ddfb69f 100644
--- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,16 +69,7 @@ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
}
try {
actionsLog.printf("%s ---%n", name);
-
- File output = workDir.resolve(OUTPUT_FILENAME).toFile();
- try {
- PrintWriter pw = new PrintWriter(new FileWriter(output, true), true);
- runGatherer(name, workDir, actionsLog, pw, pid);
- } catch (IOException e) {
- actionsLog.printf("IOException: cannot open output file[%s] : %s",
- output, e.getMessage());
- e.printStackTrace(actionsLog);
- }
+ runGatherer(name, actionsLog, pid);
} finally {
actionsLog.printf("--- %s%n", name);
// don't close jtreg log
@@ -90,9 +81,9 @@ public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
}
}
- private void runGatherer(String name, Path workDir, PrintWriter log,
- PrintWriter out, long pid) {
- try (HtmlPage html = new HtmlPage(out)) {
+ private void runGatherer(String name, PrintWriter log, long pid) {
+ Path workDir = outputDir.toPath();
+ try (HtmlPage html = new HtmlPage(workDir, OUTPUT_FILENAME, true)) {
ProcessInfoGatherer gatherer = new GathererFactory(
OS.current().family,
workDir, log, testJdk.toPath()).getProcessInfoGatherer();