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