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