Merge branch 'documentation/JAL-3407_2.11.1_release' into releases/Release_2_11_1_Branch
[jalview.git] / src / jalview / bin / Launcher.java
1 package jalview.bin;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.lang.management.ManagementFactory;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 /**
10  * A Launcher class for Jalview. This class is used to launch Jalview from the
11  * shadowJar when Getdown is not used or available. It attempts to take all the
12  * command line arguments to pass on to the jalview.bin.Jalview class, but to
13  * insert a -Xmx memory setting to a sensible default, using the -jvmmempc and
14  * -jvmmemmax application arguments if specified. If not specified then system
15  * properties will be looked for by jalview.bin.MemorySetting. If the user has
16  * provided the JVM with a -Xmx setting directly and not set -jvmmempc or
17  * -jvmmemmax then this setting will be used and system properties ignored. If
18  * -Xmx is set as well as -jvmmempc or -jvmmemmax as argument(s) then the -Xmx
19  * argument will NOT be passed on to the main application launch.
20  * 
21  * @author bsoares
22  *
23  */
24 public class Launcher
25 {
26   private final static String startClass = "jalview.bin.Jalview";
27
28   private final static String dockIconPath = "JalviewLogo_Huge.png";
29
30   /**
31    * main method for jalview.bin.Launcher. This restarts the same JRE's JVM with
32    * the same arguments but with memory adjusted based on extracted -jvmmempc and
33    * -jvmmemmax application arguments. If on a Mac then extra dock:icon and
34    * dock:name arguments are also set.
35    * 
36    * @param args
37    */
38   public static void main(String[] args)
39   {
40     final String javaBin = System.getProperty("java.home") + File.separator
41             + "bin" + File.separator + "java";
42
43     List<String> command = new ArrayList<>();
44     command.add(javaBin);
45
46     String memSetting = null;
47
48     boolean isAMac = System.getProperty("os.name").indexOf("Mac") > -1;
49
50     for (String jvmArg : ManagementFactory.getRuntimeMXBean()
51             .getInputArguments())
52     {
53       command.add(jvmArg);
54     }
55     command.add("-cp");
56     command.add(ManagementFactory.getRuntimeMXBean().getClassPath());
57
58     String jvmmempc = null;
59     String jvmmemmax = null;
60     ArrayList<String> arguments = new ArrayList<>();
61     for (String arg : args)
62     {
63       // jvmmempc and jvmmemmax args used to set memory and are not passed on to
64       // startClass
65       if (arg.startsWith(
66               "-" + MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "="))
67       {
68         jvmmempc = arg.substring(
69                 MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.length()
70                         + 2);
71       }
72       else if (arg.startsWith(
73               "-" + MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME + "="))
74       {
75         jvmmemmax = arg.substring(
76                 MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME.length() + 2);
77       }
78       else
79       {
80         arguments.add(arg);
81       }
82     }
83
84     // add memory setting if not specified
85     boolean memSet = false;
86     boolean dockIcon = false;
87     boolean dockName = false;
88     for (int i = 0; i < command.size(); i++)
89     {
90       String arg = command.get(i);
91       if (arg.startsWith("-Xmx"))
92       {
93         // only use -Xmx if jvmmemmax and jvmmempc have not been set
94         if (jvmmempc == null && jvmmemmax == null)
95         {
96           memSetting = arg;
97           memSet = true;
98         }
99       }
100       else if (arg.startsWith("-Xdock:icon"))
101       {
102         dockIcon = true;
103       }
104       else if (arg.startsWith("-Xdock:name"))
105       {
106         dockName = true;
107       }
108     }
109
110     if (!memSet)
111     {
112       long maxMemLong = MemorySetting.getMemorySetting(jvmmemmax, jvmmempc);
113       
114       if (maxMemLong > 0)
115       {
116         memSetting = "-Xmx" + Long.toString(maxMemLong);
117         memSet = true;
118         command.add(memSetting);
119       }
120     }
121
122     if (isAMac)
123     {
124       if (!dockIcon)
125       {
126         command.add("-Xdock:icon=" + dockIconPath);
127       }
128       if (!dockName)
129       {
130         // -Xdock:name=... doesn't actually work :(
131         // Leaving it in in case it gets fixed
132         command.add("-Xdock:name=" + "Jalview");
133       }
134     }
135
136     command.add(startClass);
137     command.addAll(arguments);
138
139     final ProcessBuilder builder = new ProcessBuilder(command);
140
141     // System.out.println("COMMAND: " + String.join(" ", builder.command()));
142     System.out.println("Running " + startClass + " with "
143             + (memSetting == null ? "no memory setting" : memSetting));
144
145     if (Boolean.parseBoolean(System.getProperty("launcherstop")))
146     {
147       System.exit(0);
148     }
149     try
150     {
151       builder.inheritIO();
152       Process process = builder.start();
153       process.waitFor();
154     } catch (IOException e)
155     {
156       if (e.getMessage().toLowerCase().contains("memory"))
157       {
158         System.out.println("Caught a memory exception: " + e.getMessage());
159         // Probably the "Cannot allocate memory" error, try without the memory setting
160         ArrayList<String> commandNoMem = new ArrayList<>();
161         for (int i = 0; i < command.size(); i++)
162         {
163           if (!command.get(i).startsWith("-Xmx"))
164           {
165             commandNoMem.add(command.get(i));
166           }
167         }
168         final ProcessBuilder builderNoMem = new ProcessBuilder(
169                 commandNoMem);
170         System.out.println("Command without memory setting: "
171                 + String.join(" ", builderNoMem.command()));
172         try
173         {
174           builderNoMem.inheritIO();
175           Process processNoMem = builderNoMem.start();
176           processNoMem.waitFor();
177         } catch (Exception ex)
178         {
179           ex.printStackTrace();
180         }
181       }
182       else
183       {
184         e.printStackTrace();
185       }
186     } catch (Exception e)
187     {
188       e.printStackTrace();
189     }
190     // System.exit(0);
191
192   }
193
194 }