Next version of JABA
[jabaws.git] / datamodel / compbio / metadata / Parameter.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.util.ArrayList;\r
22 import java.util.Collections;\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.XmlElement;\r
32 \r
33 import compbio.util.SysPrefs;\r
34 import compbio.util.Util;\r
35 \r
36 /**\r
37  * A single value containing option supported by the web service e.g.\r
38  * seqType=protein. Where seqType is a optionName and protein is one of\r
39  * possibleValues\r
40  * \r
41  * @see Option\r
42  * @see Argument\r
43  * \r
44  * @author pvtroshin\r
45  * \r
46  *         Date November 2009\r
47  */\r
48 @XmlAccessorType(XmlAccessType.FIELD)\r
49 public class Parameter<T> extends Option<T> {\r
50 \r
51     @XmlElement\r
52     Set<String> possibleValues = new HashSet<String>();\r
53 \r
54     ValueConstrain validValue;\r
55 \r
56     private Parameter() {\r
57         // JAXB noargs const\r
58     }\r
59 \r
60     public Parameter(String name, String description) {\r
61         super(name, description);\r
62     }\r
63 \r
64     public ValueConstrain getValidValue() {\r
65         return validValue;\r
66     }\r
67 \r
68     public void setValidValue(ValueConstrain validValue) {\r
69         if (validValue == null) {\r
70             throw new NullPointerException("ValueConstrain is expected!");\r
71         }\r
72         this.validValue = validValue;\r
73     }\r
74 \r
75     @Override\r
76     public String toString() {\r
77         String value = super.toString();\r
78         if (validValue != null) {\r
79             value += validValue.toString();\r
80         }\r
81         if (!this.possibleValues.isEmpty()) {\r
82             Set<String> sortedPosval = new TreeSet<String>(this.possibleValues);\r
83             value += "POSSIBLE VALUES:" + SysPrefs.newlinechar;\r
84             for (String val : sortedPosval) {\r
85                 value += val + SysPrefs.newlinechar;\r
86             }\r
87         }\r
88         value += SysPrefs.newlinechar;\r
89         return value;\r
90     }\r
91 \r
92     @Override\r
93     public String toCommand(String nameValueSeparator) {\r
94         if (nameValueSeparator == null) {\r
95             throw new NullPointerException("Name value separator is expected!");\r
96         }\r
97         return getOptionName() + nameValueSeparator + getValue();\r
98     }\r
99 \r
100     @Override\r
101     public boolean equals(Object obj) {\r
102         if (!super.equals(obj)) {\r
103             return false;\r
104         }\r
105         Parameter<?> objp = null;\r
106         if (obj instanceof Parameter<?>) {\r
107             objp = (Parameter<?>) obj;\r
108         } else {\r
109             return false;\r
110         }\r
111 \r
112         if (objp.possibleValues.size() != this.possibleValues.size()) {\r
113             return false;\r
114         }\r
115         int matchCount = 0;\r
116         for (String pv : objp.possibleValues) {\r
117             if (Util.isEmpty(pv)) {\r
118                 continue;\r
119             }\r
120             for (String thispv : this.possibleValues) {\r
121                 if (pv.equals(thispv)) {\r
122                     matchCount++;\r
123                     break;\r
124                 }\r
125             }\r
126         }\r
127         if (matchCount != objp.possibleValues.size()) {\r
128             return false;\r
129         }\r
130 \r
131         return true;\r
132     }\r
133 \r
134     /**\r
135      * List is more convenient to work with\r
136      * \r
137      * @return List of String\r
138      */\r
139     @Override\r
140     public List<String> getPossibleValues() {\r
141         return new ArrayList<String>(possibleValues);\r
142     }\r
143 \r
144     public void setPossibleValues(Set<String> possibleValues) {\r
145         this.possibleValues = new HashSet<String>(possibleValues);\r
146     }\r
147 \r
148     public Set<String> addPossibleValues(String... value) {\r
149         for (String v : value) {\r
150             this.possibleValues.add(v);\r
151         }\r
152         return this.possibleValues;\r
153     }\r
154 \r
155     @Override\r
156     public int hashCode() {\r
157         int code = super.hashCode();\r
158         if (possibleValues != null) {\r
159             code += possibleValues.hashCode();\r
160         }\r
161         return code;\r
162     }\r
163 \r
164     @Override\r
165     public void setOptionNames(Set<String> optionName) {\r
166         if (optionName.size() != 1) {\r
167             throw new IllegalArgumentException(\r
168                     "Parameter must have a single option name! But given "\r
169                             + optionName.size() + " names:  " + optionName);\r
170         }\r
171         super.setOptionNames(optionName);\r
172     }\r
173 \r
174     @Override\r
175     public Set<String> addOptionNames(String... value) {\r
176         throw new UnsupportedOperationException(\r
177                 "Parameter must have only one optionName! If you setting the only name that use setOptionName instead");\r
178     }\r
179 \r
180     public String getOptionName() {\r
181         assert optionNames.size() == 1;\r
182         return optionNames.iterator().next();\r
183     }\r
184 \r
185     public void setOptionName(String optionName) {\r
186         assert !Util.isEmpty(optionName);\r
187         setOptionNames(Collections.singleton(optionName));\r
188     }\r
189 \r
190     String getValue() {\r
191         if (this.possibleValues.size() == 1) {\r
192             return this.possibleValues.iterator().next();\r
193         }\r
194         return getDefaultValue();\r
195     }\r
196 \r
197     @Override\r
198     void validate() throws ValidationException {\r
199         super.validate();\r
200         if (validValue == null) {\r
201             if (this.possibleValues.isEmpty()) {\r
202                 throw new ValidationException(\r
203                         "No possible values defined for parameter: " + this);\r
204             }\r
205             if (this.possibleValues.size() > 1\r
206                     && Util.isEmpty(getDefaultValue())) {\r
207                 throw new ValidationException(\r
208                         "Multiple possible values are defined but no default value for parameter: "\r
209                                 + this);\r
210             }\r
211         } else {\r
212             if (Util.isEmpty(getDefaultValue())) {\r
213                 throw new ValidationException(\r
214                         "Default value is not defined for numeric parameter! "\r
215                                 + this);\r
216             }\r
217             validValue.checkValue(getDefaultValue());\r
218         }\r
219     }\r
220 \r
221     boolean isValidValue(String value) {\r
222         assert !Util.isEmpty(value);\r
223         return Option.valueExist(value, getPossibleValues());\r
224     }\r
225 \r
226     @Override\r
227     public void setDefaultValue(String defaultVal)\r
228             throws WrongParameterException {\r
229         // If valid value constrain is not defined, then possible values must\r
230         // be, and they must contain the value which is\r
231         // about to be set!\r
232         if (validValue == null) {\r
233             if (getPossibleValues().isEmpty()) {\r
234                 throw new IllegalStateException(\r
235                         "Attempting to set default value for parameter: "\r
236                                 + this\r
237                                 + " Without possible values! Please define possible value first!");\r
238             }\r
239             if (!isValidValue(defaultVal)) {\r
240                 throw new WrongParameterException(\r
241                         "Attempting to set illegal value '" + defaultVal\r
242                                 + "' for the parameter: " + this);\r
243             }\r
244         } else {\r
245             try {\r
246                 validValue.checkValue(defaultVal);\r
247             } catch (IndexOutOfBoundsException e) {\r
248                 throw new WrongParameterException(\r
249                         "Attempting to set default value outside boundaries defined by the constraint: "\r
250                                 + validValue + "\n For parameter: " + this);\r
251             }\r
252         }\r
253         this.defaultValue = defaultVal;\r
254     }\r
255 }\r