23d0793e74d475316a2b0bff66d24207bf68852a
[jabaws.git] / engine / compbio / engine / client / ConfExecutable.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.IOException;\r
24 import java.io.InputStream;\r
25 import java.util.ArrayList;\r
26 import java.util.Collections;\r
27 import java.util.List;\r
28 import java.util.Map;\r
29 \r
30 import javax.xml.bind.JAXBException;\r
31 \r
32 import org.apache.log4j.Logger;\r
33 \r
34 import compbio.engine.conf.PropertyHelperManager;\r
35 import compbio.engine.conf.RunnerConfigMarshaller;\r
36 import compbio.metadata.Limit;\r
37 import compbio.metadata.LimitsManager;\r
38 import compbio.metadata.PresetManager;\r
39 import compbio.metadata.ResultNotAvailableException;\r
40 import compbio.metadata.RunnerConfig;\r
41 import compbio.metadata.UnsupportedRuntimeException;\r
42 import compbio.util.FileUtil;\r
43 import compbio.util.PropertyHelper;\r
44 import compbio.util.SysPrefs;\r
45 import compbio.util.Util;\r
46 \r
47 public class ConfExecutable<T> implements ConfiguredExecutable<T> {\r
48 \r
49         private static final Logger log = Logger.getLogger(ConfExecutable.class);\r
50 \r
51         private static final PropertyHelper ph = PropertyHelperManager\r
52                         .getPropertyHelper();\r
53         public final static String CLUSTER_TASK_ID_PREFIX = "@";\r
54 \r
55         private String workDirectory;\r
56         private String taskDirectory;\r
57 \r
58         private ExecProvider provider;\r
59         private Executable<T> exec;\r
60 \r
61         public ConfExecutable(Executable<T> executable, String taskDirectory) {\r
62                 this.exec = executable;\r
63                 assert !compbio.util.Util.isEmpty(taskDirectory);\r
64                 this.taskDirectory = taskDirectory;\r
65         }\r
66 \r
67         // TODO think about appropriate exception here\r
68         ConfExecutable(RunConfiguration rconf) {\r
69                 try {\r
70                         exec = (Executable<T>) Class.forName(rconf.runnerClassName)\r
71                                         .newInstance();\r
72                 } catch (InstantiationException e) {\r
73                         e.printStackTrace();\r
74                 } catch (IllegalAccessException e) {\r
75                         e.printStackTrace();\r
76                 } catch (ClassNotFoundException e) {\r
77                         e.printStackTrace();\r
78                 }\r
79                 exec.loadRunConfiguration(rconf);\r
80                 setWorkDirectory(rconf.workDirectory);\r
81                 this.taskDirectory = rconf.taskId;\r
82         }\r
83 \r
84         @Override\r
85         public ExecProvider getExecProvider() {\r
86                 return provider;\r
87         }\r
88 \r
89         public void setExecProvider(ExecProvider provider) {\r
90                 assert provider != null && provider != ExecProvider.Any;\r
91                 this.provider = provider;\r
92                 if (provider == Executable.ExecProvider.Cluster) {\r
93                         this.taskDirectory = CLUSTER_TASK_ID_PREFIX + taskDirectory;\r
94                 }\r
95         }\r
96 \r
97         @Override\r
98         public String getCommand(ExecProvider provider)\r
99                         throws UnsupportedRuntimeException {\r
100                 String command = compbio.engine.client.Util.getCommand(provider,\r
101                                 exec.getClass());\r
102                 if (Util.isEmpty(command)) {\r
103                         throw new UnsupportedRuntimeException(\r
104                                         "Executable "\r
105                                                         + this.exec.getClass().getSimpleName()\r
106                                                         + " is not supported by the current runtime environment! Current runtime environment is "\r
107                                                         + (SysPrefs.isWindows\r
108                                                                         ? "Windows "\r
109                                                                         : "Linux/Unix/Mac"));\r
110                 }\r
111                 return command;\r
112         }\r
113 \r
114         @Override\r
115         public ExecProvider getSupportedRuntimes() {\r
116                 return compbio.engine.client.Util.getSupportedRuntimes(exec.getClass());\r
117         }\r
118 \r
119         @Override\r
120         public Limit<T> getLimit(String presetName) {\r
121                 return exec.getLimit(presetName);\r
122         }\r
123 \r
124         @Override\r
125         public LimitsManager<T> getLimits() {\r
126                 return exec.getLimits();\r
127         }\r
128 \r
129         @Override\r
130         public String getTaskId() {\r
131                 return taskDirectory;\r
132         }\r
133 \r
134         @Override\r
135         public void setWorkDirectory(String workDirectory) {\r
136                 assert !compbio.util.Util.isEmpty(workDirectory);\r
137                 this.workDirectory = workDirectory;\r
138         }\r
139 \r
140         @Override\r
141         public String getWorkDirectory() {\r
142                 return this.workDirectory;\r
143         }\r
144 \r
145         @Override\r
146         public Executable<T> addParameters(List<String> parameters) {\r
147                 exec.addParameters(parameters);\r
148                 return exec;\r
149         }\r
150 \r
151         @Override\r
152         public String getOutput() {\r
153                 return exec.getOutput();\r
154         }\r
155 \r
156         @Override\r
157         public String getError() {\r
158                 return exec.getError();\r
159         }\r
160 \r
161         @Override\r
162         public List<String> getCreatedFiles() {\r
163                 return getFullPath(exec.getCreatedFiles());\r
164         }\r
165 \r
166         List<String> getFullPath(List<String> fileNames) {\r
167                 List<String> files = new ArrayList<String>();\r
168                 for (String fileName : fileNames) {\r
169                         files.add(compbio.engine.client.Util.getFullPath(workDirectory,\r
170                                         fileName));\r
171                 }\r
172                 return files;\r
173         }\r
174 \r
175         /**\r
176          * Not all input paths are relative! Input path could be absolute!\r
177          * \r
178          * @see compbio.engine.client.Executable#getInputFiles()\r
179          */\r
180         @Override\r
181         public String getInput() {\r
182                 String path = exec.getInput();\r
183                 if (PathValidator.isAbsolutePath(path)) {\r
184                         return path;\r
185                 }\r
186                 return compbio.engine.client.Util.getFullPath(workDirectory, path);\r
187         }\r
188 \r
189         @Override\r
190         public CommandBuilder<T> getParameters() {\r
191                 return exec.getParameters(provider);\r
192         }\r
193 \r
194         @Override\r
195         public CommandBuilder<T> getParameters(\r
196                         compbio.engine.client.Executable.ExecProvider provider) {\r
197                 return getParameters();\r
198         }\r
199 \r
200         @Override\r
201         public Executable<T> getExecutable() {\r
202                 return exec;\r
203         }\r
204 \r
205         @Override\r
206         public <V> V getResults() throws ResultNotAvailableException {\r
207                 return (V) exec.getResults(workDirectory);\r
208         }\r
209 \r
210         /*\r
211          * This is just a pass through method (non-Javadoc)\r
212          * \r
213          * @see compbio.runner.Executable#getResults(java.lang.String)\r
214          */\r
215         @Override\r
216         public <V> V getResults(String directory)\r
217                         throws ResultNotAvailableException {\r
218                 return (V) exec.getResults(directory);\r
219         }\r
220 \r
221         /*\r
222          * This method should be executed once and result of its execution reused.\r
223          * If not used carefully it could slow down the system!\r
224          */\r
225         public static <V> RunnerConfig<V> getRunnerOptions(\r
226                         Class<? extends Executable<V>> clazz) throws IOException {\r
227                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
228                                 + ".parameters.file";\r
229                 return (RunnerConfig<V>) getRunnerConfiguration(clazz,\r
230                                 RunnerConfig.class, parametersFile);\r
231         }\r
232 \r
233         /*\r
234          * This method should be executed once and result of its execution reused.\r
235          * If not used carefully it could slow down the system!\r
236          */\r
237         public static <V> PresetManager<V> getRunnerPresets(\r
238                         Class<? extends Executable<V>> clazz) throws IOException {\r
239                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
240                                 + ".presets.file";\r
241                 PresetManager<V> presets = (PresetManager<V>) getRunnerConfiguration(\r
242                                 clazz, PresetManager.class, parametersFile);\r
243                 return presets;\r
244         }\r
245 \r
246         /**\r
247          * This method should be executed once and result of its execution reused.\r
248          * If not used carefully it could slow down the system!\r
249          * \r
250          * @param <V>\r
251          * @param clazz\r
252          * @return\r
253          * @throws IOException\r
254          */\r
255         public static <V> LimitsManager<V> getRunnerLimits(Class<V> clazz)\r
256                         throws IOException {\r
257                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
258                                 + ".limits.file";\r
259                 LimitsManager<V> limits = (LimitsManager<V>) getRunnerConfiguration(\r
260                                 clazz, LimitsManager.class, parametersFile);\r
261                 return limits;\r
262         }\r
263 \r
264         static <V> Object getRunnerConfiguration(Class<V> clazz,\r
265                         Class<?> configurationHolder, String propertyName)\r
266                         throws IOException {\r
267 \r
268                 Object rconf = null;\r
269                 FileInputStream confFileStream = null;\r
270                 try {\r
271                         RunnerConfigMarshaller<V> rcm = new RunnerConfigMarshaller<V>(\r
272                                         configurationHolder);\r
273                         String path = ph.getProperty(propertyName);\r
274                         if (compbio.util.Util.isEmpty(path)) {\r
275                                 log.debug("Configuration " + path + " is not provided");\r
276                                 return null;\r
277                         }\r
278                         log.debug("Loading Configuration from " + path + " Config type:"\r
279                                         + configurationHolder);\r
280                         File confFile = new File(PropertyHelperManager.getLocalPath()\r
281                                         + path);\r
282                         confFileStream = new FileInputStream(confFile);\r
283                         rconf = rcm.read(confFileStream, configurationHolder);\r
284                         confFileStream.close();\r
285                 } catch (JAXBException e) {\r
286                         log.error(e.getLocalizedMessage(), e.getCause());\r
287                 } finally {\r
288                         FileUtil.closeSilently(log, confFileStream);\r
289                 }\r
290                 return rconf;\r
291         }\r
292 \r
293         @Override\r
294         public Map<String, String> getEnvironment() {\r
295                 String envProperty = ph.getProperty(exec.getClass().getSimpleName()\r
296                                 .toLowerCase()\r
297                                 + ".bin.env");\r
298                 if (envProperty == null) {\r
299                         return Collections.emptyMap();\r
300                 }\r
301 \r
302                 return EnvVariableProcessor.getEnvVariables(envProperty,\r
303                                 this.getClass());\r
304         }\r
305 \r
306         @Override\r
307         public ConfiguredExecutable<?> loadRunConfiguration(RunConfiguration rconf) {\r
308                 if (rconf == null) {\r
309                         throw new NullPointerException("RunConfiguration is expected!");\r
310                 }\r
311                 return new ConfExecutable(rconf);\r
312         }\r
313 \r
314         public static ConfiguredExecutable<?> newConfExecutable(\r
315                         RunConfiguration rconf) {\r
316                 if (rconf == null) {\r
317                         throw new NullPointerException("RunConfiguration is expected!");\r
318                 }\r
319                 return new ConfExecutable(rconf);\r
320         }\r
321 \r
322         @Override\r
323         public boolean saveRunConfiguration() throws IOException {\r
324                 RunConfiguration rconf = getRunConfiguration();\r
325                 return RunConfiguration.write(rconf);\r
326         }\r
327 \r
328         public RunConfiguration getRunConfiguration() {\r
329                 /*\r
330                  * Distinguish between dynamic settings and static settings (set in conf\r
331                  * or class) The latter does not need saving (as if they change there\r
332                  * were a good reason for this and it make it impossible/dangerous to\r
333                  * rerun the task with old settings)\r
334                  */\r
335                 // Set within Executable\r
336                 // String taskId = executable.getTaskId();\r
337 \r
338                 /*\r
339                  * All things below are handled by Executable\r
340                  * \r
341                  * getInput() && getOutput()\r
342                  * \r
343                  * // Handle PipedExecutables String error = executable.getError(); if\r
344                  * (error != null) {\r
345                  * \r
346                  * } String output = executable.getOutput(); if (output != null) {\r
347                  * \r
348                  * } List<String> outputs = executable.getCreatedFiles(); List<String>\r
349                  * inputs = executable.getInputFiles();\r
350                  * \r
351                  * /* Environment is defined only declaratively. Map<String,String> env\r
352                  * = executable.getEnvironment();\r
353                  * \r
354                  * List<String> params = executable.getParameters();\r
355                  */\r
356                 RunConfiguration rconf = new RunConfiguration(this);\r
357                 return rconf;\r
358         }\r
359 \r
360         @Override\r
361         public ConfiguredExecutable<?> loadRunConfiguration(InputStream input)\r
362                         throws IOException {\r
363                 RunConfiguration rconf = RunConfiguration.load(input);\r
364                 log.info("Loaded saved RunConfiguration " + rconf);\r
365                 return new ConfExecutable(rconf);\r
366         }\r
367 \r
368         @Override\r
369         public String toString() {\r
370                 String value = "Work dir: " + this.workDirectory + "\n";\r
371                 value += "TaskId: " + this.taskDirectory + "\n";\r
372                 value += "Params: " + this.getParameters() + "\n";\r
373                 value += exec.toString();\r
374                 return value;\r
375         }\r
376 \r
377         @Override\r
378         public String getClusterJobSettings() {\r
379                 return exec.getClusterJobSettings();\r
380         }\r
381 }\r