From 620a654779efbb359429201682084978930b035f Mon Sep 17 00:00:00 2001 From: Rob Bavey Date: Tue, 26 Oct 2021 18:50:42 -0400 Subject: [PATCH] =?UTF-8?q?Add=20JavaVersionChecker=20to=20check=20Java=20?= =?UTF-8?q?version=20for=20compatibility=20before=E2=80=A6=20(#13356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add JavaVersionChecker to check Java version for compatibility before running Provides a "friendly" error message when running Logstash with an incompatible version of Java * Add version check to Windows * Improvements Improve readability of `JavaVersion` Fix logstash bash script to exit on JavaVersionChecker error --- bin/logstash.bat | 3 + bin/logstash.lib.sh | 5 ++ .../java/org/logstash/util/JavaVersion.java | 80 +++++++++++++++++++ .../org/logstash/util/JavaVersionChecker.java | 73 +++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 logstash-core/src/main/java/org/logstash/util/JavaVersion.java create mode 100644 logstash-core/src/main/java/org/logstash/util/JavaVersionChecker.java diff --git a/bin/logstash.bat b/bin/logstash.bat index 28850bb8f73..08f32925f7e 100644 --- a/bin/logstash.bat +++ b/bin/logstash.bat @@ -47,6 +47,9 @@ if "%MAYBE_JVM_OPTIONS_PARSER_FAILED%" == "jvm_options_parser_failed" ( ) set JAVA_OPTS=%LS_JAVA_OPTS% +rem check the Java version +%JAVA% -cp "%CLASSPATH%" "org.logstash.util.JavaVersionChecker" || exit /b 1 + %JAVA% %JAVA_OPTS% -cp "%CLASSPATH%" org.logstash.Logstash %* goto :end diff --git a/bin/logstash.lib.sh b/bin/logstash.lib.sh index efd7f49a401..28096f70824 100755 --- a/bin/logstash.lib.sh +++ b/bin/logstash.lib.sh @@ -138,6 +138,11 @@ setup_java() { export JAVACMD CLASSPATH="$(setup_classpath $LOGSTASH_JARS)" + + # Verify the version of Java being used, and exit if the wrong version of Java is not available. + if ! "${JAVACMD}" -cp "${CLASSPATH}" org.logstash.util.JavaVersionChecker ; then + exit 1 + fi JAVA_OPTS=`exec "${JAVACMD}" -cp "${CLASSPATH}" org.logstash.launchers.JvmOptionsParser "$LOGSTASH_HOME" "$LS_JVM_OPTS"` unset CLASSPATH export JAVA_OPTS diff --git a/logstash-core/src/main/java/org/logstash/util/JavaVersion.java b/logstash-core/src/main/java/org/logstash/util/JavaVersion.java new file mode 100644 index 00000000000..b5144da2837 --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/JavaVersion.java @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.logstash.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Helper class to compare current version of JVM with a target version. + * Based on JavaVersion class from elasticsearch java version checker tool + */ +public class JavaVersion { + + public static final JavaVersion CURRENT = parse(System.getProperty("java.specification.version")); + public static final JavaVersion JAVA_11 = parse("11"); + private final List version; + + private JavaVersion(List version){ + this.version = version; + } + + static JavaVersion parse(final String value) { + if (value.matches("^0*[0-9]+(\\.[0-9]+)*$") == false) { + throw new IllegalArgumentException(value); + } + + final List version = new ArrayList(); + final String[] components = value.split("\\."); + for (final String component : components) { + version.add(Integer.valueOf(component)); + } + return new JavaVersion(version); + } + + public static int majorVersion(final JavaVersion javaVersion) { + Objects.requireNonNull(javaVersion); + if (javaVersion.version.get(0) > 1) { + return javaVersion.version.get(0); + } else { + return javaVersion.version.get(1); + } + } + + public static int compare(final JavaVersion leftVersion, final JavaVersion rightVersion) { + List left = leftVersion.version; + List right = rightVersion.version; + // lexicographically compare two lists, treating missing entries as zeros + final int len = Math.max(left.size(), right.size()); + for (int i = 0; i < len; i++) { + final int l = (i < left.size()) ? left.get(i) : 0; + final int r = (i < right.size()) ? right.get(i) : 0; + if (l < r) { + return -1; + } + if (r < l) { + return 1; + } + } + return 0; + } + +} \ No newline at end of file diff --git a/logstash-core/src/main/java/org/logstash/util/JavaVersionChecker.java b/logstash-core/src/main/java/org/logstash/util/JavaVersionChecker.java new file mode 100644 index 00000000000..8e2d2c17fea --- /dev/null +++ b/logstash-core/src/main/java/org/logstash/util/JavaVersionChecker.java @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.logstash.util; + +import java.util.Arrays; +import java.util.Locale; + +/** + * Simple program that checks if the runtime Java version is at least 11. + * Based on JavaVersionChecker from Elasticsearch + */ +final class JavaVersionChecker { + + private JavaVersionChecker() {} + + /** + * The main entry point. The exit code is 0 if the Java version is at least 11, otherwise the exit code is 1. + * + * @param args the args to the program which are rejected if not empty + */ + public static void main(final String[] args) { + // no leniency! + if (args.length != 0) { + throw new IllegalArgumentException("expected zero arguments but was " + Arrays.toString(args)); + } + if (JavaVersion.compare(JavaVersion.CURRENT, JavaVersion.JAVA_11) < 0) { + final String message = String.format( + Locale.ROOT, + "the minimum required Java version is 11; your Java version from [%s] does not meet this requirement", + System.getProperty("java.home") + ); + errPrintln(message); + exit(1); + } + exit(0); + } + + /** + * Prints a string and terminates the line on standard error. + * + * @param message the message to print + */ + static void errPrintln(final String message) { + System.err.println(message); + } + + /** + * Exit the VM with the specified status. + * + * @param status the status + */ + static void exit(final int status) { + System.exit(status); + } + +} \ No newline at end of file