diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..181f63e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +[*] +charset=utf-8 +end_of_line=lf +indent_size=2 +indent_style=space +insert_final_newline=true +trim_trailing_whitespace = true + +[*.java] +indent_size=4 + +# also configure imports order manually as follows: +# import java.* +# +# import javax.* +# +# import com.samskivert.* +# import com.threerings.* +# import all other imports +# import static all other imports diff --git a/.gitignore b/.gitignore index 7034578..0526cc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ /*/target/ /target/ core/src/main/java/com/threerings/getdown/data/Build.java + +# IntelliJ IDEA +.idea/ +*.iml +*.ipr +*.iws diff --git a/core/src/main/java/com/threerings/getdown/data/Application.java b/core/src/main/java/com/threerings/getdown/data/Application.java index 90cf59b..6e45757 100644 --- a/core/src/main/java/com/threerings/getdown/data/Application.java +++ b/core/src/main/java/com/threerings/getdown/data/Application.java @@ -32,8 +32,7 @@ import static com.threerings.getdown.Log.log; import static java.nio.charset.StandardCharsets.UTF_8; /** - * Parses and provide access to the information contained in the getdown.txt - * configuration file. + * Parses and provide access to the information contained in the {@code getdown.txt} configuration file. */ public class Application { @@ -211,10 +210,10 @@ public class Application * Used by {@link #verifyMetadata} to communicate status in circumstances where it needs to * take network actions. */ - public static interface StatusDisplay + public interface StatusDisplay { /** Requests that the specified status message be displayed. */ - public void updateStatus (String message); + void updateStatus (String message); } /** @@ -238,13 +237,12 @@ public class Application public Proxy proxy = Proxy.NO_PROXY; /** - * Creates an application instance which records the location of the getdown.txt + * Creates an application instance which records the location of the {@code getdown.txt} * configuration file from the supplied application directory. - * */ public Application (EnvConfig envc) { _envc = envc; - _config = getLocalPath(envc.appDir, CONFIG_FILE); + _config = new File(envc.appDir, CONFIG_FILE); } /** @@ -368,8 +366,7 @@ public class Application */ public List getActiveCodeResources () { - ArrayList codes = new ArrayList<>(); - codes.addAll(getCodeResources()); + List codes = new ArrayList<>(getCodeResources()); for (AuxGroup aux : getAuxGroups()) { if (isAuxGroupActive(aux.name)) { codes.addAll(aux.codes); @@ -397,8 +394,7 @@ public class Application */ public List getActiveResources () { - ArrayList rsrcs = new ArrayList<>(); - rsrcs.addAll(getResources()); + List rsrcs = new ArrayList<>(getResources()); for (AuxGroup aux : getAuxGroups()) { if (isAuxGroupActive(aux.name)) { rsrcs.addAll(aux.rsrcs); @@ -435,7 +431,15 @@ public class Application } /** - * Returns a resource for a zip file containing a Java VM that can be downloaded to use in + * @return directory into which a local VM installation should be unpacked. + */ + public File getJavaLocalDir () + { + return _javaLocalDir; + } + + /** + * @return 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. */ @@ -445,7 +449,7 @@ public class Application return null; } - String vmfile = LaunchUtil.LOCAL_JAVA_DIR + ".jar"; + String vmfile = _javaLocalDir.getName() + ".jar"; try { URL remote = new URL(createVAppBase(_targetVersion), encodePath(_javaLocation)); return new Resource(vmfile, remote, getLocalPath(vmfile), @@ -591,7 +595,7 @@ public class Application _vappbase = createVAppBase(_version); } catch (MalformedURLException mue) { String err = MessageUtil.tcompose("m.invalid_appbase", _appbase); - throw (IOException) new IOException(err).initCause(mue); + throw new IOException(err, mue); } // check for a latest config URL @@ -645,6 +649,9 @@ public class Application _javaLocation = (String)javaloc; } + // used only in conjunction with java_location + _javaLocalDir = getLocalPath(config.getString("java_local_dir", LaunchUtil.LOCAL_JAVA_DIR)); + // determine whether we have any tracking configuration _trackingURL = config.getString("tracking_url"); @@ -753,7 +760,7 @@ public class Application /** * Adds strings of the form pair0=pair1 to collector for each pair parsed out of pairLocation. */ - protected void fillAssignmentListFromPairs (String pairLocation, List collector) + protected void fillAssignmentListFromPairs (String pairLocation, Collection collector) { File pairFile = getLocalPath(pairLocation); if (pairFile.exists()) { @@ -787,7 +794,7 @@ public class Application */ public File getLocalPath (String path) { - return getLocalPath(getAppDir(), path); + return new File(getAppDir(), path); } /** @@ -810,8 +817,7 @@ public class Application // 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(getAppDir(), LaunchUtil.LOCAL_JAVA_DIR); - File relfile = new File(vmdir, "release"); + File relfile = new File(_javaLocalDir, "release"); if (!relfile.exists()) { log.warning("Unpacked JVM missing 'release' file. Assuming valid version."); return true; @@ -868,7 +874,7 @@ public class Application } /** - * Attempts to redownload the getdown.txt file based on information parsed from a + * Attempts to redownload the {@code getdown.txt} file based on information parsed from a * previous call to {@link #init}. */ public void attemptRecovery (StatusDisplay status) @@ -879,7 +885,7 @@ public class Application } /** - * Downloads and replaces the getdown.txt and digest.txt files with + * Downloads and replaces the {@code getdown.txt} and {@code digest.txt} files with * those for the target version of our application. */ public void updateMetadata () @@ -890,7 +896,7 @@ public class Application _vappbase = createVAppBase(_targetVersion); } catch (MalformedURLException mue) { String err = MessageUtil.tcompose("m.invalid_appbase", _appbase); - throw (IOException) new IOException(err).initCause(mue); + throw new IOException(err, mue); } try { @@ -926,10 +932,10 @@ public class Application public Process createProcess (boolean optimum) throws IOException { - ArrayList args = new ArrayList<>(); + List args = new ArrayList<>(); // reconstruct the path to the JVM - args.add(LaunchUtil.getJVMPath(getAppDir(), _windebug || optimum)); + args.add(LaunchUtil.getJVMBinaryPath(_javaLocalDir, _windebug || optimum)); // check whether we're using -jar mode or -classpath mode boolean dashJarMode = MANIFEST_CLASS.equals(_class); @@ -1126,8 +1132,8 @@ public class Application } /** - * Loads the digest.txt file and verifies the contents of both that file and the - * getdown.text file. Then it loads the version.txt and decides + * Loads the {@code digest.txt} file and verifies the contents of both that file and the + * {@code getdown.text} file. Then it loads the {@code version.txt} and decides * whether or not the application needs to be updated or whether we can proceed to verification * and execution. * @@ -1421,7 +1427,7 @@ public class Application protected URL createVAppBase (long version) throws MalformedURLException { - String url = version < 0 ? _appbase : _appbase.replace("%VERSION%", "" + version); + String url = version < 0 ? _appbase : _appbase.replace("%VERSION%", String.valueOf(version)); return HostWhitelist.verify(new URL(url)); } @@ -1546,7 +1552,6 @@ public class Application if (!sig.verify(Base64.decode(signature, Base64.DEFAULT))) { log.info("Signature does not match", "cert", cert.getPublicKey()); - continue; } else { log.info("Signature matches", "cert", cert.getPublicKey()); validated++; @@ -1592,7 +1597,7 @@ public class Application } catch (Exception e) { log.warning("Requested to download invalid control file", "appbase", _vappbase, "path", path, "error", e); - throw (IOException) new IOException("Invalid path '" + path + "'.").initCause(e); + throw new IOException("Invalid path '" + path + "'.", e); } log.info("Attempting to refetch '" + path + "' from '" + targetURL + "'."); @@ -1627,11 +1632,9 @@ public class Application } /** Helper function to add all values in {@code values} (if non-null) to {@code target}. */ - protected static void addAll (String[] values, List target) { + protected static void addAll (String[] values, Collection target) { if (values != null) { - for (String value : values) { - target.add(value); - } + Collections.addAll(target, values); } } @@ -1713,11 +1716,6 @@ public class Application } } - protected File getLocalPath (File appdir, String path) - { - return new File(appdir, path); - } - protected final EnvConfig _envc; protected File _config; protected Digest _digest; @@ -1749,6 +1747,7 @@ public class Application protected long _javaMinVersion, _javaMaxVersion; protected boolean _javaExactVersionRequired; protected String _javaLocation; + protected File _javaLocalDir; protected List _codes = new ArrayList<>(); protected List _resources = new ArrayList<>(); @@ -1766,9 +1765,6 @@ public class Application protected List _txtJvmArgs = new ArrayList<>(); - /** If a warning has been issued about not being able to set modtimes. */ - protected boolean _warnedAboutSetLastModified; - /** Locks gettingdown.lock in the app dir. Held the entire time updating is going on.*/ protected FileLock _lock; diff --git a/core/src/main/java/com/threerings/getdown/util/Config.java b/core/src/main/java/com/threerings/getdown/util/Config.java index 4fc5e16..94588aa 100644 --- a/core/src/main/java/com/threerings/getdown/util/Config.java +++ b/core/src/main/java/com/threerings/getdown/util/Config.java @@ -237,7 +237,7 @@ public class Config */ public String getString (String name, String def) { String value = (String)_data.get(name); - return value == null ? def : value; + return StringUtil.isBlank(value) ? def : value; } /** diff --git a/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java b/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java index 4a9998e..99cc702 100644 --- a/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java +++ b/core/src/main/java/com/threerings/getdown/util/LaunchUtil.java @@ -17,21 +17,22 @@ import static com.threerings.getdown.Log.log; * Useful routines for launching Java applications from within other Java * applications. */ -public class LaunchUtil +public final class LaunchUtil { - /** The directory into which a local VM installation should be unpacked. */ + /** The default directory into which a local VM installation should be unpacked. */ public static final String LOCAL_JAVA_DIR = "java_vm"; /** - * Writes a version.txt file into the specified application directory and + * Writes a {@code version.txt} file into the specified application directory and * attempts to relaunch Getdown in that directory which will cause it to upgrade to the newly * specified version and relaunch the application. * * @param appdir the directory in which the application is installed. * @param getdownJarName the name of the getdown jar file in the application directory. This is - * probably getdown-pro.jar or getdown-retro-pro.jar if you are using + * probably {@code getdown-pro.jar} or getdown-retro-pro.jar if you are using * the results of the standard build. * @param newVersion the new version to which Getdown will update when it is executed. + * @param javaLocalDir JRE location within appdir, falls back to {@link #LOCAL_JAVA_DIR} in case if null is passed * * @return true if the relaunch succeeded, false if we were unable to relaunch due to being on * Windows 9x where we cannot launch subprocesses without waiting around for them to exit, @@ -39,13 +40,13 @@ public class LaunchUtil * after making this call as it will be upgraded and restarted. If false is returned, the * application should tell the user that they must restart the application manually. * - * @exception IOException thrown if we were unable to create the version.txt file + * @exception IOException thrown if we were unable to create the {@code version.txt} file * in the supplied application directory. If the version.txt file cannot be created, restarting * Getdown will not cause the application to be upgraded, so the application will have to * resort to telling the user that it is in a bad way. */ public static boolean updateVersionAndRelaunch ( - File appdir, String getdownJarName, String newVersion) + File appdir, String getdownJarName, String newVersion, String javaLocalDir) throws IOException { // create the file that instructs Getdown to upgrade @@ -61,8 +62,11 @@ public class LaunchUtil } // do the deed - String[] args = new String[] { - getJVMPath(appdir), "-jar", pro.toString(), appdir.getPath() + String[] args = { + getJVMBinaryPath(new File(appdir, StringUtil.isBlank(javaLocalDir) ? LOCAL_JAVA_DIR : javaLocalDir), false), + "-jar", + pro.toString(), + appdir.getPath() }; log.info("Running " + StringUtil.join(args, "\n ")); try { @@ -75,22 +79,14 @@ public class LaunchUtil } /** - * Reconstructs the path to the JVM used to launch this process. - */ - public static String getJVMPath (File appdir) - { - return getJVMPath(appdir, false); - } - - /** - * Reconstructs the path to the JVM used to launch this process. - * + * @param javaLocalDir JRE location within appdir * @param windebug if true we will use java.exe instead of javaw.exe on Windows. + * @return the path to the JVM binary used to launch this process. */ - public static String getJVMPath (File appdir, boolean windebug) + public static String getJVMBinaryPath(File javaLocalDir, boolean windebug) { // first look in our application directory for an installed VM - String vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR).getAbsolutePath(), windebug); + String vmpath = checkJVMPath(javaLocalDir.getAbsolutePath(), windebug); // then fall back to the VM in which we're already running if (vmpath == null) { @@ -99,7 +95,7 @@ public class LaunchUtil // then throw up our hands and hope for the best if (vmpath == null) { - log.warning("Unable to find java [appdir=" + appdir + + log.warning("Unable to find java [javaLocalDir=" + javaLocalDir + ", java.home=" + System.getProperty("java.home") + "]!"); vmpath = "java"; } @@ -150,8 +146,7 @@ public class LaunchUtil if (newgd.renameTo(curgd)) { FileUtil.deleteHarder(oldgd); // yay! try { - // copy the moved file back to getdown-dop-new.jar so that we don't end up - // downloading another copy next time + // copy the moved file back to newgd so that we don't end up downloading another copy next time FileUtil.copy(curgd, newgd); } catch (IOException e) { log.warning("Error copying updated Getdown back: " + e); @@ -182,23 +177,23 @@ public class LaunchUtil public static boolean mustMonitorChildren () { String osname = System.getProperty("os.name", "").toLowerCase(Locale.ROOT); - return (osname.indexOf("windows 98") != -1 || osname.indexOf("windows me") != -1); + return osname.contains("windows 98") || osname.contains("windows me"); } /** * Returns true if we're running in a JVM that identifies its operating system as Windows. */ - public static final boolean isWindows () { return _isWindows; } + public static boolean isWindows () { return _isWindows; } /** * Returns true if we're running in a JVM that identifies its operating system as MacOS. */ - public static final boolean isMacOS () { return _isMacOS; } + public static boolean isMacOS () { return _isMacOS; } /** * Returns true if we're running in a JVM that identifies its operating system as Linux. */ - public static final boolean isLinux () { return _isLinux; } + public static boolean isLinux () { return _isLinux; } /** * Checks whether a Java Virtual Machine can be located in the supplied path. @@ -236,11 +231,10 @@ public class LaunchUtil static { try { String osname = System.getProperty("os.name"); - osname = (osname == null) ? "" : osname; - _isWindows = (osname.indexOf("Windows") != -1); - _isMacOS = (osname.indexOf("Mac OS") != -1 || - osname.indexOf("MacOS") != -1); - _isLinux = (osname.indexOf("Linux") != -1); + osname = osname == null ? "" : osname; + _isWindows = osname.contains("Windows"); + _isMacOS = osname.contains("Mac OS") || osname.contains("MacOS"); + _isLinux = osname.contains("Linux"); } catch (Exception e) { // can't grab system properties; we'll just pretend we're not on any of these OSes } diff --git a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java index 99def4f..4ae0f80 100644 --- a/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -75,7 +75,7 @@ public abstract class Getdown extends Thread // welcome to hell, where java can't cope with a classpath that contains jars that live // in a directory that contains a !, at least the same bug happens on all platforms String dir = envc.appDir.toString(); - if (dir.equals(".")) { + if (".".equals(dir)) { dir = System.getProperty("user.dir"); } String errmsg = "The directory in which this application is installed:\n" + dir + @@ -130,7 +130,7 @@ public abstract class Getdown extends Thread File instdir = _app.getLocalPath(""); if (!instdir.canWrite()) { String path = instdir.getPath(); - if (path.equals(".")) { + if (".".equals(path)) { path = System.getProperty("user.dir"); } fail(MessageUtil.tcompose("m.readonly_error", path)); @@ -161,20 +161,7 @@ public abstract class Getdown extends Thread } catch (Exception e) { log.warning("run() failed.", e); - String msg = e.getMessage(); - if (msg == null) { - msg = MessageUtil.compose("m.unknown_error", _ifc.installError); - } else if (!msg.startsWith("m.")) { - // try to do something sensible based on the type of error - if (e instanceof FileNotFoundException) { - msg = MessageUtil.compose( - "m.missing_resource", MessageUtil.taint(msg), _ifc.installError); - } else { - msg = MessageUtil.compose( - "m.init_error", MessageUtil.taint(msg), _ifc.installError); - } - } - fail(msg); + fail(e); } } @@ -423,22 +410,7 @@ public abstract class Getdown extends Thread } catch (Exception e) { log.warning("getdown() failed.", e); - String msg = e.getMessage(); - if (msg == null) { - msg = MessageUtil.compose("m.unknown_error", _ifc.installError); - } else if (!msg.startsWith("m.")) { - // try to do something sensible based on the type of error - if (e instanceof FileNotFoundException) { - msg = MessageUtil.compose( - "m.missing_resource", MessageUtil.taint(msg), _ifc.installError); - } else { - msg = MessageUtil.compose( - "m.init_error", MessageUtil.taint(msg), _ifc.installError); - } - } - // Since we're dead, clear off the 'time remaining' label along with displaying the - // error message - fail(msg); + fail(e); _app.releaseLock(); } } @@ -507,13 +479,13 @@ public abstract class Getdown extends Thread vmjar.install(true); // these only run on non-Windows platforms, so we use Unix file separators - String localJavaDir = LaunchUtil.LOCAL_JAVA_DIR + "/"; - FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "bin/java")); - FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/jspawnhelper")); - FileUtil.makeExecutable(_app.getLocalPath(localJavaDir + "lib/amd64/jspawnhelper")); + File javaLocalDir = _app.getJavaLocalDir(); + FileUtil.makeExecutable(new File(javaLocalDir, "bin/java")); + FileUtil.makeExecutable(new File(javaLocalDir, "lib/jspawnhelper")); + FileUtil.makeExecutable(new File(javaLocalDir, "lib/amd64/jspawnhelper")); // lastly regenerate the .jsa dump file that helps Java to start up faster - String vmpath = LaunchUtil.getJVMPath(_app.getLocalPath("")); + String vmpath = LaunchUtil.getJVMBinaryPath(javaLocalDir, false); try { log.info("Regenerating classes.jsa for " + vmpath + "..."); Runtime.getRuntime().exec(vmpath + " -Xshare:dump"); @@ -836,8 +808,23 @@ public abstract class Getdown extends Thread } } + private void fail(Exception e) { + String msg = e.getMessage(); + if (msg == null) { + msg = MessageUtil.compose("m.unknown_error", _ifc.installError); + } else if (!msg.startsWith("m.")) { + // try to do something sensible based on the type of error + if (e instanceof FileNotFoundException) { + msg = MessageUtil.compose("m.missing_resource", MessageUtil.taint(msg), _ifc.installError); + } else { + msg = MessageUtil.compose("m.init_error", MessageUtil.taint(msg), _ifc.installError); + } + } + fail(msg); + } + /** - * Update the status to indicate getdown has failed for the reason in message. + * Update the status to indicate getdown has failed for the reason in {@code message}. */ protected void fail (String message) {