Next version of JABA
[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, exec\r
101                                 .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 ? "Windows "\r
108                                                                         : "Linux/Unix/Mac"));\r
109                 }\r
110                 return command;\r
111         }\r
112 \r
113         @Override\r
114         public ExecProvider getSupportedRuntimes() {\r
115                 return compbio.engine.client.Util.getSupportedRuntimes(exec.getClass());\r
116         }\r
117 \r
118         @Override\r
119         public Limit<T> getLimit(String presetName) {\r
120                 return exec.getLimit(presetName);\r
121         }\r
122 \r
123         @Override\r
124         public LimitsManager<T> getLimits() {\r
125                 return exec.getLimits();\r
126         }\r
127 \r
128         @Override\r
129         public String getTaskId() {\r
130                 return taskDirectory;\r
131         }\r
132 \r
133         @Override\r
134         public void setWorkDirectory(String workDirectory) {\r
135                 assert !compbio.util.Util.isEmpty(workDirectory);\r
136                 this.workDirectory = workDirectory;\r
137         }\r
138 \r
139         @Override\r
140         public String getWorkDirectory() {\r
141                 return this.workDirectory;\r
142         }\r
143 \r
144         @Override\r
145         public Executable<T> addParameters(List<String> parameters) {\r
146                 exec.addParameters(parameters);\r
147                 return exec;\r
148         }\r
149 \r
150         @Override\r
151         public String getOutput() {\r
152                 return exec.getOutput();\r
153         }\r
154 \r
155         @Override\r
156         public String getError() {\r
157                 return exec.getError();\r
158         }\r
159 \r
160         @Override\r
161         public List<String> getCreatedFiles() {\r
162                 return getFullPath(exec.getCreatedFiles());\r
163         }\r
164 \r
165         List<String> getFullPath(List<String> fileNames) {\r
166                 List<String> files = new ArrayList<String>();\r
167                 for (String fileName : fileNames) {\r
168                         files.add(compbio.engine.client.Util.getFullPath(workDirectory,\r
169                                         fileName));\r
170                 }\r
171                 return files;\r
172         }\r
173 \r
174         /**\r
175          * Not all input paths are relative! Input path could be absolute!\r
176          * \r
177          * @see compbio.engine.client.Executable#getInputFiles()\r
178          */\r
179         @Override\r
180         public String getInput() {\r
181                 String path = exec.getInput();\r
182                 if (PathValidator.isAbsolutePath(path)) {\r
183                         return path;\r
184                 }\r
185                 return compbio.engine.client.Util.getFullPath(workDirectory, path);\r
186         }\r
187 \r
188         @Override\r
189         public CommandBuilder<T> getParameters() {\r
190                 return exec.getParameters(provider);\r
191         }\r
192 \r
193         @Override\r
194         public CommandBuilder<T> getParameters(\r
195                         compbio.engine.client.Executable.ExecProvider provider) {\r
196                 return getParameters();\r
197         }\r
198 \r
199         @Override\r
200         public Executable<T> getExecutable() {\r
201                 return exec;\r
202         }\r
203 \r
204         @Override\r
205         public <V> V getResults() throws ResultNotAvailableException {\r
206                 return (V) exec.getResults(workDirectory);\r
207         }\r
208 \r
209         /*\r
210          * This is just a pass through method (non-Javadoc)\r
211          * \r
212          * @see compbio.runner.Executable#getResults(java.lang.String)\r
213          */\r
214         @Override\r
215         public <V> V getResults(String directory)\r
216                         throws ResultNotAvailableException {\r
217                 return (V) exec.getResults(directory);\r
218         }\r
219 \r
220         /*\r
221          * This method should be executed once and result of its execution reused.\r
222          * If not used carefully it could slow down the system!\r
223          */\r
224         public static <V> RunnerConfig<V> getRunnerOptions(\r
225                         Class<? extends Executable<V>> clazz) throws IOException {\r
226                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
227                                 + ".parameters.file";\r
228                 return (RunnerConfig<V>) getRunnerConfiguration(clazz,\r
229                                 RunnerConfig.class, parametersFile);\r
230         }\r
231 \r
232         /*\r
233          * This method should be executed once and result of its execution reused.\r
234          * If not used carefully it could slow down the system!\r
235          */\r
236         public static <V> PresetManager<V> getRunnerPresets(\r
237                         Class<? extends Executable<V>> clazz) throws IOException {\r
238                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
239                                 + ".presets.file";\r
240                 PresetManager<V> presets = (PresetManager<V>) getRunnerConfiguration(\r
241                                 clazz, PresetManager.class, parametersFile);\r
242                 return presets;\r
243         }\r
244 \r
245         /**\r
246          * This method should be executed once and result of its execution reused.\r
247          * If not used carefully it could slow down the system!\r
248          * \r
249          * @param <V>\r
250          * @param clazz\r
251          * @return\r
252          * @throws IOException\r
253          */\r
254         public static <V> LimitsManager<V> getRunnerLimits(\r
255                         Class<? extends Executable<V>> clazz) throws IOException {\r
256                 String parametersFile = clazz.getSimpleName().toLowerCase()\r
257                                 + ".limits.file";\r
258                 LimitsManager<V> limits = (LimitsManager<V>) getRunnerConfiguration(\r
259                                 clazz, LimitsManager.class, parametersFile);\r
260                 return limits;\r
261         }\r
262 \r
263         static <V> Object getRunnerConfiguration(\r
264                         Class<? extends Executable<V>> clazz, Class<?> configurationHolder,\r
265                         String propertyName) throws IOException {\r
266 \r
267                 Object rconf = null;\r
268                 FileInputStream confFileStream = null;\r
269                 try {\r
270                         RunnerConfigMarshaller<V> rcm = new RunnerConfigMarshaller<V>(\r
271                                         configurationHolder);\r
272                         String path = ph.getProperty(propertyName);\r
273                         if (compbio.util.Util.isEmpty(path)) {\r
274                                 log.debug("Configuration " + path + " is not provided");\r
275                                 return null;\r
276                         }\r
277                         log.debug("Loading Configuration from " + path + " Config type:"\r
278                                         + configurationHolder);\r
279                         File confFile = new File(PropertyHelperManager.getLocalPath()\r
280                                         + path);\r
281                         confFileStream = new FileInputStream(confFile);\r
282                         rconf = rcm.read(confFileStream, configurationHolder);\r
283                         confFileStream.close();\r
284                 } catch (JAXBException e) {\r
285                         log.error(e.getLocalizedMessage(), e.getCause());\r
286                 } finally {\r
287                         FileUtil.closeSilently(log, confFileStream);\r
288                 }\r
289                 return rconf;\r
290         }\r
291 \r
292         @Override\r
293         public Map<String, String> getEnvironment() {\r
294                 String envProperty = ph.getProperty(exec.getClass().getSimpleName()\r
295                                 .toLowerCase()\r
296                                 + ".bin.env");\r
297                 if (envProperty == null) {\r
298                         return Collections.emptyMap();\r
299                 }\r
300 \r
301                 return EnvVariableProcessor.getEnvVariables(envProperty, this\r
302                                 .getClass());\r
303         }\r
304 \r
305         @Override\r
306         public ConfiguredExecutable<?> loadRunConfiguration(RunConfiguration rconf) {\r
307                 if (rconf == null) {\r
308                         throw new NullPointerException("RunConfiguration is expected!");\r
309                 }\r
310                 return new ConfExecutable(rconf);\r
311         }\r
312 \r
313         public static ConfiguredExecutable<?> newConfExecutable(\r
314                         RunConfiguration rconf) {\r
315                 if (rconf == null) {\r
316                         throw new NullPointerException("RunConfiguration is expected!");\r
317                 }\r
318                 return new ConfExecutable(rconf);\r
319         }\r
320 \r
321         @Override\r
322         public boolean saveRunConfiguration() throws IOException {\r
323                 RunConfiguration rconf = getRunConfiguration();\r
324                 return RunConfiguration.write(rconf);\r
325         }\r
326 \r
327         public RunConfiguration getRunConfiguration() {\r
328                 /*\r
329                  * Distinguish between dynamic settings and static settings (set in conf\r
330                  * or class) The latter does not need saving (as if they change there\r
331                  * were a good reason for this and it make it impossible/dangerous to\r
332                  * rerun the task with old settings)\r
333                  */\r
334                 // Set within Executable\r
335                 // String taskId = executable.getTaskId();\r
336 \r
337                 /*\r
338                  * All things below are handled by Executable\r
339                  * \r
340                  * getInput() && getOutput()\r
341                  * \r
342                  * // Handle PipedExecutables String error = executable.getError(); if\r
343                  * (error != null) {\r
344                  * \r
345                  * } String output = executable.getOutput(); if (output != null) {\r
346                  * \r
347                  * } List<String> outputs = executable.getCreatedFiles(); List<String>\r
348                  * inputs = executable.getInputFiles();\r
349                  * \r
350                  * /* Environment is defined only declaratively. Map<String,String> env\r
351                  * = executable.getEnvironment();\r
352                  * \r
353                  * List<String> params = executable.getParameters();\r
354                  */\r
355                 RunConfiguration rconf = new RunConfiguration(this);\r
356                 return rconf;\r
357         }\r
358 \r
359         @Override\r
360         public ConfiguredExecutable<?> loadRunConfiguration(InputStream input)\r
361                         throws IOException {\r
362                 RunConfiguration rconf = RunConfiguration.load(input);\r
363                 log.info("Loaded saved RunConfiguration " + rconf);\r
364                 return new ConfExecutable(rconf);\r
365         }\r
366 \r
367         @Override\r
368         public String toString() {\r
369                 String value = "Work dir: " + this.workDirectory + "\n";\r
370                 value += "TaskId: " + this.taskDirectory + "\n";\r
371                 value += "Params: " + this.getParameters() + "\n";\r
372                 value += exec.toString();\r
373                 return value;\r
374         }\r
375 }\r