DisEMBL and GlobProt web services further work
[jabaws.git] / datamodel / compbio / metadata / Option.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.net.URL;\r
22 import java.util.ArrayList;\r
23 import java.util.HashSet;\r
24 import java.util.List;\r
25 import java.util.Set;\r
26 import java.util.TreeSet;\r
27 \r
28 import javax.xml.bind.ValidationException;\r
29 import javax.xml.bind.annotation.XmlAccessType;\r
30 import javax.xml.bind.annotation.XmlAccessorType;\r
31 import javax.xml.bind.annotation.XmlAttribute;\r
32 import javax.xml.bind.annotation.XmlElement;\r
33 \r
34 import compbio.util.SysPrefs;\r
35 import compbio.util.Util;\r
36 \r
37 /**\r
38  * Command line option/flag or multiple exclusive options with no value. Example\r
39  * -protein, -dna, -auto\r
40  * \r
41  * @author pvtroshin\r
42  * \r
43  * @version 1.0 October 2009\r
44  * @param <T>\r
45  *            type of executable\r
46  */\r
47 @XmlAccessorType(XmlAccessType.FIELD)\r
48 public class Option<T> implements Argument<T> {\r
49 \r
50         @XmlElement(required = true)\r
51         protected String description;\r
52 \r
53         @XmlElement(required = true)\r
54         Set<String> optionNames = new HashSet<String>();\r
55 \r
56         @XmlElement(required = true)\r
57         protected String name;\r
58 \r
59         @XmlAttribute\r
60         protected boolean isRequired;\r
61         @XmlElement\r
62         protected URL furtherDetails;\r
63         @XmlElement\r
64         protected String defaultValue;\r
65 \r
66         Option() {\r
67                 // Has to have no arg constructor for JAXB\r
68         }\r
69 \r
70         public Option(String name, String description) {\r
71                 this.name = name;\r
72                 this.description = description;\r
73         }\r
74 \r
75         /**\r
76          * Human readable name of the option\r
77          */\r
78         public String getName() {\r
79                 return name;\r
80         }\r
81 \r
82         public void setName(String name) {\r
83                 this.name = name;\r
84         }\r
85 \r
86         /**\r
87          * A long description of the Option\r
88          */\r
89         public String getDescription() {\r
90                 return description;\r
91         }\r
92 \r
93         public void setDescription(String description) {\r
94                 this.description = description;\r
95         }\r
96 \r
97         /**\r
98          * The URL where further details about the option can be found\r
99          */\r
100         public URL getFurtherDetails() {\r
101                 return furtherDetails;\r
102         }\r
103 \r
104         public void setFurtherDetails(URL furtherDetails) {\r
105                 this.furtherDetails = furtherDetails;\r
106         }\r
107 \r
108         /**\r
109          * A default value of the option. Defaults to command line argument name\r
110          * e.g. -auto\r
111          */\r
112         public String getDefaultValue() {\r
113                 return defaultValue;\r
114         }\r
115 \r
116         /**\r
117          * Sets one of the values defined in optionList as default. Attempting set\r
118          * the value not listed there will result in WrongParameter exception\r
119          * \r
120          * @param defaultVal\r
121          * @throws WrongParameterException\r
122          *             is thrown if the defaultValue is not found in optionList\r
123          */\r
124         public void setDefaultValue(String defaultVal)\r
125                         throws WrongParameterException {\r
126                 if (optionNames.isEmpty()) {\r
127                         throw new IllegalStateException("Please define optionNames first!");\r
128                 }\r
129                 if (!valueExist(defaultVal, getOptionNames())) {\r
130                         throw new WrongParameterException(\r
131                                         "Attempting to set illegal defaultValue '" + defaultVal\r
132                                                         + "' which is not defined optionNames for option: "\r
133                                                         + this);\r
134                 }\r
135                 this.defaultValue = defaultVal;\r
136         }\r
137 \r
138         static boolean valueExist(String testValue, List<String> values) {\r
139                 assert !Util.isEmpty(testValue);\r
140                 for (String val : values) {\r
141                         if (testValue.equalsIgnoreCase(val)) {\r
142                                 return true;\r
143                         }\r
144                 }\r
145                 return false;\r
146         }\r
147 \r
148         /**\r
149          * Flag that indicated that this option must be specified in the command\r
150          * line for an executable to run\r
151          * \r
152          * @return true is the option is required, false otherwise\r
153          */\r
154         public boolean isRequired() {\r
155                 return isRequired;\r
156         }\r
157 \r
158         public void setRequired(boolean isRequired) {\r
159                 this.isRequired = isRequired;\r
160         }\r
161 \r
162         /**\r
163          * \r
164          * @return List of option names\r
165          */\r
166         public List<String> getOptionNames() {\r
167                 return new ArrayList<String>(optionNames);\r
168         }\r
169 \r
170         public void setOptionNames(Set<String> optionNames) {\r
171                 this.optionNames = new HashSet<String>(optionNames);\r
172         }\r
173 \r
174         /**\r
175          * Adds an option to the optionName list\r
176          * \r
177          * @param value\r
178          * @return modified optionName list\r
179          */\r
180         public Set<String> addOptionNames(String... value) {\r
181                 for (String v : value) {\r
182                         boolean added = this.optionNames.add(v);\r
183                         assert added : "Duplicated optionName is detected!";\r
184                 }\r
185                 return this.optionNames;\r
186         }\r
187 \r
188         @Override\r
189         public String toString() {\r
190                 String value = "Option name: " + this.name + SysPrefs.newlinechar;\r
191                 value += "Description: " + this.description + SysPrefs.newlinechar;\r
192                 if (!Util.isEmpty(defaultValue)) {\r
193                         value += "Default value: " + this.defaultValue\r
194                                         + SysPrefs.newlinechar;\r
195                 }\r
196                 value += "URL: " + this.furtherDetails + SysPrefs.newlinechar;\r
197                 value += "Is required: " + this.isRequired + SysPrefs.newlinechar;\r
198                 if (!this.optionNames.isEmpty()) {\r
199                         Set<String> sortedPosval = new TreeSet<String>(this.optionNames);\r
200                         value += "Option Names: " + SysPrefs.newlinechar;\r
201                         for (String val : sortedPosval) {\r
202                                 value += val + SysPrefs.newlinechar;\r
203                         }\r
204                 }\r
205                 return value;\r
206         }\r
207 \r
208         /**\r
209          * Convert the option to the command string.\r
210          * \r
211          * @return If only one optionName is defined, than it is returned, if many\r
212          *         option names are defined, then the defaultValue is returned.\r
213          *         Option must have a default value if there are many optionNames to\r
214          *         be valid.\r
215          */\r
216         public String toCommand(String nameValueSeparator) {\r
217                 if (optionNames.size() == 1) {\r
218                         return optionNames.iterator().next();\r
219                 }\r
220                 return getDefaultValue();\r
221         }\r
222 \r
223         @Override\r
224         public boolean equals(Object obj) {\r
225                 if (obj == null) {\r
226                         return false;\r
227                 }\r
228                 Option<?> objArg = null;\r
229                 if (obj instanceof Option<?>) {\r
230                         objArg = (Option<?>) obj;\r
231                 } else {\r
232                         return false;\r
233                 }\r
234                 if (!Util.isEmpty(objArg.name) && !Util.isEmpty(name)) {\r
235                         if (!objArg.name.equals(this.name)) {\r
236                                 return false;\r
237                         }\r
238                 }\r
239                 if (!Util.isEmpty(objArg.description) && !Util.isEmpty(description)) {\r
240                         if (!objArg.description.equals(this.description)) {\r
241                                 return false;\r
242                         }\r
243                 }\r
244                 if (objArg.isRequired != this.isRequired) {\r
245                         return false;\r
246                 }\r
247                 if (!Util.isEmpty(objArg.defaultValue) && !Util.isEmpty(defaultValue)) {\r
248                         if (!objArg.defaultValue.equals(this.defaultValue)) {\r
249                                 return false;\r
250                         }\r
251                 }\r
252                 if (objArg.optionNames.size() != this.optionNames.size()) {\r
253                         return false;\r
254                 }\r
255                 int matchCount = 0;\r
256                 for (String oname : objArg.optionNames) {\r
257                         if (Util.isEmpty(oname)) {\r
258                                 continue;\r
259                         }\r
260                         for (String thisoname : this.optionNames) {\r
261                                 if (oname.equals(thisoname)) {\r
262                                         matchCount++;\r
263                                         break;\r
264                                 }\r
265                         }\r
266                 }\r
267                 if (matchCount != objArg.optionNames.size()) {\r
268                         return false;\r
269                 }\r
270                 return true;\r
271         }\r
272 \r
273         @Override\r
274         public int hashCode() {\r
275                 int code = this.name.hashCode() * this.description.hashCode();\r
276                 if (this.isRequired) {\r
277                         code += this.furtherDetails.hashCode() * 3;\r
278                 } else {\r
279                         if (defaultValue != null) {\r
280                                 code += this.defaultValue.hashCode() * 2;\r
281                         }\r
282                 }\r
283                 if (this.description != null) {\r
284                         code += this.description.hashCode() * 4;\r
285                 }\r
286 \r
287                 return code;\r
288         }\r
289 \r
290         /**\r
291          * List of possible optionNames\r
292          */\r
293         @Override\r
294         public List<String> getPossibleValues() {\r
295                 return new ArrayList<String>(optionNames);\r
296         }\r
297 \r
298         @Override\r
299         public void setValue(String dValue) throws WrongParameterException {\r
300                 this.setDefaultValue(dValue);\r
301         }\r
302 \r
303         /**\r
304          * Validate the option\r
305          * \r
306          * @throws ValidationException\r
307          *             is the option is invalid. This happens if option does not\r
308          *             have a default value but have multiple option names, or no\r
309          *             option names is defined\r
310          */\r
311         void validate() throws ValidationException {\r
312                 if (optionNames == null) {\r
313                         throw new ValidationException(\r
314                                         "Option names are not defined for option: " + this);\r
315                 }\r
316                 if (optionNames.size() > 1 && Util.isEmpty(getDefaultValue())) {\r
317                         throw new ValidationException(\r
318                                         "Default value is required as multiple optionNames are defined for option: "\r
319                                                         + this);\r
320                 }\r
321                 if (Util.isEmpty(name)) {\r
322                         throw new ValidationException("No name is defined for option: "\r
323                                         + this);\r
324                 }\r
325         }\r
326 }