Changes from JWS2 branch merged, mostly javadoc
[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 an 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  * @version 1.0 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