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