Parse and check the version of an unpacked JVM.

This relies on the existence of a 'release' file in the top-level of the
unpacked JVM. If no 'release' file exists (or it can't be read) then we fall
back to the old behavior which is to assume that an unpacked JVM meets the
app's version requirements.

This also assumes that the java_version_regex configured for the app is capable
of parsing the version string in the release file. The release file appears to
contain a string that matches the system property 'java.version', so if you are
doing version shenanigans and using 'java.runtime.version', you need to do one
of two things:

1. Make sure your regexp can handle missing bits and that the lack of said bits
doesn't hose your version checks. For example, if you need 1.8.0_42-b15 and
your version regexp turns that into 108004215, but the release file just
contains 1.8.0_42 which your version regexp turns into 108004200, then you're
going to have a problem. But if your minimum version is some previous patch
release (say 1.8.0_25-b32) and the custom JVM you ship is 1.8.0_42, then you'll
be OK because 108004200 > 108002532.

2. Create your own 'release' file in your custom packaged JVM (or modify the
existing one) which contains a line with the following syntax:

JAVA_VERSION="VVV"

where VVV is the full version string that your regexp expects. It will be
extracted and parsed with your regexp, and everything will be peachy.
This commit is contained in:
Michael Bayne
2015-03-18 10:00:39 -07:00
parent 8d0455a03c
commit 2225ae6e97
3 changed files with 88 additions and 31 deletions
@@ -790,10 +790,6 @@ public class Application
// if we're doing no version checking, then yay!
if (_javaMinVersion == 0 && _javaMaxVersion == 0) return true;
// if we have a fully unpacked VM assume it is the right version (TODO: don't)
Resource vmjar = getJavaVMResource();
if (vmjar != null && vmjar.isMarkedValid()) return true;
try {
// parse the version out of the java.version (or custom) system property
long version = SysProps.parseJavaVersion(_javaVersionProp, _javaVersionRegex);
@@ -801,6 +797,26 @@ public class Application
log.info("Checking Java version", "current", version,
"wantMin", _javaMinVersion, "wantMax", _javaMaxVersion);
// if we have an unpacked VM, check the 'release' file for its version
Resource vmjar = getJavaVMResource();
if (vmjar != null && vmjar.isMarkedValid()) {
File vmdir = new File(_appdir, LaunchUtil.LOCAL_JAVA_DIR);
File relfile = new File(vmdir, "release");
if (!relfile.exists()) {
log.warning("Unpacked JVM missing 'release' file. Assuming valid version.");
return true;
}
long vmvers = VersionUtil.readReleaseVersion(relfile, _javaVersionRegex);
if (vmvers == 0L) {
log.warning("Unable to read version from 'release' file. Assuming valid.");
return true;
}
version = vmvers;
log.info("Checking version of unpacked JVM [vers=" + version + "].");
}
if (_javaExactVersionRequired) {
if (version == _javaMinVersion) return true;
else {
@@ -5,8 +5,7 @@
package com.threerings.getdown.data;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.threerings.getdown.util.VersionUtil;
/**
* This class encapsulates all system properties that are read and processed by Getdown. Don't
@@ -111,29 +110,9 @@ public class SysProps
if (verstr == null) throw new IllegalArgumentException(
"No system property '" + propName + "'.");
Matcher m = Pattern.compile(propRegex).matcher(verstr);
if (!m.matches()) throw new IllegalArgumentException(
long vers = VersionUtil.parseJavaVersion(propRegex, verstr);
if (vers == 0L) throw new IllegalArgumentException(
"Regexp '" + propRegex + "' does not match '" + verstr + "' (from " + propName + ")");
long vers = 0L;
for (int ii = 1; ii <= m.groupCount(); ii++) {
String valstr = m.group(ii);
int value = (valstr == null) ? 0 : parseInt(valstr);
vers *= 100;
vers += value;
}
return vers;
}
private static int parseInt (String str) {
int value = 0;
for (int ii = 0, ll = str.length(); ii < ll; ii++) {
char c = str.charAt(ii);
if (c >= '0' && c <= '9') {
value *= 10;
value += (c - '0');
}
}
return value;
}
}
@@ -9,14 +9,18 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.samskivert.io.StreamUtil;
import com.samskivert.util.StringUtil;
import com.threerings.getdown.data.SysProps;
import static com.threerings.getdown.Log.log;
/**
@@ -50,8 +54,7 @@ public class VersionUtil
/**
* Writes a version number to a file.
*/
public static void writeVersion (File vfile, long version)
throws IOException
public static void writeVersion (File vfile, long version) throws IOException
{
PrintStream out = new PrintStream(new FileOutputStream(vfile));
try {
@@ -62,4 +65,63 @@ public class VersionUtil
StreamUtil.close(out);
}
}
/**
* Parses {@code versStr} using {@code versRegex} into a (long) integer version number.
* @see SysProps#parseJavaVersion
*/
public static long parseJavaVersion (String versRegex, String versStr)
{
Matcher m = Pattern.compile(versRegex).matcher(versStr);
if (!m.matches()) return 0L;
long vers = 0L;
for (int ii = 1; ii <= m.groupCount(); ii++) {
String valstr = m.group(ii);
int value = (valstr == null) ? 0 : parseInt(valstr);
vers *= 100;
vers += value;
}
return vers;
}
/**
* Reads and parses the version from the {@code release} file bundled with a JVM.
*/
public static long readReleaseVersion (File relfile, String versRegex)
{
try {
BufferedReader in = new BufferedReader(new FileReader(relfile));
String line = null, relvers = null;
while ((line = in.readLine()) != null) {
if (line.startsWith("JAVA_VERSION=")) {
relvers = line.substring("JAVA_VERSION=".length()).replace('"', ' ').trim();
}
}
in.close();
if (relvers == null) {
log.warning("No JAVA_VERSION line in 'release' file", "file", relfile);
return 0L;
}
return parseJavaVersion(versRegex, relvers);
} catch (Exception e) {
log.warning("Failed to read version from 'release' file", "file", relfile, e);
return 0L;
}
}
private static int parseInt (String str) {
int value = 0;
for (int ii = 0, ll = str.length(); ii < ll; ii++) {
char c = str.charAt(ii);
if (c >= '0' && c <= '9') {
value *= 10;
value += (c - '0');
}
}
return value;
}
}