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