aboutsummaryrefslogtreecommitdiff
path: root/test/failure_handler/src/share/classes/jdk/test/failurehandler
diff options
context:
space:
mode:
Diffstat (limited to 'test/failure_handler/src/share/classes/jdk/test/failurehandler')
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java48
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java28
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java63
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java47
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java237
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java28
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java73
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java72
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java88
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java33
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java362
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java47
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java126
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java79
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java86
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java152
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java147
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/OS.java56
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java53
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java120
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java35
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java40
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java36
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java35
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java36
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java122
-rw-r--r--test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java28
27 files changed, 2277 insertions, 0 deletions
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java
new file mode 100644
index 0000000..f1ab374
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ElapsedTimePrinter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class ElapsedTimePrinter implements AutoCloseable {
+ private final String name;
+ private final PrintWriter out;
+ private final Stopwatch stopwatch;
+
+ public ElapsedTimePrinter(Stopwatch stopwatch, String name,
+ PrintWriter out) {
+ this.stopwatch = stopwatch;
+ this.name = name;
+ this.out = out;
+ stopwatch.start();
+ }
+
+ @Override
+ public void close() {
+ stopwatch.stop();
+ out.printf("%s took %d s%n", name,
+ TimeUnit.NANOSECONDS.toSeconds(stopwatch.getElapsedTimeNs()));
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java
new file mode 100644
index 0000000..e2b9510
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/EnvironmentInfoGatherer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+public interface EnvironmentInfoGatherer {
+ void gatherEnvironmentInfo(HtmlSection section);
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java
new file mode 100644
index 0000000..4799bb8
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/GathererFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import jdk.test.failurehandler.action.ActionHelper;
+import jdk.test.failurehandler.value.InvalidValueException;
+
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.util.Properties;
+
+public final class GathererFactory {
+ private final Path workdir;
+ private final Path[] jdks;
+ private final PrintWriter log;
+ private final String osName;
+
+ public GathererFactory(String osName, Path workdir, PrintWriter log, Path... jdks) {
+ this.osName = osName;
+ this.workdir = workdir;
+ this.log = log;
+ this.jdks = jdks;
+ }
+
+ public EnvironmentInfoGatherer getEnvironmentInfoGatherer() {
+ return create();
+ }
+
+ public ProcessInfoGatherer getProcessInfoGatherer() {
+ return create();
+ }
+
+ private ToolKit create() {
+ Properties osProperty = Utils.getProperties(osName);
+ try {
+ ActionHelper helper = new ActionHelper(workdir, "config", osProperty, jdks);
+ return new ToolKit(helper, log, osName, "common");
+ } catch (InvalidValueException e) {
+ throw new IllegalStateException("can't create tool kit", e);
+ }
+ }
+}
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
new file mode 100644
index 0000000..d8fd13f
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlPage.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+public class HtmlPage implements AutoCloseable {
+ private final PrintWriter writer;
+ private final HtmlSection rootSection;
+
+ public HtmlPage(PrintWriter writer) {
+ Objects.requireNonNull(writer, "writer cannot be null");
+ this.writer = writer;
+ rootSection = new HtmlSection(writer);
+ }
+
+ @Override
+ public void close() {
+ writer.close();
+ }
+
+ public HtmlSection getRootSection() {
+ return rootSection;
+ }
+}
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
new file mode 100644
index 0000000..d20b133
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/HtmlSection.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class HtmlSection {
+ protected final HtmlSection rootSection;
+ protected final String id;
+ protected final String name;
+
+ public PrintWriter getWriter() {
+ return textWriter;
+ }
+
+ protected final PrintWriter pw;
+ protected final PrintWriter textWriter;
+ protected boolean closed;
+
+ private HtmlSection child;
+
+
+ public HtmlSection(PrintWriter pw) {
+ this(pw, "", null, null);
+ }
+
+ private HtmlSection(PrintWriter pw, String id, String name, HtmlSection rootSection) {
+ this.pw = pw;
+ textWriter = new PrintWriter(new HtmlFilterWriter(pw), true);
+ this.id = id;
+ this.name = name;
+ child = null;
+ // main
+ if (rootSection == null) {
+ this.rootSection = this;
+ this.pw.println("<html>");
+ this.pw.println("<style>\n"
+ + "div { display:none;}\n"
+ + "</style>\n"
+ + "\n"
+ + "<script>\n"
+ + "function show(e) {\n"
+ + " while (e != null) {\n"
+ + " if (e.tagName == 'DIV') {\n"
+ + " e.style.display = 'block';\n"
+ + " }\n"
+ + " e = e.parentNode;\n"
+ + " }\n"
+ + "}\n"
+ + "\n"
+ + "function toggle(id) {\n"
+ + " e = document.getElementById(id);\n"
+ + " d = e.style.display;\n"
+ + " if (d == 'block') {\n"
+ + " e.style.display = 'none';\n"
+ + " } else {\n"
+ + " show(e);\n"
+ + " }\n"
+ + "}\n"
+ + "\n"
+ + "function main() {\n"
+ + " index = location.href.indexOf(\"#\");"
+ + " if (index != -1) {\n"
+ + " show(document.getElementById(location.href.substring(index + 1)));\n"
+ + " }\n"
+ + "}\n"
+ + "\n"
+ + "</script>\n"
+ + "</head>");
+
+ this.pw.println("<body onload='main()'>");
+ } else {
+ this.rootSection = rootSection;
+ this.pw.print("<ul>");
+ }
+ }
+
+ public HtmlSection createChildren(String section) {
+ if (child != null) {
+ if (child.name.equals(section)) {
+ return child;
+ }
+ child.close();
+ }
+ child = new SubSection(this, section, rootSection);
+ return child;
+ }
+
+ protected final void removeChild(HtmlSection child) {
+ if (this.child == child) {
+ this.child = null;
+ }
+ }
+
+ public void close() {
+ closeChild();
+ if (closed) {
+ return;
+ }
+ closed = true;
+
+ if (rootSection == this) {
+ pw.println("</body>");
+ pw.println("</html>");
+ pw.close();
+ } else {
+ pw.println("</ul>");
+ }
+
+ }
+
+ protected final void closeChild() {
+ if (child != null) {
+ child.close();
+ child = null;
+ }
+ }
+
+ public void link(HtmlSection section, String child, String name) {
+ String path = section.id;
+ if (path.isEmpty()) {
+ path = child;
+ } else if (child != null) {
+ path = String.format("%s.%s", path, child);
+ }
+ pw.printf("<a href=\"#%1$s\" onclick=\"show(document.getElementById('%1$s')); return true;\">%2$s</a>%n",
+ path, name);
+ }
+
+ public HtmlSection createChildren(String[] sections) {
+ int i = 0;
+ int n = sections.length;
+ HtmlSection current = rootSection;
+ if (current != null) {
+ for (; i < n && current.child != null;
+ ++i, current = current.child) {
+ if (!sections[i].equals(current.child.name)) {
+ break;
+ }
+ }
+ }
+ for (; i < n; ++i) {
+ current = current.createChildren(sections[i]);
+ }
+ return current;
+ }
+
+ private static class SubSection extends HtmlSection {
+ private final HtmlSection parent;
+
+ public SubSection(HtmlSection parent, String name,
+ HtmlSection rootSection) {
+ super(parent.pw,
+ parent.id.isEmpty()
+ ? name
+ : String.format("%s.%s", parent.id, name),
+ name, rootSection);
+ this.parent = parent;
+ pw.printf("<li><a name='%1$s'/><a href='#%1$s' onclick=\"toggle('%1$s'); return false;\">%2$s</a><div id='%1$s'><code><pre>",
+ id, name);
+ }
+
+ @Override
+ public void close() {
+ closeChild();
+ if (closed) {
+ return;
+ }
+ pw.print("</pre></code></div></li><!-- " + id + "-->");
+ parent.removeChild(this);
+ super.close();
+ }
+ }
+
+ private static class HtmlFilterWriter extends FilterWriter {
+ public HtmlFilterWriter(PrintWriter pw) {
+ super(pw);
+ }
+
+ @Override
+ public void write(int c) throws IOException {
+ switch (c) {
+ case '<':
+ super.write("&lt;", 0, 4);
+ break;
+ case '>':
+ super.write("&gt;", 0, 4);
+ break;
+ case '"':
+ super.write("&quot;", 0, 5);
+ break;
+ case '&':
+ super.write("&amp;", 0, 4);
+ break;
+ default:
+ super.write(c);
+ }
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ for (int i = off; i < len; ++i){
+ write(cbuf[i]);
+ }
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException {
+ for (int i = off; i < len; ++i){
+ write(str.charAt(i));
+ }
+ }
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java
new file mode 100644
index 0000000..3fb407c
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ProcessInfoGatherer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+public interface ProcessInfoGatherer {
+ void gatherProcessInfo(HtmlSection section, long pid);
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java
new file mode 100644
index 0000000..2ac9895
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Stopwatch.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+public final class Stopwatch {
+ protected boolean isResultAvailable;
+ protected boolean isRunning;
+
+ private long startTimeNs;
+ private long stopTimeNs;
+
+ public Stopwatch() {
+ isResultAvailable = false;
+ }
+
+ /**
+ * Starts measuring time.
+ */
+ public void start() {
+ startTimeNs = System.nanoTime();
+ isRunning = true;
+ }
+
+ /**
+ * Stops measuring time.
+ */
+ public void stop() {
+ if (!isRunning) {
+ throw new IllegalStateException(" hasn't been started");
+ }
+ stopTimeNs = System.nanoTime();
+ isRunning = false;
+ isResultAvailable = true;
+ }
+
+ /**
+ * @return time in nanoseconds measured between
+ * calls of {@link #start()} and {@link #stop()} methods.
+ *
+ * @throws IllegalStateException if called without preceding
+ * {@link #start()} {@link #stop()} method
+ */
+ public long getElapsedTimeNs() {
+ if (isRunning) {
+ throw new IllegalStateException("hasn't been stopped");
+ }
+ if (!isResultAvailable) {
+ throw new IllegalStateException("was not run");
+ }
+ return stopTimeNs - startTimeNs;
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java
new file mode 100644
index 0000000..408bc1f
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/ToolKit.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import jdk.test.failurehandler.action.ActionSet;
+import jdk.test.failurehandler.action.ActionHelper;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+public class ToolKit implements EnvironmentInfoGatherer, ProcessInfoGatherer {
+ private final List<ActionSet> actions = new ArrayList<>();
+ private final ActionHelper helper;
+
+ public ToolKit(ActionHelper helper, PrintWriter log, String... names) {
+ this.helper = helper;
+ for (String name : names) {
+ actions.add(new ActionSet(helper, log, name));
+ }
+ }
+
+ @Override
+ public void gatherEnvironmentInfo(HtmlSection section) {
+ for (ActionSet set : actions) {
+ set.gatherEnvironmentInfo(section);
+ }
+ }
+
+ @Override
+ public void gatherProcessInfo(HtmlSection section, long pid) {
+ Queue<Long> pids = new LinkedList<>();
+ pids.add(pid);
+ for (Long p = pids.poll(); p != null; p = pids.poll()) {
+ HtmlSection pidSection = section.createChildren("" + p);
+ for (ActionSet set : actions) {
+ set.gatherProcessInfo(pidSection, p);
+ }
+ List<Long> children = helper.getChildren(pidSection, p);
+ if (!children.isEmpty()) {
+ HtmlSection s = pidSection.createChildren("children");
+ for (Long c : children) {
+ s.link(section, c.toString(), c.toString());
+ }
+ pids.addAll(children);
+ }
+ }
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java
new file mode 100644
index 0000000..ea82360
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/Utils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Properties;
+
+public final class Utils {
+ private static final int BUFFER_LENGTH = 1024;
+
+ public static String prependPrefix(String prefix, String name) {
+ return (prefix == null || prefix.isEmpty())
+ ? name
+ : (name == null || name.isEmpty())
+ ? prefix
+ : String.format("%s.%s", prefix, name);
+ }
+
+ public static void copyStream(InputStream in, OutputStream out)
+ throws IOException {
+ int n;
+ byte[] buffer = new byte[BUFFER_LENGTH];
+ while ((n = in.read(buffer)) != -1) {
+ out.write(buffer, 0, n);
+ }
+ out.flush();
+ }
+
+ public static void copyStream(Reader in, Writer out)
+ throws IOException {
+ int n;
+ char[] buffer = new char[BUFFER_LENGTH];
+ while ((n = in.read(buffer)) != -1) {
+ out.write(buffer, 0, n);
+ }
+ out.flush();
+ }
+
+ public static Properties getProperties(String name) {
+ Properties properties = new Properties();
+ String resourceName = String.format(
+ "/%s.%s", name.toLowerCase(), "properties");
+ InputStream stream = Utils.class.getResourceAsStream(resourceName);
+ if (stream == null) {
+ throw new IllegalStateException(String.format(
+ "resource '%s' doesn't exist%n", resourceName));
+ }
+ try {
+ try {
+ properties.load(stream);
+ } finally {
+ stream.close();
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(String.format(
+ "can't read resource '%s' : %s%n",
+ resourceName, e.getMessage()), e);
+ }
+ return properties;
+ }
+
+ private Utils() { }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java
new file mode 100644
index 0000000..65b2a22
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/Action.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import jdk.test.failurehandler.HtmlSection;
+
+public interface Action {
+ boolean isJavaOnly();
+ HtmlSection getSection(HtmlSection section);
+
+ ActionParameters getParameters();
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java
new file mode 100644
index 0000000..8b2d275
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import jdk.test.failurehandler.value.InvalidValueException;
+import jdk.test.failurehandler.value.Value;
+import jdk.test.failurehandler.value.ValueHandler;
+import jdk.test.failurehandler.HtmlSection;
+import jdk.test.failurehandler.Stopwatch;
+import jdk.test.failurehandler.Utils;
+
+import java.io.BufferedReader;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+public class ActionHelper {
+ private final Path workDir;
+ @Value(name = "execSuffix")
+ private String executableSuffix = "";
+ private Path[] paths;
+
+ private final PatternAction getChildren;
+
+ public ActionHelper(Path workDir, String prefix, Properties properties,
+ Path... jdks) throws InvalidValueException {
+ this.workDir = workDir.toAbsolutePath();
+ getChildren = new PatternAction("children",
+ Utils.prependPrefix(prefix, "getChildren"), properties);
+ ValueHandler.apply(this, properties, prefix);
+ String[] pathStrings = System.getenv("PATH").split(File.pathSeparator);
+ paths = new Path[pathStrings.length];
+ for (int i = 0; i < paths.length; ++i) {
+ paths[i] = Paths.get(pathStrings[i]);
+ }
+ addJdks(jdks);
+ }
+
+ public List<Long> getChildren(HtmlSection section, long pid) {
+ String pidStr = "" + pid;
+ ProcessBuilder pb = getChildren.prepareProcess(section, this, pidStr);
+ PrintWriter log = getChildren.getSection(section).getWriter();
+ CharArrayWriter writer = new CharArrayWriter();
+ ExitCode code = run(log, writer, pb, getChildren.getParameters());
+ Reader output = new CharArrayReader(writer.toCharArray());
+
+ if (!ExitCode.OK.equals(code)) {
+ log.println("WARNING: get children pids action failed");
+ try {
+ Utils.copyStream(output, log);
+ } catch (IOException e) {
+ e.printStackTrace(log);
+ }
+ return Collections.emptyList();
+ }
+
+ List<Long> result = new ArrayList<>();
+ try {
+ try (BufferedReader reader = new BufferedReader(output)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String value = line.trim();
+ if (value.isEmpty()) {
+ // ignore empty lines
+ continue;
+ }
+ try {
+ result.add(Long.valueOf(value));
+ } catch (NumberFormatException e) {
+ log.printf("WARNING: can't parse child pid %s : %s%n",
+ line, e.getMessage());
+ e.printStackTrace(log);
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace(log);
+ }
+ return result;
+ }
+
+ public ProcessBuilder prepareProcess(PrintWriter log, String app,
+ String... args) {
+ File appBin = findApp(app);
+ if (appBin == null) {
+ log.printf("ERROR: can't find %s in %s.%n",
+ app, Arrays.toString(paths));
+ return null;
+ }
+ List<String> command = new ArrayList<>(args.length + 1);
+ command.add(appBin.toString());
+ Collections.addAll(command, args);
+ return new ProcessBuilder()
+ .command(command)
+ .directory(workDir.toFile());
+ }
+
+ private File findApp(String app) {
+ String name = app + executableSuffix;
+ for (Path pathElem : paths) {
+ File result = pathElem.resolve(name).toFile();
+ if (result.exists()) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ private void addJdks(Path[] jdkPaths) {
+ if (jdkPaths != null && jdkPaths.length != 0) {
+ Path[] result = new Path[jdkPaths.length + paths.length];
+ for (int i = 0; i < jdkPaths.length; ++i) {
+ result[i] = jdkPaths[i].resolve("bin");
+ }
+ System.arraycopy(paths, 0, result, jdkPaths.length, paths.length);
+ paths = result;
+ }
+ }
+
+ private ExitCode run(PrintWriter log, Writer out, ProcessBuilder pb,
+ ActionParameters params) {
+ char[] lineChars = new char[40];
+ Arrays.fill(lineChars, '-');
+ String line = new String(lineChars);
+ Stopwatch stopwatch = new Stopwatch();
+ stopwatch.start();
+
+ log.printf("%s%n[%tF %<tT] %s timeout=%s%n%1$s%n", line, new Date(), pb.command(), params.timeout);
+
+ Process process;
+ KillerTask killer;
+
+ ExitCode result = ExitCode.NEVER_STARTED;
+
+ try {
+ process = pb.start();
+ killer = new KillerTask(process);
+ killer.schedule(params.timeout);
+ Utils.copyStream(new InputStreamReader(process.getInputStream()),
+ out);
+ try {
+ result = new ExitCode(process.waitFor());
+ } catch (InterruptedException e) {
+ log.println("WARNING: interrupted when waiting for the tool:%n");
+ e.printStackTrace(log);
+ } finally {
+ killer.cancel();
+ }
+ if (killer.hasTimedOut()) {
+ log.printf(
+ "WARNING: tool timed out: killed process after %d ms%n",
+ params.timeout);
+ result = ExitCode.TIMED_OUT;
+ }
+ } catch (IOException e) {
+ log.printf("WARNING: caught IOException while running tool%n");
+ e.printStackTrace(log);
+ result = ExitCode.LAUNCH_ERROR;
+ }
+
+ stopwatch.stop();
+ log.printf("%s%n[%tF %<tT] exit code: %d time: %d ms%n%1$s%n",
+ line, new Date(), result.value,
+ TimeUnit.NANOSECONDS.toMillis(stopwatch.getElapsedTimeNs()));
+ return result;
+ }
+
+ public void runPatternAction(SimpleAction action, HtmlSection section) {
+ if (action != null) {
+ HtmlSection subSection = action.getSection(section);
+ PrintWriter log = subSection.getWriter();
+ ProcessBuilder pb = action.prepareProcess(log, this);
+ exec(subSection, pb, action.getParameters());
+ }
+ }
+
+ public void runPatternAction(PatternAction action, HtmlSection section,
+ String value) {
+ if (action != null) {
+ ProcessBuilder pb = action.prepareProcess(section, this, value);
+ HtmlSection subSection = action.getSection(section);
+ exec(subSection, pb, action.getParameters());
+ }
+ }
+
+ public boolean isJava(long pid, PrintWriter log) {
+ ProcessBuilder pb = prepareProcess(log, "jps", "-q");
+ if (pb == null) {
+ return false;
+ }
+ pb.redirectErrorStream(true);
+ boolean result = false;
+ String pidStr = "" + pid;
+ try {
+ Process process = pb.start();
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(process.getInputStream()))) {
+ String line;
+ while ((line = reader.readLine()) != null){
+ if (pidStr.equals(line)) {
+ result = true;
+ }
+ }
+ }
+ process.waitFor();
+ } catch (IOException e) {
+ log.printf("WARNING: can't run jps : %s%n", e.getMessage());
+ e.printStackTrace(log);
+ } catch (InterruptedException e) {
+ log.printf("WARNING: interrupted%n");
+ e.printStackTrace(log);
+ }
+ return result;
+ }
+
+ private static class KillerTask extends TimerTask {
+ private static final Timer WATCHDOG = new Timer("WATCHDOG", true);
+ private final Process process;
+ private boolean timedOut;
+
+ public KillerTask(Process process) {
+ this.process = process;
+ }
+
+ public void run() {
+ try {
+ process.exitValue();
+ } catch (IllegalThreadStateException e) {
+ process.destroyForcibly();
+ timedOut = true;
+ }
+ }
+
+ public boolean hasTimedOut() {
+ return timedOut;
+ }
+
+ public void schedule(long timeout) {
+ if (timeout > 0) {
+ WATCHDOG.schedule(this, timeout);
+ }
+ }
+ }
+
+ private void exec(HtmlSection section, ProcessBuilder process,
+ ActionParameters params) {
+ if (process == null) {
+ return;
+ }
+ PrintWriter sectionWriter = section.getWriter();
+ if (params.repeat > 1) {
+ for (int i = 0, n = params.repeat; i < n; ++i) {
+ HtmlSection iteration = section.createChildren(
+ String.format("iteration_%d", i));
+ PrintWriter writer = iteration.getWriter();
+ ExitCode exitCode = run(writer, writer, process, params);
+ if (params.stopOnError && !ExitCode.OK.equals(exitCode)) {
+ sectionWriter.printf(
+ "ERROR: non zero exit code[%d] -- break.",
+ exitCode.value);
+ break;
+ }
+ // sleep, if this is not the last iteration
+ if (i < n - 1) {
+ try {
+ Thread.sleep(params.pause);
+ } catch (InterruptedException e) {
+ sectionWriter.printf(
+ "WARNING: interrupted while sleeping between invocations");
+ e.printStackTrace(sectionWriter);
+ }
+ }
+ }
+ } else {
+ run(section.getWriter(), section.getWriter(), process, params);
+ }
+ }
+
+ /**
+ * Special values for prepareProcess exit code.
+ *
+ * <p>Can we clash with normal codes?
+ * On Solaris and Linux, only [0..255] are returned.
+ * On Windows, prepareProcess exit codes are stored in unsigned int.
+ * On MacOSX no limits (except it should fit C int type)
+ * are defined in the exit() man pages.
+ */
+ private static class ExitCode {
+ /** Process exits gracefully */
+ public static final ExitCode OK = new ExitCode(0);
+ /** Error launching prepareProcess */
+ public static final ExitCode LAUNCH_ERROR = new ExitCode(-1);
+ /** Application prepareProcess has been killed by watchdog due to timeout */
+ public static final ExitCode TIMED_OUT = new ExitCode(-2);
+ /** Application prepareProcess has never been started due to program logic */
+ public static final ExitCode NEVER_STARTED = new ExitCode(-3);
+
+ public final int value;
+
+ private ExitCode(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ExitCode exitCode = (ExitCode) o;
+ return value == exitCode.value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+ }
+
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java
new file mode 100644
index 0000000..4bd919e
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionParameters.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import jdk.test.failurehandler.value.DefaultValue;
+import jdk.test.failurehandler.value.Value;
+
+public class ActionParameters {
+ @Value (name = "repeat")
+ @DefaultValue (value = "1")
+ public int repeat = 1;
+
+ @Value (name = "pause")
+ @DefaultValue (value = "500")
+ public long pause = 500;
+
+ @Value (name = "stopOnError")
+ @DefaultValue (value = "false")
+ public boolean stopOnError = false;
+
+ @Value (name = "timeout")
+ @DefaultValue (value = "" + 20_000L)
+ public long timeout = -1L;
+
+ public ActionParameters() { }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java
new file mode 100644
index 0000000..3ed5b31
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionSet.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import jdk.test.failurehandler.ProcessInfoGatherer;
+import jdk.test.failurehandler.EnvironmentInfoGatherer;
+import jdk.test.failurehandler.HtmlSection;
+import jdk.test.failurehandler.Utils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class ActionSet implements ProcessInfoGatherer, EnvironmentInfoGatherer {
+ private static final String ENVIRONMENT_PROPERTY = "environment";
+ private static final String ON_PID_PROPERTY = "onTimeout";
+
+ private final ActionHelper helper;
+
+ public String getName() {
+ return name;
+ }
+
+ private final String name;
+ private final List<SimpleAction> environmentActions;
+ private final List<PatternAction> processActions;
+
+
+ public ActionSet(ActionHelper helper, PrintWriter log, String name) {
+ this.helper = helper;
+ this.name = name;
+
+ Properties p = Utils.getProperties(name);
+ environmentActions = getSimpleActions(log, p, ENVIRONMENT_PROPERTY);
+ processActions = getPatternActions(log, p, ON_PID_PROPERTY);
+ }
+
+ private List<SimpleAction> getSimpleActions(PrintWriter log, Properties p,
+ String key) {
+ String[] tools = getTools(log, p, key);
+ List<SimpleAction> result = new ArrayList<>(tools.length);
+ for (String tool : tools) {
+ try {
+ SimpleAction action = new SimpleAction(
+ Utils.prependPrefix(name, tool), tool, p);
+ result.add(action);
+ } catch (Exception e) {
+ log.printf("ERROR: %s cannot be created : %s %n",
+ tool, e.getMessage());
+ e.printStackTrace(log);
+ }
+ }
+ return result;
+ }
+
+ private List<PatternAction> getPatternActions(PrintWriter log,
+ Properties p, String key) {
+ String[] tools = getTools(log, p, key);
+ List<PatternAction> result = new ArrayList<>(tools.length);
+ for (String tool : tools) {
+ try {
+ PatternAction action = new PatternAction(
+ Utils.prependPrefix(name, tool), tool, p);
+ result.add(action);
+ } catch (Exception e) {
+ log.printf("ERROR: %s cannot be created : %s %n",
+ tool, e.getMessage());
+ e.printStackTrace(log);
+ }
+ }
+ return result;
+ }
+
+ private String[] getTools(PrintWriter writer, Properties p, String key) {
+ String value = p.getProperty(key);
+ if (value == null || value.isEmpty()) {
+ writer.printf("ERROR: '%s' property is empty%n", key);
+ return new String[]{};
+ }
+ return value.split(" ");
+ }
+
+
+ @Override
+ public void gatherProcessInfo(HtmlSection section, long pid) {
+ String pidStr = "" + pid;
+ for (PatternAction action : processActions) {
+ if (action.isJavaOnly()) {
+ if (helper.isJava(pid, section.getWriter())) {
+ helper.runPatternAction(action, section, pidStr);
+ }
+ } else {
+ helper.runPatternAction(action, section, pidStr);
+ }
+ }
+ }
+
+ @Override
+ public void gatherEnvironmentInfo(HtmlSection section) {
+ for (SimpleAction action : environmentActions) {
+ helper.runPatternAction(action, section);
+ }
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java
new file mode 100644
index 0000000..fbcaaa7
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/PatternAction.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import jdk.test.failurehandler.value.InvalidValueException;
+import jdk.test.failurehandler.HtmlSection;
+import jdk.test.failurehandler.value.Value;
+import jdk.test.failurehandler.value.ValueHandler;
+
+import java.util.Properties;
+
+public class PatternAction implements Action {
+ @Value(name = "pattern")
+ private String pattern = null;
+
+ private final SimpleAction action;
+ private final String[] originalArgs;
+
+ public PatternAction(String id, Properties properties)
+ throws InvalidValueException {
+ this(id, id, properties);
+ }
+
+ public PatternAction(String name, String id, Properties properties)
+ throws InvalidValueException {
+ action = new SimpleAction(("pattern." + name), id, properties);
+ ValueHandler.apply(this, properties, id);
+ originalArgs = action.args.clone();
+ }
+
+ public ProcessBuilder prepareProcess(HtmlSection section,
+ ActionHelper helper, String value) {
+ action.sections[0] = value;
+ section = getSection(section);
+ String[] args = action.args;
+ System.arraycopy(originalArgs, 0, args, 0, originalArgs.length);
+
+ for (int i = 0, n = args.length; i < n; ++i) {
+ args[i] = args[i].replace(pattern, value) ;
+ }
+ return action.prepareProcess(section.getWriter(), helper);
+ }
+
+ @Override
+ public HtmlSection getSection(HtmlSection section) {
+ return action.getSection(section);
+ }
+
+ @Override
+ public ActionParameters getParameters() {
+ return action.getParameters();
+ }
+
+ @Override
+ public boolean isJavaOnly() {
+ return action.isJavaOnly();
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java
new file mode 100644
index 0000000..e6a0e9a
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/SimpleAction.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.action;
+
+import jdk.test.failurehandler.HtmlSection;
+import jdk.test.failurehandler.value.InvalidValueException;
+import jdk.test.failurehandler.value.SubValues;
+import jdk.test.failurehandler.value.Value;
+import jdk.test.failurehandler.value.ValueHandler;
+import jdk.test.failurehandler.value.DefaultValue;
+
+import java.io.PrintWriter;
+import java.util.Properties;
+
+public class SimpleAction implements Action {
+ /* package-private */ final String[] sections;
+ @Value(name = "javaOnly")
+ @DefaultValue(value = "false")
+ private boolean javaOnly = false;
+
+ @Value (name = "app")
+ private String app = null;
+
+ @Value (name = "args")
+ @DefaultValue (value = "")
+ /* package-private */ String[] args = new String[]{};
+
+ @SubValues(prefix = "params")
+ private final ActionParameters params;
+
+ public SimpleAction(String id, Properties properties)
+ throws InvalidValueException {
+ this(id, id, properties);
+ }
+ public SimpleAction(String name, String id, Properties properties)
+ throws InvalidValueException {
+ sections = name.split("\\.");
+ this.params = new ActionParameters();
+ ValueHandler.apply(this, properties, id);
+ }
+
+ public ProcessBuilder prepareProcess(PrintWriter log, ActionHelper helper) {
+ ProcessBuilder process = helper.prepareProcess(log, app, args);
+ if (process != null) {
+ process.redirectErrorStream(true);
+ }
+
+ return process;
+ }
+
+ @Override
+ public boolean isJavaOnly() {
+ return javaOnly;
+ }
+
+ @Override
+ public HtmlSection getSection(HtmlSection section) {
+ return section.createChildren(sections);
+ }
+
+ @Override
+ public ActionParameters getParameters() {
+ return params;
+ }
+}
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
new file mode 100644
index 0000000..7a14d37
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherDiagnosticInfoObserver.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.jtreg;
+
+import com.sun.javatest.Harness;
+import com.sun.javatest.Parameters;
+import com.sun.javatest.TestResult;
+import com.sun.javatest.InterviewParameters;
+import jdk.test.failurehandler.*;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The jtreg test execution observer, which gathers info about
+ * system and dumps it to a file.
+ */
+public class GatherDiagnosticInfoObserver implements Harness.Observer {
+ public static final String LOG_FILENAME = "environment.log";
+ public static final String ENVIRONMENT_OUTPUT = "environment.html";
+
+ private String compileJdk;
+ private String testJdk;
+
+ /*
+ * The harness calls this method after each test.
+ */
+ @Override
+ public void finishedTest(TestResult tr) {
+ if (!tr.getStatus().isError() && !tr.getStatus().isFailed()) {
+ return;
+ }
+
+ String jtrFile = tr.getFile().toString();
+ final Path workDir = Paths.get(
+ jtrFile.substring(0, jtrFile.lastIndexOf('.')));
+ workDir.toFile().mkdir();
+
+ String name = getClass().getName();
+ PrintWriter log;
+ boolean needClose = false;
+ try {
+ log = new PrintWriter(new FileWriter(
+ workDir.resolve(LOG_FILENAME).toFile(), true), true);
+ needClose = true;
+ } catch (IOException e) {
+ log = new PrintWriter(System.out);
+ log.printf("ERROR: %s cannot open log file %s", name,
+ LOG_FILENAME);
+ e.printStackTrace(log);
+ }
+ try {
+ log.printf("%s ---%n", name);
+ GathererFactory gathererFactory = new GathererFactory(
+ OS.current().family, workDir, log,
+ Paths.get(testJdk), Paths.get(compileJdk));
+ gatherEnvInfo(workDir, name, log,
+ gathererFactory.getEnvironmentInfoGatherer());
+ } catch (Throwable e) {
+ log.printf("ERROR: exception in observer %s:", name);
+ e.printStackTrace(log);
+ } finally {
+ log.printf("--- %s%n", name);
+ if (needClose) {
+ log.close();
+ } else {
+ log.flush();
+ }
+ }
+ }
+
+ 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 (ElapsedTimePrinter timePrinter
+ = new ElapsedTimePrinter(new Stopwatch(), name, log)) {
+ gatherer.gatherEnvironmentInfo(html.getRootSection());
+ }
+ } catch (Throwable e) {
+ log.printf("ERROR: exception in observer on getting environment "
+ + "information %s:", name);
+ e.printStackTrace(log);
+ }
+ }
+
+ /*
+ * The harness calls this method one time per run, not per test.
+ */
+ @Override
+ public void startingTestRun(Parameters params) {
+ // TODO find a better way to get JDKs
+ InterviewParameters rp = (InterviewParameters) params;
+ Map<?,?> map = new HashMap<>();
+ rp.save(map);
+ compileJdk = (String) map.get("regtest.compilejdk");
+ testJdk = (String) map.get("regtest.testjdk");
+ }
+
+ @Override
+ public void startingTest(TestResult tr) {
+ // no-op
+ }
+
+ @Override
+ public void stoppingTestRun() {
+ // no-op
+ }
+
+ @Override
+ public void finishedTesting() {
+ // no-op
+ }
+
+ @Override
+ public void finishedTestRun(boolean allOK) {
+ // no-op
+ }
+
+ @Override
+ public void error(String msg) {
+ // no-op
+ }
+}
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
new file mode 100644
index 0000000..767e866
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/GatherProcessInfoTimeoutHandler.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.jtreg;
+
+import com.sun.javatest.regtest.TimeoutHandler;
+import jdk.test.failurehandler.*;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.nio.file.Path;
+
+/**
+ * A timeout handler for jtreg, which gathers information about the timed out
+ * process and its children.
+ */
+public class GatherProcessInfoTimeoutHandler extends TimeoutHandler {
+ private static final boolean HAS_NATIVE_LIBRARY;
+ static {
+ boolean value = true;
+ try {
+ System.loadLibrary("timeoutHandler");
+ } catch (UnsatisfiedLinkError ignore) {
+ // not all os need timeoutHandler native-library
+ value = false;
+ }
+ HAS_NATIVE_LIBRARY = value;
+ }
+ private static final String LOG_FILENAME = "processes.log";
+ private static final String OUTPUT_FILENAME = "processes.html";
+
+ public GatherProcessInfoTimeoutHandler(PrintWriter jtregLog, File outputDir,
+ File testJdk) {
+ super(jtregLog, outputDir, testJdk);
+ }
+
+ /**
+ * Runs various actions for jtreg timeout handler.
+ *
+ * <p>Please see method code for the actions.
+ */
+ @Override
+ protected void runActions(Process process, long pid)
+ throws InterruptedException {
+ Path workDir = outputDir.toPath();
+
+ String name = getClass().getName();
+ PrintWriter actionsLog;
+ try {
+ // try to open a separate file for action log
+ actionsLog = new PrintWriter(new FileWriter(
+ workDir.resolve(LOG_FILENAME).toFile(), true), true);
+ } catch (IOException e) {
+ // use jtreg log as a fallback
+ actionsLog = log;
+ actionsLog.printf("ERROR: %s cannot open log file %s : %s", name,
+ LOG_FILENAME, e.getMessage());
+ }
+ 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);
+ }
+ } finally {
+ actionsLog.printf("--- %s%n", name);
+ // don't close jtreg log
+ if (actionsLog != log) {
+ actionsLog.close();
+ } else {
+ log.flush();
+ }
+ }
+ }
+
+ @Override
+ protected long getProcessId(Process process) {
+ long result = super.getProcessId(process);
+ if (result == 0L) {
+ /* jtreg didn't find pid, most probably we are on JDK < 9
+ there is no Process::getPid */
+ if (HAS_NATIVE_LIBRARY && "windows".equals(OS.current().family)) {
+ try {
+ Field field = process.getClass().getDeclaredField("handle");
+ boolean old = field.isAccessible();
+ try {
+ field.setAccessible(true);
+ long handle = field.getLong(process);
+ result = getWin32Pid(handle);
+ } finally {
+ field.setAccessible(old);
+ }
+ } catch (ReflectiveOperationException e) {
+ e.printStackTrace(log);
+ }
+ }
+ }
+ return result;
+ }
+
+ private native long getWin32Pid(long handle);
+
+ private void runGatherer(String name, Path workDir, PrintWriter log,
+ PrintWriter out, long pid) {
+ try (HtmlPage html = new HtmlPage(out)) {
+ ProcessInfoGatherer gatherer = new GathererFactory(
+ OS.current().family,
+ workDir, log, testJdk.toPath()).getProcessInfoGatherer();
+ try (ElapsedTimePrinter timePrinter
+ = new ElapsedTimePrinter(new Stopwatch(), name, log)) {
+ gatherer.gatherProcessInfo(html.getRootSection(), pid);
+ }
+ } catch (Throwable e) {
+ log.printf("ERROR: exception in timeout handler %s:", name);
+ e.printStackTrace(log);
+ }
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/OS.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/OS.java
new file mode 100644
index 0000000..ccc1861
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/jtreg/OS.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.jtreg;
+
+// Stripped down version of jtreg internal class com.sun.javatest.regtest.config.OS
+class OS {
+ public final String family;
+
+ private static OS current;
+
+ public static OS current() {
+ if (current == null) {
+ String name = System.getProperty("os.name");
+ current = new OS(name);
+ }
+ return current;
+ }
+
+ private OS(String name) {
+ if (name.startsWith("Linux")) {
+ family = "linux";
+ } else if (name.startsWith("Mac") || name.startsWith("Darwin")) {
+ family = "mac";
+ } else if (name.startsWith("SunOS") || name.startsWith("Solaris")) {
+ family = "solaris";
+ } else if (name.startsWith("Windows")) {
+ family = "windows";
+ } else {
+ // use first word of name
+ family = name.replaceFirst("^([^ ]+).*", "$1");
+ }
+ }
+}
+
+
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java
new file mode 100644
index 0000000..fd2e4e6
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ArrayParser.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.lang.reflect.Array;
+import java.util.Objects;
+
+public class ArrayParser implements ValueParser {
+ private final ValueParser parser;
+
+ public ArrayParser(ValueParser parser) {
+ Objects.requireNonNull(parser);
+ this.parser = parser;
+ }
+
+ @Override
+ public Object parse(Class<?> type, String value, String delimiter) {
+ Class<?> component = type.getComponentType();
+ if (component.isArray()) {
+ throw new IllegalArgumentException(
+ "multidimensional array fields aren't supported");
+ }
+ String[] values = (value == null || value.isEmpty())
+ ? new String[]{}
+ : value.split(delimiter);
+ Object result = Array.newInstance(component, values.length);
+ for (int i = 0, n = values.length; i < n; ++i) {
+ Array.set(result, i, parser.parse(component, values[i], delimiter));
+ }
+ return result;
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java
new file mode 100644
index 0000000..7de7442
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultParser.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DefaultParser implements ValueParser {
+ private static final Map<Class<?>, BasicParser> PARSERS = new HashMap<>();
+
+ static {
+ BasicParser.init();
+ }
+
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ if (type.isArray()) {
+ return new ArrayParser(this).parse(type, value, s);
+ }
+ ValueParser parser = PARSERS.get(type);
+ if (parser == null) {
+ throw new IllegalArgumentException("can't find parser for "
+ + type.getName());
+ }
+
+ return parser.parse(type, value, s);
+ }
+
+ private static enum BasicParser implements ValueParser {
+ BOOL(boolean.class, Boolean.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Boolean.valueOf(value);
+ }
+ },
+ BYTE(byte.class, Byte.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Byte.decode(value);
+ }
+ },
+ CHAR(char.class, Character.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ if (value.length() != 1) {
+ throw new IllegalArgumentException(
+ String.format("can't cast %s to char", value));
+ }
+ return value.charAt(0);
+ }
+ },
+ SHORT(short.class, Short.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Short.decode(value);
+ }
+ },
+ INT(int.class, Integer.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Integer.decode(value);
+ }
+ },
+ LONG(long.class, Long.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Long.decode(value);
+ }
+ },
+ FLOAT(float.class, Float.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Float.parseFloat(value);
+ }
+ },
+ DOUBLE(double.class, Double.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return Double.parseDouble(value);
+ }
+ },
+ STRING(String.class, Object.class) {
+ @Override
+ public Object parse(Class<?> type, String value, String s) {
+ return value;
+ }
+ };
+
+ private BasicParser(Class<?>... classes) {
+ for (Class<?> aClass : classes) {
+ DefaultParser.PARSERS.put(aClass, this);
+ }
+ }
+
+ private static void init() {
+ // no-op used to provoke <cinit>
+ }
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java
new file mode 100644
index 0000000..081a9fd
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/DefaultValue.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = ElementType.FIELD)
+public @interface DefaultValue {
+ String value();
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java
new file mode 100644
index 0000000..6d544c2
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/InvalidValueException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+public class InvalidValueException extends Exception {
+ public InvalidValueException() { }
+
+ public InvalidValueException(String message) {
+ super(message);
+ }
+
+ public InvalidValueException(String s, Throwable e) {
+ super(s, e);
+ }
+
+ public InvalidValueException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java
new file mode 100644
index 0000000..89ed3a7
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/PathValueParser.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.io.File;
+
+public class PathValueParser implements ValueParser {
+ @Override
+ public Object parse(Class<?> type, String value, String delimiter) {
+ if (type.isArray()) {
+ return new ArrayParser(this).parse(type, value, delimiter);
+ }
+ return new File(value).toPath();
+ }
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java
new file mode 100644
index 0000000..cc09a0d
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/SubValues.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = ElementType.FIELD)
+public @interface SubValues {
+ String prefix();
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java
new file mode 100644
index 0000000..9f4c3cd
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/Value.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = ElementType.FIELD)
+public @interface Value {
+ String name();
+ Class<? extends ValueParser> parser() default DefaultParser.class;
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java
new file mode 100644
index 0000000..971f11e
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueHandler.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+import jdk.test.failurehandler.Utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Objects;
+import java.util.Properties;
+
+public final class ValueHandler {
+ public static <T> void apply(T object, Properties properties,
+ String prefix) throws InvalidValueException {
+ Objects.requireNonNull(object, "object cannot be null");
+ Objects.requireNonNull(properties, "properties cannot be null");
+ Class<?> aClass = object.getClass();
+ while (aClass != null) {
+ for (Field field : aClass.getDeclaredFields()) {
+ Value p = field.getAnnotation(Value.class);
+ if (p != null) {
+ applyToField(p, object, field, properties, prefix);
+ } else {
+ SubValues sub
+ = field.getAnnotation(SubValues.class);
+ if (sub != null) {
+ getAccess(field);
+ try {
+ apply(field.get(object), properties,
+ Utils.prependPrefix(prefix, sub.prefix()));
+ } catch (IllegalAccessException e) {
+ throw new InvalidValueException(String.format(
+ "can't apply sub properties to %s.",
+ field.getName()));
+ }
+ }
+ }
+ }
+ aClass = aClass.getSuperclass();
+ }
+ }
+
+ private static void applyToField(Value property, Object object,
+ Field field, Properties properties, String prefix)
+ throws InvalidValueException {
+ getAccess(field);
+ if (Modifier.isFinal(field.getModifiers())) {
+ throw new InvalidValueException(
+ String.format("field '%s' is final", field));
+ }
+ String name = Utils.prependPrefix(prefix, property.name());
+ String value = getProperty(properties, prefix, property.name());
+ if (value == null) {
+ DefaultValue defaultValue
+ = field.getAnnotation(DefaultValue.class);
+ value = defaultValue == null ? null : defaultValue.value();
+ }
+ if (value == null) {
+ throw new InvalidValueException(String.format(
+ "can't set '%s', because properties don't have '%s'.",
+ field.getName(), name));
+ }
+ String delimiter = getProperty(properties,
+ Utils.prependPrefix(prefix, property.name()), "delimiter");
+ delimiter = delimiter == null ? " " : delimiter;
+ Class<? extends ValueParser> parserClass = property.parser();
+ try {
+ field.set(object, parserClass.newInstance().parse(
+ field.getType(), value, delimiter));
+ } catch (ReflectiveOperationException | IllegalArgumentException e) {
+ throw new InvalidValueException(
+ String.format("can't set field '%s' : %s",
+ field.getName(), e.getMessage()), e);
+ }
+ }
+
+ private static String getProperty(Properties properties,
+ String prefix, String name) {
+ if (prefix == null || prefix.isEmpty()) {
+ return properties.getProperty(name);
+ }
+ int index = prefix.length();
+ do {
+ String value = properties.getProperty(
+ Utils.prependPrefix(prefix.substring(0, index), name));
+ if (value != null) {
+ return value;
+ }
+ index = prefix.lastIndexOf('.', index - 1);
+ } while (index > 0);
+ return properties.getProperty(name);
+ }
+
+ private static void getAccess(Field field) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isPublic(modifiers)) {
+ field.setAccessible(true);
+ }
+ }
+
+}
diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java
new file mode 100644
index 0000000..fe7c00a
--- /dev/null
+++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/value/ValueParser.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.failurehandler.value;
+
+public interface ValueParser {
+ Object parse(Class<?> type, String value, String delimiter);
+}