JAL-3820 JAL-4189 Use the same LaunchUtils methods to check java executable symlinks...
[jalview.git] / getdown / src / getdown / core / src / main / java / com / threerings / getdown / util / LaunchUtil.java
index 829e38f..1faaa28 100644 (file)
@@ -9,8 +9,16 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Locale;
 
+import javax.xml.bind.DatatypeConverter;
+
+import java.security.MessageDigest;
+
+import jalview.util.LaunchUtils;
+
 import static com.threerings.getdown.Log.log;
 
 /**
@@ -20,7 +28,7 @@ import static com.threerings.getdown.Log.log;
 public class LaunchUtil
 {
     /** The directory into which a local VM installation should be unpacked. */
-    public static final String LOCAL_JAVA_DIR = "java_vm";
+    public static final String LOCAL_JAVA_DIR = "jre";
 
     /**
      * Writes a <code>version.txt</code> file into the specified application directory and
@@ -82,6 +90,7 @@ public class LaunchUtil
         return getJVMPath(appdir, false);
     }
 
+    private static String jvmPath = null;
     /**
      * Reconstructs the path to the JVM used to launch this process.
      *
@@ -89,22 +98,27 @@ public class LaunchUtil
      */
     public static String getJVMPath (File appdir, boolean windebug)
     {
-        // first look in our application directory for an installed VM
-        String vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR).getAbsolutePath(), windebug);
-        if (vmpath == null && isMacOS()) {
-                       vmpath = checkJVMPath(new File(appdir, LOCAL_JAVA_DIR + "/Contents/Home").getAbsolutePath(), windebug);
+        if (jvmPath != null) {
+          return jvmPath;
         }
+        
+        // first look in our application directory for an installed VM
+        final String appDir = isMacOS() ?
+                        (new File(appdir, LOCAL_JAVA_DIR).getAbsolutePath()) + "/Contents/Home"
+                        : new File(appdir, LOCAL_JAVA_DIR).getAbsolutePath();
+
+        String javaBin = LaunchUtils.findJavaBin(appDir, windebug, false);
 
         // then fall back to the VM in which we're already running
-        if (vmpath == null) {
-            vmpath = checkJVMPath(System.getProperty("java.home"), windebug);
+        if (javaBin == null) {
+            javaBin = LaunchUtils.findJavaBin(System.getProperty("java.home"), windebug, false);
         }
 
         // then throw up our hands and hope for the best
-        if (vmpath == null) {
+        if (javaBin == null) {
+            javaBin = LaunchUtils.findJavaBin(null, windebug, true);
             log.warning("Unable to find java [appdir=" + appdir +
                         ", java.home=" + System.getProperty("java.home") + "]!");
-            vmpath = "java";
         }
 
         // Oddly, the Mac OS X specific java flag -Xdock:name will only work if java is launched
@@ -114,17 +128,33 @@ public class LaunchUtil
         if (isMacOS()) {
             try {
                 File localVM = new File("/usr/bin/java").getCanonicalFile();
-                if (localVM.equals(new File(vmpath).getCanonicalFile())) {
-                    vmpath = "/usr/bin/java";
+                if (localVM.equals(new File(javaBin).getCanonicalFile())) {
+                    javaBin = "/usr/bin/java";
                 }
             } catch (IOException ioe) {
                 log.warning("Failed to check Mac OS canonical VM path.", ioe);
             }
         }
 
-        return vmpath;
+        jvmPath = javaBin;
+        return jvmPath;
     }
 
+    private static String _getMD5FileChecksum (File file) {
+       // check md5 digest
+       String algo = "MD5";
+       String checksum = "";
+       try {
+               MessageDigest md = MessageDigest.getInstance(algo);
+               md.update(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
+               byte[] digest = md.digest();
+               checksum = DatatypeConverter.printHexBinary(digest).toUpperCase(Locale.ROOT);
+       } catch (Exception e) {
+               System.out.println("Couldn't create "+algo+" digest of "+file.getPath());
+       }
+       return checksum;
+    }
+    
     /**
      * Upgrades Getdown by moving an installation managed copy of the Getdown jar file over the
      * non-managed copy (which would be used to run Getdown itself).
@@ -137,9 +167,17 @@ public class LaunchUtil
         // we assume getdown's jar file size changes with every upgrade, this is not guaranteed,
         // but in reality it will, and it allows us to avoid pointlessly upgrading getdown every
         // time the client is updated which is unnecessarily flirting with danger
-        if (!newgd.exists() || newgd.length() == curgd.length()) {
+        if (!newgd.exists())
+        {
             return;
         }
+        
+        if (newgd.length() == curgd.length()) {
+               if (_getMD5FileChecksum(newgd).equals(_getMD5FileChecksum(curgd)))
+               {
+                               return;
+               }
+        }
 
         log.info("Updating Getdown with " + newgd + "...");
 
@@ -204,12 +242,47 @@ public class LaunchUtil
     public static final boolean isLinux () { return _isLinux; }
 
     /**
+     * Check if a symlink (or file) points to a JVM
+     */
+    private static boolean checkJVMSymlink(String testBin)
+    {
+      File testBinFile = new File(testBin);
+      if (!testBinFile.exists())
+      {
+        return false;
+      }
+      File targetFile = null;
+      try
+      {
+        targetFile = testBinFile.getCanonicalFile();
+      } catch (IOException e)
+      {
+        return false;
+      }
+      if (targetFile != null && ("java".equals(targetFile.getName())
+            || "java.exe".equals(targetFile.getName())))
+      {
+        return true;
+      }
+      return false;
+    }
+
+    /**
      * 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";
+        String appName = System.getProperty("channel.app_name", "Jalview");
+        String vmpath = vmbase + appName;
+        if (checkJVMSymlink(vmpath)) {
+          return vmpath;
+        }
+        vmpath = vmbase + "Jalview";
+        if (checkJVMSymlink(vmpath)) {
+          return vmpath;
+        }
+        vmpath = vmbase + "java";
         if (new File(vmpath).exists()) {
             return vmpath;
         }