Merge branch 'develop' into spike/JAL-4047/JAL-4048_columns_in_sequenceID
[jalview.git] / src / jalview / bin / Launcher.java
index a55146d..e1415be 100644 (file)
@@ -26,6 +26,7 @@ import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 
 import jalview.util.ChannelProperties;
 import jalview.util.LaunchUtils;
@@ -49,8 +50,7 @@ public class Launcher
 {
   private final static String startClass = "jalview.bin.Jalview";
 
-  private final static String dockIconPath = ChannelProperties
-          .getProperty("logo.512");
+  private final static String headlessProperty = "java.awt.headless";
 
   /**
    * main method for jalview.bin.Launcher. This restarts the same JRE's JVM with
@@ -64,35 +64,73 @@ public class Launcher
   {
     if (!LaunchUtils.checkJavaVersion())
     {
-      System.err.println("WARNING - The Java version being used (Java "
-              + LaunchUtils.getJavaVersion()
-              + ") may lead to problems. This installation of Jalview should be used with Java "
-              + LaunchUtils.getJavaCompileVersion() + ".");
+      jalview.bin.Console
+              .errPrintln("WARNING - The Java version being used (Java "
+                      + LaunchUtils.getJavaVersion()
+                      + ") may lead to problems. This installation of Jalview should be used with Java "
+                      + LaunchUtils.getJavaCompileVersion() + ".");
     }
 
-    final String javaBin = System.getProperty("java.home") + File.separator
-            + "bin" + File.separator + "java";
-
-    List<String> command = new ArrayList<>();
-    command.add(javaBin);
-
-    String memSetting = null;
-
-    boolean isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
-
-    for (String jvmArg : ManagementFactory.getRuntimeMXBean()
-            .getInputArguments())
-    {
-      command.add(jvmArg);
-    }
-    command.add("-cp");
-    command.add(ManagementFactory.getRuntimeMXBean().getClassPath());
-
     String jvmmempc = null;
     String jvmmemmax = null;
+    boolean debug = false;
+    boolean wait = true;
+    boolean quiet = false;
+    boolean headless = false;
+    boolean gui = false;
+    boolean stdout = false;
+    // must set --debug before --launcher...
+    boolean launcherstop = false;
+    boolean launcherprint = false;
+    boolean launcherwait = false;
     ArrayList<String> arguments = new ArrayList<>();
+    String previousArg = null;
     for (String arg : args)
     {
+      if (arg.equals("--debug"))
+      {
+        debug = true;
+      }
+      if (arg.equals("--quiet"))
+      {
+        quiet = true;
+      }
+      if (arg.equals("--headless"))
+      {
+        headless = true;
+      }
+      if (arg.equals("--gui"))
+      {
+        gui = true;
+      }
+      if (arg.equals("--output=-")
+              || (arg.equals("-") && "--output".equals(previousArg)))
+      {
+        stdout = true;
+      }
+      if (debug && arg.equals("--launcherprint"))
+      {
+        launcherprint = true;
+      }
+      if (debug && arg.equals("--launcherstop"))
+      {
+        launcherstop = true;
+      }
+      if (debug && arg.equals("--launcherwait"))
+      {
+        launcherwait = true;
+      }
+      // this ends the launcher immediately
+      if (debug && arg.equals("--launchernowait"))
+      {
+        wait = false;
+      }
+      previousArg = arg;
+      // Don't add the --launcher... args to Jalview launch
+      if (arg.startsWith("--launcher"))
+      {
+        continue;
+      }
       // jvmmempc and jvmmemmax args used to set memory and are not passed on to
       // startClass
       if (arg.startsWith(
@@ -108,11 +146,49 @@ public class Launcher
         jvmmemmax = arg.substring(
                 MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME.length() + 2);
       }
+      // --doubledash versions
+      else if (arg.startsWith("--"
+              + MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "="))
+      {
+        jvmmempc = arg.substring(
+                MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.length()
+                        + 3);
+      }
+      else if (arg.startsWith(
+              "--" + MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME + "="))
+      {
+        jvmmemmax = arg.substring(
+                MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME.length() + 3);
+      }
+      // retain arg
       else
       {
         arguments.add(arg);
       }
     }
+    if (gui)
+    {
+      // --gui takes precedence over --headless
+      headless = false;
+    }
+
+    final String appName = ChannelProperties.getProperty("app_name");
+
+    // if we're using jalview.bin.Launcher we always assume a console is in use
+    final String javaBin = LaunchUtils.findJavaBin(true);
+
+    List<String> command = new ArrayList<>();
+    command.add(javaBin);
+
+    String memSetting = null;
+
+    for (String jvmArg : ManagementFactory.getRuntimeMXBean()
+            .getInputArguments())
+    {
+      command.add(jvmArg);
+    }
+    command.add("-cp");
+    command.add(ManagementFactory.getRuntimeMXBean().getClassPath());
 
     // use saved preferences if no cmdline args
     boolean useCustomisedSettings = LaunchUtils
@@ -131,10 +207,11 @@ public class Launcher
       }
     }
 
-    // add memory setting if not specified
+    // add these settings if not already specified
     boolean memSet = false;
     boolean dockIcon = false;
     boolean dockName = false;
+    boolean headlessProp = false;
     for (int i = 0; i < command.size(); i++)
     {
       String arg = command.get(i);
@@ -155,6 +232,10 @@ public class Launcher
       {
         dockName = true;
       }
+      else if (arg.startsWith("-D" + headlessProperty + "="))
+      {
+        headlessProp = true;
+      }
     }
 
     if (!memSet)
@@ -169,25 +250,37 @@ public class Launcher
       }
     }
 
-    if (isAMac)
+    if (LaunchUtils.isMac)
     {
       if (!dockIcon)
       {
+        String dockIconPath = System.getProperty("getdownappdir", ".")
+                + File.separator + "resource/jalview_logo.png";
         command.add("-Xdock:icon=" + dockIconPath);
       }
       if (!dockName)
       {
         // -Xdock:name=... doesn't actually work :(
         // Leaving it in in case it gets fixed
-        command.add(
-                "-Xdock:name=" + ChannelProperties.getProperty("app_name"));
+        command.add("-Xdock:name=" + appName);
+        // this launches WITHOUT an icon in the macOS dock. Could be useful for
+        // getdown?
+        // command.add("-Dapple.awt.UIElement=false");
+        // This also does not work for the dock
+        command.add("-Dcom.apple.mrj.application.apple.menu.about.name="
+                + appName);
       }
     }
+    if (headless && !headlessProp)
+    {
+      System.setProperty(headlessProperty, "true");
+      command.add("-D" + headlessProperty + "=true");
+    }
 
     String scalePropertyArg = HiDPISetting.getScalePropertyArg();
     if (scalePropertyArg != null)
     {
-      System.out.println("Running " + startClass + " with scale setting "
+      syserr(debug, quiet, "Running " + startClass + " with scale setting "
               + scalePropertyArg);
       command.add(scalePropertyArg);
     }
@@ -197,29 +290,47 @@ public class Launcher
 
     final ProcessBuilder builder = new ProcessBuilder(command);
 
-    if (Boolean.parseBoolean(System.getProperty("launcherprint", "false")))
+    if ((Boolean.parseBoolean(System.getProperty("launcherprint", "false"))
+            || launcherprint))
     {
-      System.out.println(
+      syserr(debug, quiet,
               "LAUNCHER COMMAND: " + String.join(" ", builder.command()));
     }
-    System.out.println("Running " + startClass + " with "
-            + (memSetting == null ? "no memory setting"
-                    : ("memory setting " + memSetting)));
+    syserr(debug, quiet,
+            "Running " + startClass + " with "
+                    + (memSetting == null ? "no memory setting"
+                            : ("memory setting " + memSetting)));
 
-    if (Boolean.parseBoolean(System.getProperty("launcherstop", "false")))
+    if (Boolean.parseBoolean(System.getProperty("launcherstop", "false"))
+            || (debug && launcherstop))
     {
+      syserr(debug, quiet,
+              "System property 'launcherstop' is set and not 'false'. Exiting.");
       System.exit(0);
     }
     try
     {
       builder.inheritIO();
       Process process = builder.start();
-      process.waitFor();
+      if (wait || launcherwait)
+      {
+        syserr(debug, quiet, "Launching application process");
+        process.waitFor();
+      }
+      else
+      {
+        int waitInt = 0;
+        syserr(debug, quiet,
+                "Wait time for application process is " + waitInt + "ms");
+        process.waitFor(waitInt, TimeUnit.MILLISECONDS);
+      }
+      syserr(debug, quiet, "Launcher process ending");
     } catch (IOException e)
     {
       if (e.getMessage().toLowerCase(Locale.ROOT).contains("memory"))
       {
-        System.out.println("Caught a memory exception: " + e.getMessage());
+        jalview.bin.Console
+                .errPrintln("Caught a memory exception: " + e.getMessage());
         // Probably the "Cannot allocate memory" error, try without the memory
         // setting
         ArrayList<String> commandNoMem = new ArrayList<>();
@@ -232,7 +343,7 @@ public class Launcher
         }
         final ProcessBuilder builderNoMem = new ProcessBuilder(
                 commandNoMem);
-        System.out.println("Command without memory setting: "
+        jalview.bin.Console.errPrintln("Command without memory setting: "
                 + String.join(" ", builderNoMem.command()));
         try
         {
@@ -252,7 +363,14 @@ public class Launcher
     {
       e.printStackTrace();
     }
-    // System.exit(0);
+  }
+
+  private static void syserr(boolean debug, boolean quiet, String message)
+  {
+    if (debug && !quiet)
+    {
+      jalview.bin.Console.errPrintln("LAUNCHERDEBUG - " + message);
+    }
   }
 
 }