Clover Coverage Report - Kuali Student 1.2-M5-SNAPSHOT (Aggregated)
Coverage timestamp: Mon Aug 29 2011 05:04:27 EDT
../../../../../img/srcFileCovDistChart7.png 33% of files have more coverage
477   1,075   261   11.93
306   791   0.55   40
40     6.53  
1    
 
  DefaultValidatorImpl       Line # 45 477 0% 261 267 67.6% 0.67557716
 
  (75)
 
1    /**
2    * Copyright 2010 The Kuali Foundation Licensed under the Educational Community License, Version 2.0 (the "License"); you may
3    * not use this file except in compliance with the License. You may obtain a copy of the License at
4    * http://www.osedu.org/licenses/ECL-2.0 Unless required by applicable law or agreed to in writing, software distributed
5    * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
6    * implied. See the License for the specific language governing permissions and limitations under the License.
7    */
8   
9    package org.kuali.student.common.validator;
10   
11    import java.lang.reflect.InvocationTargetException;
12    import java.util.ArrayList;
13    import java.util.Collection;
14    import java.util.Date;
15    import java.util.HashMap;
16    import java.util.Iterator;
17    import java.util.List;
18    import java.util.Map;
19    import java.util.Stack;
20   
21    import org.apache.commons.beanutils.PropertyUtils;
22    import org.apache.log4j.Logger;
23    import org.kuali.student.common.dictionary.dto.CaseConstraint;
24    import org.kuali.student.common.dictionary.dto.CommonLookupParam;
25    import org.kuali.student.common.dictionary.dto.Constraint;
26    import org.kuali.student.common.dictionary.dto.DataType;
27    import org.kuali.student.common.dictionary.dto.FieldDefinition;
28    import org.kuali.student.common.dictionary.dto.LookupConstraint;
29    import org.kuali.student.common.dictionary.dto.MustOccurConstraint;
30    import org.kuali.student.common.dictionary.dto.ObjectStructureDefinition;
31    import org.kuali.student.common.dictionary.dto.RequiredConstraint;
32    import org.kuali.student.common.dictionary.dto.ValidCharsConstraint;
33    import org.kuali.student.common.dictionary.dto.WhenConstraint;
34    import org.kuali.student.common.messages.dto.Message;
35    import org.kuali.student.common.messages.service.MessageService;
36    import org.kuali.student.common.search.dto.SearchParam;
37    import org.kuali.student.common.search.dto.SearchRequest;
38    import org.kuali.student.common.search.dto.SearchResult;
39    import org.kuali.student.common.search.service.SearchDispatcher;
40    import org.kuali.student.common.util.MessageUtils;
41    import org.kuali.student.common.validation.dto.ValidationResultInfo;
42    import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
43    import org.springframework.beans.BeanUtils;
44   
 
45    public class DefaultValidatorImpl extends BaseAbstractValidator {
46    final static Logger LOG = Logger.getLogger(DefaultValidatorImpl.class);
47   
48    private MessageService messageService = null;
49   
50    private SearchDispatcher searchDispatcher;
51   
52    private String messageLocaleKey = "en";
53   
54    private String messageGroupKey = "validation";
55   
56    private DateParser dateParser = new ServerDateParser();
57   
58    private boolean serverSide = true;
59   
 
60  0 toggle public MessageService getMessageService() {
61  0 return messageService;
62    }
63   
 
64  11 toggle public void setMessageService(MessageService messageService) {
65  11 this.messageService = messageService;
66    }
67   
 
68  0 toggle public String getMessageLocaleKey() {
69  0 return messageLocaleKey;
70    }
71   
 
72  0 toggle public void setMessageLocaleKey(String messageLocaleKey) {
73  0 this.messageLocaleKey = messageLocaleKey;
74    }
75   
 
76  0 toggle public String getMessageGroupKey() {
77  0 return messageGroupKey;
78    }
79   
 
80  0 toggle public void setMessageGroupKey(String messageGroupKey) {
81  0 this.messageGroupKey = messageGroupKey;
82    }
83   
 
84  19 toggle public void setDateParser(DateParser dateParser) {
85  19 this.dateParser = dateParser;
86    }
87   
88    /**
89    * @return the serverSide
90    */
 
91  0 toggle public boolean isServerSide() {
92  0 return serverSide;
93    }
94   
95    /**
96    * @param serverSide
97    * the serverSide to set
98    */
 
99  0 toggle public void setServerSide(boolean serverSide) {
100  0 this.serverSide = serverSide;
101    }
102   
103    /**
104    * @return the dateParser
105    */
 
106  0 toggle public DateParser getDateParser() {
107  0 return dateParser;
108    }
109   
110    /**
111    * Validate Object and all its nested child objects for given type and state
112    *
113    * @param data
114    * @param objStructure
115    * @return
116    */
 
117  137 toggle public List<ValidationResultInfo> validateObject(Object data, ObjectStructureDefinition objStructure) {
118   
119  137 List<ValidationResultInfo> results = new ArrayList<ValidationResultInfo>();
120  137 Stack<String> elementStack = new Stack<String>();
121   
122  137 validateObject(results, data, objStructure, elementStack, data, objStructure, true);
123   
124  137 return results;
125    }
126   
 
127  1576 toggle private void validateObject(List<ValidationResultInfo> results, Object data, ObjectStructureDefinition objStructure, Stack<String> elementStack, Object rootData, ObjectStructureDefinition rootObjStructure, boolean isRoot) {
128   
129  1576 ConstraintDataProvider dataProvider = new BeanConstraintDataProvider();
130  1576 dataProvider.initialize(data);
131   
132    // Push object structure to the top of the stack
133  1576 StringBuilder objXPathElement = new StringBuilder(dataProvider.getPath());
134   
135  1576 if(!isRoot && !objXPathElement.toString().isEmpty()){
136  0 elementStack.push(objXPathElement.toString());
137    }
138   
139    /*
140    * Do nothing if the object to be validated is not type/state or if the objectstructure with constraints is not
141    * provided
142    */
143  1576 if (null == objStructure) {
144  25 return;
145    }
146   
147  1551 for (FieldDefinition f : objStructure.getAttributes()) {
148  8569 validateField(results, f, objStructure, dataProvider, elementStack, rootData, rootObjStructure);
149   
150    // Use Custom Validators
151  8569 if (f.getCustomValidatorClass() != null || f.isServerSide() && serverSide) {
152  74 Validator customValidator = validatorFactory.getValidator(f.getCustomValidatorClass());
153  74 if(customValidator==null){
154  0 throw new RuntimeException("Custom Validator "+f.getCustomValidatorClass()+" was not configured in this context");
155    }
156  74 List<ValidationResultInfo> l = customValidator.validateObject(f,data, objStructure,elementStack);
157  74 results.addAll(l);
158    }
159    }
160  1551 if(!isRoot && !objXPathElement.toString().isEmpty()){
161  0 elementStack.pop();
162    }
163   
164    /* All Field validations are returned right now */
165    // List<ValidationResultInfo> resultsBuffer = new
166    // ArrayList<ValidationResultInfo>();
167    // for (ValidationResultContainer vc : results) {
168    // if (skipFields.contains(vc.getElement()) == false) {
169    // resultsBuffer.add(vc);
170    // }
171    // }
172    // results = resultsBuffer;
173    }
174   
 
175  8569 toggle public void validateField(List<ValidationResultInfo> results, FieldDefinition field, ObjectStructureDefinition objStruct, ConstraintDataProvider dataProvider, Stack<String> elementStack, Object rootData, ObjectStructureDefinition rootObjectStructure) {
176   
177  8569 Object value = dataProvider.getValue(field.getName());
178   
179    // Handle null values in field
180  8569 if (value == null || "".equals(value.toString().trim())) {
181  1401 processConstraint(results, field, objStruct, value, dataProvider, elementStack, rootData, rootObjectStructure);
182  1401 return; //no need to do further processing
183    }
184   
185    /*
186    * For complex object structures only the following constraints apply 1. TypeStateCase 2. MinOccurs 3. MaxOccurs
187    */
188  7168 if (DataType.COMPLEX.equals(field.getDataType())) {
189  1252 ObjectStructureDefinition nestedObjStruct = null;
190   
191  1252 if (null != field.getDataObjectStructure()) {
192  1252 nestedObjStruct = field.getDataObjectStructure();
193    }
194   
195  1252 elementStack.push(field.getName());
196    // beanPathStack.push(field.isDynamic()?"attributes("+field.getName()+")":field.getName());
197   
198  1252 if (value instanceof Collection) {
199   
200  474 String xPathForCollection = getElementXpath(elementStack) + "/*";
201   
202  474 int i=0;
203  474 for (Object o : (Collection<?>) value) {
204  661 elementStack.push(Integer.toString(i));
205    // beanPathStack.push(!beanPathStack.isEmpty()?beanPathStack.pop():""+"["+i+"]");
206  661 processNestedObjectStructure(results, o, nestedObjStruct, field, elementStack, rootData, rootObjectStructure);
207    // beanPathStack.pop();
208    // beanPathStack.push(field.isDynamic()?"attributes("+field.getName()+")":field.getName());
209  661 elementStack.pop();
210  661 i++;
211    }
212  474 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
213  0 ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
214  0 valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
215  0 results.add(valRes);
216    }
217   
218  474 Integer maxOccurs = tryParse(field.getMaxOccurs());
219  474 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
220  0 ValidationResultInfo valRes = new ValidationResultInfo(xPathForCollection, value);
221  0 valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
222  0 results.add(valRes);
223    }
224    } else {
225  778 if (null != value) {
226  778 processNestedObjectStructure(results, value, nestedObjStruct, field, elementStack, rootData, rootObjectStructure);
227    } else {
228  0 if (field.getMinOccurs() != null && field.getMinOccurs() > 0) {
229  0 ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack), value);
230  0 if(field.getLabelKey()!=null){
231  0 val.setError(getMessage(field.getLabelKey()));
232    } else {
233  0 val.setError(getMessage("validation.required"));
234    }
235  0 results.add(val);
236    }
237    }
238    }
239   
240    // beanPathStack.pop();
241  1252 elementStack.pop();
242   
243    } else { // If non complex data type
244   
245  5916 if (value instanceof Collection) {
246   
247  262 if(((Collection<?>)value).isEmpty()){
248  103 processConstraint(results, field, objStruct, "", dataProvider, elementStack, rootData, rootObjectStructure);
249    }
250   
251  262 int i = 0;
252  262 for (Object o : (Collection<?>) value) {
253    //This is tricky, change the field name to the index in the elementStack(this is for lists of non complex types)
254  324 elementStack.push(field.getName());
255  324 FieldDefinition tempField = new FieldDefinition();
256  324 BeanUtils.copyProperties(field, tempField);
257  324 tempField.setName(Integer.toBinaryString(i));
258  324 processConstraint(results, tempField, objStruct, o, dataProvider, elementStack, rootData, rootObjectStructure);
259  324 elementStack.pop();
260  324 i++;
261    }
262   
263  262 String xPath = getElementXpath(elementStack) + "/" + field.getName() + "/*";
264  262 if (field.getMinOccurs() != null && field.getMinOccurs() > ((Collection<?>) value).size()) {
265  0 ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
266  0 valRes.setError(MessageUtils.interpolate(getMessage("validation.minOccurs"), toMap(field)));
267  0 results.add(valRes);
268    }
269   
270  262 Integer maxOccurs = tryParse(field.getMaxOccurs());
271  262 if (maxOccurs != null && maxOccurs < ((Collection<?>) value).size()) {
272  0 ValidationResultInfo valRes = new ValidationResultInfo(xPath, value);
273  0 valRes.setError(MessageUtils.interpolate(getMessage("validation.maxOccurs"), toMap(field)));
274  0 results.add(valRes);
275    }
276    } else {
277  5654 processConstraint(results, field, objStruct, value, dataProvider, elementStack, rootData, rootObjectStructure);
278    }
279   
280    }
281    }
282   
 
283  5453 toggle protected Integer tryParse(String s) {
284  5453 Integer result = null;
285  5453 if (s != null) {
286  5371 try {
287  5371 result = Integer.valueOf(s);
288    } catch (NumberFormatException e) {
289    // do nothing
290    }
291    }
292  5453 return result;
293    }
294   
 
295  1439 toggle protected void processNestedObjectStructure(List<ValidationResultInfo> results, Object value, ObjectStructureDefinition nestedObjStruct, FieldDefinition field, Stack<String> elementStack, Object rootData, ObjectStructureDefinition rootObjStructure) {
296  1439 validateObject(results, value, nestedObjStruct, elementStack, rootData, rootObjStructure, false);
297    }
298   
 
299  7482 toggle protected void processConstraint(List<ValidationResultInfo> valResults, FieldDefinition field, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack, Object rootData, ObjectStructureDefinition rootObjStructure) {
300   
301    // Process Case Constraint
302    // Case Constraint are only evaluated on the field. Nested case constraints are currently ignored
303  7482 Constraint caseConstraint = processCaseConstraint(valResults, field.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
304   
305  7482 Constraint constraint = (null != caseConstraint) ? caseConstraint : field;
306   
307  7482 processBaseConstraints(valResults, constraint, field, value, elementStack);
308   
309    // Stop other checks if value is null
310  7482 if (value == null || "".equals(value.toString().trim())) {
311  1504 return;
312    }
313   
314  5978 String elementPath = getElementXpath(elementStack) + "/" + field.getName();
315   
316    // Process Valid Chars
317  5978 if (null != constraint.getValidChars()) {
318  2269 ValidationResultInfo val = processValidCharConstraint(elementPath, constraint.getValidChars(), dataProvider, value);
319  2269 if (null != val) {
320  16 valResults.add(val);
321    }
322    }
323   
324    // Process Require Constraints (only if this field has value)
325  5978 if (value != null && !"".equals(value.toString().trim())) {
326  5978 if (null != constraint.getRequireConstraint() && constraint.getRequireConstraint().size() > 0) {
327  136 for (RequiredConstraint rc : constraint.getRequireConstraint()) {
328  136 ValidationResultInfo val = processRequireConstraint(elementPath, rc, field, objStructure, dataProvider);
329  136 if (null != val) {
330  5 valResults.add(val);
331    //FIXME: For clarity, might be better to handle this in the processRequireConstraint method instead.
332  5 processCrossFieldWarning(valResults, rc, val.getErrorLevel(), field.getName());
333    }
334    }
335    }
336    }
337   
338    // Process Occurs Constraint
339  5978 if (null != constraint.getOccursConstraint() && constraint.getOccursConstraint().size() > 0) {
340  0 for (MustOccurConstraint oc : constraint.getOccursConstraint()) {
341  0 ValidationResultInfo val = processOccursConstraint(elementPath, oc, field, objStructure, dataProvider);
342  0 if (null != val) {
343  0 valResults.add(val);
344    }
345    }
346    }
347   
348    // Process lookup Constraint
349  5978 if (null != constraint.getLookupDefinition()) {
350  317 processLookupConstraint(valResults, constraint.getLookupDefinition(), field, elementStack, dataProvider,objStructure, rootData, rootObjStructure, value);
351    }
352    }
353   
 
354  136 toggle protected ValidationResultInfo processRequireConstraint(String element, RequiredConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
355   
356  136 ValidationResultInfo val = null;
357   
358  136 String fieldName = constraint.getFieldPath();// TODO parse fieldname from here
359  136 Object fieldValue = dataProvider.getValue(fieldName);
360   
361  136 boolean result = true;
362   
363  136 if (fieldValue instanceof java.lang.String) {
364  132 result = hasText((String) fieldValue);
365  4 } else if (fieldValue instanceof Collection) {
366  0 result = (((Collection<?>) fieldValue).size() > 0);
367    } else {
368  4 result = (null != fieldValue) ? true : false;
369    }
370   
371  136 if (!result) {
372  5 Map<String, Object> rMap = new HashMap<String, Object>();
373  5 rMap.put("field1", field.getName());
374  5 rMap.put("field2", fieldName);
375  5 val = new ValidationResultInfo(element, fieldValue);
376  5 val.setMessage(MessageUtils.interpolate(getMessage("validation.requiresField"), rMap));
377  5 val.setLevel(constraint.getErrorLevel());
378    }
379   
380  136 return val;
381    }
382   
383    /**
384    * Process caseConstraint tag and sets any of the base constraint items if any of the when condition matches
385    *
386    * @param caseConstraint
387    * @param caseConstraint
388    * @param field
389    */
 
390  7549 toggle protected Constraint processCaseConstraint(List<ValidationResultInfo> valResults, CaseConstraint caseConstraint, ObjectStructureDefinition objStructure, Object value, ConstraintDataProvider dataProvider, Stack<String> elementStack, Object rootData, ObjectStructureDefinition rootObjStructure) {
391   
392  7549 if (null == caseConstraint) {
393  7086 return null;
394    }
395   
396  463 String operator = (hasText(caseConstraint.getOperator())) ? caseConstraint.getOperator() : "EQUALS";
397  463 FieldDefinition caseField = null;
398  463 boolean absolutePath = false;
399  463 if(hasText(caseConstraint.getFieldPath())){
400  463 if(caseConstraint.getFieldPath().startsWith("/")){
401  14 absolutePath = true;
402  14 caseField = ValidatorUtils.getField(caseConstraint.getFieldPath().substring(1), rootObjStructure);
403    }else{
404  449 caseField = ValidatorUtils.getField(caseConstraint.getFieldPath(), objStructure);
405    }
406    }
407   
408    // TODO: What happens when the field is not in the dataProvider?
409  463 Object fieldValue = value;
410  463 if(caseField!=null){
411  362 if(absolutePath){
412  14 try {
413  14 if(caseField.isDynamic()){
414    //Pull the value from the dynamic attribute map
415    //TODO There needs to be some mapping from PropertyUtils to the KS path
416    //Until then, this will only work for root level properties
417  2 Map<String,String> attributes = (Map<String,String>) PropertyUtils.getNestedProperty(rootData, "attributes");
418  2 if(attributes!=null){
419  2 fieldValue = attributes.get(caseConstraint.getFieldPath().substring(1));
420    }
421    }else{
422  12 fieldValue = PropertyUtils.getNestedProperty(rootData, caseConstraint.getFieldPath().substring(1));
423    }
424    } catch (IllegalAccessException e) {
425    } catch (InvocationTargetException e) {
426    } catch (NoSuchMethodException e) {
427    }
428    }else{
429  348 fieldValue = dataProvider.getValue(caseField.getName());
430    }
431    }
432  463 DataType fieldDataType = (null != caseField ? caseField.getDataType():null);
433   
434    // If fieldValue is null then skip Case check
435  463 if(null == fieldValue) {
436  57 return null;
437    }
438   
439    // Extract value for field Key
440  406 for (WhenConstraint wc : caseConstraint.getWhenConstraint()) {
441   
442  515 if(hasText(wc.getValuePath())){
443  0 Object whenValue = null;
444  0 if(wc.getValuePath().startsWith("/")){
445  0 try {
446  0 whenValue = PropertyUtils.getNestedProperty(rootData, wc.getValuePath().substring(1));
447    } catch (IllegalAccessException e) {
448    } catch (InvocationTargetException e) {
449    } catch (NoSuchMethodException e) {
450    }
451    }else{
452  0 whenValue = dataProvider.getValue(wc.getValuePath());
453    }
454  0 if (ValidatorUtils.compareValues(fieldValue, whenValue, fieldDataType, operator, caseConstraint.isCaseSensitive(), dateParser) && null != wc.getConstraint()) {
455  0 Constraint constraint = wc.getConstraint();
456  0 if (constraint.getCaseConstraint() != null){
457  0 return processCaseConstraint(valResults, constraint.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
458    } else {
459  0 processCrossFieldWarning(valResults, caseConstraint, constraint, value, constraint.getErrorLevel());
460  0 return constraint;
461    }
462    }
463    }else{
464  515 List<Object> whenValueList = wc.getValues();
465   
466  515 for (Object whenValue : whenValueList) {
467  1152 if (ValidatorUtils.compareValues(fieldValue, whenValue, fieldDataType, operator, caseConstraint.isCaseSensitive(), dateParser) && null != wc.getConstraint()) {
468  139 Constraint constraint = wc.getConstraint();
469  139 if (constraint.getCaseConstraint() != null){
470  67 return processCaseConstraint(valResults, constraint.getCaseConstraint(), objStructure, value, dataProvider, elementStack, rootData, rootObjStructure);
471    } else {
472  72 processCrossFieldWarning(valResults, caseConstraint, constraint, value, constraint.getErrorLevel());
473  72 return constraint;
474    }
475    }
476    }
477    }
478    }
479   
480  267 return null;
481    }
482   
 
483  2531 toggle public ValidationResultInfo processValidCharConstraint(String element, ValidCharsConstraint vcConstraint, ConstraintDataProvider dataProvider, Object value) {
484   
485  2531 ValidationResultInfo val = null;
486   
487  2531 StringBuilder fieldValue = new StringBuilder();
488  2531 String validChars = vcConstraint.getValue();
489   
490  2531 fieldValue.append(ValidatorUtils.getString(value));
491   
492  2531 int typIdx = validChars.indexOf(":");
493  2531 String processorType = "regex";
494  2531 if (-1 == typIdx) {
495  0 validChars = "[" + validChars + "]*";
496    } else {
497  2531 processorType = validChars.substring(0, typIdx);
498  2531 validChars = validChars.substring(typIdx + 1);
499    }
500   
501  2531 if ("regex".equalsIgnoreCase(processorType)) {
502  2531 if (fieldValue == null || !fieldValue.toString().matches(validChars)) {
503  129 val = new ValidationResultInfo(element, fieldValue);
504  129 if(vcConstraint.getLabelKey()!=null){
505  87 val.setError(getMessage(vcConstraint.getLabelKey()));
506    }else{
507  42 val.setError(getMessage("validation.validCharsFailed"));
508    }
509    }
510    }
511   
512  2531 return val;
513    }
514   
515    /**
516    * Computes if all the filed required in the occurs clause are between the min and max
517    *
518    * @param valResults
519    * @param constraint
520    * @param field
521    * @param type
522    * @param state
523    * @param objStructure
524    * @param dataProvider
525    * @return
526    */
 
527  0 toggle protected ValidationResultInfo processOccursConstraint(String element, MustOccurConstraint constraint, FieldDefinition field, ObjectStructureDefinition objStructure, ConstraintDataProvider dataProvider) {
528   
529  0 boolean result = false;
530  0 int trueCount = 0;
531   
532  0 ValidationResultInfo val = null;
533   
534  0 for (RequiredConstraint rc : constraint.getRequiredFields()) {
535  0 trueCount += (processRequireConstraint("", rc, field, objStructure, dataProvider) != null) ? 1 : 0;
536    }
537   
538  0 for (MustOccurConstraint oc : constraint.getOccurs()) {
539  0 trueCount += (processOccursConstraint("", oc, field, objStructure, dataProvider) != null) ? 1 : 0;
540    }
541   
542  0 result = (trueCount >= constraint.getMin() && trueCount <= constraint.getMax()) ? true : false;
543   
544  0 if (!result) {
545    // TODO: figure out what data should go here instead of null
546  0 val = new ValidationResultInfo(element, null);
547  0 val.setMessage(getMessage("validation.occurs"));
548  0 val.setLevel(constraint.getErrorLevel());
549    }
550   
551  0 return val;
552    }
553   
554    // TODO: Implement lookup constraint
 
555  317 toggle protected void processLookupConstraint(List<ValidationResultInfo> valResults, LookupConstraint lookupConstraint, FieldDefinition field, Stack<String> elementStack, ConstraintDataProvider dataProvider, ObjectStructureDefinition objStructure, Object rootData, ObjectStructureDefinition rootObjStructure, Object value) {
556  317 if (lookupConstraint == null) {
557  0 return;
558    }
559   
560    // Create search params based on the param mapping
561  317 List<SearchParam> params = new ArrayList<SearchParam>();
562   
563  317 for (CommonLookupParam paramMapping : lookupConstraint.getParams()) {
564    //Skip params that are the search param id key
565  549 if(lookupConstraint.getSearchParamIdKey()!=null&&lookupConstraint.getSearchParamIdKey().equals(paramMapping.getKey())){
566  172 continue;
567    }
568   
569  377 SearchParam param = new SearchParam();
570   
571  377 param.setKey(paramMapping.getKey());
572   
573    // If the value of the search param comes form another field then get it
574  377 if (paramMapping.getFieldPath() != null && !paramMapping.getFieldPath().isEmpty()) {
575  88 FieldDefinition lookupField = null;
576  88 boolean absolutePath = false;
577  88 if(hasText(paramMapping.getFieldPath())){
578  88 if(paramMapping.getFieldPath().startsWith("/")){
579  60 absolutePath = true;
580  60 lookupField = ValidatorUtils.getField(paramMapping.getFieldPath().substring(1), rootObjStructure);
581    }else{
582  28 lookupField = ValidatorUtils.getField(paramMapping.getFieldPath(), objStructure);
583    }
584    }
585  88 Object fieldValue = null;
586  88 if(lookupField!=null){
587  88 if(absolutePath){
588  60 try {
589  60 if(lookupField.isDynamic()){
590    //Pull the value from the dynamic attribute map
591    //Until then, this will only work for root level properties
592  0 Map<String,String> attributes = (Map<String,String>) PropertyUtils.getNestedProperty(rootData, "attributes");
593  0 if(attributes!=null){
594  0 fieldValue = attributes.get(paramMapping.getFieldPath().substring(1));
595    }
596    }else{
597  60 fieldValue = PropertyUtils.getNestedProperty(rootData, paramMapping.getFieldPath().substring(1));
598    }
599    } catch (IllegalAccessException e) {
600    } catch (InvocationTargetException e) {
601    } catch (NoSuchMethodException e) {
602    }
603    }else{
604  28 fieldValue = dataProvider.getValue(lookupField.getName());
605    }
606    }else{
607  0 fieldValue = dataProvider.getValue(paramMapping.getFieldPath());
608    }
609   
610  88 if (fieldValue instanceof String) {
611  30 param.setValue((String) fieldValue);
612  58 } else if (fieldValue instanceof List<?>) {
613  58 param.setValue((List<String>) fieldValue);
614    }
615  289 } else if (paramMapping.getDefaultValueString() != null) {
616  91 param.setValue(paramMapping.getDefaultValueString());
617    } else {
618  198 param.setValue(paramMapping.getDefaultValueList());
619    }
620  377 params.add(param);
621    }
622   
623  317 if(lookupConstraint.getSearchParamIdKey()!=null){
624  313 SearchParam param = new SearchParam();
625  313 param.setKey(lookupConstraint.getSearchParamIdKey());
626  313 if (value instanceof String) {
627  313 param.setValue((String) value);
628  0 } else if (value instanceof List<?>) {
629  0 param.setValue((List<String>) value);
630    }
631  313 params.add(param);
632    }
633   
634  317 SearchRequest searchRequest = new SearchRequest();
635  317 searchRequest.setMaxResults(1);
636  317 searchRequest.setStartAt(0);
637  317 searchRequest.setNeededTotalResults(false);
638  317 searchRequest.setSearchKey(lookupConstraint.getSearchTypeId());
639  317 searchRequest.setParams(params);
640   
641  317 SearchResult searchResult = null;
642  317 try {
643  317 searchResult = searchDispatcher.dispatchSearch(searchRequest);
644    } catch (Exception e) {
645  2 LOG.info("Error calling Search", e);
646    }
647    //If there are no search results then make a validation result
648  317 if (searchResult == null || searchResult.getRows() == null || searchResult.getRows().isEmpty()) {
649  4 ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + field.getName(), value);
650  4 val.setLevel(lookupConstraint.getErrorLevel());
651  4 val.setMessage(getMessage("validation.lookup"));
652  4 valResults.add(val);
653  4 processCrossFieldWarning(valResults, lookupConstraint, lookupConstraint.getErrorLevel());
654    }
655    }
656   
 
657  7482 toggle protected void processBaseConstraints(List<ValidationResultInfo> valResults, Constraint constraint, FieldDefinition field, Object value, Stack<String> elementStack) {
658  7482 DataType dataType = field.getDataType();
659  7482 String name = field.getName();
660   
661  7482 if (value == null || "".equals(value.toString().trim())) {
662  1504 if (constraint.getMinOccurs() != null && constraint.getMinOccurs() > 0) {
663  63 ValidationResultInfo val = new ValidationResultInfo(getElementXpath(elementStack) + "/" + name, value);
664  63 if(constraint.getLabelKey()!=null){
665  0 val.setError(getMessage(constraint.getLabelKey()));
666    } else {
667  63 val.setMessage(getMessage("validation.required"));
668    }
669  63 val.setLevel(constraint.getErrorLevel());
670  63 valResults.add(val);
671    }
672  1504 return;
673    }
674   
675  5978 String elementPath = getElementXpath(elementStack) + "/" + name;
676   
677  5978 if (DataType.STRING.equals(dataType)) {
678  4717 validateString(value, constraint, elementPath, valResults);
679  1261 } else if (DataType.INTEGER.equals(dataType)) {
680  143 validateInteger(value, constraint, elementPath, valResults);
681  1118 } else if (DataType.LONG.equals(dataType)) {
682  43 validateLong(value, constraint, elementPath, valResults);
683  1075 } else if (DataType.DOUBLE.equals(dataType)) {
684  1 validateDouble(value, constraint, elementPath, valResults);
685  1074 } else if (DataType.FLOAT.equals(dataType)) {
686  0 validateFloat(value, constraint, elementPath, valResults);
687  1074 } else if (DataType.BOOLEAN.equals(dataType)) {
688  87 validateBoolean(value, constraint, elementPath, valResults);
689  987 } else if (DataType.DATE.equals(dataType)) {
690  987 validateDate(value, constraint, elementPath, valResults, dateParser);
691    }
692    }
693   
694    /**
695    * This adds a warning on the related field when a processed case-constraint results in a warning
696    *
697    * @param valResults
698    * @param crossConstraint
699    * @param field
700    */
 
701  72 toggle protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, CaseConstraint crossConstraint, Constraint constraint, Object value, ErrorLevel errorLevel){
702  72 if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && (value == null || "".equals(value.toString().trim()))) {
703  7 if (constraint.getMinOccurs() != null && constraint.getMinOccurs() > 0) {
704   
705  7 String crossFieldPath = crossConstraint.getFieldPath();
706  7 String crossFieldMessageId = crossConstraint.getFieldPathMessageId() == null ?
707    "validation.required":crossConstraint.getFieldPathMessageId();
708  7 addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
709    }
710    }
711    }
712   
713    /**
714    * This adds a warning on the related field when a processed case-constraint results in a warning
715    *
716    * @param valResults
717    * @param requiredConstraint
718    * @param field
719    */
 
720  5 toggle protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, RequiredConstraint requiredConstraint, ErrorLevel errorLevel, String field){
721  5 if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && requiredConstraint != null){
722  5 String crossFieldPath = requiredConstraint.getFieldPath();
723  5 String crossFieldMessageId = requiredConstraint.getFieldPathMessageId() == null ?
724    "validation.required":requiredConstraint.getFieldPathMessageId();
725  5 addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
726    }
727    }
728   
729    /**
730    * This adds a warning on the related field when a processed lookup-constraint results in a warning
731    *
732    * @param valResults
733    * @param lookupConstraint
734    */
 
735  4 toggle protected void processCrossFieldWarning(List<ValidationResultInfo> valResults, LookupConstraint lookupConstraint, ErrorLevel errorLevel){
736  4 if ((ErrorLevel.WARN == errorLevel || ErrorLevel.ERROR == errorLevel) && lookupConstraint != null){
737  4 for(CommonLookupParam param:lookupConstraint.getParams()){
738  8 if(param.getFieldPath()!=null && !param.getFieldPath().isEmpty()){
739  4 String crossFieldPath = param.getFieldPath();
740  4 String crossFieldMessageId = param.getFieldPathMessageId() == null ?
741    "validation.lookup.cause":param.getFieldPathMessageId();
742  4 addCrossFieldWarning(valResults, crossFieldPath, getMessage(crossFieldMessageId), errorLevel);
743    }
744    }
745    }
746    }
747   
 
748  16 toggle protected void addCrossFieldWarning(List<ValidationResultInfo> valResults, String crossFieldPath, String message, ErrorLevel errorLevel){
749    //Check to see if the exact same validation message already exists on referenced field
750  16 boolean warnAlreadyExists = false;
751  16 for (ValidationResultInfo vr:valResults){
752  36 if (vr.getElement().equals(crossFieldPath) && vr.getMessage().equals(message)){
753  1 warnAlreadyExists = true;
754    }
755    }
756   
757    //Only add this warning, if it hasn't been already added
758  16 if (!warnAlreadyExists){
759  15 ValidationResultInfo val = new ValidationResultInfo(crossFieldPath, null);
760  15 val.setMessage(message);
761  15 val.setLevel(errorLevel);
762  15 valResults.add(val);
763    }
764    }
765   
 
766  87 toggle protected void validateBoolean(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
767  87 if (!(value instanceof Boolean)) {
768  0 try {
769  0 Boolean.valueOf(value.toString());
770    } catch (Exception e) {
771  0 ValidationResultInfo val = new ValidationResultInfo(element, value);
772  0 val.setError(getMessage("validation.mustBeBoolean"));
773  0 results.add(val);
774    }
775    }
776    }
777   
 
778  1 toggle protected void validateDouble(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
779  1 Double v = null;
780   
781  1 ValidationResultInfo val = new ValidationResultInfo(element, value);
782   
783  1 if (value instanceof Number) {
784  1 v = ((Number) value).doubleValue();
785    } else {
786  0 try {
787  0 v = Double.valueOf(value.toString());
788    } catch (Exception e) {
789  0 val.setError(getMessage("validation.mustBeDouble"));
790    }
791    }
792   
793  1 if (val.isOk()) {
794  1 Double maxValue = ValidatorUtils.getDouble(constraint.getInclusiveMax());
795  1 Double minValue = ValidatorUtils.getDouble(constraint.getExclusiveMin());
796   
797  1 if (maxValue != null && minValue != null) {
798    // validate range
799  1 if (v > maxValue || v < minValue) {
800  1 val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
801    }
802  0 } else if (maxValue != null) {
803  0 if (v > maxValue) {
804  0 val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
805    }
806  0 } else if (minValue != null) {
807  0 if (v < minValue) {
808  0 val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
809    }
810    }
811    }
812   
813  1 if (!val.isOk()) {
814  1 results.add(val);
815    }
816    }
817   
 
818  0 toggle protected void validateFloat(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
819  0 Float v = null;
820   
821  0 ValidationResultInfo val = new ValidationResultInfo(element, value);
822  0 if (value instanceof Number) {
823  0 v = ((Number) value).floatValue();
824    } else {
825  0 try {
826  0 v = Float.valueOf(value.toString());
827    } catch (Exception e) {
828  0 val.setError(getMessage("validation.mustBeFloat"));
829    }
830    }
831   
832  0 if (val.isOk()) {
833  0 Float maxValue = ValidatorUtils.getFloat(constraint.getInclusiveMax());
834  0 Float minValue = ValidatorUtils.getFloat(constraint.getExclusiveMin());
835   
836  0 if (maxValue != null && minValue != null) {
837    // validate range
838  0 if (v > maxValue || v < minValue) {
839  0 val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
840    }
841  0 } else if (maxValue != null) {
842  0 if (v > maxValue) {
843  0 val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
844    }
845  0 } else if (minValue != null) {
846  0 if (v < minValue) {
847  0 val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
848    }
849    }
850    }
851   
852  0 if (!val.isOk()) {
853  0 results.add(val);
854    }
855    }
856   
 
857  43 toggle protected void validateLong(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
858  43 Long v = null;
859   
860  43 ValidationResultInfo val = new ValidationResultInfo(element, value);
861  43 if (value instanceof Number) {
862  43 v = ((Number) value).longValue();
863    } else {
864  0 try {
865  0 v = Long.valueOf(value.toString());
866    } catch (Exception e) {
867  0 val.setError(getMessage("validation.mustBeLong"));
868    }
869    }
870   
871  43 if (val.isOk()) {
872  43 Long maxValue = ValidatorUtils.getLong(constraint.getInclusiveMax());
873  43 Long minValue = ValidatorUtils.getLong(constraint.getExclusiveMin());
874   
875  43 if (maxValue != null && minValue != null) {
876    // validate range
877  0 if (v > maxValue || v < minValue) {
878  0 val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
879    }
880  43 } else if (maxValue != null) {
881  0 if (v > maxValue) {
882  0 val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
883    }
884  43 } else if (minValue != null) {
885  0 if (v < minValue) {
886  0 val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
887    }
888    }
889    }
890   
891  43 if (!val.isOk()) {
892  0 results.add(val);
893    }
894   
895    }
896   
 
897  143 toggle protected void validateInteger(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
898  143 Integer v = null;
899   
900  143 ValidationResultInfo val = new ValidationResultInfo(element, value);
901   
902  143 if (value instanceof Number) {
903  143 v = ((Number) value).intValue();
904    } else {
905  0 try {
906  0 v = Integer.valueOf(value.toString());
907    } catch (Exception e) {
908  0 val.setError(getMessage("validation.mustBeInteger"));
909    }
910    }
911   
912  143 if (val.isOk()) {
913  143 Integer maxValue = ValidatorUtils.getInteger(constraint.getInclusiveMax());
914  143 Integer minValue = ValidatorUtils.getInteger(constraint.getExclusiveMin());
915   
916  143 if (maxValue != null && minValue != null) {
917    // validate range
918  24 if (v > maxValue || v < minValue) {
919  0 val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
920    }
921  119 } else if (maxValue != null) {
922  0 if (v > maxValue) {
923  0 val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
924    }
925  119 } else if (minValue != null) {
926  0 if (v < minValue) {
927  0 val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
928    }
929    }
930    }
931   
932  143 if (!val.isOk()) {
933  0 results.add(val);
934    }
935    }
936   
 
937  987 toggle protected void validateDate(Object value, Constraint constraint, String element, List<ValidationResultInfo> results, DateParser dateParser) {
938  987 ValidationResultInfo val = new ValidationResultInfo(element, value);
939   
940  987 Date v = null;
941   
942  987 if (value instanceof Date) {
943  987 v = (Date) value;
944    } else {
945  0 try {
946  0 v = dateParser.parseDate(value.toString());
947    } catch (Exception e) {
948  0 val.setError(getMessage("validation.mustBeDate"));
949    }
950    }
951   
952  987 if (val.isOk()) {
953  987 Date maxValue = ValidatorUtils.getDate(constraint.getInclusiveMax(), dateParser);
954  987 Date minValue = ValidatorUtils.getDate(constraint.getExclusiveMin(), dateParser);
955   
956  987 if (maxValue != null && minValue != null) {
957    // validate range
958  0 if (v.getTime() > maxValue.getTime() || v.getTime() < minValue.getTime()) {
959  0 val.setError(MessageUtils.interpolate(getMessage("validation.outOfRange"), toMap(constraint)));
960    }
961  987 } else if (maxValue != null) {
962  0 if (v.getTime() > maxValue.getTime()) {
963  0 val.setError(MessageUtils.interpolate(getMessage("validation.maxValueFailed"), toMap(constraint)));
964    }
965  987 } else if (minValue != null) {
966  7 if (v.getTime() < minValue.getTime()) {
967  1 val.setError(MessageUtils.interpolate(getMessage("validation.minValueFailed"), toMap(constraint)));
968    }
969    }
970    }
971   
972  987 if (!val.isOk()) {
973  1 results.add(val);
974    }
975    }
976   
 
977  4717 toggle protected void validateString(Object value, Constraint constraint, String element, List<ValidationResultInfo> results) {
978   
979  4717 if (value == null) {
980  0 value = "";
981    }
982  4717 String s = value.toString().trim();
983   
984  4717 ValidationResultInfo val = new ValidationResultInfo(element, value);
985   
986  4717 Integer maxLength = tryParse(constraint.getMaxLength());
987  4717 if (maxLength != null && constraint.getMinLength() != null && constraint.getMinLength() > 0) {
988  2674 if (s.length() > maxLength || s.length() < constraint.getMinLength()) {
989  13 val.setError(MessageUtils.interpolate(getMessage("validation.lengthOutOfRange"), toMap(constraint)));
990    }
991  2043 } else if (maxLength != null) {
992  1966 if (s.length() > Integer.parseInt(constraint.getMaxLength())) {
993  1 val.setError(MessageUtils.interpolate(getMessage("validation.maxLengthFailed"), toMap(constraint)));
994    }
995  77 } else if (constraint.getMinLength() != null && constraint.getMinLength() > 0) {
996  1 if (s.length() < constraint.getMinLength()) {
997  1 val.setError(MessageUtils.interpolate(getMessage("validation.minLengthFailed"), toMap(constraint)));
998    }
999    }
1000   
1001  4717 if (!val.isOk()) {
1002  15 results.add(val);
1003    }
1004    }
1005   
 
1006  246 toggle protected String getMessage(String messageId) {
1007  246 if (null == messageService) {
1008  236 return messageId;
1009    }
1010   
1011  10 Message msg = messageService.getMessage(messageLocaleKey, messageGroupKey, messageId);
1012   
1013  10 return msg.getValue();
1014    }
1015   
 
1016  12783 toggle protected String getElementXpath(Stack<String> elementStack) {
1017  12783 StringBuilder xPath = new StringBuilder();
1018  12783 Iterator<String> itr = elementStack.iterator();
1019  74556 while (itr.hasNext()) {
1020  61773 xPath.append(itr.next());
1021  61773 if(itr.hasNext()){
1022  50428 xPath.append("/");
1023    }
1024    }
1025   
1026  12783 return xPath.toString();
1027    }
1028   
1029    /*
1030    * Homemade has text so we dont need outside libs.
1031    */
 
1032  1709 toggle protected boolean hasText(String string) {
1033   
1034  1709 if (string == null || string.length() < 1) {
1035  516 return false;
1036    }
1037  1193 int stringLength = string.length();
1038   
1039  1193 for (int i = 0; i < stringLength; i++) {
1040  1193 char currentChar = string.charAt(i);
1041  1193 if (' ' != currentChar || '\t' != currentChar || '\n' != currentChar) {
1042  1193 return true;
1043    }
1044    }
1045   
1046  0 return false;
1047    }
1048   
 
1049  19 toggle protected Map<String, Object> toMap(Constraint c) {
1050  19 Map<String, Object> result = new HashMap<String, Object>();
1051  19 result.put("minOccurs", c.getMinOccurs());
1052  19 result.put("maxOccurs", c.getMaxOccurs());
1053  19 result.put("minLength", c.getMinLength());
1054  19 result.put("maxLength", c.getMaxLength());
1055  19 result.put("minValue", c.getExclusiveMin());
1056  19 result.put("maxValue", c.getInclusiveMax());
1057    // result.put("dataType", c.getDataType());
1058   
1059  19 return result;
1060    }
1061   
 
1062  25 toggle public SearchDispatcher getSearchDispatcher() {
1063  25 return searchDispatcher;
1064    }
1065   
 
1066  14 toggle public void setSearchDispatcher(SearchDispatcher searchDispatcher) {
1067  14 this.searchDispatcher = searchDispatcher;
1068    }
1069   
 
1070  0 toggle @Override
1071    public List<ValidationResultInfo> validateObject(FieldDefinition field,
1072    Object o, ObjectStructureDefinition objStructure,Stack<String> elementStack) {
1073  0 return null;
1074    }
1075    }