afe2b6c3ec0289c518030739497e3b6e950b0e69
[jabaws.git] / engine / compbio / engine / client / Util.java
1 /* Copyright (c) 2009 Peter Troshin\r
2  *  \r
3  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 1.0     \r
4  * \r
5  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
6  *  Apache License version 2 as published by the Apache Software Foundation\r
7  * \r
8  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
9  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
10  *  License for more details.\r
11  * \r
12  *  A copy of the license is in apache_license.txt. It is also available here:\r
13  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
14  * \r
15  * Any republication or derived work distributed in source code form\r
16  * must include this copyright and license notice.\r
17  */\r
18 \r
19 package compbio.engine.client;\r
20 \r
21 import java.io.File;\r
22 import java.io.FileInputStream;\r
23 import java.io.FileNotFoundException;\r
24 import java.io.FileWriter;\r
25 import java.io.IOException;\r
26 import java.security.InvalidParameterException;\r
27 import java.util.Map;\r
28 \r
29 import org.apache.log4j.Logger;\r
30 \r
31 import compbio.engine.client.Executable.ExecProvider;\r
32 import compbio.engine.conf.DirectoryManager;\r
33 import compbio.engine.conf.PropertyHelperManager;\r
34 import compbio.metadata.JobStatus;\r
35 import compbio.metadata.ResultNotAvailableException;\r
36 import compbio.util.FileUtil;\r
37 import compbio.util.PropertyHelper;\r
38 import compbio.util.SysPrefs;\r
39 \r
40 public final class Util {\r
41 \r
42         private static final PropertyHelper ph = PropertyHelperManager\r
43                         .getPropertyHelper();\r
44 \r
45         private static final Logger log = Logger.getLogger(Util.class);\r
46 \r
47         public static boolean isValidJobId(final String key) {\r
48                 if (compbio.util.Util.isEmpty(key)) {\r
49                         return false;\r
50                 }\r
51                 int delIdx = key.indexOf(DirectoryManager.DELIM);\r
52                 if (delIdx < 0) {\r
53                         return false;\r
54                 }\r
55                 String id = key.substring(delIdx + DirectoryManager.DELIM.length());\r
56                 try {\r
57                         Long.parseLong(id);\r
58                 } catch (NumberFormatException e) {\r
59                         log.debug("Invalid key! " + e.getLocalizedMessage());\r
60                         return false;\r
61                 }\r
62                 return true;\r
63         }\r
64 \r
65         public static void writeStatFile(String workDirectory,\r
66                         String fileAndEventName) {\r
67                 // never override old stat files!\r
68                 // Work directory could be null for cancelled or incomplete jobs, just\r
69                 // ignore\r
70                 if (!compbio.util.Util.isEmpty(workDirectory)) {\r
71                         writeFile(workDirectory, fileAndEventName, new Long(System\r
72                                         .currentTimeMillis()).toString(), false);\r
73                 }\r
74         }\r
75 \r
76         public static void writeFile(String workDirectory, String fileAndEventName,\r
77                         String content, boolean override) {\r
78                 File file = null;\r
79                 if (compbio.util.Util.isEmpty(workDirectory)) {\r
80                         log\r
81                                         .debug("Calling compbio.engine.Util.writeFile() with not work directory."\r
82                                                         + " Skipping writing statistics!");\r
83                         return;\r
84                 }\r
85                 assert !compbio.util.Util.isEmpty(content) : "Content expected!";\r
86                 FileWriter writer = null;\r
87                 try {\r
88                         file = new File(workDirectory, fileAndEventName);\r
89                         // Do not override existing files unless asked to do so !\r
90                         if (file.exists() && !override) {\r
91                                 return;\r
92                         }\r
93                         writer = new FileWriter(file);\r
94                         writer.write(content);\r
95                         writer.close();\r
96                         log.debug("File " + fileAndEventName + " with content: " + content\r
97                                         + " has been recorder successfully! ");\r
98                 } catch (IOException e) {\r
99                         log.error("Could not record the " + fileAndEventName + " file in "\r
100                                         + workDirectory + " for local execution! Ignoring... "\r
101                                         + e.getMessage());\r
102                 } finally {\r
103                         FileUtil.closeSilently(log, writer);\r
104                 }\r
105         }\r
106 \r
107         public static final boolean writeMarker(String workDirectory,\r
108                         JobStatus fileType) {\r
109                 if (fileType == null) {\r
110                         throw new NullPointerException("MarkerType must be provided!");\r
111                 }\r
112                 if (fileType == fileType.FINISHED || fileType == fileType.STARTED) {\r
113                         throw new IllegalArgumentException(\r
114                                         "Please use Util.writeStatFile(workDirectory, fileAndEventName) to record FINISHED and STARTED statuses!");\r
115                 }\r
116                 if (!PathValidator.isValidDirectory(workDirectory)) {\r
117                         // This is OK as some task could be cancelled even before they\r
118                         // started\r
119                         log.warn("Attempting to write " + fileType\r
120                                         + " marker in the work directory " + workDirectory\r
121                                         + " is not provided or does not exist!");\r
122                         return false;\r
123                 }\r
124                 try {\r
125                         File sfile = new File(workDirectory, fileType.toString());\r
126                         if (!sfile.exists()) {\r
127                                 return sfile.createNewFile();\r
128                         }\r
129                 } catch (IOException e) {\r
130                         log.error("Could not record stat marker file " + fileType\r
131                                         + " into the directory " + workDirectory + " ! "\r
132                                         + e.getMessage(), e.getCause());\r
133                 }\r
134                 return false;\r
135         }\r
136 \r
137         public static boolean isMarked(String workDirectory, JobStatus marker) {\r
138                 if (!PathValidator.isValidDirectory(workDirectory)) {\r
139                         throw new NullPointerException("Work directory " + workDirectory\r
140                                         + " is not provided or does not exist!");\r
141                 }\r
142                 return new File(workDirectory, marker.toString()).exists();\r
143         }\r
144 \r
145         public static Map<String, String> mergeEnvVariables(\r
146                         final Map<String, String> sysEnvTobeModified,\r
147                         final Map<String, String> variables) {\r
148                 if (variables.containsKey(EnvVariableProcessor.PATH)) {\r
149                         String propPath = variables.get(EnvVariableProcessor.PATH);\r
150                         String sysPATH = sysEnvTobeModified.get(EnvVariableProcessor.PATH);\r
151                         String syspath = sysEnvTobeModified.get(EnvVariableProcessor.PATH\r
152                                         .toLowerCase());\r
153                         // This version appears surprisingly often on windows machines\r
154                         boolean added = false;\r
155                         String sysPath = sysEnvTobeModified.get("Path");\r
156                         if (sysPATH != null) {\r
157                                 sysEnvTobeModified.put(EnvVariableProcessor.PATH, sysPATH\r
158                                                 + File.pathSeparator + propPath);\r
159                                 added = true;\r
160                         }\r
161                         if (syspath != null) {\r
162                                 sysEnvTobeModified.put(EnvVariableProcessor.PATH.toLowerCase(),\r
163                                                 syspath + File.pathSeparator + propPath);\r
164                                 added = true;\r
165                         }\r
166                         if (sysPath != null) {\r
167                                 sysEnvTobeModified.put("Path", sysPath + File.pathSeparator\r
168                                                 + propPath);\r
169                                 added = true;\r
170                         }\r
171                         // If not path variable is found, then add it\r
172                         if (!added) {\r
173                                 sysEnvTobeModified.put(EnvVariableProcessor.PATH, propPath);\r
174                         }\r
175                         variables.remove(EnvVariableProcessor.PATH);\r
176                 }\r
177                 sysEnvTobeModified.putAll(variables);\r
178                 return sysEnvTobeModified;\r
179         }\r
180 \r
181         public static String convertToAbsolute(String relativePath) {\r
182                 // If specified path is relative, than make it absolute\r
183                 String absolute = relativePath;\r
184                 if (!PathValidator.isAbsolutePath(relativePath)) {\r
185                         absolute = PropertyHelperManager.getLocalPath() + relativePath;\r
186                         Util.log\r
187                                         .trace("Changing local path in enviromental variable to absolute: FROM "\r
188                                                         + relativePath + " TO " + absolute);\r
189                 }\r
190                 return absolute;\r
191         }\r
192 \r
193         public static String getExecProperty(String propertySpec, Executable<?> exec) {\r
194                 assert !compbio.util.Util.isEmpty(propertySpec);\r
195                 assert exec != null;\r
196                 return Util.getExecProperty(propertySpec, exec.getClass());\r
197         }\r
198 \r
199         public static String getExecProperty(String propertySpec, Class<?> clazz) {\r
200                 assert !compbio.util.Util.isEmpty(propertySpec);\r
201                 assert clazz != null;\r
202                 String property = clazz.getSimpleName().toLowerCase() + "."\r
203                                 + propertySpec.toLowerCase();\r
204                 log.trace("Processing property: " + property);\r
205                 return ph.getProperty(property);\r
206         }\r
207 \r
208         public static String getFullPath(String workDirectory, String fileName) {\r
209                 assert !compbio.util.Util.isEmpty(fileName) : "Filename must be provided! ";\r
210                 assert !compbio.util.Util.isEmpty(workDirectory) : "Workdirectory must be provided! ";\r
211                 return workDirectory + File.separator + fileName;\r
212         }\r
213 \r
214         public static String getCommand(ExecProvider provider, Class<?> clazz) {\r
215                 if (provider == ExecProvider.Any) {\r
216                         throw new IllegalArgumentException(\r
217                                         "A particular execution environment must be chosen");\r
218                 }\r
219                 String execCommandName = clazz.getSimpleName().toLowerCase();\r
220                 String bin = "";\r
221                 if (provider == ExecProvider.Local) {\r
222                         if (SysPrefs.isWindows) {\r
223                                 bin = ph.getProperty("local." + execCommandName\r
224                                                 + ".bin.windows");\r
225                         } else {\r
226                                 bin = ph.getProperty("local." + execCommandName + ".bin");\r
227                         }\r
228                         // If path to executable defined in the properties is not absolute,\r
229                         // then make it so\r
230                         // as setting working directory of ProcessBuilder will make it\r
231                         // impossible\r
232                         // to find an executable otherwise\r
233                         if (!compbio.util.Util.isEmpty(bin)\r
234                                         && !PathValidator.isAbsolutePath(bin)) {\r
235                                 bin = PropertyHelperManager.getLocalPath() + bin;\r
236                         }\r
237                 } else {\r
238                         bin = ph.getProperty("cluster." + execCommandName + ".bin");\r
239                 }\r
240                 return bin; // File.separator\r
241         }\r
242 \r
243         public static ExecProvider getSupportedRuntimes(Class<?> clazz) {\r
244                 boolean localRuntimeSupport = false;\r
245                 boolean clusterRuntimeSupport = false;\r
246                 String executableName = clazz.getSimpleName().toLowerCase();\r
247                 String localRuntime1 = ph.getProperty("local." + executableName\r
248                                 + ".bin.windows");\r
249                 String localRuntime2 = ph.getProperty("local." + executableName\r
250                                 + ".bin");\r
251                 if (!compbio.util.Util.isEmpty(localRuntime1)\r
252                                 || !compbio.util.Util.isEmpty(localRuntime2)) {\r
253                         localRuntimeSupport = true;\r
254                 }\r
255                 String clusterRuntime = ph.getProperty("cluster." + executableName\r
256                                 + ".bin");\r
257                 if (!compbio.util.Util.isEmpty(clusterRuntime)) {\r
258                         clusterRuntimeSupport = true;\r
259                 }\r
260                 if (localRuntimeSupport && clusterRuntimeSupport) {\r
261                         return ExecProvider.Any;\r
262                 } else if (localRuntimeSupport) {\r
263                         return ExecProvider.Local;\r
264                 } else if (clusterRuntimeSupport) {\r
265                         return ExecProvider.Cluster;\r
266                 }\r
267                 // Means executable cannot be executed -> is improperly configured\r
268                 // should be ignored\r
269                 throw new InvalidParameterException(\r
270                                 "Executable is not provided for any runtime environments");\r
271         }\r
272 \r
273         public static ConfiguredExecutable<?> loadExecutable(String taskId)\r
274                         throws ResultNotAvailableException {\r
275                 String workDir = compbio.engine.Configurator.getWorkDirectory(taskId);\r
276                 // The results for this job has been collected once, or the JVM may\r
277                 // have been restarted,\r
278                 // so that the job is not in the job list\r
279                 // ->load a ConfiguredExercutable from saved run and return it\r
280                 FileInputStream fileInStream = null;\r
281                 ConfiguredExecutable<?> exec = null;\r
282                 try {\r
283                         fileInStream = new FileInputStream(workDir + File.separator\r
284                                         + RunConfiguration.rconfigFile);\r
285                         RunConfiguration rconf = RunConfiguration.load(fileInStream);\r
286                         exec = ConfExecutable.newConfExecutable(rconf);\r
287                         fileInStream.close();\r
288                 } catch (FileNotFoundException e) {\r
289                         log.error("Could not find run configuration to load!"\r
290                                         + e.getLocalizedMessage(), e.getCause());\r
291                         throw new ResultNotAvailableException(\r
292                                         "Could not find run configuration to load!"\r
293                                                         + e.getMessage(), e.getCause());\r
294                 } catch (IOException e) {\r
295                         log.error("IO Exception while reading run configuration file!"\r
296                                         + e.getLocalizedMessage(), e.getCause());\r
297                         throw new ResultNotAvailableException(\r
298                                         "Could not load run configuration!" + e.getMessage(), e\r
299                                                         .getCause());\r
300                 } finally {\r
301                         FileUtil.closeSilently(log, fileInStream);\r
302                 }\r
303                 return exec;\r
304         }\r
305 \r
306 }\r