Clover Coverage Report - KS Contract Documentation Generator 0.0.1-SNAPSHOT
Coverage timestamp: Wed Dec 31 1969 19:00:00 EST
../../../../../img/srcFileCovDistChart0.png 0% of files have more coverage
128   334   58   12.8
64   266   0.45   10
10     5.8  
1    
 
  DictionaryValidator       Line # 35 128 0% 58 202 0% 0.0
 
No Tests
 
1    /*
2    * Copyright 2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 1.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16    package org.kuali.student.datadictionary.util;
17   
18    import java.util.ArrayList;
19    import java.util.Date;
20    import java.util.HashSet;
21    import java.util.List;
22    import java.util.Set;
23    import java.util.regex.Pattern;
24    import java.util.regex.PatternSyntaxException;
25    import org.kuali.rice.core.api.datetime.DateTimeService;
26    import org.kuali.rice.core.api.uif.DataType;
27    import org.kuali.rice.krad.datadictionary.AttributeDefinition;
28    import org.kuali.rice.krad.datadictionary.DataObjectEntry;
29    import org.kuali.rice.krad.datadictionary.validation.ValidationUtils;
30    import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
31    import org.kuali.rice.krad.datadictionary.validation.constraint.LookupConstraint;
32    import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
33    import org.kuali.rice.krad.datadictionary.validation.constraint.WhenConstraint;
34   
 
35    public class DictionaryValidator {
36   
37    private DateTimeService dateTimeService;
38    private DataObjectEntry doe;
39    private Set<DataObjectEntry> alreadyValidated;
40   
 
41  0 toggle public DictionaryValidator(DataObjectEntry doe,
42    Set<DataObjectEntry> alreadyValidated) {
43  0 this.doe = doe;
44  0 this.alreadyValidated = alreadyValidated;
45    }
46   
 
47  0 toggle public DateTimeService getDateTimeService() {
48  0 return dateTimeService;
49    }
50   
 
51  0 toggle public void setDateTimeService(DateTimeService dateTimeService) {
52  0 this.dateTimeService = dateTimeService;
53    }
54   
 
55  0 toggle public List<String> validate() {
56  0 List<String> errors = new ArrayList();
57  0 if (doe.getFullClassName() == null) {
58  0 errors.add("The class name cannot be be left null");
59    }
60  0 if (doe.getEntryClass() == null) {
61  0 errors.add("The entry class should not be left null");
62    }
63  0 if (!doe.getEntryClass().getName().equals(doe.getFullClassName())) {
64  0 errors.add("The entry class should match the full class name");
65    }
66   
67    // else if (this.getClass (ode.getName ()) == null)
68    // {
69    // errors.add ("The name does not exist on the class path");
70    // }
71   
72  0 if (doe.getAttributes() == null) {
73  0 errors.add("getAttribues () is null");
74  0 return errors;
75    }
76  0 if (doe.getCollections() == null) {
77  0 errors.add("getCollections () is null");
78  0 return errors;
79    }
80  0 if (doe.getComplexAttributes() == null) {
81  0 errors.add("getComplexAttributes ()");
82  0 return errors;
83    }
84  0 if (doe.getCollections().isEmpty()
85    && doe.getComplexAttributes().isEmpty()
86    && doe.getAttributes().isEmpty()) {
87  0 errors.add("No fields of any kind defined for this complex object structure");
88  0 return errors;
89    }
90   
91  0 Set<String> fieldNames = new HashSet();
92   
93  0 for (AttributeDefinition ad : doe.getAttributes()) {
94  0 if (ad.getName() != null) {
95  0 if (!fieldNames.add(ad.getName())) {
96  0 errors.add(ad.getName() + " is defined more than once");
97    }
98    }
99  0 errors.addAll(validateAttributeDefinition(ad));
100    }
101   
102  0 doe.completeValidation();
103   
104  0 return errors;
105    }
106   
 
107  0 toggle private List<String> validateAttributeDefinition(AttributeDefinition ad) {
108  0 List<String> errors = new ArrayList();
109  0 if (ad.getName() == null) {
110  0 errors.add("name cannot be null");
111  0 } else if (ad.getName().trim().equals("")) {
112  0 errors.add("name cannot be blank");
113  0 } else if (ad.getDataType() == null) {
114  0 errors.add(ad.getName() + " has a null data type");
115    // } else if (ad.getDataType().equals(DataType.COMPLEX)) {
116    // errorIfNotNull(errors, ad, "exclusiveMin", ad.getExclusiveMin());
117    // errorIfNotNull(errors, ad, "inclusiveMax", ad.getInclusiveMax());
118    // errorIfNotNull(errors, ad, "max length", ad.getMaxLength());
119    // errorIfNotNull(errors, ad, "min length", ad.getMinLength());
120    // errorIfNotNull(errors, ad, "valid chars", ad.getValidCharactersConstraint());
121    // errorIfNotNull(errors, ad, "lookup", ad.getLookupDefinition());
122    }
123    // validateConversion(errors, ad.getName(), "defaultValue", ad.getDataType(), ad.getDefaultValue());
124  0 validateConversion(errors, ad.getName(), "exclusiveMin", ad.getDataType(), ad.getExclusiveMin());
125  0 validateConversion(errors, ad.getName(), "inclusiveMax", ad.getDataType(), ad.getInclusiveMax());
126    //TODO: Cross compare to make sure min is not greater than max and that default value is valid itself
127   
128  0 if (ad.getLookupDefinition() != null) {
129  0 errors.addAll(validateLookup(ad, ad.getLookupDefinition()));
130    }
131  0 if (ad.getCaseConstraint() != null) {
132  0 errors.addAll(validateCase(ad, ad.getCaseConstraint()));
133    }
134  0 if (ad.getValidCharactersConstraint() != null) {
135  0 errors.addAll(validateValidChars(ad, ad.getValidCharactersConstraint()));
136    }
137  0 return errors;
138    }
139   
 
140  0 toggle private void errorIfNotNull(List<String> errors, AttributeDefinition fd,
141    String validation,
142    Object value) {
143  0 if (value != null) {
144  0 errors.add("field " + fd.getName() + " has a " + validation
145    + " but it cannot be specified on a complex type");
146    }
147    }
148   
 
149  0 toggle private Object validateConversion(List<String> errors, String fieldName,
150    String propertyName, DataType dataType,
151    Object value) {
152  0 if (value == null) {
153  0 return null;
154    }
155  0 switch (dataType) {
156  0 case STRING:
157  0 return value.toString().trim();
158    // case DATE, TRUNCATED_DATE, BOOLEAN, INTEGER, FLOAT, DOUBLE, LONG, COMPLEX
159  0 case LONG:
160  0 try {
161  0 return ValidationUtils.getLong(value);
162    } catch (NumberFormatException ex) {
163  0 errors.add(
164    "field " + fieldName
165    + " has a " + propertyName
166    + " that cannot be converted into a long integer");
167    }
168  0 return null;
169  0 case INTEGER:
170  0 try {
171  0 return ValidationUtils.getInteger(value);
172    } catch (NumberFormatException ex) {
173  0 errors.add(
174    "field " + fieldName
175    + " has a " + propertyName + " that cannot be converted into an integer");
176    }
177  0 return null;
178  0 case FLOAT:
179  0 try {
180  0 return ValidationUtils.getFloat(value);
181    } catch (NumberFormatException ex) {
182  0 errors.add(
183    "field " + fieldName
184    + " has a " + propertyName
185    + " that cannot be converted into a floating point value");
186    }
187  0 return null;
188  0 case DOUBLE:
189  0 try {
190  0 return ValidationUtils.getFloat(value);
191    } catch (NumberFormatException ex) {
192  0 errors.add(
193    "field " + fieldName
194    + " has a " + propertyName
195    + " that cannot be converted into a double sized floating point value");
196    }
197  0 return null;
198  0 case BOOLEAN:
199  0 if (value instanceof Boolean) {
200  0 return ((Boolean) value).booleanValue();
201    }
202  0 if (value instanceof String) {
203  0 if (((String) value).trim().equalsIgnoreCase("true")) {
204  0 return true;
205    }
206  0 if (((String) value).trim().equalsIgnoreCase("false")) {
207  0 return true;
208    }
209    }
210  0 errors.add(
211    "field " + fieldName
212    + " has a " + propertyName
213    + " that cannot be converted into a boolean true/false");
214  0 return null;
215  0 case DATE:
216  0 case TRUNCATED_DATE:
217  0 if (value instanceof Date) {
218  0 return (Date) value;
219    }
220  0 try {
221    // TODO: make the date parser configurable like the validator is
222  0 return ValidationUtils.getDate(value, dateTimeService);
223    } catch (Exception e) {
224  0 errors.add(
225    "field " + fieldName
226    + " has a " + propertyName
227    + " that cannot be converted into a date");
228    }
229  0 return null;
230  0 default:
231  0 errors.add(
232    "field " + fieldName
233    + " has a " + propertyName
234    + " that cannot be converted into an unknown/unhandled data type");
235  0 return null;
236    }
237    }
238   
 
239  0 toggle private List<String> validateValidChars(AttributeDefinition fd,
240    ValidCharactersConstraint vc) {
241  0 List<String> errors = new ArrayList();
242  0 String validChars = vc.getValue();
243    /*
244    int typIdx = validChars.indexOf(":");
245    String processorType = "regex";
246    if (-1 == typIdx) {
247    validChars = "[" + validChars + "]*";
248    } else {
249    processorType = validChars.substring(0, typIdx);
250    validChars = validChars.substring(typIdx + 1);
251    }
252    if (!processorType.equalsIgnoreCase("regex")) {
253    errors.add(
254    "field " + fd.getName()
255    + " has an invalid valid chars processor type: a simple list of characters or a regex: is supported");
256    return errors;
257    }
258    */
259  0 try {
260  0 Pattern pattern = Pattern.compile(validChars);
261    } catch (PatternSyntaxException ex) {
262  0 errors.add("field " + fd.getName()
263    + " has in invalid character pattern for a regular expression: "
264    + validChars);
265    }
266  0 return errors;
267    }
268   
 
269  0 toggle private List<String> validateLookup(AttributeDefinition fd, LookupConstraint lc) {
270  0 List<String> errors = new ArrayList();
271  0 if (lc.getParams() == null) {
272  0 errors.add("field " + fd.getName() + " has a lookup with null parameters");
273    }
274    //TODO: more validation
275  0 return errors;
276    }
277    public static final String GREATER_THAN_EQUAL = "greater_than_equal";
278    public static final String LESS_THAN_EQUAL = "less_than_equal";
279    public static final String GREATER_THAN = "greater_than";
280    public static final String LESS_THAN = "less_than";
281    public static final String EQUALS = "equals";
282    public static final String NOT_EQUAL = "not_equal";
283    private static final String[] VALID_OPERATORS = {
284    NOT_EQUAL, EQUALS, GREATER_THAN_EQUAL, LESS_THAN_EQUAL, GREATER_THAN, LESS_THAN
285    };
286   
 
287  0 toggle private List<String> validateCase(AttributeDefinition fd, CaseConstraint cc) {
288  0 List<String> errors = new ArrayList();
289  0 if (cc.getOperator() == null) {
290  0 errors.add("field " + fd.getName()
291    + " has a case constraint with no operator");
292    } else {
293  0 boolean found = false;
294  0 for (int i = 0; i < VALID_OPERATORS.length; i++) {
295  0 if (VALID_OPERATORS[i].equalsIgnoreCase(cc.getOperator())) {
296  0 found = true;
297  0 break;
298    }
299    }
300  0 if (!found) {
301  0 errors.add("field " + fd.getName()
302    + " has a case constraint with an unknown operator "
303    + cc.getOperator());
304    }
305    }
306  0 if (cc.getPropertyName() == null) {
307  0 errors.add(
308    "field " + fd.getName()
309    + " has a case constraint with a null for the field to use for the comparison");
310  0 } else if (cc.getPropertyName().trim().equals("")) {
311  0 errors.add(
312    "field " + fd.getName()
313    + " has a case constraint with blanks for the field to use for the comparison");
314    }
315  0 if (cc.getWhenConstraint() == null) {
316  0 errors.add("field " + fd.getName()
317    + " has a case constraint but null when statements");
318  0 return errors;
319    }
320  0 if (cc.getWhenConstraint().size() == 0) {
321  0 errors.add("field " + fd.getName()
322    + " has a case constraint but has no when statements");
323    }
324  0 for (WhenConstraint wc : cc.getWhenConstraint()) {
325  0 if (wc.getConstraint() == null) {
326  0 errors.add(
327    "field " + fd.getName()
328    + " has a as case constraint with a when statement that has no overriding constraints specified");
329    }
330    }
331    //TODO: more validation
332  0 return errors;
333    }
334    }