Skip to content

Commit

Permalink
Add JavaVersionChecker to check Java version for compatibility before… (
Browse files Browse the repository at this point in the history
#13356)

* 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
  • Loading branch information
robbavey authored Oct 26, 2021
1 parent a6e3914 commit 620a654
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
3 changes: 3 additions & 0 deletions bin/logstash.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions bin/logstash.lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
80 changes: 80 additions & 0 deletions logstash-core/src/main/java/org/logstash/util/JavaVersion.java
Original file line number Diff line number Diff line change
@@ -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<Integer> version;

private JavaVersion(List<Integer> 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<Integer> version = new ArrayList<Integer>();
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<Integer> left = leftVersion.version;
List<Integer> 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;
}

}
Original file line number Diff line number Diff line change
@@ -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);
}

}

0 comments on commit 620a654

Please sign in to comment.