1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.lang.ArrayUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.kuali.rice.core.api.mo.common.active.Inactivatable;
22 import org.kuali.rice.core.api.util.RiceKeyConstants;
23 import org.kuali.rice.krad.bo.BusinessObject;
24 import org.kuali.rice.krad.bo.PersistableBusinessObject;
25 import org.kuali.rice.krad.data.DataObjectWrapper;
26 import org.kuali.rice.krad.data.KradDataServiceLocator;
27 import org.kuali.rice.krad.datadictionary.CollectionDefinition;
28 import org.kuali.rice.krad.datadictionary.ComplexAttributeDefinition;
29 import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
30 import org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase;
31 import org.kuali.rice.krad.datadictionary.DataObjectEntry;
32 import org.kuali.rice.krad.datadictionary.ReferenceDefinition;
33 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
34 import org.kuali.rice.krad.datadictionary.state.StateMapping;
35 import org.kuali.rice.krad.datadictionary.validation.AttributeValueReader;
36 import org.kuali.rice.krad.datadictionary.validation.DictionaryObjectAttributeValueReader;
37 import org.kuali.rice.krad.datadictionary.validation.ErrorLevel;
38 import org.kuali.rice.krad.datadictionary.validation.capability.Constrainable;
39 import org.kuali.rice.krad.datadictionary.validation.constraint.Constraint;
40 import org.kuali.rice.krad.datadictionary.validation.constraint.provider.ConstraintProvider;
41 import org.kuali.rice.krad.datadictionary.validation.processor.CollectionConstraintProcessor;
42 import org.kuali.rice.krad.datadictionary.validation.processor.ConstraintProcessor;
43 import org.kuali.rice.krad.datadictionary.validation.result.ConstraintValidationResult;
44 import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
45 import org.kuali.rice.krad.datadictionary.validation.result.ProcessorResult;
46 import org.kuali.rice.krad.document.Document;
47 import org.kuali.rice.krad.document.TransactionalDocument;
48 import org.kuali.rice.krad.service.DataDictionaryService;
49 import org.kuali.rice.krad.service.DictionaryValidationService;
50 import org.kuali.rice.krad.service.DocumentDictionaryService;
51 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
52 import org.kuali.rice.krad.service.LegacyDataAdapter;
53 import org.kuali.rice.krad.uif.UifConstants;
54 import org.kuali.rice.krad.uif.util.ConstraintStateUtils;
55 import org.kuali.rice.krad.util.ErrorMessage;
56 import org.kuali.rice.krad.util.GlobalVariables;
57 import org.kuali.rice.krad.util.KRADUtils;
58 import org.kuali.rice.krad.util.MessageMap;
59 import org.springframework.beans.PropertyAccessorUtils;
60
61 import java.beans.PropertyDescriptor;
62 import java.lang.reflect.InvocationTargetException;
63 import java.util.Collection;
64 import java.util.IdentityHashMap;
65 import java.util.Iterator;
66 import java.util.LinkedList;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Queue;
70 import java.util.Set;
71
72
73
74
75
76
77
78
79
80
81 public class DictionaryValidationServiceImpl implements DictionaryValidationService {
82 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
83 DictionaryValidationServiceImpl.class);
84
85
86
87
88
89 public static final String VALIDATE_METHOD = "validate";
90
91 protected DataDictionaryService dataDictionaryService;
92
93
94 protected DocumentDictionaryService documentDictionaryService;
95
96 @Deprecated
97 private LegacyDataAdapter legacyDataAdapter;
98
99 @SuppressWarnings("unchecked")
100 private List<CollectionConstraintProcessor> collectionConstraintProcessors;
101 @SuppressWarnings("unchecked")
102 private List<ConstraintProvider> constraintProviders;
103 @SuppressWarnings("unchecked")
104 private List<ConstraintProcessor> elementConstraintProcessors;
105
106
107
108
109
110
111 protected final Set<Object> newIdentitySet() {
112 return java.util.Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());
113 }
114
115
116
117
118 @Override
119 public DictionaryValidationResult validate(Object object) {
120 return validate(object, object.getClass().getName(), (String) null, true);
121 }
122
123
124
125
126
127 @Override
128 public DictionaryValidationResult validate(Object object, String entryName, String attributeName,
129 boolean doOptionalProcessing) {
130 StateMapping stateMapping = null;
131 String validationState = null;
132 DataDictionaryEntry entry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(entryName);
133 if (entry != null) {
134 stateMapping = entry.getStateMapping();
135 if (stateMapping != null) {
136 validationState = stateMapping.getCurrentState(object);
137 }
138 }
139
140 AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object, entryName, entry);
141 attributeValueReader.setAttributeName(attributeName);
142 return validate(attributeValueReader, doOptionalProcessing, validationState, stateMapping);
143 }
144
145
146
147
148 @Override
149 public DictionaryValidationResult validateAgainstNextState(Object object) {
150 String entryName = object.getClass().getName();
151 StateMapping stateMapping = null;
152 String validationState = null;
153 DataDictionaryEntry entry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(entryName);
154 if (entry != null) {
155 stateMapping = entry.getStateMapping();
156 if (stateMapping != null) {
157 validationState = stateMapping.getNextState(object);
158 }
159 }
160 AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object, entryName, entry);
161 return validate(attributeValueReader, true, validationState, stateMapping);
162 }
163
164
165
166
167 @Override
168 public DictionaryValidationResult validateAgainstState(Object object, String validationState) {
169 String entryName = object.getClass().getName();
170 StateMapping stateMapping = null;
171 DataDictionaryEntry entry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(entryName);
172 if (entry != null) {
173 stateMapping = entry.getStateMapping();
174 if (stateMapping != null && StringUtils.isBlank(validationState)) {
175 validationState = stateMapping.getCurrentState(object);
176 }
177 }
178
179 AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object, entryName, entry);
180 return validate(attributeValueReader, true, validationState, stateMapping);
181 }
182
183
184
185
186 @Override
187 public DictionaryValidationResult validate(Object object, String entryName, DataDictionaryEntry entry,
188 boolean doOptionalProcessing) {
189 StateMapping stateMapping = null;
190 String validationState = null;
191 if (entry != null) {
192 stateMapping = entry.getStateMapping();
193 if (stateMapping != null) {
194 validationState = stateMapping.getCurrentState(object);
195 }
196 }
197 AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object, entryName, entry);
198 return validate(attributeValueReader, doOptionalProcessing, validationState, stateMapping);
199 }
200
201
202
203
204 @Override
205 public void validateDocument(Document document) {
206 String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
207
208 validate(document, documentEntryName, (String) null, true);
209 }
210
211
212
213
214
215 @Override
216 public void validateDocumentAttribute(Document document, String attributeName, String errorPrefix) {
217 String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
218
219 validate(document, documentEntryName, attributeName, true);
220 }
221
222
223
224
225
226 @Override
227 public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth,
228 boolean validateRequired) {
229 validateDocumentAndUpdatableReferencesRecursively(document, maxDepth, validateRequired, false);
230 }
231
232
233
234
235
236 @Override
237 public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth,
238 boolean validateRequired, boolean chompLastLetterSFromCollectionName) {
239 String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
240 validate(document, documentEntryName, (String) null, true);
241
242 if (maxDepth > 0) {
243 validateUpdatabableReferencesRecursively(document, maxDepth - 1, validateRequired,
244 chompLastLetterSFromCollectionName, newIdentitySet());
245 }
246 }
247
248 protected void validateUpdatabableReferencesRecursively(Object businessObject, int maxDepth,
249 boolean validateRequired, boolean chompLastLetterSFromCollectionName, Set<Object> processedBOs) {
250
251 if (KRADUtils.isNull(businessObject) || processedBOs.contains(businessObject)) {
252 return;
253 }
254 processedBOs.add(businessObject);
255 Map<String, Class> references = getLegacyDataAdapter().listReferenceObjectFields(businessObject.getClass());
256 for (String referenceName : references.keySet()) {
257 if (getLegacyDataAdapter().isReferenceUpdatable(businessObject.getClass(), referenceName)) {
258 Object referenceObj = KradDataServiceLocator.getDataObjectService().wrap(businessObject)
259 .getPropertyValueNullSafe(referenceName);
260
261 if (KRADUtils.isNull(referenceObj) || !(referenceObj instanceof PersistableBusinessObject)) {
262 continue;
263 }
264
265 BusinessObject referenceBusinessObject = (BusinessObject) referenceObj;
266 GlobalVariables.getMessageMap().addToErrorPath(referenceName);
267 validateBusinessObject(referenceBusinessObject, validateRequired);
268 if (maxDepth > 0) {
269 validateUpdatabableReferencesRecursively(referenceBusinessObject, maxDepth - 1, validateRequired,
270 chompLastLetterSFromCollectionName, processedBOs);
271 }
272 GlobalVariables.getMessageMap().removeFromErrorPath(referenceName);
273 }
274 }
275 Map<String, Class> collections = getLegacyDataAdapter().listCollectionObjectTypes(businessObject.getClass());
276 for (String collectionName : collections.keySet()) {
277 if (getLegacyDataAdapter().isCollectionUpdatable(businessObject.getClass(), collectionName)) {
278 Object listObj = KradDataServiceLocator.getDataObjectService().wrap(businessObject)
279 .getPropertyValueNullSafe(collectionName);
280
281 if (KRADUtils.isNull(listObj)) {
282 continue;
283 }
284
285 if (!(listObj instanceof List)) {
286 if (LOG.isInfoEnabled()) {
287 LOG.info("The reference named " + collectionName + " of BO class " +
288 businessObject.getClass().getName() +
289 " should be of type java.util.List to be validated properly.");
290 }
291 continue;
292 }
293
294 List list = (List) listObj;
295
296
297 KRADUtils.materializeObjects(list);
298
299 for (int i = 0; i < list.size(); i++) {
300 final Object o = list.get(i);
301 if (KRADUtils.isNotNull(o) && o instanceof PersistableBusinessObject) {
302 final BusinessObject element = (BusinessObject) o;
303
304 final String errorPathAddition;
305 if (chompLastLetterSFromCollectionName) {
306 errorPathAddition = StringUtils.chomp(collectionName, "s")
307 + "["
308 + Integer.toString(i)
309 + "]";
310 } else {
311 errorPathAddition = collectionName + "[" + Integer.toString(i) + "]";
312 }
313
314 GlobalVariables.getMessageMap().addToErrorPath(errorPathAddition);
315 validateBusinessObject(element, validateRequired);
316 if (maxDepth > 0) {
317 validateUpdatabableReferencesRecursively(element, maxDepth - 1, validateRequired,
318 chompLastLetterSFromCollectionName, processedBOs);
319 }
320 GlobalVariables.getMessageMap().removeFromErrorPath(errorPathAddition);
321 }
322 }
323 }
324 }
325 }
326
327
328
329
330 @Override
331 public boolean isBusinessObjectValid(Object businessObject) {
332 return isBusinessObjectValid(businessObject, null);
333 }
334
335
336
337
338
339 @Override
340 public boolean isBusinessObjectValid(Object businessObject, String prefix) {
341 final MessageMap errorMap = GlobalVariables.getMessageMap();
342 int originalErrorCount = errorMap.getErrorCount();
343
344 errorMap.addToErrorPath(prefix);
345 validateBusinessObject(businessObject);
346 errorMap.removeFromErrorPath(prefix);
347
348 return errorMap.getErrorCount() == originalErrorCount;
349 }
350
351
352
353
354 public void validateBusinessObjectsRecursively(Object businessObject, int depth) {
355 if (KRADUtils.isNull(businessObject)) {
356 return;
357 }
358
359
360 validateBusinessObject(businessObject);
361
362
363 validateBusinessObjectsFromDescriptors(businessObject, PropertyUtils.getPropertyDescriptors(
364 businessObject.getClass()), depth);
365 }
366
367
368
369
370 @Override
371 public void validateBusinessObject(Object businessObject) {
372 validateBusinessObject(businessObject, true);
373 }
374
375
376
377
378
379 @Override
380 public void validateBusinessObject(Object businessObject, boolean validateRequired) {
381 if (KRADUtils.isNull(businessObject)) {
382 return;
383 }
384
385 validate(businessObject, businessObject.getClass().getName(), (String) null, validateRequired);
386 }
387
388
389
390
391
392
393
394
395
396 protected void validateBusinessObjectsFromDescriptors(Object object, PropertyDescriptor[] propertyDescriptors,
397 int depth) {
398 DataObjectWrapper<Object> wrapper = KradDataServiceLocator.getDataObjectService().wrap(object);
399
400 for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
401
402 if (propertyDescriptor.getPropertyType() != null &&
403 PersistableBusinessObject.class.isAssignableFrom(propertyDescriptor.getPropertyType()) &&
404 wrapper.getPropertyValueNullSafe(propertyDescriptor.getName()) != null) {
405 BusinessObject bo = (BusinessObject) wrapper.getPropertyValueNullSafe(propertyDescriptor.getName());
406 if (depth == 0) {
407 GlobalVariables.getMessageMap().addToErrorPath(propertyDescriptor.getName());
408 validateBusinessObject(bo);
409 GlobalVariables.getMessageMap().removeFromErrorPath(propertyDescriptor.getName());
410 } else {
411 validateBusinessObjectsRecursively(bo, depth - 1);
412 }
413 }
414
415
416
417
418
419 else if (propertyDescriptor.getPropertyType() != null &&
420 (List.class).isAssignableFrom(propertyDescriptor.getPropertyType()) &&
421 wrapper.getPropertyValueNullSafe(propertyDescriptor.getName()) != null) {
422 List propertyList = (List) wrapper.getPropertyValueNullSafe(propertyDescriptor.getName());
423 for (int j = 0; j < propertyList.size(); j++) {
424 if (propertyList.get(j) != null && propertyList.get(j) instanceof PersistableBusinessObject) {
425 if (depth == 0) {
426 GlobalVariables.getMessageMap().addToErrorPath(StringUtils.chomp(
427 propertyDescriptor.getName(), "s") + "[" +
428 (new Integer(j)).toString() + "]");
429 validateBusinessObject((BusinessObject) propertyList.get(j));
430 GlobalVariables.getMessageMap().removeFromErrorPath(StringUtils.chomp(
431 propertyDescriptor.getName(), "s") + "[" +
432 (new Integer(j)).toString() + "]");
433 } else {
434 validateBusinessObjectsRecursively((BusinessObject) propertyList.get(j), depth - 1);
435 }
436 }
437 }
438 }
439 }
440 }
441
442
443
444
445
446
447
448
449
450
451 @Override
452 @Deprecated
453 public void validatePrimitiveFromDescriptor(String entryName, Object object, PropertyDescriptor propertyDescriptor,
454 String errorPrefix, boolean validateRequired) {
455
456
457 if (null != propertyDescriptor) {
458 validate(object, entryName, propertyDescriptor.getName(), validateRequired);
459 }
460 }
461
462
463
464
465
466 @Override
467 public boolean validateReferenceExists(Object dataObject, ReferenceDefinition reference) {
468 return validateReferenceExists(dataObject, reference.getAttributeName());
469 }
470
471
472
473
474
475 @Override
476 public boolean validateReferenceExists(Object dataObject, String referenceName) {
477
478
479 Object referenceDataObject = getLegacyDataAdapter().getReferenceIfExists(dataObject, referenceName);
480
481
482 if (KRADUtils.isNotNull(referenceDataObject)) {
483 return true;
484 }
485
486
487 return false;
488 }
489
490
491
492
493
494
495 @Override
496 public boolean validateReferenceIsActive(Object dataObject, ReferenceDefinition reference) {
497 return validateReferenceIsActive(dataObject, reference.getAttributeName());
498 }
499
500
501
502
503
504
505 @Override
506 public boolean validateReferenceIsActive(Object dataObject, String referenceName) {
507
508 Object referenceDataObject = getLegacyDataAdapter().getReferenceIfExists(dataObject, referenceName);
509 if (referenceDataObject == null) {
510 return false;
511 }
512
513 if (!(referenceDataObject instanceof Inactivatable) || ((Inactivatable) referenceDataObject).isActive()) {
514 return true;
515 }
516
517 return false;
518 }
519
520
521
522
523
524
525 @Override
526 public boolean validateReferenceExistsAndIsActive(Object dataObject, ReferenceDefinition reference) {
527 boolean success = true;
528
529
530 String displayFieldName;
531 if (reference.isDisplayFieldNameSet()) {
532 displayFieldName = reference.getDisplayFieldName();
533 } else {
534 Class<?> boClass = reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() :
535 dataObject.getClass();
536 displayFieldName = dataDictionaryService.getAttributeLabel(boClass,
537 reference.getAttributeToHighlightOnFail());
538 }
539
540 if (reference.isCollectionReference()) {
541 success = validateCollectionReferenceExistsAndIsActive(dataObject, reference, displayFieldName,
542 StringUtils.split(reference.getCollection(), "."), null);
543 } else {
544 success = validateReferenceExistsAndIsActive(dataObject, reference.getAttributeName(),
545 reference.getAttributeToHighlightOnFail(), displayFieldName);
546 }
547 return success;
548 }
549
550
551
552
553
554
555
556
557
558
559
560
561 private boolean validateCollectionReferenceExistsAndIsActive(Object dataObject, ReferenceDefinition reference,
562 String displayFieldName, String[] intermediateCollections, String pathToAttributeI) {
563 boolean success = true;
564 Collection<?> referenceCollection;
565 String collectionName = intermediateCollections[0];
566
567 intermediateCollections = (String[]) ArrayUtils.removeElement(intermediateCollections, collectionName);
568 try {
569 referenceCollection = (Collection) PropertyUtils.getProperty(dataObject, collectionName);
570 } catch (Exception e) {
571 throw new RuntimeException(e);
572 }
573
574 int pos = 0;
575 Iterator<?> iterator = referenceCollection.iterator();
576 while (iterator.hasNext()) {
577 String pathToAttribute = StringUtils.defaultString(pathToAttributeI)
578 + collectionName + "[" + (pos++) + "].";
579
580 if (intermediateCollections.length > 0) {
581 success &= validateCollectionReferenceExistsAndIsActive(iterator.next(), reference, displayFieldName,
582 intermediateCollections, pathToAttribute);
583 } else {
584 String attributeToHighlightOnFail = pathToAttribute + reference.getAttributeToHighlightOnFail();
585 success &= validateReferenceExistsAndIsActive(iterator.next(), reference.getAttributeName(),
586 attributeToHighlightOnFail, displayFieldName);
587 }
588 }
589
590 return success;
591 }
592
593
594
595
596
597
598 @Override
599 public boolean validateReferenceExistsAndIsActive(Object dataObject, String referenceName,
600 String attributeToHighlightOnFail, String displayFieldName) {
601
602
603
604
605 if (PropertyAccessorUtils.isNestedOrIndexedProperty(referenceName)) {
606 String nestedAttributePrefix = KRADUtils.getNestedAttributePrefix(referenceName);
607 String nestedAttributePrimitive = KRADUtils.getNestedAttributePrimitive(referenceName);
608 Object nestedObject = KradDataServiceLocator.getDataObjectService().wrap(dataObject)
609 .getPropertyValueNullSafe(nestedAttributePrefix);
610 return validateReferenceExistsAndIsActive(nestedObject, nestedAttributePrimitive,
611 attributeToHighlightOnFail, displayFieldName);
612 }
613
614 boolean hasReferences = validateFkFieldsPopulated(dataObject, referenceName);
615 boolean referenceExists = hasReferences && validateReferenceExists(dataObject, referenceName);
616 boolean canIncludeActiveReference = referenceExists && (!(dataObject instanceof Inactivatable) ||
617 ((Inactivatable) dataObject).isActive());
618 boolean referenceActive = canIncludeActiveReference && validateReferenceIsActive(dataObject, referenceName);
619
620 if(hasReferences && !referenceExists) {
621 GlobalVariables.getMessageMap().putError(attributeToHighlightOnFail, RiceKeyConstants.ERROR_EXISTENCE,
622 displayFieldName);
623 return false;
624 } else if(canIncludeActiveReference && !referenceActive) {
625 GlobalVariables.getMessageMap().putError(attributeToHighlightOnFail, RiceKeyConstants.ERROR_INACTIVE,
626 displayFieldName);
627 return false;
628 }
629
630 return true;
631 }
632
633 private boolean validateFkFieldsPopulated(Object dataObject, String referenceName) {
634
635 List<String> fkFields = getDataDictionaryService().getRelationshipSourceAttributes(
636 dataObject.getClass().getName(), referenceName);
637 if (fkFields != null) {
638 for (String fkFieldName : fkFields) {
639 Object fkFieldValue = null;
640 try {
641 fkFieldValue = PropertyUtils.getProperty(dataObject, fkFieldName);
642 }
643
644
645 catch (IllegalAccessException e) {
646 return false;
647 } catch (InvocationTargetException e) {
648 return false;
649 } catch (NoSuchMethodException e) {
650 return false;
651 }
652
653
654 if (fkFieldValue == null) {
655 return false;
656 } else if (String.class.isAssignableFrom(fkFieldValue.getClass())) {
657 if (StringUtils.isBlank((String) fkFieldValue)) {
658 return false;
659 }
660 }
661 }
662 } else {
663 return getLegacyDataAdapter().allForeignKeyValuesPopulatedForReference(dataObject, referenceName);
664 }
665 return true;
666 }
667
668
669
670
671
672 @Override
673 public boolean validateDefaultExistenceChecks(Object dataObject) {
674 boolean success = true;
675
676
677 Collection references = getDocumentDictionaryService().getDefaultExistenceChecks(dataObject.getClass());
678
679
680 for (Iterator iter = references.iterator(); iter.hasNext(); ) {
681 ReferenceDefinition reference = (ReferenceDefinition) iter.next();
682
683
684 success &= validateReferenceExistsAndIsActive(dataObject, reference);
685 }
686 return success;
687 }
688
689
690
691
692
693
694 @Override
695 public boolean validateDefaultExistenceChecksForNewCollectionItem(Object dataObject, Object newCollectionItem,
696 String collectionName) {
697 boolean success = true;
698
699 if (StringUtils.isNotBlank(collectionName)) {
700
701 Collection references = getDocumentDictionaryService().getDefaultExistenceChecks(dataObject.getClass());
702
703
704 for (Iterator iter = references.iterator(); iter.hasNext(); ) {
705 ReferenceDefinition reference = (ReferenceDefinition) iter.next();
706 if (collectionName != null && collectionName.equals(reference.getCollection())) {
707 String displayFieldName;
708 if (reference.isDisplayFieldNameSet()) {
709 displayFieldName = reference.getDisplayFieldName();
710 } else {
711 Class boClass =
712 reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() :
713 dataObject.getClass();
714 displayFieldName = dataDictionaryService.getAttributeLabel(boClass,
715 reference.getAttributeToHighlightOnFail());
716 }
717
718 success &= validateReferenceExistsAndIsActive(newCollectionItem, reference.getAttributeName(),
719 reference.getAttributeToHighlightOnFail(), displayFieldName);
720 }
721 }
722 }
723
724 return success;
725 }
726
727
728
729
730 @Override
731 public boolean validateDefaultExistenceChecksForTransDoc(TransactionalDocument document) {
732 boolean success = true;
733
734
735 Collection references = getDocumentDictionaryService().getDefaultExistenceChecks(document);
736
737
738 for (Iterator iter = references.iterator(); iter.hasNext(); ) {
739 ReferenceDefinition reference = (ReferenceDefinition) iter.next();
740
741
742 success &= validateReferenceExistsAndIsActive(document, reference);
743 }
744 return success;
745 }
746
747
748
749
750
751 @Override
752 public boolean validateDefaultExistenceChecksForNewCollectionItem(TransactionalDocument document,
753 Object newCollectionItem, String collectionName) {
754 boolean success = true;
755 if (StringUtils.isNotBlank(collectionName)) {
756
757 Collection references = getDocumentDictionaryService().getDefaultExistenceChecks(document);
758
759
760 for (Iterator iter = references.iterator(); iter.hasNext(); ) {
761 ReferenceDefinition reference = (ReferenceDefinition) iter.next();
762 if (collectionName != null && collectionName.equals(reference.getCollection())) {
763 String displayFieldName;
764 if (reference.isDisplayFieldNameSet()) {
765 displayFieldName = reference.getDisplayFieldName();
766 } else {
767 Class boClass =
768 reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() :
769 document.getClass();
770 displayFieldName = dataDictionaryService.getAttributeLabel(boClass,
771 reference.getAttributeToHighlightOnFail());
772 }
773
774 success &= validateReferenceExistsAndIsActive(newCollectionItem, reference.getAttributeName(),
775 reference.getAttributeToHighlightOnFail(), displayFieldName);
776 }
777 }
778 }
779 return success;
780 }
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800 @Override
801 public DictionaryValidationResult validate(AttributeValueReader valueReader, boolean doOptionalProcessing,
802 String validationState, StateMapping stateMapping) {
803 DictionaryValidationResult result = new DictionaryValidationResult();
804
805 if (valueReader.getAttributeName() == null) {
806 validateObject(result, valueReader, doOptionalProcessing, true, validationState, stateMapping);
807 } else {
808 validateAttribute(result, valueReader, doOptionalProcessing, validationState, stateMapping);
809 }
810
811 if (result.getNumberOfErrors() > 0) {
812
813 String[] prefixParams = new String[1];
814 String prefixMessageKey = UifConstants.Messages.STATE_PREFIX;
815 if (stateMapping != null) {
816 prefixParams[0] = stateMapping.getStateNameMessage(validationState);
817 }
818
819 if (StringUtils.isBlank(prefixParams[0])) {
820 prefixMessageKey = null;
821 }
822
823 for (Iterator<ConstraintValidationResult> iterator = result.iterator(); iterator.hasNext(); ) {
824 ConstraintValidationResult constraintValidationResult = iterator.next();
825 if (constraintValidationResult.getStatus().getLevel() >= ErrorLevel.WARN.getLevel()) {
826 String attributePath = constraintValidationResult.getAttributePath();
827 if (attributePath == null || attributePath.isEmpty()) {
828 attributePath = constraintValidationResult.getAttributeName();
829 }
830
831 if (constraintValidationResult.getConstraintLabelKey() != null) {
832 ErrorMessage errorMessage = new ErrorMessage(constraintValidationResult.getConstraintLabelKey(),
833 constraintValidationResult.getErrorParameters());
834 errorMessage.setMessagePrefixKey(prefixMessageKey);
835 errorMessage.setMessagePrefixParameters(prefixParams);
836 GlobalVariables.getMessageMap().putError(attributePath, errorMessage);
837 } else {
838 ErrorMessage errorMessage = new ErrorMessage(constraintValidationResult.getErrorKey(),
839 constraintValidationResult.getErrorParameters());
840 errorMessage.setMessagePrefixKey(prefixMessageKey);
841 errorMessage.setMessagePrefixParameters(prefixParams);
842 GlobalVariables.getMessageMap().putError(attributePath, errorMessage);
843 }
844 }
845 }
846 }
847
848 return result;
849 }
850
851
852
853
854
855
856
857
858
859
860
861 protected void processElementConstraints(DictionaryValidationResult result, Object value, Constrainable definition,
862 AttributeValueReader attributeValueReader, boolean doOptionalProcessing, String validationState,
863 StateMapping stateMapping) {
864 processConstraints(result, elementConstraintProcessors, value, definition, attributeValueReader,
865 doOptionalProcessing, validationState, stateMapping);
866 }
867
868
869
870
871
872
873
874
875
876
877
878 protected void processCollectionConstraints(DictionaryValidationResult result, Collection<?> collection,
879 Constrainable definition, AttributeValueReader attributeValueReader, boolean doOptionalProcessing,
880 String validationState, StateMapping stateMapping) {
881 processConstraints(result, collectionConstraintProcessors, collection, definition, attributeValueReader,
882 doOptionalProcessing, validationState, stateMapping);
883 }
884
885
886
887
888
889
890
891
892
893
894
895
896 @SuppressWarnings("unchecked")
897 private void processConstraints(DictionaryValidationResult result,
898 List<? extends ConstraintProcessor> constraintProcessors, Object value, Constrainable definition,
899 AttributeValueReader attributeValueReader, boolean doOptionalProcessing, String validationState,
900 StateMapping stateMapping) {
901
902
903 if (constraintProcessors != null) {
904 Constrainable selectedDefinition = definition;
905 AttributeValueReader selectedAttributeValueReader = attributeValueReader;
906
907
908
909 Queue<Constraint> constraintQueue = new LinkedList<Constraint>();
910
911
912 for (ConstraintProcessor<Object, Constraint> processor : constraintProcessors) {
913
914
915 if (!doOptionalProcessing && processor.isOptional()) {
916 result.addSkipped(attributeValueReader, processor.getName());
917 continue;
918 }
919
920 Class<? extends Constraint> constraintType = processor.getConstraintType();
921
922
923 for (ConstraintProvider constraintProvider : constraintProviders) {
924 if (constraintProvider.isSupported(selectedDefinition)) {
925 Collection<Constraint> constraintList = constraintProvider.getConstraints(selectedDefinition,
926 constraintType);
927 if (constraintList != null) {
928 constraintQueue.addAll(constraintList);
929 }
930 }
931 }
932
933
934 if (constraintQueue.isEmpty()) {
935 result.addSkipped(attributeValueReader, processor.getName());
936 continue;
937 }
938
939 Collection<Constraint> additionalConstraints = new LinkedList<Constraint>();
940
941
942
943 while (!constraintQueue.isEmpty()) {
944
945 Constraint constraint = constraintQueue.poll();
946
947
948
949
950 if (!constraintType.isInstance(constraint)) {
951 result.addSkipped(attributeValueReader, processor.getName());
952 additionalConstraints.add(constraint);
953 continue;
954 }
955
956 constraint = ConstraintStateUtils.getApplicableConstraint(constraint, validationState,
957 stateMapping);
958
959 if (constraint != null) {
960 ProcessorResult processorResult = processor.process(result, value, constraint,
961 selectedAttributeValueReader);
962
963 Collection<Constraint> processorResultContraints = processorResult.getConstraints();
964 if (processorResultContraints != null && processorResultContraints.size() > 0) {
965 constraintQueue.addAll(processorResultContraints);
966 }
967
968
969 if (processorResult.isDefinitionProvided()) {
970 selectedDefinition = processorResult.getDefinition();
971 }
972
973 if (processorResult.isAttributeValueReaderProvided()) {
974 selectedAttributeValueReader = processorResult.getAttributeValueReader();
975 }
976 }
977 }
978
979
980 constraintQueue.addAll(additionalConstraints);
981 }
982 }
983 }
984
985
986
987
988
989
990
991
992
993
994 protected void validateAttribute(DictionaryValidationResult result, AttributeValueReader attributeValueReader,
995 boolean checkIfRequired, String validationState,
996 StateMapping stateMapping) throws AttributeValidationException {
997 Constrainable definition = attributeValueReader.getDefinition(attributeValueReader.getAttributeName());
998 validateAttribute(result, definition, attributeValueReader, checkIfRequired, validationState, stateMapping);
999 }
1000
1001
1002
1003
1004
1005
1006
1007 protected void validateAttribute(DictionaryValidationResult result, Constrainable definition,
1008 AttributeValueReader attributeValueReader, boolean checkIfRequired, String validationState,
1009 StateMapping stateMapping) throws AttributeValidationException {
1010
1011 if (definition == null) {
1012 throw new AttributeValidationException(
1013 "Unable to validate constraints for attribute \"" + attributeValueReader.getAttributeName() +
1014 "\" on entry \"" + attributeValueReader.getEntryName() +
1015 "\" because no attribute definition can be found.");
1016 }
1017
1018 Object value = attributeValueReader.getValue();
1019
1020 processElementConstraints(result, value, definition, attributeValueReader, checkIfRequired, validationState,
1021 stateMapping);
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034 protected void validateObject(DictionaryValidationResult result, AttributeValueReader attributeValueReader,
1035 boolean doOptionalProcessing, boolean processAttributes, String validationState,
1036 StateMapping stateMapping) throws AttributeValidationException {
1037
1038
1039 Constrainable objectEntry = attributeValueReader.getEntry();
1040 processElementConstraints(result, attributeValueReader.getObject(), objectEntry, attributeValueReader,
1041 doOptionalProcessing, validationState, stateMapping);
1042
1043 List<Constrainable> definitions = attributeValueReader.getDefinitions();
1044
1045
1046 if (null == definitions) {
1047 return;
1048 }
1049
1050
1051 if (processAttributes) {
1052 for (Constrainable definition : definitions) {
1053 String attributeName = definition.getName();
1054 attributeValueReader.setAttributeName(attributeName);
1055
1056 if (attributeValueReader.isReadable()) {
1057 Object value = attributeValueReader.getValue(attributeName);
1058
1059 processElementConstraints(result, value, definition, attributeValueReader, doOptionalProcessing,
1060 validationState, stateMapping);
1061 }
1062 }
1063 }
1064
1065
1066 if (objectEntry instanceof DataDictionaryEntryBase) {
1067 List<ComplexAttributeDefinition> complexAttrDefinitions =
1068 ((DataDictionaryEntryBase) objectEntry).getComplexAttributes();
1069
1070 if (complexAttrDefinitions != null) {
1071 for (ComplexAttributeDefinition complexAttrDefinition : complexAttrDefinitions) {
1072 String attributeName = complexAttrDefinition.getName();
1073 attributeValueReader.setAttributeName(attributeName);
1074
1075 if (attributeValueReader.isReadable()) {
1076 Object value = attributeValueReader.getValue();
1077
1078 DataDictionaryEntry childEntry = complexAttrDefinition.getDataObjectEntry();
1079 if (value != null) {
1080 AttributeValueReader nestedAttributeValueReader = new DictionaryObjectAttributeValueReader(
1081 value, childEntry.getFullClassName(), childEntry, attributeValueReader.getPath());
1082 nestedAttributeValueReader.setAttributeName(attributeValueReader.getAttributeName());
1083
1084
1085 validateObject(result, nestedAttributeValueReader, doOptionalProcessing, false,
1086 validationState, stateMapping);
1087 }
1088
1089 processElementConstraints(result, value, complexAttrDefinition, attributeValueReader,
1090 doOptionalProcessing, validationState, stateMapping);
1091 }
1092 }
1093 }
1094 }
1095
1096
1097
1098 DataObjectEntry entry = (DataObjectEntry) attributeValueReader.getEntry();
1099 if (entry != null) {
1100 for (CollectionDefinition collectionDefinition : entry.getCollections()) {
1101
1102
1103 String childEntryName = collectionDefinition.getDataObjectClass();
1104 String attributeName = collectionDefinition.getName();
1105 attributeValueReader.setAttributeName(attributeName);
1106
1107 if (attributeValueReader.isReadable()) {
1108 Collection<?> collectionObject = attributeValueReader.getValue();
1109 DataDictionaryEntry childEntry = childEntryName != null ?
1110 getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(childEntryName) :
1111 null;
1112 if (collectionObject != null) {
1113 int index = 0;
1114 for (Object value : collectionObject) {
1115
1116 String objectAttributePath = attributeValueReader.getPath() + "[" + index + "]";
1117
1118
1119 AttributeValueReader nestedAttributeValueReader = new DictionaryObjectAttributeValueReader(
1120 value, childEntryName, childEntry, objectAttributePath);
1121 validateObject(result, nestedAttributeValueReader, doOptionalProcessing, true,
1122 validationState, stateMapping);
1123 index++;
1124 }
1125 }
1126
1127 processCollectionConstraints(result, collectionObject, collectionDefinition, attributeValueReader,
1128 doOptionalProcessing, validationState, stateMapping);
1129 }
1130 }
1131 }
1132 }
1133
1134
1135
1136
1137
1138
1139 public DataDictionaryService getDataDictionaryService() {
1140 return dataDictionaryService;
1141 }
1142
1143
1144
1145
1146
1147
1148 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1149 this.dataDictionaryService = dataDictionaryService;
1150 }
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160 @SuppressWarnings("unchecked")
1161 public List<CollectionConstraintProcessor> getCollectionConstraintProcessors() {
1162 return this.collectionConstraintProcessors;
1163 }
1164
1165
1166
1167
1168
1169
1170 @SuppressWarnings("unchecked")
1171 public void setCollectionConstraintProcessors(List<CollectionConstraintProcessor> collectionConstraintProcessors) {
1172 this.collectionConstraintProcessors = collectionConstraintProcessors;
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183 @SuppressWarnings("unchecked")
1184 public List<ConstraintProvider> getConstraintProviders() {
1185 return this.constraintProviders;
1186 }
1187
1188
1189
1190
1191
1192
1193 @SuppressWarnings("unchecked")
1194 public void setConstraintProviders(List<ConstraintProvider> constraintProviders) {
1195 this.constraintProviders = constraintProviders;
1196 }
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206 @SuppressWarnings("unchecked")
1207 public List<ConstraintProcessor> getElementConstraintProcessors() {
1208 return this.elementConstraintProcessors;
1209 }
1210
1211
1212
1213
1214
1215
1216 @SuppressWarnings("unchecked")
1217 public void setElementConstraintProcessors(List<ConstraintProcessor> elementConstraintProcessors) {
1218 this.elementConstraintProcessors = elementConstraintProcessors;
1219 }
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229 public DocumentDictionaryService getDocumentDictionaryService() {
1230 if (documentDictionaryService == null) {
1231 this.documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
1232 }
1233 return documentDictionaryService;
1234 }
1235
1236
1237
1238
1239
1240
1241 public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
1242 this.documentDictionaryService = documentDictionaryService;
1243 }
1244
1245 @Deprecated
1246 public LegacyDataAdapter getLegacyDataAdapter() {
1247 if (legacyDataAdapter == null) {
1248 legacyDataAdapter = KRADServiceLocatorWeb.getLegacyDataAdapter();
1249 }
1250 return legacyDataAdapter;
1251 }
1252 }