fix jabaws download link
[jabaws.git] / datamodel / compbio / metadata / RunnerConfig.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.metadata;\r
20 \r
21 import java.security.InvalidParameterException;\r
22 import java.util.ArrayList;\r
23 import java.util.List;\r
24 \r
25 import javax.xml.bind.ValidationException;\r
26 import javax.xml.bind.annotation.XmlElement;\r
27 import javax.xml.bind.annotation.XmlRootElement;\r
28 import javax.xml.bind.annotation.XmlTransient;\r
29 \r
30 import compbio.util.SysPrefs;\r
31 import compbio.util.annotation.NotThreadSafe;\r
32 \r
33 /**\r
34  * The list of {@link Parameter}s and {@link Option}s supported by executable.\r
35  * The lists is defined in and loaded from <ExecutableName>Parameters.xml file.\r
36  * \r
37  * @author pvtroshin\r
38  * \r
39  * @version 1.0 October 2009\r
40  * @param <T>\r
41  *            type of an Executable\r
42  */\r
43 @XmlRootElement\r
44 @NotThreadSafe\r
45 public class RunnerConfig<T> {\r
46 \r
47         /*\r
48          * Please note that the order of the fields in this class is important to\r
49          * generate xml compliant to the hand written schema!!!\r
50          */\r
51 \r
52         /**\r
53          * The class name of a runnable e.g. T\r
54          */\r
55         private String runnerClassName;\r
56         List<Option<T>> options = new ArrayList<Option<T>>();\r
57         String prmSeparator;\r
58         List<Parameter<T>> parameters = new ArrayList<Parameter<T>>();\r
59 \r
60         @XmlTransient\r
61         List<Option<T>> arguments;\r
62 \r
63         public RunnerConfig() {\r
64                 // JAXB default constructor\r
65         }\r
66 \r
67         public RunnerConfig<T> copyAndValidateRConfig(RunnerConfig<?> runnerConf) {\r
68                 if (this.runnerClassName != runnerConf.runnerClassName) {\r
69                         throw new InvalidParameterException("Wrong runner configuration! ");\r
70                 }\r
71                 RunnerConfig<T> newrconfig = new RunnerConfig<T>();\r
72                 newrconfig.runnerClassName = runnerConf.runnerClassName;\r
73                 newrconfig.options = new ArrayList<Option<T>>(options);\r
74                 return newrconfig;\r
75         }\r
76 \r
77         /**\r
78          * Returns the list of the Options supported by the executable of type T\r
79          * \r
80          * @return list of {@link Option} supported by type T\r
81          * @see Option\r
82          */\r
83         public List<Option<T>> getOptions() {\r
84                 return options;\r
85         }\r
86 \r
87         /**\r
88          * Adds parameter to the internal parameter list\r
89          * \r
90          * @param param\r
91          *            the {@link Parameter} to add\r
92          * @see Parameter\r
93          */\r
94         public void addParameter(Parameter<T> param) {\r
95                 assert param != null;\r
96                 parameters.add(param);\r
97         }\r
98 \r
99         /**\r
100          * Adds Option to the internal list of options\r
101          * \r
102          * @param option\r
103          *            the {@link Option} to add\r
104          */\r
105         public void addOption(Option<T> option) {\r
106                 assert option != null;\r
107                 options.add(option);\r
108         }\r
109 \r
110         /**\r
111          * Returns list of {@link Parameter} and {@link Option} supported by current\r
112          * runner\r
113          * \r
114          * @return list of {@link Option} and {@link Parameter} supported by type T\r
115          */\r
116         @XmlTransient\r
117         public List<Option<T>> getArguments() {\r
118                 arguments = new ArrayList<Option<T>>(options);\r
119                 arguments.addAll(parameters);\r
120                 return arguments;\r
121         }\r
122 \r
123         /**\r
124          * \r
125          * @return name value separator character\r
126          */\r
127         public String getPrmSeparator() {\r
128                 return prmSeparator;\r
129         }\r
130 \r
131         /**\r
132          * Sets name value separator character\r
133          * \r
134          * @param prmSeparator\r
135          *            the separator char\r
136          */\r
137         public void setPrmSeparator(String prmSeparator) {\r
138                 this.prmSeparator = prmSeparator;\r
139         }\r
140 \r
141         /**\r
142          * Adds the list of options or parameters to the internal list of options\r
143          * \r
144          * @param parameters\r
145          *            the list of parameters to add\r
146          * \r
147          */\r
148         public void setOptions(List<Option<T>> parameters) {\r
149                 this.options = parameters;\r
150         }\r
151 \r
152         /**\r
153          * \r
154          * @return fully qualified class name for type T\r
155          */\r
156         @XmlElement(required = true)\r
157         public String getRunnerClassName() {\r
158                 return runnerClassName;\r
159         }\r
160 \r
161         /**\r
162          * Set the name of a runner class\r
163          * \r
164          * @param runnerClassName\r
165          *            the name of the executable wrapping class\r
166          */\r
167         public void setRunnerClassName(String runnerClassName) {\r
168                 this.runnerClassName = runnerClassName;\r
169         }\r
170 \r
171         /**\r
172          * Sets the list of parameters as internal list\r
173          * \r
174          * @param parameters\r
175          *            the list of parameters\r
176          */\r
177         public void setParameters(List<Parameter<T>> parameters) {\r
178                 this.parameters = parameters;\r
179         }\r
180 \r
181         /**\r
182          * Returns the list of parameters supported executable of type T. Where\r
183          * {@link Parameter} is an {@link Option} with value.\r
184          * \r
185          * @return List of {@link Parameter} supported by type T.\r
186          */\r
187         public List<Parameter<T>> getParameters() {\r
188                 return parameters;\r
189         }\r
190 \r
191         @Override\r
192         public String toString() {\r
193                 String value = "Runner: " + this.runnerClassName + SysPrefs.newlinechar;\r
194                 for (Option<T> par : this.getArguments()) {\r
195                         value += par;\r
196                 }\r
197                 return value;\r
198         }\r
199 \r
200         /*\r
201          * Cast is safe as runnerClassNames equality checked (non-Javadoc)\r
202          * @see java.lang.Object#equals(java.lang.Object)\r
203          */\r
204         @SuppressWarnings("unchecked")\r
205         @Override\r
206         public boolean equals(Object obj) {\r
207                 if (obj == null) {\r
208                         return false;\r
209                 }\r
210                 RunnerConfig<?> rconf = null;\r
211                 if (obj instanceof RunnerConfig) {\r
212                         rconf = (RunnerConfig) obj;\r
213                 }\r
214                 if (!rconf.runnerClassName.equals(this.runnerClassName)) {\r
215                         return false;\r
216                 }\r
217                 if (this.options.size() != rconf.options.size()) {\r
218                         return false;\r
219                 }\r
220                 if (this.parameters.size() != rconf.parameters.size()) {\r
221                         return false;\r
222                 }\r
223                 if (!this.prmSeparator.equals(rconf.prmSeparator)) {\r
224                         return false;\r
225                 }\r
226                 // Size of option list is the same at that point\r
227                 for (Option<T> op : options) {\r
228                         Option<T> roption = (Option<T>) rconf.getArgument(op.getName());\r
229                         if (roption == null) {\r
230                                 return false;\r
231                         }\r
232                         if (!op.equals(roption)) {\r
233                                 return false;\r
234                         }\r
235                 }\r
236                 // Size of parameters list is the same at that point\r
237                 for (Parameter<T> par : parameters) {\r
238                         Parameter<T> rpar = (Parameter<T>) rconf.getArgument(par.getName());\r
239                         if (rpar == null) {\r
240                                 return false;\r
241                         }\r
242                         if (!par.equals(rpar)) {\r
243                                 return false;\r
244                         }\r
245                 }\r
246                 return true;\r
247         }\r
248 \r
249         /**\r
250          * Returns the argument by its name if found, NULL otherwise. Where the\r
251          * Argument is a common interface for {@link Option} and {@link Parameter}\r
252          * therefore this method can return either. If you need to retrieve the\r
253          * Option by its optionNames use @link\r
254          * {@link RunnerConfig#getArgumentByOptionName(String)} method. The\r
255          * difference between option name and optionName is explained by the\r
256          * following example:\r
257          * \r
258          * <pre>\r
259          * <name>Sequence type</name>\r
260          *         <description>\r
261          *         --nuc - Assume the sequences are nucleotide.\r
262          *         --amino - Assume the sequences are amino acid. </description>\r
263          *         <optionNames>--amino</optionNames>\r
264          *         <optionNames>--nuc</optionNames>\r
265          *         <optionNames>--auto</optionNames>\r
266          * </pre>\r
267          * \r
268          * In the example, the "Sequence type" is a name whereas --amino, --nuc and\r
269          * --auto are all optionNames. This dichotomy only manifests in\r
270          * <code>Option</code> never in <code>Parameters</code> as the latter can\r
271          * only have single <optioNames> element\r
272          * \r
273          * @param name\r
274          *            the Parameter of Option name\r
275          * @return {@link Argument}\r
276          */\r
277         public Option<T> getArgument(String name) {\r
278                 for (Option<T> par : getArguments()) {\r
279                         if (par.getName().equalsIgnoreCase(name)) {\r
280                                 return par;\r
281                         }\r
282                 }\r
283                 return null;\r
284         }\r
285 \r
286         /**\r
287          * Removes the argument {@link Argument} if found. Where Argument is either\r
288          * {@link Option} or {@link Parameter}.\r
289          * \r
290          * @param name\r
291          *            of the argument\r
292          * @return true if argument was removed, false otherwise\r
293          */\r
294         @SuppressWarnings("unchecked")\r
295         // Just use raw type in instanceof this is safe\r
296         public boolean removeArgument(String name) {\r
297                 Option<T> par = getArgument(name);\r
298                 if (par != null) {\r
299                         if (par instanceof Parameter) {\r
300                                 parameters.remove(par);\r
301                                 return true;\r
302                         } else {\r
303                                 this.options.remove(par);\r
304                                 return true;\r
305                         }\r
306                 }\r
307                 return false;\r
308         }\r
309 \r
310         /**\r
311          * Returns the argument by option name, NULL if the argument is not found\r
312          * \r
313          * @param optionName\r
314          *            - the optionName. This is not the same as an Option name.\r
315          * \r
316          *            For example:\r
317          * \r
318          *            <pre>\r
319          *            <name>Output sequences order</name>\r
320          *                        <description>--inputorder - Output order: same as input. \r
321          *                         --reorder - Output order: aligned. Default: same as input</description>\r
322          *                        <optionNames>--inputorder</optionNames>\r
323          *                        <optionNames>--reorder</optionNames>\r
324          * </pre>\r
325          * \r
326          *            The name of the option in the example is\r
327          *            "Output sequences order" whereas optionNames are\r
328          *            "--inputorder" and "--reorder". If you need to retrieve the\r
329          *            Option or Parameter by its names use\r
330          *            {@link RunnerConfig#getArgument(String)} method\r
331          * @return Option\r
332          */\r
333         public Option<T> getArgumentByOptionName(String optionName) {\r
334                 for (Option<T> opt : getArguments()) {\r
335                         for (String val : opt.getOptionNames()) {\r
336                                 if (val.equalsIgnoreCase(optionName)) {\r
337                                         return opt;\r
338                                 }\r
339                         }\r
340                 }\r
341 \r
342                 return null;\r
343         }\r
344 \r
345         /**\r
346          * Removes the argument which can be a Parameter or an Option instance by\r
347          * the value in <optionNames> element of the runner configuration\r
348          * descriptor.\r
349          * \r
350          * @param optionName\r
351          *            the optionName of the option, do not confuse with the name!\r
352          * @return true if argument with optionName exists and was removed, false\r
353          *         otherwise\r
354          * @see RunnerConfig#getArgumentByOptionName(String) for destinctions\r
355          *      between optionNames and the name of the Option\r
356          */\r
357         @SuppressWarnings("unchecked")\r
358         // Just use raw type in instanceof this is safe\r
359         public boolean removeArgumentByOptionName(String optionName) {\r
360                 Option<T> par = getArgumentByOptionName(optionName);\r
361                 if (par != null) {\r
362                         if (par instanceof Parameter) {\r
363                                 this.parameters.remove(par);\r
364                                 return true;\r
365                         } else {\r
366                                 this.options.remove(par);\r
367                                 return true;\r
368                         }\r
369                 }\r
370                 return false;\r
371         }\r
372 \r
373         /**\r
374          * Validate the value of the argument. Checks whether the argument value is\r
375          * in the valid values range.\r
376          * \r
377          * @throws ValidationException\r
378          *             if any of the arguments found invalid which is when\r
379          *             <dl>\r
380          *             <li>Parameter value outside {@link ValueConstrain} boundary</li>\r
381          *             <li>Parameter name is not listed in possible values</li>\r
382          *             </dl>\r
383          */\r
384         public void validate() throws ValidationException {\r
385                 for (Option<?> option : getArguments()) {\r
386                         option.validate();\r
387                 }\r
388         }\r
389 }\r