1 /* Copyright (c) 2009 Peter Troshin
\r
3 * JAva Bioinformatics Analysis Web Services (JABAWS) @version: 1.0
\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
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
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
15 * Any republication or derived work distributed in source code form
\r
16 * must include this copyright and license notice.
\r
19 package compbio.engine.client;
\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
29 import org.apache.log4j.Logger;
\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.LimitsManager;
\r
36 import compbio.metadata.ResultNotAvailableException;
\r
37 import compbio.util.FileUtil;
\r
38 import compbio.util.PropertyHelper;
\r
39 import compbio.util.SysPrefs;
\r
41 public final class Util {
\r
43 private static final PropertyHelper ph = PropertyHelperManager
\r
44 .getPropertyHelper();
\r
46 private static final Logger log = Logger.getLogger(Util.class);
\r
48 public static boolean isValidJobId(final String key) {
\r
49 if (compbio.util.Util.isEmpty(key)) {
\r
52 int delIdx = key.indexOf(DirectoryManager.DELIM);
\r
56 String id = key.substring(delIdx + DirectoryManager.DELIM.length());
\r
59 } catch (NumberFormatException e) {
\r
60 log.debug("Invalid key! " + e.getLocalizedMessage());
\r
66 public static void writeStatFile(String workDirectory,
\r
67 String fileAndEventName) {
\r
68 // never override old stat files!
\r
69 // Work directory could be null for cancelled or incomplete jobs, just
\r
71 if (!compbio.util.Util.isEmpty(workDirectory)) {
\r
72 writeFile(workDirectory, fileAndEventName,
\r
73 new Long(System.currentTimeMillis()).toString(), false);
\r
77 public static void writeFile(String workDirectory, String fileAndEventName,
\r
78 String content, boolean override) {
\r
80 if (compbio.util.Util.isEmpty(workDirectory)) {
\r
81 log.debug("Calling compbio.engine.Util.writeFile() with not work directory."
\r
82 + " Skipping writing statistics!");
\r
85 assert !compbio.util.Util.isEmpty(content) : "Content expected!";
\r
86 FileWriter writer = null;
\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
93 writer = new FileWriter(file);
\r
94 writer.write(content);
\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
103 FileUtil.closeSilently(log, writer);
\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
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
116 if (!PathValidator.isValidDirectory(workDirectory)) {
\r
117 // This is OK as some task could be cancelled even before they
\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
125 File sfile = new File(workDirectory, fileType.toString());
\r
126 if (!sfile.exists()) {
\r
127 return sfile.createNewFile();
\r
129 } catch (IOException e) {
\r
131 "Could not record stat marker file " + fileType
\r
132 + " into the directory " + workDirectory + " ! "
\r
133 + e.getMessage(), e.getCause());
\r
138 public static boolean isMarked(String workDirectory, JobStatus marker) {
\r
139 if (!PathValidator.isValidDirectory(workDirectory)) {
\r
140 throw new NullPointerException("Work directory " + workDirectory
\r
141 + " is not provided or does not exist!");
\r
143 return new File(workDirectory, marker.toString()).exists();
\r
146 public static Map<String, String> mergeEnvVariables(
\r
147 final Map<String, String> sysEnvTobeModified,
\r
148 final Map<String, String> variables) {
\r
149 if (variables.containsKey(EnvVariableProcessor.PATH)) {
\r
150 String propPath = variables.get(EnvVariableProcessor.PATH);
\r
151 String sysPATH = sysEnvTobeModified.get(EnvVariableProcessor.PATH);
\r
152 String syspath = sysEnvTobeModified.get(EnvVariableProcessor.PATH
\r
154 // This version appears surprisingly often on windows machines
\r
155 boolean added = false;
\r
156 String sysPath = sysEnvTobeModified.get("Path");
\r
157 if (sysPATH != null) {
\r
158 sysEnvTobeModified.put(EnvVariableProcessor.PATH, sysPATH
\r
159 + File.pathSeparator + propPath);
\r
162 if (syspath != null) {
\r
163 sysEnvTobeModified.put(EnvVariableProcessor.PATH.toLowerCase(),
\r
164 syspath + File.pathSeparator + propPath);
\r
167 if (sysPath != null) {
\r
168 sysEnvTobeModified.put("Path", sysPath + File.pathSeparator
\r
172 // If not path variable is found, then add it
\r
174 sysEnvTobeModified.put(EnvVariableProcessor.PATH, propPath);
\r
176 variables.remove(EnvVariableProcessor.PATH);
\r
178 sysEnvTobeModified.putAll(variables);
\r
179 return sysEnvTobeModified;
\r
182 public static String convertToAbsolute(String relativePath) {
\r
183 // If specified path is relative, than make it absolute
\r
184 String absolute = relativePath;
\r
185 if (!PathValidator.isAbsolutePath(relativePath)) {
\r
186 absolute = PropertyHelperManager.getLocalPath() + relativePath;
\r
187 Util.log.trace("Changing local path in enviromental variable to absolute: FROM "
\r
188 + relativePath + " TO " + absolute);
\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
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
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
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
219 String execCommandName = clazz.getSimpleName().toLowerCase();
\r
221 if (provider == ExecProvider.Local) {
\r
222 if (SysPrefs.isWindows) {
\r
223 bin = ph.getProperty("local." + execCommandName
\r
226 bin = ph.getProperty("local." + execCommandName + ".bin");
\r
228 // For executable Jar files the location of Java executable is not
\r
229 // required for local execution. If it is not provided, JABAWS will
\r
230 // attempt to use Java from JAVA_HOME env variable
\r
231 if (isJavaLibrary(clazz)) {
\r
232 if (compbio.util.Util.isEmpty(bin)) {
\r
236 // If path to executable defined in the properties is not absolute,
\r
238 // as setting working directory of ProcessBuilder will make it
\r
240 // to find an executable otherwise
\r
241 if (!compbio.util.Util.isEmpty(bin)
\r
242 && !PathValidator.isAbsolutePath(bin)) {
\r
244 if (bin.equalsIgnoreCase("java")
\r
245 || bin.equalsIgnoreCase("java.exe")) {
\r
246 // do not make path absolute to the java executable if
\r
247 // relative path is provided. Java executable is not a part
\r
248 // of JABAWS distribution!
\r
250 bin = PropertyHelperManager.getLocalPath() + bin;
\r
254 bin = ph.getProperty("cluster." + execCommandName + ".bin");
\r
256 // Could have done: Set executable flag if not set
\r
257 // but - do not because in some cases more than one file must be made
\r
260 * if (!compbio.util.Util.isEmpty(bin)) { File command = new File(bin);
\r
261 * if (!command.canExecute()) { log.debug(
\r
262 * "The command line binary is not executable! (just unpacked from war file? )"
\r
263 * ); log.debug("Attempting to set executable flag for command: " +
\r
264 * bin); command.setExecutable(true, false); } }
\r
266 log.debug("Using executable: " + bin);
\r
267 return bin; // File.separator
\r
270 * Returns true of executableName.jar.file property has some value in the
\r
271 * Executable.properties file, false otherwise.
\r
276 public static boolean isJavaLibrary(Class<?> clazz) {
\r
277 String execCommandName = clazz.getSimpleName().toLowerCase();
\r
278 String java_lib = ph.getProperty(execCommandName + ".jar.file");
\r
279 return !compbio.util.Util.isEmpty(java_lib);
\r
283 * Returns the absolute path to the Java executable from JAVA_HOME
\r
285 * @return returns the absolute path to the Java executable from JAVA_HOME
\r
287 public static String getJava() {
\r
288 String javahome = System.getProperty("java.home");
\r
289 if (compbio.util.Util.isEmpty(javahome)) {
\r
290 javahome = System.getenv("JAVA_HOME");
\r
292 if (compbio.util.Util.isEmpty(javahome)) {
\r
293 log.warn("Cannot find Java in java.home system property "
\r
294 + "or JAVA_HOME environment variable! ");
\r
297 File jh = new File(javahome);
\r
298 if (jh.exists() && jh.isDirectory()) {
\r
299 String java = javahome + File.separator + "bin" + File.separator
\r
301 if (SysPrefs.isWindows) {
\r
304 File jexe = new File(java);
\r
305 if (jexe.exists() && jexe.isFile() && jexe.canExecute()) {
\r
306 log.info("Using Java from: " + jexe.getAbsolutePath());
\r
307 return jexe.getAbsolutePath();
\r
309 log.warn("Cannot find java executable in the JAVA_HOME!");
\r
312 log.warn("JAVA_HOME does not seems to point to a valid directory! Value: "
\r
318 public static ExecProvider getSupportedRuntimes(Class<?> clazz) {
\r
319 boolean localRuntimeSupport = false;
\r
320 boolean clusterRuntimeSupport = false;
\r
321 String executableName = clazz.getSimpleName().toLowerCase();
\r
322 String localRuntime1 = ph.getProperty("local." + executableName
\r
324 String localRuntime2 = ph.getProperty("local." + executableName
\r
326 if (!compbio.util.Util.isEmpty(localRuntime1)
\r
327 || !compbio.util.Util.isEmpty(localRuntime2)) {
\r
328 localRuntimeSupport = true;
\r
330 localRuntimeSupport = isJavaLibrary(clazz) && getJava() != null;
\r
333 String clusterRuntime = ph.getProperty("cluster." + executableName
\r
335 if (!compbio.util.Util.isEmpty(clusterRuntime)) {
\r
336 clusterRuntimeSupport = true;
\r
338 if (localRuntimeSupport && clusterRuntimeSupport) {
\r
339 return ExecProvider.Any;
\r
340 } else if (localRuntimeSupport) {
\r
341 return ExecProvider.Local;
\r
342 } else if (clusterRuntimeSupport) {
\r
343 return ExecProvider.Cluster;
\r
345 // Means executable cannot be executed -> is improperly configured
\r
346 // should be ignored
\r
347 throw new InvalidParameterException(
\r
348 "Executable is not provided for any runtime environments");
\r
350 public static ConfiguredExecutable<?> loadExecutable(String taskId)
\r
351 throws ResultNotAvailableException {
\r
352 String workDir = compbio.engine.Configurator.getWorkDirectory(taskId);
\r
353 // The results for this job has been collected once, or the JVM may
\r
354 // have been restarted,
\r
355 // so that the job is not in the job list
\r
356 // ->load a ConfiguredExercutable from saved run and return it
\r
357 FileInputStream fileInStream = null;
\r
358 ConfiguredExecutable<?> exec = null;
\r
360 fileInStream = new FileInputStream(workDir + File.separator
\r
361 + RunConfiguration.rconfigFile);
\r
362 RunConfiguration rconf = RunConfiguration.load(fileInStream);
\r
363 exec = ConfExecutable.newConfExecutable(rconf);
\r
364 fileInStream.close();
\r
365 } catch (FileNotFoundException e) {
\r
367 "Could not find run configuration to load!"
\r
368 + e.getLocalizedMessage(), e.getCause());
\r
369 throw new ResultNotAvailableException(
\r
370 "Could not find run configuration to load!"
\r
371 + e.getMessage(), e.getCause());
\r
372 } catch (IOException e) {
\r
374 "IO Exception while reading run configuration file!"
\r
375 + e.getLocalizedMessage(), e.getCause());
\r
376 throw new ResultNotAvailableException(
\r
377 "Could not load run configuration!" + e.getMessage(),
\r
380 FileUtil.closeSilently(log, fileInStream);
\r
386 * For now just assume that all parameters which came in needs setting it
\r
387 * will be a client responsibility to prepare RunnerConfig object then
\r
392 * public static List<String> toOptionString(RunnerConfig<?>
\r
393 * rconfig) { String option = ""; List<String> options = new
\r
394 * ArrayList<String>(); for (Parameter<?> par :
\r
395 * rconfig.getParameters()) { if (par.getPossibleValues().isEmpty())
\r
396 * { option = par.getOptionName(); } else { option =
\r
397 * par.getOptionName() + "=" + par.getPossibleValues().get(0); } //
\r
398 * separate options options.add(option); } return options; }
\r
401 public static <T> LimitsManager<T> getLimits(Class<T> clazz) {
\r
402 LimitsManager<T> limits = null;
\r
404 limits = ConfExecutable.getRunnerLimits(clazz);
\r
405 } catch (FileNotFoundException e) {
\r
406 Util.log.warn("No limits are found for " + clazz + " executable! "
\r
407 + e.getLocalizedMessage(), e.getCause());
\r
408 // its ok, limit may not be initialized
\r
409 } catch (IOException e) {
\r
410 Util.log.warn("IO exception while attempting to read limits for "
\r
411 + clazz + " executable! " + e.getLocalizedMessage(),
\r