Provide support for automatically downloading and installing a local Java
version from within Getdown if the user does not have the desired version for the application. This does not yet support upgrading a locally installed version of Java, right now it assumes that if we have a locally installed version, it's good enough. We can make that do the right thing too, later.
This commit is contained in:
@@ -49,6 +49,8 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.samskivert.io.StreamUtil;
|
||||
import com.samskivert.text.MessageUtil;
|
||||
@@ -277,6 +279,29 @@ public class Application
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource for a zip file containing a Java VM that can be downloaded to use in
|
||||
* place of the installed VM (in the case where the VM that launched Getdown does not meet the
|
||||
* application's version requirements) or null if no VM is available for this platform.
|
||||
*/
|
||||
public Resource getJavaVMResource ()
|
||||
{
|
||||
if (StringUtil.isBlank(_javaLocation)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String vmfile = LaunchUtil.LOCAL_JAVA_DIR + ".jar";
|
||||
try {
|
||||
URL remote = new URL(createVAppBase(_targetVersion), _javaLocation);
|
||||
return new Resource(vmfile, remote, getLocalPath(vmfile), true);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Failed to create VM resource [vmfile=" + vmfile + ", appbase=" + _appbase +
|
||||
", tvers=" + _targetVersion + ", javaloc=" + _javaLocation +
|
||||
", error=" + e + "].");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a resource that can be used to download an archive containing all files belonging to
|
||||
* the application.
|
||||
@@ -493,7 +518,34 @@ public class Application
|
||||
*/
|
||||
public boolean haveValidJavaVersion ()
|
||||
{
|
||||
return true; // TODO
|
||||
// if we're doing no version checking, then yay!
|
||||
if (_javaVersion <= 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;
|
||||
}
|
||||
|
||||
// parse the version out of the java.version system property
|
||||
String verstr = System.getProperty("java.version");
|
||||
Matcher m = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)_(\\d+)").matcher(verstr);
|
||||
if (!m.matches()) {
|
||||
// if we can't parse the java version we're in weird land and should probably just try
|
||||
// our luck with what we've got rather than try to download a new jvm
|
||||
Log.warning("Unable to parse VM version, hoping for the best [version=" + verstr +
|
||||
", needed=" + _javaVersion + "].");
|
||||
return true;
|
||||
}
|
||||
|
||||
int one = Integer.parseInt(m.group(1)); // will there ever be a two?
|
||||
int major = Integer.parseInt(m.group(2));
|
||||
int minor = Integer.parseInt(m.group(3));
|
||||
int patch = Integer.parseInt(m.group(4));
|
||||
int version = patch + 100 * (minor + 100 * (major + 100 * one));
|
||||
return version >= _javaVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -548,7 +600,7 @@ public class Application
|
||||
ArrayList<String> args = new ArrayList<String>();
|
||||
|
||||
// reconstruct the path to the JVM
|
||||
args.add(LaunchUtil.getJVMPath(_windebug));
|
||||
args.add(LaunchUtil.getJVMPath(_appdir, _windebug));
|
||||
|
||||
// add the classpath arguments
|
||||
args.add("-classpath");
|
||||
|
||||
@@ -152,11 +152,9 @@ public class Resource
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return FileUtil.unpackJar(
|
||||
new JarFile(_local), _local.getParentFile());
|
||||
return FileUtil.unpackJar(new JarFile(_local), _local.getParentFile());
|
||||
} catch (IOException ioe) {
|
||||
Log.warning("Failed to create JarFile from '" +
|
||||
_local + "': " + ioe);
|
||||
Log.warning("Failed to create JarFile from '" + _local + "': " + ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,10 +340,17 @@ public abstract class Getdown extends Thread
|
||||
createInterface(true);
|
||||
}
|
||||
|
||||
// if we aren't running in a JVM that meets our version requirements, either complain
|
||||
// or attempt to download and install the appropriate version
|
||||
|
||||
for (int ii = 0; ii < MAX_LOOPS; ii++) {
|
||||
// if we aren't running in a JVM that meets our version requirements, either
|
||||
// complain or attempt to download and install the appropriate version
|
||||
if (!_app.haveValidJavaVersion()) {
|
||||
// download and install the necessary version of java, then loop back again and
|
||||
// reverify everything; if we can't download java; we'll throw an exception
|
||||
Log.info("Attempting to update Java VM...");
|
||||
updateJava();
|
||||
continue;
|
||||
}
|
||||
|
||||
// make sure we have the desired version and that the metadata files are valid...
|
||||
setStatus("m.validating", -1, -1L, false);
|
||||
if (_app.verifyMetadata(this)) {
|
||||
@@ -397,6 +404,47 @@ public abstract class Getdown extends Thread
|
||||
setStatus(message, -1, -1L, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads and installs an Java VM bundled with the application. This is called if we are not
|
||||
* running with the necessary Java version.
|
||||
*/
|
||||
protected void updateJava ()
|
||||
throws IOException
|
||||
{
|
||||
Resource vmjar = _app.getJavaVMResource();
|
||||
if (vmjar == null) {
|
||||
throw new IOException("m.java_download_failed");
|
||||
}
|
||||
|
||||
updateStatus("m.downloading_java");
|
||||
ArrayList<Resource> list = new ArrayList<Resource>();
|
||||
list.add(vmjar);
|
||||
download(list);
|
||||
|
||||
updateStatus("m.unpacking_java");
|
||||
if (!vmjar.unpack()) {
|
||||
throw new IOException("m.java_unpack_failed");
|
||||
}
|
||||
vmjar.markAsValid();
|
||||
|
||||
// Sun, why dost thou spite me? Java doesn't know anything about file permissions (and by
|
||||
// extension then, neither does Jar), so on Joonix we have to hackily make java_vm/bin/java
|
||||
// executable by execing chmod; a pox on their children!
|
||||
if (RunAnywhere.isLinux()) {
|
||||
String vmbin = LaunchUtil.LOCAL_JAVA_DIR + File.separator + "bin" +
|
||||
File.separator + "java";
|
||||
String cmd = "chmod a+rx " + _app.getLocalPath(vmbin);
|
||||
try {
|
||||
Log.info("Please smack a Java engineer. Running: " + cmd);
|
||||
Runtime.getRuntime().exec(cmd);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Failed to mark VM binary as executable [cmd=" + cmd +
|
||||
", error=" + e + "].");
|
||||
// we should do something like tell the user or something but fucking fuck
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if the application is determined to be of an old version.
|
||||
*/
|
||||
@@ -480,8 +528,7 @@ public abstract class Getdown extends Thread
|
||||
}
|
||||
|
||||
public void downloadFailed (Resource rsrc, Exception e) {
|
||||
updateStatus(
|
||||
MessageUtil.tcompose("m.failure", e.getMessage()));
|
||||
updateStatus(MessageUtil.tcompose("m.failure", e.getMessage()));
|
||||
Log.warning("Download failed [rsrc=" + rsrc + "].");
|
||||
Log.logStackTrace(e);
|
||||
synchronized (lock) {
|
||||
@@ -643,22 +690,20 @@ public abstract class Getdown extends Thread
|
||||
createInterface(false);
|
||||
}
|
||||
|
||||
if (_status != null) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
if (_status == null) {
|
||||
Log.info("Dropping status '" + message + "'.");
|
||||
return;
|
||||
}
|
||||
if (message != null) {
|
||||
_status.setStatus(message);
|
||||
}
|
||||
if (percent >= 0) {
|
||||
_status.setProgress(percent, remaining);
|
||||
}
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
if (_status == null) {
|
||||
Log.info("Dropping status '" + message + "'.");
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (message != null) {
|
||||
_status.setStatus(message);
|
||||
}
|
||||
if (percent >= 0) {
|
||||
_status.setProgress(percent, remaining);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,9 @@ m.proxy_port = Proxy port
|
||||
m.proxy_ok = OK
|
||||
m.proxy_cancel = Cancel
|
||||
|
||||
m.downloading_java = Downloading Java Virtual Machine...
|
||||
m.unpacking_java = Unpacking Java Virtual Machine...
|
||||
|
||||
m.resolving = Resolving downloads...
|
||||
m.downloading = Downloading data...
|
||||
m.failure = Download failed: {0}
|
||||
@@ -49,6 +52,17 @@ m.updating_metadata = Downloading control files...
|
||||
m.init_failed = Our configuration file is missing or corrupt. Attempting \
|
||||
to download a new copy...
|
||||
|
||||
m.java_download_failed = We were unable to automatically download the \
|
||||
necessary verson of Java for your computer.\n\n\
|
||||
Please go to www.java.com and download the latest version of \
|
||||
Java, then try running the application again.
|
||||
|
||||
m.java_unpack_failed = We were unable to unpack an updated version of \
|
||||
Java. Please make sure you have at least 100 MB of free space on your \
|
||||
harddrive and try running the application again.\n\n\
|
||||
If that does not solve the problem, go to www.java.com and download and \
|
||||
install the latest version of Java and try again.
|
||||
|
||||
m.unable_to_repair = We were unable to download the necessary files after \
|
||||
five attempts. You can try running the application again, but if it \
|
||||
fails you may need to uninstall and reinstall.
|
||||
|
||||
@@ -35,43 +35,40 @@ import com.threerings.getdown.Log;
|
||||
*/
|
||||
public class LaunchUtil
|
||||
{
|
||||
/** The directory into which a local VM installation should be unpacked. */
|
||||
public static final String LOCAL_JAVA_DIR = "java_vm";
|
||||
|
||||
/**
|
||||
* Reconstructs the path to the JVM used to launch this process.
|
||||
*/
|
||||
public static String getJVMPath ()
|
||||
public static String getJVMPath (File appdir)
|
||||
{
|
||||
return getJVMPath(false);
|
||||
return getJVMPath(appdir, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs the path to the JVM used to launch this process.
|
||||
*
|
||||
* @param windebug if true we will use java.exe instead of javaw.exe on
|
||||
* Windows.
|
||||
* @param windebug if true we will use java.exe instead of javaw.exe on Windows.
|
||||
*/
|
||||
public static String getJVMPath (boolean windebug)
|
||||
public static String getJVMPath (File appdir, boolean windebug)
|
||||
{
|
||||
String apbase = System.getProperty("java.home") +
|
||||
File.separator + "bin" + File.separator;
|
||||
String apath = apbase + "java";
|
||||
if (new File(apath).exists()) {
|
||||
return apath;
|
||||
// first look in our application directory for an installed VM
|
||||
String vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR).getPath(), windebug);
|
||||
if (vmpath != null) {
|
||||
return vmpath;
|
||||
}
|
||||
|
||||
if (!windebug) {
|
||||
apath = apbase + "javaw.exe";
|
||||
if (new File(apath).exists()) {
|
||||
return apath;
|
||||
}
|
||||
// then fall back to the VM in which we're already running
|
||||
vmpath = checkJVMPath(System.getProperty("java.home"), windebug);
|
||||
if (vmpath != null) {
|
||||
return vmpath;
|
||||
}
|
||||
|
||||
apath = apbase + "java.exe";
|
||||
if (new File(apath).exists()) {
|
||||
return apath;
|
||||
}
|
||||
|
||||
Log.warning("Unable to find java! [jhome=" + apbase + "].");
|
||||
return apbase + "java";
|
||||
// then throw up our hands and hope for the best
|
||||
Log.warning("Unable to find java [appdir=" + appdir +
|
||||
", java.home=" + System.getProperty("java.home") + "]!");
|
||||
return "java";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,4 +139,30 @@ public class LaunchUtil
|
||||
return (osname.indexOf("windows 98") != -1 ||
|
||||
osname.indexOf("windows me") != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a Java Virtual Machine can be located in the supplied path.
|
||||
*/
|
||||
protected static String checkJVMPath (String vmhome, boolean windebug)
|
||||
{
|
||||
String vmbase = vmhome + File.separator + "bin" + File.separator;
|
||||
String vmpath = vmbase + "java";
|
||||
if (new File(vmpath).exists()) {
|
||||
return vmpath;
|
||||
}
|
||||
|
||||
if (!windebug) {
|
||||
vmpath = vmbase + "javaw.exe";
|
||||
if (new File(vmpath).exists()) {
|
||||
return vmpath;
|
||||
}
|
||||
}
|
||||
|
||||
vmpath = vmbase + "java.exe";
|
||||
if (new File(vmpath).exists()) {
|
||||
return vmpath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user