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     protected final 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, validateRequired);
226 
227         if (maxDepth > 0) {
228             validateUpdatabableReferencesRecursively(document, maxDepth - 1, validateRequired,
229                     chompLastLetterSFromCollectionName, newIdentitySet());
230         }
231     }
232 
233     protected 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 }