Merge branch 'feature/JAL-629_--output_-_means_output_to_STDOUT' into improvement...
[jalview.git] / src / jalview / util / LaunchUtils.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.util.Properties;
31
32 import jalview.bin.Console;
33
34 public class LaunchUtils
35 {
36
37   // setting these is LaunchUtils so don't need to import Platform
38   public final static boolean isMac = System.getProperty("os.name")
39           .indexOf("Mac") > -1;
40
41   public final static boolean isWindows = System.getProperty("os.name")
42           .indexOf("Win") > -1;
43
44   private static boolean isJS = /** @j2sNative true || */
45           false;
46
47   public static void loadChannelProps(File dir)
48   {
49     ChannelProperties.loadProps(dir);
50   }
51
52   private static Properties userPreferences = null;
53
54   public static String getUserPreference(String key)
55   {
56     if (userPreferences == null)
57     {
58       String channelPrefsFilename = ChannelProperties
59               .getProperty("preferences.filename");
60       if (channelPrefsFilename == null)
61       {
62         return null;
63       }
64       File propertiesFile = new File(System.getProperty("user.home"),
65               channelPrefsFilename);
66       if (!propertiesFile.exists())
67       {
68         return null;
69       }
70       try
71       {
72         userPreferences = new Properties();
73         userPreferences.load(new FileInputStream(propertiesFile));
74       } catch (FileNotFoundException e)
75       {
76         // didn't find user preferences file
77         return null;
78       } catch (IOException e)
79       {
80         jalview.bin.Console.errPrintln(e.getMessage());
81         return null;
82       }
83     }
84     return userPreferences.getProperty(key);
85   }
86
87   public static boolean getBooleanUserPreference(String key)
88   {
89     return Boolean.parseBoolean(getUserPreference(key));
90   }
91
92   public static int JAVA_COMPILE_VERSION = 0;
93
94   public static int getJavaCompileVersion()
95   {
96     if (LaunchUtils.isJS)
97     {
98       return -1;
99     }
100     else if (JAVA_COMPILE_VERSION > 0)
101     {
102       return JAVA_COMPILE_VERSION;
103     }
104     String buildDetails = "jar:".concat(LaunchUtils.class
105             .getProtectionDomain().getCodeSource().getLocation().toString()
106             .concat("!" + "/.build_properties"));
107     try
108     {
109       URL localFileURL = new URL(buildDetails);
110       InputStream in = localFileURL.openStream();
111       Properties buildProperties = new Properties();
112       buildProperties.load(in);
113       in.close();
114       String JCV = buildProperties.getProperty("JAVA_COMPILE_VERSION",
115               null);
116       if (JCV == null)
117       {
118         Console.errPrintln(
119                 "Could not obtain JAVA_COMPILE_VERSION for comparison");
120         return -2;
121       }
122       JAVA_COMPILE_VERSION = Integer.parseInt(JCV);
123     } catch (MalformedURLException e)
124     {
125       jalview.bin.Console.errPrintln("Could not find " + buildDetails);
126       return -3;
127     } catch (IOException e)
128     {
129       jalview.bin.Console.errPrintln("Could not load " + buildDetails);
130       return -4;
131     } catch (NumberFormatException e)
132     {
133       jalview.bin.Console.errPrintln("Could not parse JAVA_COMPILE_VERSION");
134       return -5;
135     }
136
137     return JAVA_COMPILE_VERSION;
138   }
139
140   public static int JAVA_VERSION = 0;
141
142   public static int getJavaVersion()
143   {
144     if (LaunchUtils.isJS)
145     {
146       return -1;
147     }
148     else if (JAVA_VERSION > 0)
149     {
150       return JAVA_VERSION;
151     }
152     try
153     {
154       String JV = System.getProperty("java.version");
155       if (JV == null)
156       {
157         Console.errPrintln("Could not obtain java.version for comparison");
158         return -2;
159       }
160       if (JV.startsWith("1."))
161       {
162         JV = JV.substring(2);
163       }
164       JAVA_VERSION = JV.indexOf(".") == -1 ? Integer.parseInt(JV)
165               : Integer.parseInt(JV.substring(0, JV.indexOf(".")));
166     } catch (NumberFormatException e)
167     {
168       jalview.bin.Console.errPrintln("Could not parse java.version");
169       return -3;
170     }
171     return JAVA_VERSION;
172   }
173
174   public static boolean checkJavaVersion()
175   {
176     if (LaunchUtils.isJS)
177     {
178       return true;
179     }
180     String buildDetails = "jar:".concat(LaunchUtils.class
181             .getProtectionDomain().getCodeSource().getLocation().toString()
182             .concat("!" + "/.build_properties"));
183
184     int java_compile_version = getJavaCompileVersion();
185     int java_version = getJavaVersion();
186
187     if (java_compile_version <= 0 || java_version <= 0)
188     {
189       Console.errPrintln("Could not make Java version check");
190       return true;
191     }
192     // Warn if these java.version and JAVA_COMPILE_VERSION conditions exist
193     // Usually this means a Java 11 compiled JAR being run by a Java 11 JVM
194     if (java_version >= 11 && java_compile_version < 11)
195     {
196       return false;
197     }
198
199     return true;
200   }
201
202   public static String findJavaBin(boolean winConsole)
203   {
204     return findJavaBin(System.getProperty("java.home"), winConsole, true);
205   }
206
207   /*
208    * Returns a string path to the most likely java binary wanted to run this
209    * installation of Jalview.
210    * 
211    * @param  winConsole  whether to use java.exe (console) in preference to javaw.exe
212    *                     (only affects Windows).
213    * @param  javaHome    Try this javaHome dir (defaults to the running java.home).
214    * @param  generic     Return a generic java command if not found.
215    */
216   public static String findJavaBin(String javaHome, boolean winConsole,
217           boolean generic)
218   {
219     String javaBin = null;
220     final String javaExe = winConsole ? "java.exe" : "javaw.exe";
221     final String java = "java";
222
223     if (javaHome != null)
224     {
225       // property "channel.app_name" is set by install4j when launching getdown
226       String propertyAppName = System.getProperty("channel.app_name");
227       final String appName = (propertyAppName != null
228               && propertyAppName.length() > 0) ? propertyAppName
229                       : ChannelProperties.getProperty("app_name");
230
231       final String javaBinDir = javaHome + File.separator + "bin"
232               + File.separator;
233
234       // appName and "Jalview" will not point to javaw.exe or java.exe but in
235       // this case that's okay because the taskbar display name problem doesn't
236       // manifest in Windows. See JAL-3820, JAL-4189.
237       for (String name : new String[] { appName, "Jalview", java, javaExe })
238       {
239         if (LaunchUtils.checkJVMSymlink(javaBinDir + name, winConsole))
240         {
241           javaBin = javaBinDir + name;
242           break;
243         }
244       }
245     }
246
247     if (javaBin == null && generic)
248     {
249       javaBin = LaunchUtils.isWindows ? javaExe : java;
250     }
251
252     return javaBin;
253   }
254
255   /*
256    * checkJVMSymlink returns true if the path in testBin *is* a java binary, or
257    * points to a java binary.
258    * @param  testBin     The binary or symbolic link to check
259    * @param  winConsole  whether we are in/want a Windows console (only relevant for Windows,
260    *                     determines whether we use java.exe or javaw.exe)
261    */
262   private static boolean checkJVMSymlink(String testBin, boolean winConsole)
263   {
264     File testBinFile = new File(testBin);
265     if (!testBinFile.exists())
266     {
267       return false;
268     }
269     File targetFile = null;
270     try
271     {
272       targetFile = testBinFile.getCanonicalFile();
273     } catch (IOException e)
274     {
275       return false;
276     }
277     final String javaExe = winConsole ? "java.exe" : "javaw.exe";
278     if (targetFile != null && ("java".equals(targetFile.getName())
279             || javaExe.equals(targetFile.getName())))
280     {
281       return true;
282     }
283     return false;
284   }
285 }