From 9eb2207e36921df148bfed1c1807dd3e4344cc86 Mon Sep 17 00:00:00 2001 From: Joe Lauer Date: Fri, 3 Nov 2023 00:45:01 -0400 Subject: [PATCH] Improved java detection --- pom.xml | 7 + .../com/fizzed/jne/HardwareArchitecture.java | 4 +- src/main/java/com/fizzed/jne/JavaHomes.java | 146 +++++++++++++++--- .../java/com/fizzed/jne/OperatingSystem.java | 25 ++- .../java/com/fizzed/jne/PlatformInfo.java | 19 ++- .../java/com/fizzed/jne/JavaHomesTest.java | 135 +++++++++++++++- .../resources/jdkversions/graalvm-jdk-21.txt | 3 + .../resources/jdkversions/oracle-jdk-6.txt | 3 + .../resources/jdkversions/zulu-jdk-11.txt | 3 + src/test/resources/jdkversions/zulu-jdk-7.txt | 3 + .../resources/mockjdks/jdk-8-legacy/bin/java | 0 .../mockjdks/jdk-8-legacy/bin/java.exe | 0 .../mockjdks/jdk-8-legacy/jre/bin/java | 0 .../mockjdks/jdk-8-legacy/jre/bin/java.exe | 0 .../mockjdks/jdk-8-legacy/jre/lib/test.txt | 0 .../mockjdks/jdk-8-legacy/lib/test.txt | 0 .../resources/mockjdks/jdk-8-legacy/release | 10 ++ .../mockjdks/jdk-zulu-11-arm64-musl/bin/java | 0 .../jdk-zulu-11-arm64-musl/bin/java.exe | 0 .../jdk-zulu-11-arm64-musl/lib/test.txt | 0 .../mockjdks/jdk-zulu-11-arm64-musl/release | 10 ++ .../mockjdks/jdk-zulu-11-armel/bin/java | 0 .../mockjdks/jdk-zulu-11-armel/bin/java.exe | 0 .../mockjdks/jdk-zulu-11-armel/lib/test.txt | 0 .../mockjdks/jdk-zulu-11-armel/release | 11 ++ .../mockjdks/jdk-zulu-11-armhf/bin/java | 0 .../mockjdks/jdk-zulu-11-armhf/bin/java.exe | 0 .../mockjdks/jdk-zulu-11-armhf/lib/test.txt | 0 .../mockjdks/jdk-zulu-11-armhf/release | 10 ++ 29 files changed, 356 insertions(+), 33 deletions(-) create mode 100644 src/test/resources/jdkversions/graalvm-jdk-21.txt create mode 100644 src/test/resources/jdkversions/oracle-jdk-6.txt create mode 100644 src/test/resources/jdkversions/zulu-jdk-11.txt create mode 100644 src/test/resources/jdkversions/zulu-jdk-7.txt create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/bin/java create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/bin/java.exe create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java.exe create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/jre/lib/test.txt create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/lib/test.txt create mode 100644 src/test/resources/mockjdks/jdk-8-legacy/release create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java.exe create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/lib/test.txt create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/release create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java.exe create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armel/lib/test.txt create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armel/release create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java.exe create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armhf/lib/test.txt create mode 100644 src/test/resources/mockjdks/jdk-zulu-11-armhf/release diff --git a/pom.xml b/pom.xml index 5befdb0..d76a12a 100644 --- a/pom.xml +++ b/pom.xml @@ -74,5 +74,12 @@ test + + com.fizzed + crux-util + 1.0.43 + test + + diff --git a/src/main/java/com/fizzed/jne/HardwareArchitecture.java b/src/main/java/com/fizzed/jne/HardwareArchitecture.java index a5d932d..497f748 100644 --- a/src/main/java/com/fizzed/jne/HardwareArchitecture.java +++ b/src/main/java/com/fizzed/jne/HardwareArchitecture.java @@ -28,10 +28,10 @@ public enum HardwareArchitecture { X32("x32", new String[] { "i386", "i586", "i686" }, new String[] { "x86" }), X64("x64", new String[] { "x86_64", "amd64" }), // also known as amd64 or x86_64 ARMEL("armel", null, new String[] { "arm32v5", "arm32v6" }), // ARMEL, ARM 32-bit SF v6, v7, v5 - ARMHF("armhf", null, new String[] { "arm32v7" }), // ARMHF stands for "ARM hard float", and is the name given to a Debian port for ARM processors (armv7+) that have hardware floating point support, which is found on most modern 32-bit ARM boards + ARMHF("armhf", null, new String[] { "arm32v7", "armv7l" }), // ARMHF stands for "ARM hard float", and is the name given to a Debian port for ARM processors (armv7+) that have hardware floating point support, which is found on most modern 32-bit ARM boards ARM64("arm64", new String[] { "aarch64" }, new String[] { "arm64v8" }), // used by docker RISCV64("riscv64", null, new String[] { "riscv64gc" }), // used by llvm - MIPS64LE("mips64le", null), + MIPS64LE("mips64le", new String[] { "mips64el" }), S390X("s390x", null), PPC64LE("ppc64le", null); diff --git a/src/main/java/com/fizzed/jne/JavaHomes.java b/src/main/java/com/fizzed/jne/JavaHomes.java index 0116109..94358f2 100644 --- a/src/main/java/com/fizzed/jne/JavaHomes.java +++ b/src/main/java/com/fizzed/jne/JavaHomes.java @@ -23,14 +23,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.UncheckedIOException; +import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -38,6 +37,10 @@ public class JavaHomes { static private final Logger log = LoggerFactory.getLogger(JavaHome.class); static public JavaHome fromDirectory(Path javaHomeDir) throws IOException { + return fromDirectory(javaHomeDir, false); + } + + static public JavaHome fromDirectory(Path javaHomeDir, boolean requireReleaseFile) throws IOException { if (!Files.isDirectory(javaHomeDir)) { throw new FileNotFoundException("Java home directory " + javaHomeDir + " does not exist"); } @@ -46,12 +49,22 @@ static public JavaHome fromDirectory(Path javaHomeDir) throws IOException { // Test #1: bin/java exists? final String javaExeFileName = NativeTarget.resolveExecutableFileName(thisOs, "java"); - final Path javaExeFile = javaHomeDir.resolve("bin").resolve(javaExeFileName); + Path javaExeFile = javaHomeDir.resolve("bin").resolve(javaExeFileName); if (!Files.isRegularFile(javaExeFile)) { throw new FileNotFoundException("Java executable " + javaExeFile + " was not found in " + javaHomeDir); } + // For old Java 8, sometimes we're in the "jre" directory, where we really need to probe the directory above + if ("jre".equalsIgnoreCase(javaHomeDir.getFileName().toString())) { + Path jdkHomeDir = javaHomeDir.getParent(); + Path javaExeFileAlt = jdkHomeDir.resolve("bin").resolve(javaExeFileName); + if (Files.isRegularFile(javaExeFileAlt)) { + javaHomeDir = jdkHomeDir; + javaExeFile = javaExeFileAlt; + } + } + // Test #2: sometimes we can find a bin/java, especially if we're dealing with a directory simply on the PATH // we need to make sure this directory "looks" like a typical java home, with a "lib" dir, etc. final Path javaLibDir = javaHomeDir.resolve("lib"); @@ -79,28 +92,54 @@ static public JavaHome fromDirectory(Path javaHomeDir) throws IOException { final Path releaseFile = javaHomeDir.resolve("release"); if (Files.isRegularFile(releaseFile)) { releaseProperties = JavaHomes.readReleaseProperties(releaseFile); + } - String releaseJavaVersion = releaseProperties.get("JAVA_VERSION"); - if (releaseJavaVersion != null) { - version = JavaVersion.parse(releaseJavaVersion); + if (releaseProperties == null) { + if (requireReleaseFile){ + throw new FileNotFoundException("Java release file " + releaseFile + " was not found in " + javaHomeDir); } - - String releaseOs = releaseProperties.get("OS_NAME"); - if (releaseOs != null) { - operatingSystem = OperatingSystem.resolve(releaseOs); + // otherwise, we could do "java -version" to try and detect it + try { + String versionOutput = executeJavaVersion(javaExeFile); + releaseProperties = readJavaVersionOutput(versionOutput); + } catch (Exception e) { + throw new IOException("Unable to execute -version command on " + javaExeFile, e); } + } + + String releaseJavaVersion = releaseProperties.get("JAVA_VERSION"); + if (releaseJavaVersion != null) { + version = JavaVersion.parse(releaseJavaVersion); + } - String releaseArch = releaseProperties.get("OS_ARCH"); - if (releaseArch != null) { - hardwareArchitecture = HardwareArchitecture.resolve(releaseArch); - // TODO: need special handling for "arm" + String releaseOs = releaseProperties.get("OS_NAME"); + if (releaseOs != null) { + operatingSystem = OperatingSystem.resolve(releaseOs); + } + + String releaseArch = releaseProperties.get("OS_ARCH"); + if (releaseArch != null) { + hardwareArchitecture = HardwareArchitecture.resolve(releaseArch); + // special handling for "arm" + if (hardwareArchitecture == null) { + if ("arm".equalsIgnoreCase(releaseArch)) { + String sunArchAbi = releaseProperties.get("SUN_ARCH_ABI"); + if ("gnueabihf".equalsIgnoreCase(sunArchAbi)) { + hardwareArchitecture = HardwareArchitecture.ARMHF; + } else if ("gnueabi".equalsIgnoreCase(sunArchAbi)) { + hardwareArchitecture = HardwareArchitecture.ARMEL; + } + } } + } - vendor = releaseProperties.get("IMPLEMENTOR"); - } else { - throw new FileNotFoundException("Java release file " + releaseFile + " was not found in " + javaHomeDir); + String releaseLibc = releaseProperties.get("LIBC"); + if (releaseLibc != null) { + abi = ABI.resolve(releaseLibc); } + vendor = releaseProperties.get("IMPLEMENTOR"); + return new JavaHome(javaHomeDir, javaExeFile, javacExeFile, operatingSystem, hardwareArchitecture, abi, vendor, version, releaseProperties); } @@ -125,6 +164,75 @@ static public Map readReleaseProperties(Path releaseFile) throws return nameValues; } + static public String executeJavaVersion(Path javaExeFile) throws IOException, InterruptedException { + final Process process = new ProcessBuilder() + .command(javaExeFile.toString(), "-version") + .redirectErrorStream(true) + .start(); + + // we do not need the input stream + process.getOutputStream().close(); + + // read all the output + final StringBuilder output = new StringBuilder(); + final byte[] buf = new byte[1024]; + try (InputStream input = process.getInputStream()) { + int read = 1; + while (read > 0) { + read = input.read(buf); + if (read > 0) { + output.append(new String(buf, 0, read, StandardCharsets.UTF_8)); + } + } + } + + // the exit value MUST be zero + process.waitFor(5, TimeUnit.SECONDS); + + if (process.exitValue() != 0) { + throw new IOException("Version command failed with exit value " + process.exitValue()); + } + + return output.toString(); + } + + static public Map readJavaVersionOutput(String versionOutput) throws IOException { + final String[] lines = versionOutput.split("\n"); + final Map nameValues = new HashMap<>(); + + // first line should have the version + String line1 = lines[0]; + int doubleQuoteStartPos = line1.indexOf('"'); + if (doubleQuoteStartPos > 0) { + int doubleQuoteEndPos = line1.indexOf('"', doubleQuoteStartPos+1); + if (doubleQuoteEndPos > doubleQuoteStartPos) { + String version = line1.substring(doubleQuoteStartPos+1, doubleQuoteEndPos); + nameValues.put("JAVA_VERSION", version.trim()); + } + } + + // second line should have the implementer version + if (lines.length > 1) { + String line2 = lines[1]; + int implStartPos = line2.toLowerCase().indexOf("runtime environment "); + if (implStartPos > 0) { + int implEndPos = line2.indexOf(" (build", implStartPos+1); + if (implEndPos > implStartPos+23) { + String implementerVersion = line2.substring(implStartPos+20, implEndPos); + + // remove ( and ) from it? + if (implementerVersion.charAt(0) == '(' && implementerVersion.charAt(implementerVersion.length()-1) == ')') { + implementerVersion = implementerVersion.substring(1, implementerVersion.length()-1); + } + + nameValues.put("IMPLEMENTOR_VERSION", implementerVersion.trim()); + } + } + } + + return nameValues; + } + static public List detect() throws Exception { final NativeTarget nativeTarget = NativeTarget.detect(); diff --git a/src/main/java/com/fizzed/jne/OperatingSystem.java b/src/main/java/com/fizzed/jne/OperatingSystem.java index eaf0af2..4f959f5 100644 --- a/src/main/java/com/fizzed/jne/OperatingSystem.java +++ b/src/main/java/com/fizzed/jne/OperatingSystem.java @@ -26,18 +26,24 @@ public enum OperatingSystem { WINDOWS("Windows", null), - MACOS("MacOS", new String[] { "osx" }), + MACOS("MacOS", new String[] { "osx" }, new String[] { "darwin" }), LINUX("Linux", null), FREEBSD("FreeBSD", null), OPENBSD("OpenBSD", null), - SOLARIS("Solaris", null); + SOLARIS("Solaris", new String[] { "sun" }); private final String descriptor; private final String[] aliases; + private final String[] extraAliases; OperatingSystem(String descriptor, String[] aliases) { + this(descriptor, aliases, null); + } + + OperatingSystem(String descriptor, String[] aliases, String[] extraAliases) { this.descriptor = descriptor; this.aliases = aliases; + this.extraAliases = extraAliases; } public String getDescriptor() { @@ -48,18 +54,29 @@ public String[] getAliases() { return aliases; } + public String[] getExtraAliases() { + return extraAliases; + } + static public OperatingSystem resolve(String value) { for (OperatingSystem os : OperatingSystem.values()) { if (os.name().equalsIgnoreCase(value)) { return os; } - if (os.getAliases() != null) { - for (String alias : os.getAliases()) { + if (os.aliases != null) { + for (String alias : os.aliases) { if (alias.equalsIgnoreCase(value)) { return os; } } } + if (os.extraAliases != null) { + for (String extraAlias : os.extraAliases) { + if (extraAlias.equalsIgnoreCase(value)) { + return os; + } + } + } } return null; } diff --git a/src/main/java/com/fizzed/jne/PlatformInfo.java b/src/main/java/com/fizzed/jne/PlatformInfo.java index a19427b..78b184a 100644 --- a/src/main/java/com/fizzed/jne/PlatformInfo.java +++ b/src/main/java/com/fizzed/jne/PlatformInfo.java @@ -66,7 +66,8 @@ static OperatingSystem doDetectOperatingSystem() { } static OperatingSystem detectOperatingSystemFromValues(String osName) { - if (osName != null) { + return OperatingSystem.resolve(osName); + /*if (osName != null) { osName = osName.toLowerCase(); if (osName.contains("windows")) { return OperatingSystem.WINDOWS; @@ -82,7 +83,7 @@ static OperatingSystem detectOperatingSystemFromValues(String osName) { return OperatingSystem.OPENBSD; } } - return null; + return null;*/ } // @@ -135,7 +136,13 @@ static HardwareArchitecture detectHardwareArchitectureFromValues( abiType = abiType != null ? abiType.toLowerCase() : "none"; bootLibPath = bootLibPath != null ? bootLibPath.toLowerCase() : "none"; - if (osArch.contains("amd64") || osArch.contains("x86_64")) { + // delegate most of the lookup to the HW enum + HardwareArchitecture hardwareArchitecture = HardwareArchitecture.resolve(osArch); + if (hardwareArchitecture != null) { + return hardwareArchitecture; + } + + /*if (osArch.contains("amd64") || osArch.contains("x86_64")) { return HardwareArchitecture.X64; } else if (osArch.contains("i386") || osArch.contains("i686") || osArch.contains("x86")) { return HardwareArchitecture.X32; @@ -143,7 +150,7 @@ static HardwareArchitecture detectHardwareArchitectureFromValues( return HardwareArchitecture.ARM64; } else if (osArch.contains("armv7l")) { return HardwareArchitecture.ARMHF; - } else if (osArch.contains("arm") || osArch.contains("aarch32")) { + } else*/ if (osArch.contains("arm") || osArch.contains("aarch32")) { // unfortunately, this arch is used for ARMEL vs ARMHF, we can leverage the mapped files on linux to help differentiate log.trace("System property arch [{}] is ambiguous, will try a few workarounds", osArch); // abitype? e.g. gnueabihf @@ -168,7 +175,7 @@ static HardwareArchitecture detectHardwareArchitectureFromValues( return linuxMappedFilesResult.getArch(); } // the most common is likely hard float - } else if (osArch.contains("riscv64")) { + } /*else if (osArch.contains("riscv64")) { return HardwareArchitecture.RISCV64; } else if (osArch.contains("s390x")) { return HardwareArchitecture.S390X; @@ -176,7 +183,7 @@ static HardwareArchitecture detectHardwareArchitectureFromValues( return HardwareArchitecture.PPC64LE; } else if (osArch.contains("mips64el") || osArch.contains("mips64le")) { return HardwareArchitecture.MIPS64LE; - } + }*/ } return null; } diff --git a/src/test/java/com/fizzed/jne/JavaHomesTest.java b/src/test/java/com/fizzed/jne/JavaHomesTest.java index 44c8efc..d29e839 100644 --- a/src/test/java/com/fizzed/jne/JavaHomesTest.java +++ b/src/test/java/com/fizzed/jne/JavaHomesTest.java @@ -20,11 +20,15 @@ * #L% */ +import com.fizzed.crux.util.Resources; +import com.fizzed.crux.util.StopWatch; import org.junit.jupiter.api.Test; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.nio.file.Path; +import java.util.Map; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -84,8 +88,8 @@ public void fromDirectoryJdkMissingReleaseFile() throws Exception { try { JavaHomes.fromDirectory(javaHomeDir); fail(); - } catch (FileNotFoundException e) { - // expected + } catch (IOException e) { + // expected since java isn't a real executable } } @@ -114,9 +118,136 @@ public void fromDirectoryJdkZulu11() throws Exception { assertThat(javaHome.getVendor(), is("Azul Systems, Inc.")); assertThat(javaHome.getHardwareArchitecture(), is(HardwareArchitecture.X64)); assertThat(javaHome.getOperatingSystem(), is(OperatingSystem.WINDOWS)); + assertThat(javaHome.getAbi(), is(ABI.DEFAULT)); assertThat(javaHome.getVersion().getMajor(), is(11)); assertThat(javaHome.getVersion().getMinor(), is(0)); assertThat(javaHome.getVersion().getSecurity(), is(17)); } + @Test + public void fromDirectoryJdkZulu11Arm64Musl() throws Exception { + final Path javaHomeDir = this.mockJdksDir.resolve("jdk-zulu-11-arm64-musl"); + + final JavaHome javaHome = JavaHomes.fromDirectory(javaHomeDir); + + assertThat(javaHome.getJavaExe(), is(not(nullValue()))); + assertThat(javaHome.getVendor(), is("Azul Systems, Inc.")); + assertThat(javaHome.getHardwareArchitecture(), is(HardwareArchitecture.ARM64)); + assertThat(javaHome.getOperatingSystem(), is(OperatingSystem.LINUX)); + assertThat(javaHome.getAbi(), is(ABI.MUSL)); + assertThat(javaHome.getVersion().getMajor(), is(11)); + assertThat(javaHome.getVersion().getMinor(), is(0)); + assertThat(javaHome.getVersion().getSecurity(), is(20)); + assertThat(javaHome.getVersion().getBuild(), is(1)); + } + + @Test + public void fromDirectoryJdkZulu11Armel() throws Exception { + final Path javaHomeDir = this.mockJdksDir.resolve("jdk-zulu-11-armel"); + + final JavaHome javaHome = JavaHomes.fromDirectory(javaHomeDir); + + assertThat(javaHome.getJavaExe(), is(not(nullValue()))); + assertThat(javaHome.getVendor(), is("Azul Systems, Inc.")); + assertThat(javaHome.getHardwareArchitecture(), is(HardwareArchitecture.ARMEL)); + assertThat(javaHome.getOperatingSystem(), is(OperatingSystem.LINUX)); + assertThat(javaHome.getAbi(), is(ABI.DEFAULT)); + assertThat(javaHome.getVersion().getMajor(), is(11)); + assertThat(javaHome.getVersion().getMinor(), is(0)); + assertThat(javaHome.getVersion().getSecurity(), is(20)); + assertThat(javaHome.getVersion().getBuild(), is(1)); + } + + @Test + public void fromDirectoryJdkZulu11Armhf() throws Exception { + final Path javaHomeDir = this.mockJdksDir.resolve("jdk-zulu-11-armhf"); + + final JavaHome javaHome = JavaHomes.fromDirectory(javaHomeDir); + + assertThat(javaHome.getJavaExe(), is(not(nullValue()))); + assertThat(javaHome.getVendor(), is("Azul Systems, Inc.")); + assertThat(javaHome.getHardwareArchitecture(), is(HardwareArchitecture.ARMHF)); + assertThat(javaHome.getOperatingSystem(), is(OperatingSystem.LINUX)); + assertThat(javaHome.getAbi(), is(ABI.DEFAULT)); + assertThat(javaHome.getVersion().getMajor(), is(11)); + assertThat(javaHome.getVersion().getMinor(), is(0)); + assertThat(javaHome.getVersion().getSecurity(), is(19)); + assertThat(javaHome.getVersion().getBuild(), is(0)); + } + + @Test + public void fromDirectoryJdk8Legacy() throws Exception { + // resolve the jre directory of the jdk such as how java 8 does it + final Path javaHomeJreDir = this.mockJdksDir.resolve("jdk-8-legacy/jre"); + + final JavaHome javaHome = JavaHomes.fromDirectory(javaHomeJreDir); + + assertThat(javaHome.getJavaExe(), is(not(nullValue()))); + assertThat(javaHome.getVendor(), is("Azul Systems, Inc.")); + assertThat(javaHome.getHardwareArchitecture(), is(HardwareArchitecture.ARMHF)); + assertThat(javaHome.getOperatingSystem(), is(OperatingSystem.LINUX)); + assertThat(javaHome.getAbi(), is(ABI.DEFAULT)); + assertThat(javaHome.getVersion().getMajor(), is(11)); + assertThat(javaHome.getVersion().getMinor(), is(0)); + assertThat(javaHome.getVersion().getSecurity(), is(19)); + assertThat(javaHome.getVersion().getBuild(), is(0)); + } + + @Test + public void readJdk6VersionOutput() throws Exception { + // resolve the jre directory of the jdk such as how java 8 does it + final String output = Resources.stringUTF8("/jdkversions/oracle-jdk-6.txt"); + + final Map props = JavaHomes.readJavaVersionOutput(output); + + assertThat(props.get("JAVA_VERSION"), is("1.6.0_45")); + assertThat(props.get("IMPLEMENTOR_VERSION"), is(nullValue())); + } + + @Test + public void readJdk7VersionOutput() throws Exception { + // resolve the jre directory of the jdk such as how java 8 does it + final String output = Resources.stringUTF8("/jdkversions/zulu-jdk-7.txt"); + + final Map props = JavaHomes.readJavaVersionOutput(output); + + assertThat(props.get("JAVA_VERSION"), is("1.7.0_352")); + assertThat(props.get("IMPLEMENTOR_VERSION"), is("Zulu 7.56.0.11-CA-linux64")); + } + + @Test + public void readJdk11VersionOutput() throws Exception { + // resolve the jre directory of the jdk such as how java 8 does it + final String output = Resources.stringUTF8("/jdkversions/zulu-jdk-11.txt"); + + final Map props = JavaHomes.readJavaVersionOutput(output); + + assertThat(props.get("JAVA_VERSION"), is("11.0.17")); + assertThat(props.get("IMPLEMENTOR_VERSION"), is("Zulu11.60+19-CA")); + } + + @Test + public void readJdk21VersionOutput() throws Exception { + // resolve the jre directory of the jdk such as how java 8 does it + final String output = Resources.stringUTF8("/jdkversions/graalvm-jdk-21.txt"); + + final Map props = JavaHomes.readJavaVersionOutput(output); + + assertThat(props.get("JAVA_VERSION"), is("21")); + assertThat(props.get("IMPLEMENTOR_VERSION"), is("Oracle GraalVM 21+35.1")); + } + + @Test + public void executeJavaVersion() throws Exception { + final JavaHome javaHome = JavaHome.current(); + + final StopWatch timer = StopWatch.timeMillis(); + + final String versionOutput = JavaHomes.executeJavaVersion(javaHome.getJavaExe()); + + assertThat(versionOutput, is(not(nullValue()))); + /*System.out.println("Queried version in " + timer); + System.out.println(versionOutput);*/ + } + } diff --git a/src/test/resources/jdkversions/graalvm-jdk-21.txt b/src/test/resources/jdkversions/graalvm-jdk-21.txt new file mode 100644 index 0000000..f44e1d7 --- /dev/null +++ b/src/test/resources/jdkversions/graalvm-jdk-21.txt @@ -0,0 +1,3 @@ +java version "21" 2023-09-19 +Java(TM) SE Runtime Environment Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15) +Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing) \ No newline at end of file diff --git a/src/test/resources/jdkversions/oracle-jdk-6.txt b/src/test/resources/jdkversions/oracle-jdk-6.txt new file mode 100644 index 0000000..3d2c648 --- /dev/null +++ b/src/test/resources/jdkversions/oracle-jdk-6.txt @@ -0,0 +1,3 @@ +java version "1.6.0_45" +Java(TM) SE Runtime Environment (build 1.6.0_45-b06) +Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode) \ No newline at end of file diff --git a/src/test/resources/jdkversions/zulu-jdk-11.txt b/src/test/resources/jdkversions/zulu-jdk-11.txt new file mode 100644 index 0000000..765b41c --- /dev/null +++ b/src/test/resources/jdkversions/zulu-jdk-11.txt @@ -0,0 +1,3 @@ +openjdk version "11.0.17" 2022-10-18 LTS +OpenJDK Runtime Environment Zulu11.60+19-CA (build 11.0.17+8-LTS) +OpenJDK 64-Bit Server VM Zulu11.60+19-CA (build 11.0.17+8-LTS, mixed mode) \ No newline at end of file diff --git a/src/test/resources/jdkversions/zulu-jdk-7.txt b/src/test/resources/jdkversions/zulu-jdk-7.txt new file mode 100644 index 0000000..2ef6e3d --- /dev/null +++ b/src/test/resources/jdkversions/zulu-jdk-7.txt @@ -0,0 +1,3 @@ +openjdk version "1.7.0_352" +OpenJDK Runtime Environment (Zulu 7.56.0.11-CA-linux64) (build 1.7.0_352-b01) +OpenJDK 64-Bit Server VM (Zulu 7.56.0.11-CA-linux64) (build 24.352-b01, mixed mode) \ No newline at end of file diff --git a/src/test/resources/mockjdks/jdk-8-legacy/bin/java b/src/test/resources/mockjdks/jdk-8-legacy/bin/java new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/bin/java.exe b/src/test/resources/mockjdks/jdk-8-legacy/bin/java.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java b/src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java.exe b/src/test/resources/mockjdks/jdk-8-legacy/jre/bin/java.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/jre/lib/test.txt b/src/test/resources/mockjdks/jdk-8-legacy/jre/lib/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/lib/test.txt b/src/test/resources/mockjdks/jdk-8-legacy/lib/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-8-legacy/release b/src/test/resources/mockjdks/jdk-8-legacy/release new file mode 100644 index 0000000..3e25f92 --- /dev/null +++ b/src/test/resources/mockjdks/jdk-8-legacy/release @@ -0,0 +1,10 @@ +IMPLEMENTOR="Azul Systems, Inc." +IMPLEMENTOR_VERSION="Zulu11.64+19-CA" +JAVA_VERSION="11.0.19" +JAVA_VERSION_DATE="2023-04-18" +LIBC="default" +MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.le jdk.internal.opt jdk.jartool jdk.javadoc jdk.jcmd jdk.management jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.ldap jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported jdk.unsupported.desktop jdk.xml.dom jdk.zipfs" +OS_ARCH="arm" +OS_NAME="Linux" +SOURCE=".:git:7e42ec4d96f6" +SUN_ARCH_ABI="gnueabihf" \ No newline at end of file diff --git a/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java b/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java.exe b/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/bin/java.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/lib/test.txt b/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/lib/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/release b/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/release new file mode 100644 index 0000000..8424a7f --- /dev/null +++ b/src/test/resources/mockjdks/jdk-zulu-11-arm64-musl/release @@ -0,0 +1,10 @@ +IMPLEMENTOR="Azul Systems, Inc." +IMPLEMENTOR_VERSION="Zulu11.66+19-CA" +JAVA_RUNTIME_VERSION="11.0.20.1+1-LTS" +JAVA_VERSION="11.0.20.1" +JAVA_VERSION_DATE="2023-08-24" +LIBC="musl" +MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.vm.ci jdk.management jdk.unsupported jdk.internal.vm.compiler jdk.aot jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.le jdk.internal.opt jdk.internal.vm.compiler.management jdk.jartool jdk.javadoc jdk.jcmd jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.ldap jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported.desktop jdk.xml.dom jdk.zipfs" +OS_ARCH="aarch64" +OS_NAME="Linux" +SOURCE=".:git:5a316f5eb90c" \ No newline at end of file diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java b/src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java.exe b/src/test/resources/mockjdks/jdk-zulu-11-armel/bin/java.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armel/lib/test.txt b/src/test/resources/mockjdks/jdk-zulu-11-armel/lib/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armel/release b/src/test/resources/mockjdks/jdk-zulu-11-armel/release new file mode 100644 index 0000000..0f4de7d --- /dev/null +++ b/src/test/resources/mockjdks/jdk-zulu-11-armel/release @@ -0,0 +1,11 @@ +IMPLEMENTOR="Azul Systems, Inc." +IMPLEMENTOR_VERSION="Zulu11.66+19-CA" +JAVA_RUNTIME_VERSION="11.0.20.1+1-LTS" +JAVA_VERSION="11.0.20.1" +JAVA_VERSION_DATE="2023-08-24" +LIBC="default" +MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.le jdk.internal.opt jdk.jartool jdk.javadoc jdk.jcmd jdk.management jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.ldap jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported jdk.unsupported.desktop jdk.xml.dom jdk.zipfs" +OS_ARCH="arm" +OS_NAME="Linux" +SOURCE=".:git:5a316f5eb90c" +SUN_ARCH_ABI="gnueabi" \ No newline at end of file diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java b/src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java.exe b/src/test/resources/mockjdks/jdk-zulu-11-armhf/bin/java.exe new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armhf/lib/test.txt b/src/test/resources/mockjdks/jdk-zulu-11-armhf/lib/test.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/mockjdks/jdk-zulu-11-armhf/release b/src/test/resources/mockjdks/jdk-zulu-11-armhf/release new file mode 100644 index 0000000..3e25f92 --- /dev/null +++ b/src/test/resources/mockjdks/jdk-zulu-11-armhf/release @@ -0,0 +1,10 @@ +IMPLEMENTOR="Azul Systems, Inc." +IMPLEMENTOR_VERSION="Zulu11.64+19-CA" +JAVA_VERSION="11.0.19" +JAVA_VERSION_DATE="2023-04-18" +LIBC="default" +MODULES="java.base java.compiler java.datatransfer java.xml java.prefs java.desktop java.instrument java.logging java.management java.security.sasl java.naming java.rmi java.management.rmi java.net.http java.scripting java.security.jgss java.transaction.xa java.sql java.sql.rowset java.xml.crypto java.se java.smartcardio jdk.accessibility jdk.internal.jvmstat jdk.attach jdk.charsets jdk.compiler jdk.crypto.ec jdk.crypto.cryptoki jdk.dynalink jdk.internal.ed jdk.editpad jdk.hotspot.agent jdk.httpserver jdk.internal.le jdk.internal.opt jdk.jartool jdk.javadoc jdk.jcmd jdk.management jdk.management.agent jdk.jconsole jdk.jdeps jdk.jdwp.agent jdk.jdi jdk.jfr jdk.jlink jdk.jshell jdk.jsobject jdk.jstatd jdk.localedata jdk.management.jfr jdk.naming.dns jdk.naming.ldap jdk.naming.rmi jdk.net jdk.pack jdk.rmic jdk.scripting.nashorn jdk.scripting.nashorn.shell jdk.sctp jdk.security.auth jdk.security.jgss jdk.unsupported jdk.unsupported.desktop jdk.xml.dom jdk.zipfs" +OS_ARCH="arm" +OS_NAME="Linux" +SOURCE=".:git:7e42ec4d96f6" +SUN_ARCH_ABI="gnueabihf" \ No newline at end of file