Date: Mon, 29 May 2017 14:06:24 +0200
Subject: [PATCH 10/13] 8180651: Make target to run tests on exploded image
Reviewed-by: ihse
---
common/doc/testing.html | 4 +++-
common/doc/testing.md | 6 ++++++
make/Help.gmk | 2 ++
make/Main.gmk | 15 +++++++++++++--
4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/common/doc/testing.html b/common/doc/testing.html
index 265be8b9e8a..1b782f07eae 100644
--- a/common/doc/testing.html
+++ b/common/doc/testing.html
@@ -29,13 +29,15 @@
Using the run-test framework
This new way of running tests is developer-centric. It assumes that you have built a jdk locally and want to test it. Running common test targets is simple, and more complex ad-hoc combination of tests is possible. The user interface is forgiving, and clearly report errors it cannot resolve.
+The main target "run-test" uses the jdk-image as the tested product. There is also an alternate target "exploded-run-test" that uses the exploded image instead. Not all tests will run successfully on the exploded image, but using this target can greatly improve rebuild times for certain workflows.
Some example command-lines:
$ make run-test-tier1
$ make run-test-jdk_lang JTREG="JOBS=8"
$ make run-test TEST=jdk_lang
$ make run-test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"
-$ make run-test TEST="jtreg:hotspot/test:hotspot_gc hotspot/test/native_sanity/JniVersion.java"
+$ make run-test TEST="jtreg:hotspot/test:hotspot_gc hotspot/test/native_sanity/JniVersion.java"
+$ make exploded-run-test TEST=hotspot_tier1
Test selection
All functionality is available using the run-test make target. In this use case, the test or tests to be executed is controlled using the TEST variable. To speed up subsequent test runs with no source code changes, run-test-only can be used instead, which do not depend on the source and test image build.
For some common top-level tests, direct make targets have been generated. This includes all JTreg test groups, the hotspot gtest, and custom tests (if present). This means that make run-test-tier1 is equivalent to make run-test TEST="tier1", but the latter is more tab-completion friendly. For more complex test runs, the run-test TEST="x" solution needs to be used.
diff --git a/common/doc/testing.md b/common/doc/testing.md
index f84bd27dda2..231755c92b1 100644
--- a/common/doc/testing.md
+++ b/common/doc/testing.md
@@ -7,6 +7,11 @@ built a jdk locally and want to test it. Running common test targets is simple,
and more complex ad-hoc combination of tests is possible. The user interface is
forgiving, and clearly report errors it cannot resolve.
+The main target "run-test" uses the jdk-image as the tested product. There is
+also an alternate target "exploded-run-test" that uses the exploded image
+instead. Not all tests will run successfully on the exploded image, but using
+this target can greatly improve rebuild times for certain workflows.
+
Some example command-lines:
$ make run-test-tier1
@@ -15,6 +20,7 @@ Some example command-lines:
$ make run-test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
$ make run-test TEST="hotspot/test:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OTIONS=-XshowSettings -Xlog:gc+ref=debug"
$ make run-test TEST="jtreg:hotspot/test:hotspot_gc hotspot/test/native_sanity/JniVersion.java"
+ $ make exploded-run-test TEST=hotspot_tier1
## Test selection
diff --git a/make/Help.gmk b/make/Help.gmk
index c9a06d291af..4514eb08b8d 100644
--- a/make/Help.gmk
+++ b/make/Help.gmk
@@ -56,6 +56,8 @@ help:
$(info $(_) make test # Run tests, default is all tests (see TEST below))
$(info $(_) make run-test- # Run test, e.g. run-test-tier1)
$(info $(_) make run-test TEST= # Run test(s) given by TEST specification)
+ $(info $(_) make exploded-run-test TEST= # Run test(s) on the exploded image instead of)
+ $(info $(_) # the full jdk image)
$(info )
$(info Targets for cleaning)
$(info $(_) make clean # Remove all files generated by make, but not those)
diff --git a/make/Main.gmk b/make/Main.gmk
index ab6eb7d2e2b..7d85c1b062a 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -450,13 +450,18 @@ define DeclareRunTestRecipe
run-test-$1:
+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f RunTests.gmk run-test TEST="$1")
+ exploded-run-test-$1:
+ +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f RunTests.gmk run-test \
+ TEST="$1" JDK_IMAGE_DIR=$(JDK_OUTPUTDIR))
+
endef
# ALL_NAMED_TESTS is defined in FindTests.gmk
$(foreach t, $(ALL_NAMED_TESTS), $(eval $(call DeclareRunTestRecipe,$t)))
ALL_TEST_TARGETS := $(addprefix run-test-, $(ALL_NAMED_TESTS))
+ALL_EXPLODED_TEST_TARGETS := $(addprefix exploded-run-test-, $(ALL_NAMED_TESTS))
-ALL_TARGETS += $(ALL_TEST_TARGETS)
+ALL_TARGETS += $(ALL_TEST_TARGETS) $(ALL_EXPLODED_TEST_TARGETS)
################################################################################
# Build tests
@@ -485,6 +490,10 @@ test-image-jdk-jtreg-native:
run-test:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f RunTests.gmk run-test TEST="$(TEST)")
+exploded-run-test:
+ +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f RunTests.gmk run-test \
+ TEST="$(TEST)" JDK_IMAGE_DIR=$(JDK_OUTPUTDIR))
+
ifeq ($(BUILD_GTEST), true)
test-image-hotspot-gtest:
+($(CD) $(HOTSPOT_TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) -f GtestImage.gmk)
@@ -514,7 +523,7 @@ ALL_TARGETS += prepare-test-image build-test-hotspot-jtreg-native \
test-image-hotspot-jtreg-native build-test-jdk-jtreg-native \
test-image-jdk-jtreg-native build-test-lib build-test-failure-handler \
test-failure-handler test-image-failure-handler test-image-hotspot-gtest \
- run-test
+ run-test exploded-run-test
################################################################################
# Run tests
@@ -807,9 +816,11 @@ else
test: jdk-image test-image
run-test: jdk-image test-image
+ exploded-run-test: exploded-image test-image
# Declare dependency for all generated test targets
$(foreach t, $(ALL_TEST_TARGETS), $(eval $t: jdk-image test-image))
+ $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image))
create-buildjdk-copy: jdk.jlink-java java.base-gendata \
$(addsuffix -java, $(INTERIM_IMAGE_MODULES))
From 6d94dde81362e5bc451048afbd0bc5466c825009 Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Tue, 30 May 2017 14:56:43 -0700
Subject: [PATCH 11/13] 8180887: move FileUtils to top level testlibrary
Reviewed-by: psandoz
---
test/lib/jdk/test/lib/util/FileUtils.java | 229 ++++++++++++++++++++++
1 file changed, 229 insertions(+)
create mode 100644 test/lib/jdk/test/lib/util/FileUtils.java
diff --git a/test/lib/jdk/test/lib/util/FileUtils.java b/test/lib/jdk/test/lib/util/FileUtils.java
new file mode 100644
index 00000000000..8bbaded9586
--- /dev/null
+++ b/test/lib/jdk/test/lib/util/FileUtils.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2017, 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.lib.util;
+
+import jdk.test.lib.Platform;
+
+import java.io.IOException;
+import java.nio.file.DirectoryNotEmptyException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Common library for various test file utility functions.
+ */
+public final class FileUtils {
+ private static final boolean IS_WINDOWS = Platform.isWindows();
+ private static final int RETRY_DELETE_MILLIS = IS_WINDOWS ? 500 : 0;
+ private static final int MAX_RETRY_DELETE_TIMES = IS_WINDOWS ? 15 : 0;
+
+ /**
+ * Deletes a file, retrying if necessary.
+ *
+ * @param path the file to delete
+ *
+ * @throws NoSuchFileException
+ * if the file does not exist (optional specific exception)
+ * @throws DirectoryNotEmptyException
+ * if the file is a directory and could not otherwise be deleted
+ * because the directory is not empty (optional specific exception)
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public static void deleteFileWithRetry(Path path) throws IOException {
+ try {
+ deleteFileWithRetry0(path);
+ } catch (InterruptedException x) {
+ throw new IOException("Interrupted while deleting.", x);
+ }
+ }
+
+ /**
+ * Deletes a file, retrying if necessary.
+ * No exception thrown if file doesn't exist.
+ *
+ * @param path the file to delete
+ *
+ * @throws NoSuchFileException
+ * if the file does not exist (optional specific exception)
+ * @throws DirectoryNotEmptyException
+ * if the file is a directory and could not otherwise be deleted
+ * because the directory is not empty (optional specific exception)
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ public static void deleteFileIfExistsWithRetry(Path path) throws IOException {
+ try {
+ if (Files.exists(path)) {
+ deleteFileWithRetry0(path);
+ }
+ } catch (InterruptedException x) {
+ throw new IOException("Interrupted while deleting.", x);
+ }
+ }
+
+ private static void deleteFileWithRetry0(Path path)
+ throws IOException, InterruptedException {
+ int times = 0;
+ IOException ioe = null;
+ while (true) {
+ try {
+ Files.delete(path);
+ while (Files.exists(path)) {
+ times++;
+ if (times > MAX_RETRY_DELETE_TIMES) {
+ throw new IOException("File still exists after " + times + " waits.");
+ }
+ Thread.sleep(RETRY_DELETE_MILLIS);
+ }
+ break;
+ } catch (NoSuchFileException | DirectoryNotEmptyException x) {
+ throw x;
+ } catch (IOException x) {
+ // Backoff/retry in case another process is accessing the file
+ times++;
+ if (ioe == null) {
+ ioe = x;
+ } else {
+ ioe.addSuppressed(x);
+ }
+
+ if (times > MAX_RETRY_DELETE_TIMES) {
+ throw ioe;
+ }
+ Thread.sleep(RETRY_DELETE_MILLIS);
+ }
+ }
+ }
+
+ /**
+ * Deletes a directory and its subdirectories, retrying if necessary.
+ *
+ * @param dir the directory to delete
+ *
+ * @throws IOException
+ * If an I/O error occurs. Any such exceptions are caught
+ * internally. If only one is caught, then it is re-thrown.
+ * If more than one exception is caught, then the second and
+ * following exceptions are added as suppressed exceptions of the
+ * first one caught, which is then re-thrown.
+ */
+ public static void deleteFileTreeWithRetry(Path dir) throws IOException {
+ IOException ioe = null;
+ final List excs = deleteFileTreeUnchecked(dir);
+ if (!excs.isEmpty()) {
+ ioe = excs.remove(0);
+ for (IOException x : excs) {
+ ioe.addSuppressed(x);
+ }
+ }
+ if (ioe != null) {
+ throw ioe;
+ }
+ }
+
+ public static List deleteFileTreeUnchecked(Path dir) {
+ final List excs = new ArrayList<>();
+ try {
+ java.nio.file.Files.walkFileTree(dir, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ try {
+ deleteFileWithRetry0(file);
+ } catch (IOException x) {
+ excs.add(x);
+ } catch (InterruptedException x) {
+ excs.add(new IOException("Interrupted while deleting.", x));
+ return FileVisitResult.TERMINATE;
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ try {
+ deleteFileWithRetry0(dir);
+ } catch (IOException x) {
+ excs.add(x);
+ } catch (InterruptedException x) {
+ excs.add(new IOException("Interrupted while deleting.", x));
+ return FileVisitResult.TERMINATE;
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ excs.add(exc);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException x) {
+ excs.add(x);
+ }
+ return excs;
+ }
+
+ /**
+ * Checks whether all file systems are accessible. This is performed
+ * by checking free disk space on all mounted file systems via a
+ * separate, spawned process. File systems are considered to be
+ * accessible if this process completes successfully before a given
+ * fixed duration has elapsed.
+ *
+ * @implNote On Unix this executes the {@code df} command in a separate
+ * process and on Windows always returns {@code true}.
+ */
+ public static boolean areFileSystemsAccessible() throws IOException {
+ boolean areFileSystemsAccessible = true;
+ if (!IS_WINDOWS) {
+ // try to check whether 'df' hangs
+ System.out.println("\n--- df output ---");
+ System.out.flush();
+ Process proc = new ProcessBuilder("df").inheritIO().start();
+ try {
+ proc.waitFor(90, TimeUnit.SECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ try {
+ int exitValue = proc.exitValue();
+ if (exitValue != 0) {
+ System.err.printf("df process exited with %d != 0%n",
+ exitValue);
+ areFileSystemsAccessible = false;
+ }
+ } catch (IllegalThreadStateException ignored) {
+ System.err.println("df command apparently hung");
+ areFileSystemsAccessible = false;
+ }
+ }
+ return areFileSystemsAccessible;
+ }
+}
From 88c4940eeb34d8d2a702a21ce1ef8ad7cf781b62 Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Tue, 30 May 2017 21:07:14 -0700
Subject: [PATCH 12/13] 8180888: move jdk.testlibrary.JarUtils to the top level
testlibrary
Reviewed-by: weijun
---
test/lib/jdk/test/lib/util/JarUtils.java | 148 +++++++++++++++++++++++
1 file changed, 148 insertions(+)
create mode 100644 test/lib/jdk/test/lib/util/JarUtils.java
diff --git a/test/lib/jdk/test/lib/util/JarUtils.java b/test/lib/jdk/test/lib/util/JarUtils.java
new file mode 100644
index 00000000000..76705f5395c
--- /dev/null
+++ b/test/lib/jdk/test/lib/util/JarUtils.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2017, 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.lib.util;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ * Common library for various test jar file utility functions.
+ */
+public final class JarUtils {
+
+ /**
+ * Create jar file with specified files. If a specified file does not exist,
+ * a new jar entry will be created with the file name itself as the content.
+ */
+ public static void createJar(String dest, String... files)
+ throws IOException {
+ try (JarOutputStream jos = new JarOutputStream(
+ new FileOutputStream(dest), new Manifest())) {
+ for (String file : files) {
+ System.out.println(String.format("Adding %s to %s",
+ file, dest));
+
+ // add an archive entry, and write a file
+ jos.putNextEntry(new JarEntry(file));
+ try (FileInputStream fis = new FileInputStream(file)) {
+ fis.transferTo(jos);
+ } catch (FileNotFoundException e) {
+ jos.write(file.getBytes());
+ }
+ }
+ }
+ System.out.println();
+ }
+
+ /**
+ * Add or remove specified files to existing jar file. If a specified file
+ * to be updated or added does not exist, the jar entry will be created
+ * with the file name itself as the content.
+ *
+ * @param src the original jar file name
+ * @param dest the new jar file name
+ * @param files the files to update. The list is broken into 2 groups
+ * by a "-" string. The files before in the 1st group will
+ * be either updated or added. The files in the 2nd group
+ * will be removed. If no "-" exists, all files belong to
+ * the 1st group.
+ */
+ public static void updateJar(String src, String dest, String... files)
+ throws IOException {
+ try (JarOutputStream jos = new JarOutputStream(
+ new FileOutputStream(dest))) {
+
+ // copy each old entry into destination unless the entry name
+ // is in the updated list
+ List updatedFiles = new ArrayList<>();
+ try (JarFile srcJarFile = new JarFile(src)) {
+ Enumeration entries = srcJarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+ boolean found = false;
+ boolean update = true;
+ for (String file : files) {
+ if (file.equals("-")) {
+ update = false;
+ } else if (name.equals(file)) {
+ updatedFiles.add(file);
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (update) {
+ System.out.println(String.format("Updating %s with %s",
+ dest, name));
+ jos.putNextEntry(new JarEntry(name));
+ try (FileInputStream fis = new FileInputStream(name)) {
+ fis.transferTo(jos);
+ } catch (FileNotFoundException e) {
+ jos.write(name.getBytes());
+ }
+ } else {
+ System.out.println(String.format("Removing %s from %s",
+ name, dest));
+ }
+ } else {
+ System.out.println(String.format("Copying %s to %s",
+ name, dest));
+ jos.putNextEntry(entry);
+ srcJarFile.getInputStream(entry).transferTo(jos);
+ }
+ }
+ }
+
+ // append new files
+ for (String file : files) {
+ if (file.equals("-")) {
+ break;
+ }
+ if (!updatedFiles.contains(file)) {
+ System.out.println(String.format("Adding %s with %s",
+ dest, file));
+ jos.putNextEntry(new JarEntry(file));
+ try (FileInputStream fis = new FileInputStream(file)) {
+ fis.transferTo(jos);
+ } catch (FileNotFoundException e) {
+ jos.write(file.getBytes());
+ }
+ }
+ }
+ }
+ System.out.println();
+ }
+
+}
From 1ccebabd11bc30ab0bf4dd9f1f03bd4359ee29c1 Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Tue, 30 May 2017 21:14:02 -0700
Subject: [PATCH 13/13] 8180805: move RandomFactory to the top level
testlibrary
Reviewed-by: bpb, rriggs
---
test/lib/jdk/test/lib/RandomFactory.java | 103 +++++++++++++++++++++++
1 file changed, 103 insertions(+)
create mode 100644 test/lib/jdk/test/lib/RandomFactory.java
diff --git a/test/lib/jdk/test/lib/RandomFactory.java b/test/lib/jdk/test/lib/RandomFactory.java
new file mode 100644
index 00000000000..8930a380008
--- /dev/null
+++ b/test/lib/jdk/test/lib/RandomFactory.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, 2017, 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.lib;
+
+import java.util.Random;
+import java.util.SplittableRandom;
+
+/**
+ * Factory class which generates and prints to STDOUT a long-valued seed
+ * for use in initializing a PRNG. An instance of {@code Random} or
+ * {@code SplittableRandom} may likewise be obtained.
+ */
+public class RandomFactory {
+ /**
+ * Attempt to obtain the seed from the value of the "seed" property.
+ * @return The seed or {@code null} if the "seed" property was not set or
+ * could not be parsed.
+ */
+ private static Long getSystemSeed() {
+ Long seed = null;
+ try {
+ // note that Long.valueOf(null) also throws a
+ // NumberFormatException so if the property is undefined this
+ // will still work correctly
+ seed = Long.valueOf(System.getProperty("seed"));
+ } catch (NumberFormatException e) {
+ // do nothing: seed is still null
+ }
+
+ return seed;
+ }
+
+ /**
+ * Obtain a seed from an independent PRNG.
+ *
+ * @return A random seed.
+ */
+ private static long getRandomSeed() {
+ return new Random().nextLong();
+ }
+
+ /**
+ * Obtain and print to STDOUT a seed appropriate for initializing a PRNG.
+ * If the system property "seed" is set and has value which may be correctly
+ * parsed it is used, otherwise a seed is generated using an independent
+ * PRNG.
+ *
+ * @return The seed.
+ */
+ public static long getSeed() {
+ Long seed = getSystemSeed();
+ if (seed == null) {
+ seed = getRandomSeed();
+ }
+ System.out.println("Seed from RandomFactory = "+seed+"L");
+ return seed;
+ }
+
+ /**
+ * Obtain and print to STDOUT a seed and use it to initialize a new
+ * {@code Random} instance which is returned. If the system
+ * property "seed" is set and has value which may be correctly parsed it
+ * is used, otherwise a seed is generated using an independent PRNG.
+ *
+ * @return The {@code Random} instance.
+ */
+ public static Random getRandom() {
+ return new Random(getSeed());
+ }
+
+ /**
+ * Obtain and print to STDOUT a seed and use it to initialize a new
+ * {@code SplittableRandom} instance which is returned. If the system
+ * property "seed" is set and has value which may be correctly parsed it
+ * is used, otherwise a seed is generated using an independent PRNG.
+ *
+ * @return The {@code SplittableRandom} instance.
+ */
+ public static SplittableRandom getSplittableRandom() {
+ return new SplittableRandom(getSeed());
+ }
+}