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