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