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