1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.r2.common.datadictionary.util;
17
18 import org.kuali.rice.core.api.data.DataType;
19 import org.kuali.student.r2.common.datadictionary.infc.AttributeDefinitionInfc;
20 import org.kuali.student.r2.common.datadictionary.infc.DictionaryEntry;
21 import org.kuali.student.r2.common.exceptions.InvalidParameterException;
22 import org.kuali.student.r2.common.exceptions.OperationFailedException;
23 import org.kuali.student.r2.common.infc.Comparison;
24 import org.kuali.student.r2.common.infc.Criteria;
25 import org.kuali.student.r2.common.util.date.DateFormatters;
26
27 import java.sql.Timestamp;
28 import java.util.ArrayList;
29 import java.util.Date;
30 import java.util.List;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class CriteriaValidatorParser {
49
50 public enum Operator {
51
52 EQ, IN, GT, LT, NEQ, GTE, LTE, LIKE, BETWEEN;
53 }
54 private Criteria criteria;
55 private DictionaryEntry dictionaryEntry;
56 private transient List<Object> parsedValues;
57 private transient List<Operator> parsedOperators;
58
59 public CriteriaValidatorParser() {
60 }
61
62 public Criteria getCriteria() {
63 return criteria;
64 }
65
66 public void setCriteria(Criteria criteria) {
67 this.criteria = criteria;
68 }
69
70 public DictionaryEntry getDictionaryEntry() {
71 return dictionaryEntry;
72 }
73
74 public void setDictionaryEntry(DictionaryEntry dictionaryEntry) {
75 this.dictionaryEntry = dictionaryEntry;
76 }
77
78
79
80
81
82 public List<Operator> getParsedOperators() {
83 return parsedOperators;
84 }
85
86
87
88
89
90
91
92
93
94
95 public List<Object> getParsedValues() {
96 return parsedValues;
97 }
98
99
100
101
102
103
104
105
106
107
108
109 public void validate()
110 throws InvalidParameterException,
111 OperationFailedException {
112 parsedValues = new ArrayList<Object>();
113 parsedOperators = new ArrayList <Operator> ();
114 if (this.criteria.getComparisons() == null) {
115 throw new InvalidParameterException ("Comparisons list is null -- to select all specify an empty list");
116 }
117 int i = 0;
118 for (Comparison comparison : this.criteria.getComparisons()) {
119 this.validate(i, comparison);
120 i++;
121 }
122 }
123
124 private void validate(int i, Comparison comparison)
125 throws InvalidParameterException,
126 OperationFailedException {
127 String fieldKey = comparison.getFieldKey();
128 String operator = comparison.getOperator();
129 List<String> values = comparison.getValues();
130 AttributeDefinitionInfc ad = this.getAttributeDefinition(fieldKey);
131 if (ad == null) {
132 throw new InvalidParameterException("The " + i + "th comparison's field key " + fieldKey + " is not defined in the dictionary");
133 }
134 if (operator == null) {
135 throw new InvalidParameterException("The " + i + "th comparison's operator is null");
136 }
137 if (operator.equals("=")) {
138 this.parsedOperators.add(Operator.EQ);
139 } else if (operator.equals("<")) {
140 this.parsedOperators.add(Operator.LT);
141 } else if (operator.equals(">")) {
142 this.parsedOperators.add(Operator.GT);
143 } else if (operator.equals("!=")) {
144 this.parsedOperators.add(Operator.NEQ);
145 } else if (operator.equals("<=")) {
146 this.parsedOperators.add(Operator.LTE);
147 } else if (operator.equals(">=")) {
148 this.parsedOperators.add(Operator.GTE);
149 } else if (operator.equals("in")) {
150 this.parsedOperators.add(Operator.IN);
151 } else if (operator.equals("between")) {
152 this.parsedOperators.add(Operator.BETWEEN);
153 } else if (operator.equals("like")) {
154 this.parsedOperators.add(Operator.LIKE);
155 if (ad.getDataType().equals (DataType.STRING)) {
156 throw new InvalidParameterException("The " + i + "th comparison's operator is LIKE which can only be applied to strings, " + ad.getDataType() + " is invalid.");
157 }
158 } else {
159 throw new InvalidParameterException("The " + i + "th comparison's operator, " + operator + ", is invalid.");
160 }
161 if (values == null) {
162 throw new InvalidParameterException("The " + i + "th comparison's values list is required and cannot be null");
163 }
164 if (values.isEmpty()) {
165 throw new InvalidParameterException("The " + i + "th comparison's values list is required and cannot be an empty list");
166 }
167 if (values.get(0) == null) {
168 if (!operator.equals("=") && !operator.equals("!=")) {
169 throw new InvalidParameterException("The " + i + "th comparison's value is null but the operator " + operator + " is a comparison operator that does not apply");
170 }
171 return;
172 }
173 if (operator.equals("between")) {
174 if (values.size() != 2) {
175 throw new InvalidParameterException("The " + i + "th comparison is a between operator which requires two values, found " + values.size());
176 }
177 if (values.get(0) == null) {
178 throw new InvalidParameterException("The " + i + "th comparison is a between operator but the first value is null");
179 }
180 if (values.get(1) == null) {
181 throw new InvalidParameterException("The " + i + "th comparison is a between operator but the second value is null");
182 }
183 } else if (values.size() > 1) {
184 if (!operator.equals("in")) {
185 throw new InvalidParameterException("The " + i + "th comparison's value is a list but the operator " + operator + " is a comparison operator that does not apply");
186 }
187 }
188 switch (ad.getDataType()) {
189 case STRING:
190 break;
191 case DATE:
192 case TRUNCATED_DATE:
193 break;
194 case BOOLEAN:
195 if (! operator.equals("=") && !operator.equals("!=")) {
196 throw new InvalidParameterException("The " + i + "th comparison's operator " + operator + " is a comparison operator that does not apply to the field's boolean data type");
197 }
198 case INTEGER:
199 case FLOAT:
200 case DOUBLE:
201 case LONG:
202 break;
203
204
205
206
207
208
209
210 }
211 parsedValues.add(parseValues(i, ad.getDataType(), comparison.getValues(), comparison.getIsIgnoreCase()));
212 }
213
214 private Object parseValues(int i, DataType dataType, List<String> values, boolean ignoreCase)
215 throws InvalidParameterException {
216 if (values.size() == 1) {
217 return parseValue(i, dataType, values.get(0), ignoreCase);
218 }
219 List<Object> list = new ArrayList<Object>();
220 for (String value : values) {
221 list.add(parseValue(i, dataType, value, ignoreCase));
222 }
223 return list;
224 }
225
226 private Object parseValue(int i, DataType dataType, String value, boolean ignoreCase)
227 throws InvalidParameterException {
228 if (value == null) {
229 return null;
230 }
231 switch (dataType) {
232 case STRING:
233 return parseString(i, value, ignoreCase);
234 case DATE:
235 return parseDateTime(i, value);
236 case TRUNCATED_DATE:
237 return parseDate(i, value);
238 case BOOLEAN:
239 return parseBoolean(i, value);
240 case INTEGER:
241 return parseInteger(i, value);
242 case FLOAT:
243 return parseFloat(i, value);
244 case DOUBLE:
245 return parseDouble(i, value);
246 case LONG:
247 return parseLong(i, value);
248
249
250 default:
251 throw new IllegalArgumentException("Unknown/unhandled datatype " + dataType);
252 }
253 }
254
255 private String parseString(int i, String cv, boolean ignoreCase) throws InvalidParameterException {
256 if (cv == null) {
257 return null;
258 }
259 if (ignoreCase) {
260 return cv.toLowerCase();
261 }
262 return cv;
263 }
264
265 private Timestamp parseDateTime(int i, String cv) throws InvalidParameterException {
266 try {
267 return new Timestamp(DateFormatters.DEFAULT_TIMESTAMP_FORMATTER.parse(cv).getTime());
268 } catch (IllegalArgumentException ex) {
269 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as a dateTime");
270 }
271 }
272
273 private Date parseDate(int i, String cv) throws InvalidParameterException {
274 try {
275 return DateFormatters.DEFAULT_DATE_FORMATTER.parse(cv);
276 } catch (IllegalArgumentException ex) {
277 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as a date");
278 }
279 }
280
281 private Integer parseInteger(int i, String cv) throws InvalidParameterException {
282 try {
283 return Integer.parseInt(cv);
284 } catch (NumberFormatException ex) {
285 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as an integer");
286 }
287 }
288
289 private Long parseLong(int i, String cv) throws InvalidParameterException {
290 try {
291 return Long.parseLong(cv);
292 } catch (NumberFormatException ex) {
293 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as a Long");
294 }
295 }
296
297 private Boolean parseBoolean(int i, String cv) throws InvalidParameterException {
298 if (cv.equalsIgnoreCase("true")) {
299 return Boolean.TRUE;
300 }
301 if (cv.equalsIgnoreCase("false")) {
302 return Boolean.FALSE;
303 }
304 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as a Boolean");
305
306 }
307
308 private Float parseFloat(int i, String cv) throws InvalidParameterException {
309 try {
310 return Float.parseFloat(cv);
311 } catch (NumberFormatException ex) {
312 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as an float");
313 }
314 }
315
316 private Double parseDouble(int i, String cv) throws InvalidParameterException {
317 try {
318 return Double.parseDouble(cv);
319 } catch (NumberFormatException ex) {
320 throw new InvalidParameterException("The " + i + "th comparison's value " + cv + " cannot be parsed as an double");
321 }
322 }
323
324 private String initLower(String str) {
325 if (str == null) {
326 return null;
327 }
328 if (str.length() == 0) {
329 return str;
330 }
331 if (str.length() == 1) {
332 return str.toLowerCase();
333 }
334 return str.substring(0, 1).toLowerCase() + str.substring(1);
335 }
336
337 private boolean calcIsList(AttributeDefinitionInfc ad) {
338 if (ad.getMaxOccurs() == null) {
339 return false;
340 }
341 if (ad.getMaxOccurs() <= 1) {
342 return false;
343 }
344 return true;
345
346 }
347
348 private AttributeDefinitionInfc getAttributeDefinition(String fk)
349 throws InvalidParameterException,
350 OperationFailedException {
351 for (AttributeDefinitionInfc ad : this.dictionaryEntry.getAttributes()) {
352 if (ad.getName().equals(fk)) {
353 return ad;
354 }
355 }
356 return null;
357 }
358
359 }
360