b89f150d38e67bf066aa3baae520cfd40f6f1463
[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.net.MalformedURLException;\r
22 import java.util.ArrayList;\r
23 import java.util.Collections;\r
24 import java.util.HashSet;\r
25 import java.util.List;\r
26 import java.util.Set;\r
27 import java.util.TreeSet;\r
28 \r
29 import javax.xml.bind.ValidationException;\r
30 import javax.xml.bind.annotation.XmlAccessType;\r
31 import javax.xml.bind.annotation.XmlAccessorType;\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  * A single value containing an option supported by the web service e.g.\r
39  * seqType=protein. Where seqType is a optionName and protein is one of\r
40  * possibleValues\r
41  * \r
42  * @see Option\r
43  * @see Argument\r
44  * \r
45  * @author pvtroshin\r
46  * \r
47  * @version 1.0 November 2009\r
48  */\r
49 @XmlAccessorType(XmlAccessType.FIELD)\r
50 public class Parameter<T> extends Option<T> {\r
51 \r
52         @XmlElement\r
53         Set<String> possibleValues = new HashSet<String>();\r
54 \r
55         ValueConstrain validValue;\r
56 \r
57         private Parameter() {\r
58                 // JAXB noargs const\r
59         }\r
60 \r
61         public Parameter(String name, String description) throws MalformedURLException {\r
62                 super(name, description);\r
63         }\r
64 \r
65         public ValueConstrain getValidValue() {\r
66                 return validValue;\r
67         }\r
68 \r
69         public void setValidValue(ValueConstrain validValue) {\r
70                 if (validValue == null) {\r
71                         throw new NullPointerException("ValueConstrain is expected!");\r
72                 }\r
73                 this.validValue = validValue;\r
74         }\r
75 \r
76         @Override\r
77         public String toString() {\r
78                 String value = super.toString();\r
79                 if (validValue != null) {\r
80                         value += validValue.toString();\r
81                 }\r
82                 if (!this.possibleValues.isEmpty()) {\r
83                         Set<String> sortedPosval = new TreeSet<String>(this.possibleValues);\r
84                         value += "POSSIBLE VALUES:" + SysPrefs.newlinechar;\r
85                         for (String val : sortedPosval) {\r
86                                 value += val + SysPrefs.newlinechar;\r
87                         }\r
88                 }\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