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