Coverage Report - org.kuali.rice.kns.service.impl.DictionaryValidationServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DictionaryValidationServiceImpl
0%
0/481
0%
0/282
3.767
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.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.services.CoreApiServiceLocator;
 22  
 import org.kuali.rice.core.framework.persistence.jdbc.sql.SQLUtils;
 23  
 import org.kuali.rice.core.util.RiceKeyConstants;
 24  
 import org.kuali.rice.core.web.format.DateFormatter;
 25  
 import org.kuali.rice.kns.bo.BusinessObject;
 26  
 import org.kuali.rice.kns.bo.Inactivateable;
 27  
 import org.kuali.rice.kns.bo.PersistableBusinessObject;
 28  
 import org.kuali.rice.kns.datadictionary.AttributeDefinition;
 29  
 import org.kuali.rice.kns.datadictionary.CollectionDefinition;
 30  
 import org.kuali.rice.kns.datadictionary.ComplexAttributeDefinition;
 31  
 import org.kuali.rice.kns.datadictionary.DataDictionaryEntry;
 32  
 import org.kuali.rice.kns.datadictionary.DataDictionaryEntryBase;
 33  
 import org.kuali.rice.kns.datadictionary.DataObjectEntry;
 34  
 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
 35  
 import org.kuali.rice.kns.datadictionary.ReferenceDefinition;
 36  
 import org.kuali.rice.kns.datadictionary.control.ControlDefinition;
 37  
 import org.kuali.rice.kns.datadictionary.exception.AttributeValidationException;
 38  
 import org.kuali.rice.kns.datadictionary.validation.AttributeValueReader;
 39  
 import org.kuali.rice.kns.datadictionary.validation.DictionaryObjectAttributeValueReader;
 40  
 import org.kuali.rice.kns.datadictionary.validation.ErrorLevel;
 41  
 import org.kuali.rice.kns.datadictionary.validation.MaintenanceDocumentAttributeValueReader;
 42  
 import org.kuali.rice.kns.datadictionary.validation.SingleAttributeValueReader;
 43  
 import org.kuali.rice.kns.datadictionary.validation.capability.Constrainable;
 44  
 import org.kuali.rice.kns.datadictionary.validation.constraint.Constraint;
 45  
 import org.kuali.rice.kns.datadictionary.validation.constraint.provider.ConstraintProvider;
 46  
 import org.kuali.rice.kns.datadictionary.validation.processor.CollectionConstraintProcessor;
 47  
 import org.kuali.rice.kns.datadictionary.validation.processor.ConstraintProcessor;
 48  
 import org.kuali.rice.kns.datadictionary.validation.result.ConstraintValidationResult;
 49  
 import org.kuali.rice.kns.datadictionary.validation.result.DictionaryValidationResult;
 50  
 import org.kuali.rice.kns.datadictionary.validation.result.ProcessorResult;
 51  
 import org.kuali.rice.kns.document.Document;
 52  
 import org.kuali.rice.kns.document.TransactionalDocument;
 53  
 import org.kuali.rice.kns.exception.ObjectNotABusinessObjectRuntimeException;
 54  
 import org.kuali.rice.kns.service.BusinessObjectService;
 55  
 import org.kuali.rice.kns.service.DataDictionaryService;
 56  
 import org.kuali.rice.kns.service.DictionaryValidationService;
 57  
 import org.kuali.rice.kns.service.KNSServiceLocatorInternal;
 58  
 import org.kuali.rice.kns.service.KNSServiceLocatorWeb;
 59  
 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
 60  
 import org.kuali.rice.kns.service.PersistenceService;
 61  
 import org.kuali.rice.kns.service.PersistenceStructureService;
 62  
 import org.kuali.rice.kns.service.TransactionalDocumentDictionaryService;
 63  
 import org.kuali.rice.kns.util.GlobalVariables;
 64  
 import org.kuali.rice.kns.util.KNSConstants;
 65  
 import org.kuali.rice.kns.util.MessageMap;
 66  
 import org.kuali.rice.kns.util.ObjectUtils;
 67  
 import org.kuali.rice.kns.workflow.service.WorkflowAttributePropertyResolutionService;
 68  
 
 69  
 import java.beans.PropertyDescriptor;
 70  
 import java.lang.reflect.InvocationTargetException;
 71  
 import java.lang.reflect.Method;
 72  
 import java.math.BigDecimal;
 73  
 import java.util.Arrays;
 74  
 import java.util.Collection;
 75  
 import java.util.IdentityHashMap;
 76  
 import java.util.Iterator;
 77  
 import java.util.LinkedList;
 78  
 import java.util.List;
 79  
 import java.util.Map;
 80  
 import java.util.Queue;
 81  
 import java.util.Set;
 82  
 import java.util.regex.Pattern;
 83  
 
 84  
 /**
 85  
  * Validates Documents, Business Objects, and Attributes against the data dictionary. Including min, max lengths, and validating
 86  
  * expressions. This is the default, Kuali delivered implementation.
 87  
  * 
 88  
  * KULRICE - 3355 Modified to prevent infinite looping (to maxDepth) scenario when a parent references a child which references a parent
 89  
  */
 90  0
 public class DictionaryValidationServiceImpl implements DictionaryValidationService {
 91  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DictionaryValidationServiceImpl.class);
 92  
 
 93  
     /**
 94  
      * Constant defines a validation method for an attribute value.
 95  
      * <p>Value is "validate"
 96  
      */
 97  
     public static final String VALIDATE_METHOD="validate";
 98  
     
 99  
     private DataDictionaryService dataDictionaryService;
 100  
     private BusinessObjectService businessObjectService;
 101  
     private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 102  
     private TransactionalDocumentDictionaryService transactionalDocumentDictionaryService;
 103  
     private PersistenceService persistenceService;
 104  
     private WorkflowAttributePropertyResolutionService workflowAttributePropertyResolutionService;
 105  
 
 106  
     private PersistenceStructureService persistenceStructureService;
 107  
     
 108  
     @SuppressWarnings("unchecked")
 109  
         private List<CollectionConstraintProcessor> collectionConstraintProcessors;
 110  
     @SuppressWarnings("unchecked")
 111  
     private List<ConstraintProvider> constraintProviders;
 112  
         @SuppressWarnings("unchecked")
 113  
         private List<ConstraintProcessor> elementConstraintProcessors;
 114  
         
 115  
         
 116  
     /** 
 117  
      * creates a new IdentitySet.
 118  
      * @return a new Set
 119  
      */
 120  
     private static Set<BusinessObject> newIdentitySet() {
 121  0
             return java.util.Collections.newSetFromMap(new IdentityHashMap<BusinessObject, Boolean>());
 122  
     }
 123  
     
 124  
     /**
 125  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object)
 126  
      */
 127  
         public DictionaryValidationResult validate(Object object) {
 128  0
             return validate(object, object.getClass().getName(), true);
 129  
     }
 130  
     
 131  
     /**
 132  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object, boolean)
 133  
      */
 134  
         public DictionaryValidationResult validate(Object object, boolean doOptionalProcessing) {
 135  0
             return validate(object, object.getClass().getName(), doOptionalProcessing);
 136  
     }
 137  
     
 138  
     /**
 139  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object, java.lang.String)
 140  
      */
 141  
         public DictionaryValidationResult validate(Object object, String entryName) {
 142  0
             return validate(object, entryName, true);
 143  
     }
 144  
     
 145  
     /**
 146  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object, java.lang.String, boolean)
 147  
      */
 148  
         public DictionaryValidationResult validate(Object object, String entryName, boolean doOptionalProcessing) {
 149  0
             return validate(object, entryName, (String)null, doOptionalProcessing);
 150  
     }
 151  
     
 152  
     /**
 153  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object, java.lang.String, java.lang.String)
 154  
      */
 155  
         public DictionaryValidationResult validate(Object object, String entryName, String attributeName) {
 156  0
             return validate(object, entryName, attributeName, true);
 157  
     }
 158  
     
 159  
     /**
 160  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validate(java.lang.Object, java.lang.String, java.lang.String, boolean)
 161  
      */
 162  
         public DictionaryValidationResult validate(Object object, String entryName, String attributeName, boolean doOptionalProcessing) {
 163  0
             DataDictionaryEntry entry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(entryName);
 164  0
             AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object, entryName, entry);
 165  0
             attributeValueReader.setAttributeName(attributeName);
 166  0
             return validate(attributeValueReader, doOptionalProcessing);
 167  
     }
 168  
     
 169  
     public DictionaryValidationResult validate(Object object, String entryName, DataDictionaryEntry entry, boolean doOptionalProcessing) {
 170  0
             AttributeValueReader attributeValueReader = new DictionaryObjectAttributeValueReader(object,entryName, entry);
 171  0
             return validate(attributeValueReader, doOptionalProcessing);
 172  
     }
 173  
     
 174  
     public void validate(String entryName, String attributeName, Object attributeValue) {
 175  0
             validate(entryName, attributeName, attributeValue, true);
 176  0
     }
 177  
     
 178  
     public void validate(String entryName, String attributeName, Object attributeValue, boolean doOptionalProcessing) {
 179  0
                AttributeDefinition attributeDefinition = getDataDictionaryService().getAttributeDefinition(entryName, attributeName);
 180  
             
 181  0
             if (attributeDefinition == null) {
 182  
                     // FIXME: JLR - this is what the code was doing effectively already, but seems weird not to throw an exception here if you try to validate 
 183  
                     // something that doesn't have an attribute definition
 184  0
                     return;
 185  
             }
 186  
             
 187  0
             SingleAttributeValueReader attributeValueReader = new SingleAttributeValueReader(attributeValue, entryName, attributeName, attributeDefinition);
 188  0
             validate(attributeValueReader, doOptionalProcessing);
 189  0
     }
 190  
     
 191  
     /**
 192  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDocument(org.kuali.rice.kns.document.Document)
 193  
      */
 194  
     @Override
 195  
         public void validateDocument(Document document) {
 196  0
         String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentType();
 197  
 
 198  0
         validate(document, documentEntryName);        
 199  0
     }
 200  
 
 201  
 
 202  
     /**
 203  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDocumentAttribute(org.kuali.rice.kns.document.Document,
 204  
      *      java.lang.String,java.lang.String)
 205  
      */
 206  
     @Override
 207  
         public void validateDocumentAttribute(Document document, String attributeName, String errorPrefix) {
 208  0
         String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentType();
 209  
 
 210  0
         validate(document, documentEntryName, attributeName, true);        
 211  0
     }
 212  
 
 213  
     /**
 214  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDocumentRecursively
 215  
      */
 216  
     @Deprecated public void validateDocumentRecursively(Document document, int depth) {
 217  
         // validate primitives of document
 218  0
         validateDocument(document);
 219  
 
 220  
         // call method to recursively find business objects and validate
 221  0
         validateBusinessObjectsFromDescriptors(document, PropertyUtils.getPropertyDescriptors(document.getClass()), depth);
 222  0
     }
 223  
 
 224  
     public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth, boolean validateRequired) {
 225  0
             validateDocumentAndUpdatableReferencesRecursively(document, maxDepth, validateRequired, false);
 226  0
     }
 227  
     
 228  
     public void validateDocumentAndUpdatableReferencesRecursively(Document document, int maxDepth, boolean validateRequired, boolean chompLastLetterSFromCollectionName) {
 229  0
         String documentEntryName = document.getDocumentHeader().getWorkflowDocument().getDocumentType();
 230  0
         validate(document, documentEntryName);
 231  
         
 232  0
         if (maxDepth > 0) {
 233  0
             validateUpdatabableReferencesRecursively(document, maxDepth - 1, validateRequired, chompLastLetterSFromCollectionName,  newIdentitySet());
 234  
         }
 235  0
     }
 236  
     
 237  
     private void validateUpdatabableReferencesRecursively(BusinessObject businessObject, int maxDepth, boolean validateRequired, boolean chompLastLetterSFromCollectionName, Set<BusinessObject> processedBOs) {
 238  
             // if null or already processed, return
 239  0
             if (ObjectUtils.isNull(businessObject) || processedBOs.contains(businessObject)) {
 240  0
                     return;
 241  
             }
 242  0
         processedBOs.add(businessObject);  // add bo to list to prevent excessive looping
 243  0
             Map<String, Class> references = persistenceStructureService.listReferenceObjectFields(businessObject.getClass());
 244  0
             for (String referenceName : references.keySet()) {
 245  0
                     if (persistenceStructureService.isReferenceUpdatable(businessObject.getClass(), referenceName)) {
 246  0
                             Object referenceObj = ObjectUtils.getPropertyValue(businessObject, referenceName);
 247  
 
 248  0
                             if (ObjectUtils.isNull(referenceObj) || !(referenceObj instanceof PersistableBusinessObject)) {
 249  0
                                     continue;
 250  
                             }
 251  
 
 252  0
                             BusinessObject referenceBusinessObject = (BusinessObject) referenceObj;
 253  0
                             GlobalVariables.getMessageMap().addToErrorPath(referenceName);
 254  0
                             validateBusinessObject(referenceBusinessObject, validateRequired);
 255  0
                             if (maxDepth > 0) {
 256  0
                                     validateUpdatabableReferencesRecursively(referenceBusinessObject, maxDepth - 1, validateRequired, chompLastLetterSFromCollectionName, processedBOs);
 257  
                             }
 258  0
                             GlobalVariables.getMessageMap().removeFromErrorPath(referenceName);
 259  
 
 260  0
                     }
 261  
             }
 262  0
             Map<String, Class> collections = persistenceStructureService.listCollectionObjectTypes(businessObject.getClass());
 263  0
             for (String collectionName : collections.keySet()) {
 264  0
                     if (persistenceStructureService.isCollectionUpdatable(businessObject.getClass(), collectionName)) {
 265  0
                             Object listObj = ObjectUtils.getPropertyValue(businessObject, collectionName);
 266  
 
 267  0
                             if (ObjectUtils.isNull(listObj)) {
 268  0
                                     continue;
 269  
                             }
 270  
 
 271  0
                             if (!(listObj instanceof List)) {
 272  0
                                         if ( LOG.isInfoEnabled() ) {
 273  0
                                                 LOG.info("The reference named " + collectionName + " of BO class " + businessObject.getClass().getName() + " should be of type java.util.List to be validated properly.");
 274  
                                         }
 275  
                                     continue;
 276  
                             }
 277  
 
 278  0
                             List list = (List) listObj;
 279  
                             
 280  
                             //should we materialize the proxied collection or just skip validation here assuming an unmaterialized objects are valid?
 281  0
                             ObjectUtils.materializeObjects(list);
 282  
                             
 283  0
                             for (int i = 0; i < list.size(); i++) {
 284  0
                                     final Object o = list.get(i);
 285  0
                                     if (ObjectUtils.isNotNull(o) && o instanceof PersistableBusinessObject) {
 286  0
                                             final BusinessObject element = (BusinessObject) o;
 287  
                                             
 288  
                                             final String errorPathAddition;
 289  0
                                             if (chompLastLetterSFromCollectionName) {
 290  0
                                                     errorPathAddition = StringUtils.chomp(collectionName, "s") + "[" + Integer.toString(i) + "]";
 291  
                                             } else {
 292  0
                                                     errorPathAddition = collectionName + "[" + Integer.toString(i) + "]";
 293  
                                             }
 294  
 
 295  0
                                             GlobalVariables.getMessageMap().addToErrorPath(errorPathAddition);
 296  0
                                             validateBusinessObject(element, validateRequired);
 297  0
                                             if (maxDepth > 0) {
 298  0
                                                     validateUpdatabableReferencesRecursively(element, maxDepth - 1, validateRequired, chompLastLetterSFromCollectionName, processedBOs);
 299  
                                             }
 300  0
                                             GlobalVariables.getMessageMap().removeFromErrorPath(errorPathAddition);
 301  
                                     }
 302  
                             }
 303  0
                     }
 304  
             }
 305  0
     }
 306  
     
 307  
     /**
 308  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateBusinessObject(org.kuali.rice.kns.bo.BusinessObject)
 309  
      */
 310  
     @Override
 311  
     public void validateBusinessObject(BusinessObject businessObject) {
 312  0
         validateBusinessObject(businessObject, true);
 313  0
     }
 314  
 
 315  
     /**
 316  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateBusinessObject(org.kuali.rice.kns.bo.BusinessObject,boolean)
 317  
      */
 318  
     @Override
 319  
     public void validateBusinessObject(BusinessObject businessObject, boolean validateRequired) {
 320  0
         if (ObjectUtils.isNull(businessObject)) {
 321  0
             return;
 322  
         }
 323  
         
 324  0
         validate(businessObject, businessObject.getClass().getName());        
 325  0
     }
 326  
 
 327  
     /**
 328  
          * @see org.kuali.rice.kns.service.DictionaryValidationService#validateBusinessObjectOnMaintenanceDocument(org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
 329  
          * 
 330  
          * @deprecated since 1.1
 331  
          */
 332  
         @Deprecated public void validateBusinessObjectOnMaintenanceDocument(BusinessObject businessObject, String docTypeName) {
 333  
 
 334  0
                 MaintenanceDocumentEntry entry = KNSServiceLocatorWeb.getMaintenanceDocumentDictionaryService().getMaintenanceDocumentEntry(docTypeName);
 335  0
                 validate(new MaintenanceDocumentAttributeValueReader(businessObject, docTypeName, entry, persistenceStructureService), true);
 336  0
         }
 337  
         
 338  
 //        protected void validateBusinessObjectOnMaintenanceDocumentHelper(BusinessObject businessObject, List<? extends MaintainableItemDefinition> itemDefinitions, String errorPrefix) {
 339  
 //                
 340  
 //                for (MaintainableItemDefinition itemDefinition : itemDefinitions) {
 341  
 //                        if (itemDefinition instanceof MaintainableFieldDefinition) {
 342  
 //                        if (getDataDictionaryService().isAttributeDefined(businessObject.getClass(), itemDefinition.getName())) {
 343  
 //                            Object value = ObjectUtils.getPropertyValue(businessObject, itemDefinition.getName());
 344  
 //                            if (value != null && StringUtils.isNotBlank(value.toString())) {
 345  
 //                                    Class propertyType = ObjectUtils.getPropertyType(businessObject, itemDefinition.getName(), persistenceStructureService);
 346  
 //                                    if (TypeUtils.isStringClass(propertyType) || TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType) || TypeUtils.isTemporalClass(propertyType)) {
 347  
 //                                        // check value format against dictionary
 348  
 //                                    if (!TypeUtils.isTemporalClass(propertyType)) {
 349  
 //                                        validateAttributeFormat(businessObject.getClass().getName(), itemDefinition.getName(), value.toString(), errorPrefix + itemDefinition.getName());
 350  
 //                                    }
 351  
 //                                    }
 352  
 //                            }
 353  
 //                        }
 354  
 //                        }
 355  
 //                        /*
 356  
 //                        TODO: reenable when we come up with a strategy to handle fields that are not editable
 357  
 //                        else if (itemDefinition instanceof MaintainableCollectionDefinition) {
 358  
 //                                MaintainableCollectionDefinition collectionDefinition = (MaintainableCollectionDefinition) itemDefinition;
 359  
 //                                Collection<BusinessObject> c = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(businessObject, itemDefinition.getName());
 360  
 //                                if (c != null) {
 361  
 //                                        int i = 0;
 362  
 //                                        for (BusinessObject o : c) {
 363  
 //                                                String newErrorPrefix = errorPrefix + itemDefinition.getName() + "[" + i + "].";
 364  
 //                                                validateBusinessObjectOnMaintenanceDocumentHelper(o, collectionDefinition.getMaintainableCollections(), newErrorPrefix);
 365  
 //                                                validateBusinessObjectOnMaintenanceDocumentHelper(o, collectionDefinition.getMaintainableFields(), newErrorPrefix);
 366  
 //                                                i++;
 367  
 //                                        }
 368  
 //                                }
 369  
 //                        }*/
 370  
 //                }
 371  
 //        }
 372  
 
 373  
 
 374  
         /**
 375  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#isBusinessObjectValid(org.kuali.rice.kns.bo.BusinessObject)
 376  
      */
 377  
     public boolean isBusinessObjectValid(BusinessObject businessObject) {
 378  0
         return isBusinessObjectValid(businessObject, null);
 379  
     }
 380  
 
 381  
     /**
 382  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#isBusinessObjectValid(org.kuali.rice.kns.bo.BusinessObject, String)
 383  
      */
 384  
     public boolean isBusinessObjectValid(BusinessObject businessObject, String prefix) {
 385  0
         final MessageMap errorMap = GlobalVariables.getMessageMap();
 386  0
         int originalErrorCount = errorMap.getErrorCount();
 387  
 
 388  0
         errorMap.addToErrorPath(prefix);
 389  0
         validateBusinessObject(businessObject);
 390  0
         errorMap.removeFromErrorPath(prefix);
 391  
 
 392  0
         return errorMap.getErrorCount() == originalErrorCount;
 393  
     }
 394  
 
 395  
 
 396  
     /**
 397  
      * @param businessObject - business object to validate
 398  
      */
 399  
     public void validateBusinessObjectsRecursively(BusinessObject businessObject, int depth) {
 400  0
         if (ObjectUtils.isNull(businessObject)) {
 401  0
             return;
 402  
         }
 403  
 
 404  
         // validate primitives and any specific bo validation
 405  0
         validateBusinessObject(businessObject);
 406  
 
 407  
         // call method to recursively find business objects and validate
 408  0
         validateBusinessObjectsFromDescriptors(businessObject, PropertyUtils.getPropertyDescriptors(businessObject.getClass()), depth);
 409  0
     }
 410  
 
 411  
 
 412  
     /**
 413  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateAttributeFormat
 414  
      * objectClassName is the docTypeName
 415  
      * 
 416  
      * @deprecated since 1.1
 417  
      */
 418  
     @Deprecated public void validateAttributeFormat(String objectClassName, String attributeName, String attributeInValue, String errorKey) {
 419  
         // Retrieve the field's data type, or set to the string data type if an exception occurs when retrieving the class or the DD entry.
 420  0
         String attributeDataType = null;
 421  
         try {
 422  0
                 attributeDataType = getWorkflowAttributePropertyResolutionService().determineFieldDataType((Class<? extends BusinessObject>)Class.forName(
 423  
                                 getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(objectClassName).getFullClassName()), attributeName);
 424  0
         } catch(ClassNotFoundException e) {
 425  0
                 attributeDataType = KNSConstants.DATA_TYPE_STRING;
 426  0
         } catch (NullPointerException e) {
 427  0
                 attributeDataType = KNSConstants.DATA_TYPE_STRING;
 428  0
         }
 429  
         
 430  0
         validateAttributeFormat(objectClassName, attributeName, attributeInValue, attributeDataType, errorKey);
 431  0
     }
 432  
 
 433  
     /**
 434  
      * The attributeDataType parameter should be one of the data types specified by the SearchableAttribute interface; will
 435  
      * default to DATA_TYPE_STRING if a data type other than the ones from SearchableAttribute is specified.
 436  
      * 
 437  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateAttributeFormat(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
 438  
      * objectClassName is the docTypeName
 439  
      * 
 440  
      * @deprecated since 1.1
 441  
      */
 442  
     @Deprecated public void validateAttributeFormat(String objectClassName, String attributeName, String attributeInValue, String attributeDataType, String errorKey) {
 443  0
             boolean checkDateBounds = false; // this is used so we can check date bounds
 444  0
             Class<?> formatterClass = null;
 445  
 
 446  0
             if ( LOG.isDebugEnabled() ) {
 447  0
                     LOG.debug("(bo, attributeName, attributeValue) = (" + objectClassName + "," + attributeName + "," + attributeInValue + ")");
 448  
             }
 449  
 
 450  
             /*
 451  
              *  This will return a list of searchable attributes. so if the value is
 452  
              *  12/07/09 .. 12/08/09 it will return [12/07/09,12/08/09]
 453  
              */
 454  
 
 455  0
             final List<String> attributeValues = SQLUtils.getCleanedSearchableValues(attributeInValue, attributeDataType);
 456  
 
 457  0
             if(attributeValues == null || attributeValues.isEmpty()) {
 458  0
                     return;
 459  
             }
 460  
             
 461  0
             for(String attributeValue : attributeValues){
 462  
 
 463  
                     // FIXME: JLR : Replacing this logic with KS-style validation is trickier, since KS validation requires a DataProvider object that can
 464  
                     // look back and find other attribute values aside from the one we're working on.
 465  
                     // Also - the date stuff below is implemented very differently.
 466  
                     //validator.validateAttributeField(businessObject, fieldName);
 467  
                     
 468  0
                     if (StringUtils.isNotBlank(attributeValue)) {
 469  0
                             Integer minLength = getDataDictionaryService().getAttributeMinLength(objectClassName, attributeName);
 470  0
                             if ((minLength != null) && (minLength.intValue() > attributeValue.length())) {
 471  0
                                     String errorLabel = getDataDictionaryService().getAttributeErrorLabel(objectClassName, attributeName);
 472  0
                                     GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_MIN_LENGTH, new String[] { errorLabel, minLength.toString() });
 473  0
                                     return;
 474  
                             }
 475  0
                             Integer maxLength = getDataDictionaryService().getAttributeMaxLength(objectClassName, attributeName);
 476  0
                             if ((maxLength != null) && (maxLength.intValue() < attributeValue.length())) {
 477  0
                                     String errorLabel = getDataDictionaryService().getAttributeErrorLabel(objectClassName, attributeName);
 478  0
                                     GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_MAX_LENGTH, new String[] { errorLabel, maxLength.toString() });
 479  0
                                     return;
 480  
                             }
 481  0
                             Pattern validationExpression = getDataDictionaryService().getAttributeValidatingExpression(objectClassName, attributeName);
 482  0
                             if (validationExpression != null && !validationExpression.pattern().equals(".*")) {
 483  0
                                     if ( LOG.isDebugEnabled() ) {
 484  0
                                             LOG.debug("(bo, attributeName, validationExpression) = (" + objectClassName + "," + attributeName + "," + validationExpression + ")");
 485  
                                     }
 486  
 
 487  0
                                     if (!validationExpression.matcher(attributeValue).matches()) {
 488  
                                             // Retrieving formatter class
 489  0
                                             if(formatterClass == null){
 490  
                                                     // this is just a cache check... all dates ranges get called twice
 491  0
                                                     formatterClass=getDataDictionaryService().getAttributeFormatter(
 492  
                                                                     objectClassName, attributeName);
 493  
                                             }
 494  
 
 495  0
                                             if (formatterClass != null) {
 496  0
                                                     boolean valuesAreValid = true;
 497  0
                                                     boolean isError=true;
 498  0
                                                     String errorKeyPrefix = "";
 499  
                                                     try {
 500  
 
 501  
                                                             // this is a special case for date ranges in order to set the proper error message
 502  0
                                                             if (DateFormatter.class.isAssignableFrom(formatterClass)) {
 503  0
                                                                     String[] values = attributeInValue.split("\\.\\."); // is it a range
 504  0
                                                                     if(values.length == 2 && attributeValues.size() == 2){ // make sure it's not like a .. b | c
 505  0
                                                                             checkDateBounds = true; // now we need to check that a <= b
 506  0
                                                                             if(attributeValues.indexOf(attributeValue) == 0){ // only care about lower bound
 507  0
                                                                                     errorKeyPrefix = KNSConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX;
 508  
                                                                             }
 509  
                                                                     }
 510  
                                                             }
 511  
 
 512  0
                                                             Method validatorMethod=formatterClass.getDeclaredMethod(
 513  
                                                                             VALIDATE_METHOD, new Class<?>[] {String.class});
 514  0
                                                             Object o=validatorMethod.invoke(
 515  
                                                                             formatterClass.newInstance(), attributeValue);
 516  0
                                                             if (o instanceof Boolean) {
 517  0
                                                                     isError = !((Boolean)o).booleanValue();
 518  
                                                             }
 519  0
                                                             valuesAreValid &= !isError;
 520  0
                                                     } catch (Exception e) {
 521  0
                                                             if ( LOG.isDebugEnabled() ) {
 522  0
                                                                     LOG.debug(e.getMessage(), e);
 523  
                                                             }
 524  0
                                                             isError =true;
 525  0
                                                             valuesAreValid = false;
 526  0
                                                     }
 527  0
                                                     if (isError) {
 528  0
                                                             checkDateBounds = false; // it's already invalid, no need to check date bounds
 529  0
                                                             String errorMessageKey = getDataDictionaryService().getAttributeValidatingErrorMessageKey(objectClassName, attributeName);
 530  0
                                                             String[] errorMessageParameters = getDataDictionaryService().getAttributeValidatingErrorMessageParameters(objectClassName, attributeName);
 531  0
                                                             GlobalVariables.getMessageMap().putError(errorKeyPrefix + errorKey, errorMessageKey, errorMessageParameters);
 532  
                                                     }
 533  0
                                             } else {
 534  
                                                     // if it fails the default validation and has no formatter class then it's still a std failure.
 535  0
                                                     String errorMessageKey = getDataDictionaryService().getAttributeValidatingErrorMessageKey(objectClassName, attributeName);
 536  0
                                                     String[] errorMessageParameters = getDataDictionaryService().getAttributeValidatingErrorMessageParameters(objectClassName, attributeName);
 537  0
                                                     GlobalVariables.getMessageMap().putError(errorKey, errorMessageKey, errorMessageParameters);
 538  
                                             }
 539  
                                     }
 540  
 
 541  
                             }
 542  0
                             /*BigDecimal*/ String exclusiveMin = getDataDictionaryService().getAttributeExclusiveMin(objectClassName, attributeName);
 543  0
                             if (exclusiveMin != null) {
 544  
                                     try {
 545  0
                                             BigDecimal exclusiveMinBigDecimal = new BigDecimal(exclusiveMin);
 546  0
                                             if (exclusiveMinBigDecimal.compareTo(new BigDecimal(attributeValue)) >= 0) {
 547  0
                                                     String errorLabel = getDataDictionaryService().getAttributeErrorLabel(objectClassName, attributeName);
 548  0
                                                     GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_EXCLUSIVE_MIN,
 549  
                                                                     // todo: Formatter for currency?
 550  
                                                                     new String[] { errorLabel, exclusiveMin.toString() });
 551  0
                                                     return;
 552  
                                             }
 553  
                                     }
 554  0
                                     catch (NumberFormatException e) {
 555  
                                             // quash; this indicates that the DD contained a min for a non-numeric attribute
 556  0
                                     }
 557  
                             }
 558  0
                             /*BigDecimal*/ String inclusiveMax = getDataDictionaryService().getAttributeInclusiveMax(objectClassName, attributeName);
 559  0
                             if (inclusiveMax != null) {
 560  
                                     try {
 561  0
                                             BigDecimal inclusiveMaxBigDecimal = new BigDecimal(inclusiveMax);
 562  0
                                             if (inclusiveMaxBigDecimal.compareTo(new BigDecimal(attributeValue)) < 0) {
 563  0
                                                     String errorLabel = getDataDictionaryService().getAttributeErrorLabel(objectClassName, attributeName);
 564  0
                                                     GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_INCLUSIVE_MAX,
 565  
                                                                     // todo: Formatter for currency?
 566  
                                                                     new String[] { errorLabel, inclusiveMax.toString() });
 567  0
                                                     return;
 568  
                                             }
 569  
                                     }
 570  0
                                     catch (NumberFormatException e) {
 571  
                                             // quash; this indicates that the DD contained a max for a non-numeric attribute
 572  0
                                     }
 573  
                             }
 574  0
                     }
 575  
             }
 576  
 
 577  0
             if(checkDateBounds){
 578  
                     // this means that we only have 2 values and it's a date range.
 579  0
                     java.sql.Timestamp lVal = null;
 580  0
                     java.sql.Timestamp uVal = null;
 581  
                     try{
 582  0
                             lVal = CoreApiServiceLocator.getDateTimeService().convertToSqlTimestamp(attributeValues.get(0));
 583  0
                             uVal = CoreApiServiceLocator.getDateTimeService().convertToSqlTimestamp(attributeValues.get(1));
 584  0
                     }catch(Exception ex){
 585  
                             // this shouldn't happen because the tests passed above.
 586  0
                             String errorMessageKey = getDataDictionaryService().getAttributeValidatingErrorMessageKey(objectClassName, attributeName);
 587  0
                             String[] errorMessageParameters = getDataDictionaryService().getAttributeValidatingErrorMessageParameters(objectClassName, attributeName);
 588  0
                             GlobalVariables.getMessageMap().putError(KNSConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + errorKey, errorMessageKey, errorMessageParameters);
 589  0
                     }
 590  
 
 591  0
                     if(lVal != null && lVal.compareTo(uVal) > 0){ // check the bounds
 592  0
                             String errorMessageKey = getDataDictionaryService().getAttributeValidatingErrorMessageKey(objectClassName, attributeName);
 593  0
                             String[] errorMessageParameters = getDataDictionaryService().getAttributeValidatingErrorMessageParameters(objectClassName, attributeName);
 594  0
                             GlobalVariables.getMessageMap().putError(KNSConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + errorKey, errorMessageKey + ".range", errorMessageParameters);
 595  
                     }
 596  
             }
 597  0
     }
 598  
 
 599  
 
 600  
 
 601  
     /**
 602  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateAttributeRequired
 603  
      */
 604  
     // FIXME: JLR - this is now redundant and should be using the same code as the required processing elsewhere, but the control definition stuff doesn't really fit
 605  
     // it doesn't seem to be used anywhere
 606  
     @Deprecated public void validateAttributeRequired(String objectClassName, String attributeName, Object attributeValue, Boolean forMaintenance, String errorKey) {
 607  
         // check if field is a required field for the business object
 608  0
         if (attributeValue == null || (attributeValue instanceof String && StringUtils.isBlank((String) attributeValue))) {
 609  0
             Boolean required = getDataDictionaryService().isAttributeRequired(objectClassName, attributeName);
 610  0
             ControlDefinition controlDef = getDataDictionaryService().getAttributeControlDefinition(objectClassName, attributeName);
 611  
 
 612  0
             if (required != null && required.booleanValue() && !(controlDef != null && controlDef.isHidden())) {
 613  
 
 614  
                 // get label of attribute for message
 615  0
                 String errorLabel = getDataDictionaryService().getAttributeErrorLabel(objectClassName, attributeName);
 616  0
                 GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_REQUIRED, errorLabel);
 617  
             }
 618  
         }
 619  0
     }
 620  
 
 621  
     /**
 622  
      * iterates through the property discriptors looking for business objects or lists of business objects. calls validate method
 623  
      * for each bo found
 624  
      * 
 625  
      * @param object
 626  
      * @param propertyDescriptors
 627  
      */
 628  
     private void validateBusinessObjectsFromDescriptors(Object object, PropertyDescriptor[] propertyDescriptors, int depth) {
 629  0
         for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
 630  
             // validate the properties that are descended from BusinessObject
 631  0
             if (propertyDescriptor.getPropertyType() != null && PersistableBusinessObject.class.isAssignableFrom(propertyDescriptor.getPropertyType()) && ObjectUtils.getPropertyValue(object, propertyDescriptor.getName()) != null) {
 632  0
                 BusinessObject bo = (BusinessObject) ObjectUtils.getPropertyValue(object, propertyDescriptor.getName());
 633  0
                 if (depth == 0) {
 634  0
                     GlobalVariables.getMessageMap().addToErrorPath(propertyDescriptor.getName());
 635  0
                     validateBusinessObject(bo);
 636  0
                     GlobalVariables.getMessageMap().removeFromErrorPath(propertyDescriptor.getName());
 637  
                 }
 638  
                 else {
 639  0
                     validateBusinessObjectsRecursively(bo, depth - 1);
 640  
                 }
 641  0
             }
 642  
 
 643  
             /*
 644  
              * if property is a List, then walk the list and do the validation on each contained object that is a descendent of
 645  
              * BusinessObject
 646  
              */
 647  0
             else if (propertyDescriptor.getPropertyType() != null && (List.class).isAssignableFrom(propertyDescriptor.getPropertyType()) && ObjectUtils.getPropertyValue(object, propertyDescriptor.getName()) != null) {
 648  0
                 List propertyList = (List) ObjectUtils.getPropertyValue(object, propertyDescriptor.getName());
 649  0
                 for (int j = 0; j < propertyList.size(); j++) {
 650  0
                     if (propertyList.get(j) != null && propertyList.get(j) instanceof PersistableBusinessObject) {
 651  0
                         if (depth == 0) {
 652  0
                             GlobalVariables.getMessageMap().addToErrorPath(StringUtils.chomp(propertyDescriptor.getName(), "s") + "[" + (new Integer(j)).toString() + "]");
 653  0
                             validateBusinessObject((BusinessObject) propertyList.get(j));
 654  0
                             GlobalVariables.getMessageMap().removeFromErrorPath(StringUtils.chomp(propertyDescriptor.getName(), "s") + "[" + (new Integer(j)).toString() + "]");
 655  
                         }
 656  
                         else {
 657  0
                             validateBusinessObjectsRecursively((BusinessObject) propertyList.get(j), depth - 1);
 658  
                         }
 659  
                     }
 660  
                 }
 661  
 
 662  
             }
 663  
         }
 664  0
     }
 665  
 
 666  
     /**
 667  
      * calls validate format and required check for the given propertyDescriptor
 668  
      * 
 669  
      * @param entryName
 670  
      * @param object
 671  
      * @param propertyDescriptor
 672  
      * @param errorPrefix
 673  
      * 
 674  
      * @deprecated since 1.1
 675  
      */
 676  
     @Deprecated public void validatePrimitiveFromDescriptor(String entryName, Object object, PropertyDescriptor propertyDescriptor, String errorPrefix, boolean validateRequired) {
 677  
             
 678  
             // validate the primitive attributes if defined in the dictionary
 679  0
         if (null != propertyDescriptor) { 
 680  0
                 validate(object, entryName, propertyDescriptor.getName(), validateRequired);
 681  
         }
 682  0
     }
 683  
 
 684  
     /**
 685  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceExists(org.kuali.rice.kns.bo.BusinessObject,
 686  
      *      org.kuali.rice.kns.datadictionary.ReferenceDefinition)
 687  
      */
 688  
     public boolean validateReferenceExists(BusinessObject bo, ReferenceDefinition reference) {
 689  0
         return validateReferenceExists(bo, reference.getAttributeName());
 690  
     }
 691  
 
 692  
     /**
 693  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceExists(org.kuali.rice.kns.bo.BusinessObject,
 694  
      *      java.lang.String)
 695  
      */
 696  
     public boolean validateReferenceExists(BusinessObject bo, String referenceName) {
 697  
 
 698  
         // attempt to retrieve the specified object from the db
 699  0
         BusinessObject referenceBo = businessObjectService.getReferenceIfExists(bo, referenceName);
 700  
 
 701  
         // if it isn't there, then it doesn't exist, return false
 702  0
         if (ObjectUtils.isNotNull(referenceBo)) {
 703  0
             return true;
 704  
         }
 705  
 
 706  
         // otherwise, it is there, return true
 707  0
         return false;
 708  
     }
 709  
 
 710  
     /**
 711  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceIsActive(org.kuali.rice.kns.bo.BusinessObject,
 712  
      *      org.kuali.rice.kns.datadictionary.ReferenceDefinition)
 713  
      */
 714  
     public boolean validateReferenceIsActive(BusinessObject bo, ReferenceDefinition reference) {
 715  0
         return validateReferenceIsActive(bo, reference.getAttributeName());
 716  
     }
 717  
 
 718  
     /**
 719  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceIsActive(org.kuali.rice.kns.bo.BusinessObject,
 720  
      *      java.lang.String, java.lang.String, boolean)
 721  
      */
 722  
     public boolean validateReferenceIsActive(BusinessObject bo, String referenceName) {
 723  
 
 724  
         // attempt to retrieve the specified object from the db
 725  0
         BusinessObject referenceBo = businessObjectService.getReferenceIfExists(bo, referenceName);
 726  0
         if (referenceBo == null) {
 727  0
                 return false;
 728  
         }
 729  0
         if (!(referenceBo instanceof Inactivateable) || ((Inactivateable) referenceBo).isActive()) {
 730  0
             return true;
 731  
         }
 732  
 
 733  0
         return false;
 734  
     }
 735  
 
 736  
     /**
 737  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceExistsAndIsActive(org.kuali.rice.kns.bo.BusinessObject,
 738  
      *      org.kuali.rice.kns.datadictionary.ReferenceDefinition)
 739  
      */
 740  
     public boolean validateReferenceExistsAndIsActive(BusinessObject bo, ReferenceDefinition reference) {
 741  0
         boolean success = true;
 742  
         // intelligently use the fieldname from the reference, or get it out
 743  
         // of the dataDictionaryService
 744  
         String displayFieldName;
 745  0
         if (reference.isDisplayFieldNameSet()) {
 746  0
             displayFieldName = reference.getDisplayFieldName();
 747  
         }
 748  
         else {
 749  0
             Class<?> boClass = reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() : bo.getClass();
 750  0
             displayFieldName = dataDictionaryService.getAttributeLabel(boClass, reference.getAttributeToHighlightOnFail());
 751  
         }
 752  
 
 753  0
         if (reference.isCollectionReference()) {
 754  0
             success = validateCollectionReferenceExistsAndIsActive(bo, reference, displayFieldName, StringUtils.split(reference.getCollection(), "."), null);
 755  
         }
 756  
         else {
 757  0
             success = validateReferenceExistsAndIsActive(bo, reference.getAttributeName(),reference.getAttributeToHighlightOnFail(), displayFieldName);
 758  
         }
 759  0
         return success;
 760  
     }
 761  
 
 762  
     /**
 763  
      * @param bo the object to get the collection from
 764  
      * @param reference the <code>ReferenceDefinition</code> of the collection to validate
 765  
      * @param displayFieldName the name of the field
 766  
      * @param intermediateCollections array containing the path to the collection as tokens
 767  
      * @param pathToAttribute the rebuilt path to the ReferenceDefinition.attributeToHighlightOnFail which includes the index of
 768  
      *        each subcollection
 769  
      * @return
 770  
      */
 771  
     private boolean validateCollectionReferenceExistsAndIsActive(BusinessObject bo, ReferenceDefinition reference, String displayFieldName, String[] intermediateCollections, String pathToAttributeI) {
 772  0
         boolean success = true;
 773  
         Collection<PersistableBusinessObject> referenceCollection;
 774  0
         String collectionName = intermediateCollections[0];
 775  
         // remove current collection from intermediates
 776  0
         intermediateCollections = (String[]) ArrayUtils.removeElement(intermediateCollections, collectionName);
 777  
         try {
 778  0
             referenceCollection = (Collection) PropertyUtils.getProperty(bo, collectionName);
 779  
         }
 780  0
         catch (Exception e) {
 781  0
             throw new RuntimeException(e);
 782  0
         }
 783  0
         int pos = 0;
 784  0
         Iterator<PersistableBusinessObject> iterator = referenceCollection.iterator();
 785  0
         while (iterator.hasNext()) {
 786  0
             String pathToAttribute = StringUtils.defaultString(pathToAttributeI) + collectionName + "[" + (pos++) + "].";
 787  
             // keep drilling down until we reach the nested collection we want
 788  0
             if (intermediateCollections.length > 0) {
 789  0
                 success &= validateCollectionReferenceExistsAndIsActive(iterator.next(), reference, displayFieldName, intermediateCollections, pathToAttribute);
 790  
             }
 791  
             else {
 792  0
                 String attributeToHighlightOnFail = pathToAttribute + reference.getAttributeToHighlightOnFail();
 793  0
                 success &= validateReferenceExistsAndIsActive(iterator.next(), reference.getAttributeName(), attributeToHighlightOnFail, displayFieldName);
 794  
             }
 795  0
         }
 796  
 
 797  0
         return success;
 798  
 
 799  
     }
 800  
 
 801  
     /**
 802  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateReferenceExistsAndIsActive(org.kuali.rice.kns.bo.BusinessObject,
 803  
      *      java.lang.String, java.lang.String, boolean, boolean, java.lang.String, java.lang.String)
 804  
      */
 805  
 
 806  
     public boolean validateReferenceExistsAndIsActive(BusinessObject bo, String referenceName, String attributeToHighlightOnFail, String displayFieldName) {
 807  
             
 808  
             // if we're dealing with a nested attribute, we need to resolve down to the BO where the primitive attribute is located
 809  
             // this is primarily to deal with the case of a defaultExistenceCheck that uses an "extension", i.e referenceName
 810  
             // would be extension.attributeName
 811  0
             if (ObjectUtils.isNestedAttribute(referenceName)) {
 812  0
                     String nestedAttributePrefix = ObjectUtils.getNestedAttributePrefix(referenceName);
 813  0
                     String nestedAttributePrimitive = ObjectUtils.getNestedAttributePrimitive(referenceName);
 814  0
                     Object nestedObject = ObjectUtils.getPropertyValue(bo, nestedAttributePrefix);
 815  0
                     if (!(nestedObject instanceof BusinessObject)) {
 816  0
                             throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + nestedAttributePrefix + ") is of class: " + "'" + nestedObject.getClass().getName() + "' and is not a " + "descendent of BusinessObject.");
 817  
                     }
 818  0
                     return validateReferenceExistsAndIsActive((BusinessObject)nestedObject, nestedAttributePrimitive, attributeToHighlightOnFail, displayFieldName);
 819  
             }
 820  
             
 821  0
         boolean success = true;
 822  
         boolean exists;
 823  
         boolean active;
 824  
 
 825  0
         boolean fkFieldsPopulated = true;
 826  
         // need to check for DD relationship FKs
 827  0
         List<String> fkFields = getDataDictionaryService().getRelationshipSourceAttributes(bo.getClass().getName(), referenceName);
 828  0
         if (fkFields != null) {
 829  0
             for (String fkFieldName : fkFields) {
 830  0
                 Object fkFieldValue = null;
 831  
                 try {
 832  0
                     fkFieldValue = PropertyUtils.getProperty(bo, fkFieldName);
 833  
                 }
 834  
                 // if we cant retrieve the field value, then
 835  
                 // it doesnt have a value
 836  0
                 catch (IllegalAccessException e) {
 837  0
                     fkFieldsPopulated = false;
 838  
                 }
 839  0
                 catch (InvocationTargetException e) {
 840  0
                     fkFieldsPopulated = false;
 841  
                 }
 842  0
                 catch (NoSuchMethodException e) {
 843  0
                     fkFieldsPopulated = false;
 844  0
                 }
 845  
 
 846  
                 // test the value
 847  0
                 if (fkFieldValue == null) {
 848  0
                     fkFieldsPopulated = false;
 849  
                 }
 850  0
                 else if (String.class.isAssignableFrom(fkFieldValue.getClass())) {
 851  0
                     if (StringUtils.isBlank((String) fkFieldValue)) {
 852  0
                         fkFieldsPopulated = false;
 853  
                     }
 854  
                 }
 855  0
             }
 856  
         }
 857  0
         else if ( bo instanceof PersistableBusinessObject ) { // if no DD relationship exists, check the persistence service
 858  0
             fkFieldsPopulated = persistenceService.allForeignKeyValuesPopulatedForReference((PersistableBusinessObject)bo, referenceName);
 859  
         }
 860  
 
 861  
         // only bother if all the fk fields have values
 862  0
         if (fkFieldsPopulated) {
 863  
 
 864  
             // do the existence test
 865  0
             exists = validateReferenceExists(bo, referenceName);
 866  0
             if (exists) {
 867  
 
 868  
                 // do the active test, if appropriate
 869  0
                 if (!(bo instanceof Inactivateable) || ((Inactivateable) bo).isActive()) {
 870  0
                     active = validateReferenceIsActive(bo, referenceName);
 871  0
                     if (!active) {
 872  0
                         GlobalVariables.getMessageMap().putError(attributeToHighlightOnFail, RiceKeyConstants.ERROR_INACTIVE, displayFieldName);
 873  0
                         success &= false;
 874  
                     }
 875  
                 }
 876  
             }
 877  
             else {
 878  0
                 GlobalVariables.getMessageMap().putError(attributeToHighlightOnFail, RiceKeyConstants.ERROR_EXISTENCE, displayFieldName);
 879  0
                 success &= false;
 880  
             }
 881  
         }
 882  0
         return success;
 883  
     }
 884  
 
 885  
     /**
 886  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDefaultExistenceChecks(org.kuali.rice.kns.bo.BusinessObject)
 887  
      */
 888  
     public boolean validateDefaultExistenceChecks(BusinessObject bo) {
 889  
 
 890  0
         boolean success = true;
 891  
 
 892  
         // get a collection of all the referenceDefinitions setup for this object
 893  0
         Collection references = maintenanceDocumentDictionaryService.getDefaultExistenceChecks(bo.getClass());
 894  
 
 895  
         // walk through the references, doing the tests on each
 896  0
         for (Iterator iter = references.iterator(); iter.hasNext();) {
 897  0
             ReferenceDefinition reference = (ReferenceDefinition) iter.next();
 898  
 
 899  
             // do the existence and validation testing
 900  0
             success &= validateReferenceExistsAndIsActive(bo, reference);
 901  0
         }
 902  0
         return success;
 903  
     }
 904  
     
 905  
     /**
 906  
      * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDefaultExistenceChecksForNewCollectionItem(org.kuali.rice.kns.bo.BusinessObject, org.kuali.rice.kns.bo.BusinessObject, java.lang.String)
 907  
      */
 908  
         public boolean validateDefaultExistenceChecksForNewCollectionItem(BusinessObject bo, BusinessObject newCollectionItem,
 909  
                         String collectionName) {
 910  0
         boolean success = true;
 911  
         
 912  0
         if (StringUtils.isNotBlank(collectionName)) {
 913  
                 // get a collection of all the referenceDefinitions setup for this object
 914  0
                 Collection references = maintenanceDocumentDictionaryService.getDefaultExistenceChecks(bo.getClass());
 915  
         
 916  
                 // walk through the references, doing the tests on each
 917  0
                 for (Iterator iter = references.iterator(); iter.hasNext();) {
 918  0
                     ReferenceDefinition reference = (ReferenceDefinition) iter.next();
 919  0
                                 if(collectionName != null && collectionName.equals(reference.getCollection())){
 920  
                                         String displayFieldName;
 921  0
                             if (reference.isDisplayFieldNameSet()) {
 922  0
                                 displayFieldName = reference.getDisplayFieldName();
 923  
                             }
 924  
                             else {
 925  0
                                 Class boClass = reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() : bo.getClass();
 926  0
                                 displayFieldName = dataDictionaryService.getAttributeLabel(boClass, reference.getAttributeToHighlightOnFail());
 927  
                             }
 928  
                 
 929  0
                             success &= validateReferenceExistsAndIsActive(newCollectionItem, reference.getAttributeName(), reference.getAttributeToHighlightOnFail(), displayFieldName);
 930  
                                 }
 931  0
                 }
 932  
         }
 933  
         
 934  0
         return success;
 935  
         }
 936  
 
 937  
         /**
 938  
          * This overridden method ...
 939  
          * 
 940  
          * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDefaultExistenceChecksForTransDoc(org.kuali.rice.kns.document.TransactionalDocument)
 941  
          */
 942  
         public boolean validateDefaultExistenceChecksForTransDoc(TransactionalDocument document) {
 943  0
         boolean success = true;
 944  
 
 945  
         // get a collection of all the referenceDefinitions setup for this object
 946  0
         Collection references = transactionalDocumentDictionaryService.getDefaultExistenceChecks(document);
 947  
 
 948  
         // walk through the references, doing the tests on each
 949  0
         for (Iterator iter = references.iterator(); iter.hasNext();) {
 950  0
             ReferenceDefinition reference = (ReferenceDefinition) iter.next();
 951  
 
 952  
             // do the existence and validation testing
 953  0
             success &= validateReferenceExistsAndIsActive(document, reference);
 954  0
         }
 955  0
         return success;
 956  
         }
 957  
 
 958  
 
 959  
         /**
 960  
          * This overridden method ...
 961  
          * 
 962  
          * @see org.kuali.rice.kns.service.DictionaryValidationService#validateDefaultExistenceChecksForNewCollectionItem(org.kuali.rice.kns.document.TransactionalDocument, org.kuali.rice.kns.bo.PersistableBusinessObject)
 963  
          */
 964  
         public boolean validateDefaultExistenceChecksForNewCollectionItem(
 965  
                         TransactionalDocument document,
 966  
                         BusinessObject newCollectionItem, String collectionName) {
 967  0
         boolean success = true;
 968  0
         if (StringUtils.isNotBlank(collectionName)) {
 969  
                 // get a collection of all the referenceDefinitions setup for this object
 970  0
                 Collection references = transactionalDocumentDictionaryService.getDefaultExistenceChecks(document);
 971  
         
 972  
                 // walk through the references, doing the tests on each
 973  0
                 for (Iterator iter = references.iterator(); iter.hasNext();) {
 974  0
                     ReferenceDefinition reference = (ReferenceDefinition) iter.next();
 975  0
                                 if(collectionName != null && collectionName.equals(reference.getCollection())){
 976  
                                         String displayFieldName;
 977  0
                             if (reference.isDisplayFieldNameSet()) {
 978  0
                                 displayFieldName = reference.getDisplayFieldName();
 979  
                             }
 980  
                             else {
 981  0
                                 Class boClass = reference.isCollectionReference() ? reference.getCollectionBusinessObjectClass() : document.getClass();
 982  0
                                 displayFieldName = dataDictionaryService.getAttributeLabel(boClass, reference.getAttributeToHighlightOnFail());
 983  
                             }
 984  
                 
 985  0
                             success &= validateReferenceExistsAndIsActive(newCollectionItem, reference.getAttributeName(), reference.getAttributeToHighlightOnFail(), displayFieldName);
 986  
                                 }
 987  0
                 }
 988  
         }
 989  0
         return success;
 990  
         }
 991  
 
 992  
      
 993  
     /*
 994  
      * 1.1 validation methods 
 995  
      */
 996  
         
 997  
         /*
 998  
          * This is the top-level validation method for all attribute value readers
 999  
          */
 1000  
         public DictionaryValidationResult validate(AttributeValueReader valueReader, boolean doOptionalProcessing) {            
 1001  
             
 1002  0
             DictionaryValidationResult result = new DictionaryValidationResult();
 1003  
             
 1004  0
             if (valueReader.getAttributeName() == null){ 
 1005  0
                     validateObject(result, valueReader, doOptionalProcessing);
 1006  
             } else { 
 1007  0
                     validateAttribute(result, valueReader, doOptionalProcessing);
 1008  
             }
 1009  
             
 1010  0
             if (result.getNumberOfErrors() > 0) {
 1011  0
                     for (Iterator<ConstraintValidationResult> iterator = result.iterator() ; iterator.hasNext() ;) {
 1012  0
                             ConstraintValidationResult constraintValidationResult = iterator.next();
 1013  0
                             if (constraintValidationResult.getStatus().getLevel() >= ErrorLevel.WARN.getLevel()) 
 1014  0
                                     setFieldError(constraintValidationResult.getEntryName(), constraintValidationResult.getAttributeName(), constraintValidationResult.getErrorKey(), constraintValidationResult.getErrorParameters());                   
 1015  0
                     }
 1016  
             }
 1017  
             
 1018  0
             return result;
 1019  
     }
 1020  
                 
 1021  
     private void processElementConstraints(DictionaryValidationResult result, Object value, Constrainable definition, AttributeValueReader attributeValueReader, boolean doOptionalProcessing) {
 1022  0
             processConstraints(result, elementConstraintProcessors, value, definition, attributeValueReader, doOptionalProcessing);
 1023  0
     }
 1024  
     
 1025  
     private void processCollectionConstraints(DictionaryValidationResult result, Collection<?> collection, Constrainable definition, AttributeValueReader attributeValueReader, boolean doOptionalProcessing) {
 1026  0
             processConstraints(result, collectionConstraintProcessors, collection, definition, attributeValueReader, doOptionalProcessing);
 1027  0
     }
 1028  
     
 1029  
     @SuppressWarnings("unchecked")
 1030  
         private void processConstraints(DictionaryValidationResult result, List<? extends ConstraintProcessor> constraintProcessors, Object value, Constrainable definition, AttributeValueReader attributeValueReader, boolean doOptionalProcessing) {
 1031  
                 //TODO: Implement custom validators
 1032  
             
 1033  0
             if (constraintProcessors != null) {
 1034  0
                         Constrainable selectedDefinition = definition;
 1035  0
                         AttributeValueReader selectedAttributeValueReader = attributeValueReader;
 1036  
                         
 1037  
                         
 1038  
                         // First - take the constrainable definition and get its constraints
 1039  
                         
 1040  0
                         Queue<Constraint> constraintQueue = new LinkedList<Constraint>();
 1041  
                         
 1042  
                         // Using a for loop to iterate through constraint processors because ordering is important 
 1043  0
                         for (ConstraintProcessor<Object, Constraint> processor : constraintProcessors) {
 1044  
                                 
 1045  
                                 // Let the calling method opt out of any optional processing
 1046  0
                                 if (!doOptionalProcessing && processor.isOptional()) {
 1047  0
                                         result.addSkipped(attributeValueReader, processor.getName());
 1048  0
                                         continue;
 1049  
                                 }
 1050  
                                 
 1051  0
                                 Class<? extends Constraint> constraintType = processor.getConstraintType();
 1052  
                                 
 1053  
                                 // Add all of the constraints for this constraint type for all providers to the queue
 1054  0
                                 for (ConstraintProvider constraintProvider : constraintProviders) {        
 1055  0
                                         if (constraintProvider.isSupported(selectedDefinition)) {
 1056  0
                                                 Collection<Constraint> constraintList = constraintProvider.getConstraints(selectedDefinition, constraintType);
 1057  0
                                                 if (constraintList != null)
 1058  0
                                                         constraintQueue.addAll(constraintList);
 1059  0
                                         }
 1060  
                                 }
 1061  
                                 
 1062  
                                 // If there are no constraints provided for this definition, then just skip it
 1063  0
                                 if (constraintQueue.isEmpty()) {
 1064  0
                                         result.addSkipped(attributeValueReader, processor.getName());
 1065  0
                                         continue;
 1066  
                                 }
 1067  
                                 
 1068  0
                                 Collection<Constraint> additionalConstraints = new LinkedList<Constraint>();
 1069  
                                 
 1070  
                                 // This loop is functionally identical to a for loop, but it has the advantage of letting us keep the queue around
 1071  
                                 // and populate it with any new constraints contributed by the processor
 1072  0
                                 while (!constraintQueue.isEmpty()) {
 1073  
                                         
 1074  0
                                         Constraint constraint = constraintQueue.poll();
 1075  
                                         
 1076  
                                         // If this constraint is not one that this process handles, then skip and add to the queue for the next processor;
 1077  
                                         // obviously this would be redundant (we're only looking at constraints that this processor can process) except that
 1078  
                                         // the previous processor might have stuck a new constraint (or constraints) on the queue
 1079  0
                                         if (!constraintType.isInstance(constraint)) {
 1080  0
                                                 result.addSkipped(attributeValueReader, processor.getName());
 1081  0
                                                 additionalConstraints.add(constraint);
 1082  0
                                                 continue;
 1083  
                                         }
 1084  
                                         
 1085  0
                                         ProcessorResult processorResult = processor.process(result, value, constraint, selectedAttributeValueReader);
 1086  
                                         
 1087  0
                                         Collection<Constraint> processorResultContraints = processorResult.getConstraints();
 1088  0
                                         if (processorResultContraints != null && processorResultContraints.size() > 0)
 1089  0
                                                 additionalConstraints.addAll(processorResultContraints);
 1090  
                                         
 1091  
                                         // Change the selected definition to whatever was returned from the processor
 1092  0
                                         if (processorResult.isDefinitionProvided())
 1093  0
                                                 selectedDefinition = processorResult.getDefinition();
 1094  
                                         // Change the selected attribute value reader to whatever was returned from the processor
 1095  0
                                         if (processorResult.isAttributeValueReaderProvided())
 1096  0
                                                 selectedAttributeValueReader = processorResult.getAttributeValueReader();
 1097  0
                                 }
 1098  
                                 
 1099  
                                 // After iterating through all the constraints for this processor, add additional constraints for following processors
 1100  0
                                 constraintQueue.addAll(additionalConstraints);
 1101  0
                         }
 1102  
                 }
 1103  0
     }
 1104  
             
 1105  
     private void setFieldError(String entryName, String attributeName, String key, String ... args) {
 1106  0
             if (getDataDictionaryService() == null)
 1107  0
                     return;
 1108  
             
 1109  0
             String errorLabel = getDataDictionaryService().getAttributeErrorLabel(entryName, attributeName);
 1110  
             // FIXME: There's got to be a cleaner way of doing this.
 1111  0
             List<String> list = new LinkedList<String>();
 1112  0
             list.add(errorLabel);
 1113  0
             list.addAll(Arrays.asList(args));
 1114  0
             String[] array = new String[list.size()];
 1115  0
             array = list.toArray(array);
 1116  0
             GlobalVariables.getMessageMap().putError(attributeName, key, array);
 1117  0
     }
 1118  
         
 1119  
 
 1120  
     private void validateAttribute(DictionaryValidationResult result, AttributeValueReader attributeValueReader, boolean checkIfRequired) throws AttributeValidationException {
 1121  0
                 Constrainable definition = attributeValueReader.getDefinition(attributeValueReader.getAttributeName());
 1122  0
         validateAttribute(result, definition, attributeValueReader, checkIfRequired);
 1123  0
     }
 1124  
     
 1125  
     private void validateAttribute(DictionaryValidationResult result, Constrainable definition, AttributeValueReader attributeValueReader,  boolean checkIfRequired) throws AttributeValidationException {
 1126  
             
 1127  0
             if (definition == null)
 1128  0
                     throw new AttributeValidationException("Unable to validate constraints for attribute \"" + attributeValueReader.getAttributeName() + "\" on entry \"" + attributeValueReader.getEntryName() + "\" because no attribute definition can be found.");
 1129  
             
 1130  0
             Object value = attributeValueReader.getValue();
 1131  
             
 1132  0
             processElementConstraints(result, value, definition, attributeValueReader, checkIfRequired);
 1133  0
     }
 1134  
     
 1135  
     private void validateObject(DictionaryValidationResult result, AttributeValueReader attributeValueReader, boolean doOptionalProcessing) throws AttributeValidationException {
 1136  
             
 1137  
             // If the entry itself is constrainable then the attribute value reader will return it here and we'll need to check if it has any constraints
 1138  
             //FIXME: WJG - Do we want to make entry be constrainable?
 1139  0
             Constrainable objectEntry = attributeValueReader.getEntry();
 1140  0
             processElementConstraints(result, attributeValueReader.getObject(), objectEntry, attributeValueReader, doOptionalProcessing);
 1141  
 
 1142  0
             List<Constrainable> definitions = attributeValueReader.getDefinitions();
 1143  
 
 1144  
             // Exit if the attribute value reader has no child definitions
 1145  0
             if (null == definitions) 
 1146  0
                     return;
 1147  
             
 1148  
             //Process all attribute definitions
 1149  0
             for (Constrainable definition : definitions) {                   
 1150  0
                     String attributeName = definition.getName();
 1151  0
                         attributeValueReader.setAttributeName(attributeName);                            
 1152  0
                         Object value = attributeValueReader.getValue(attributeName);
 1153  
                         
 1154  0
                     processElementConstraints(result, value, definition, attributeValueReader, doOptionalProcessing);
 1155  0
             }
 1156  
             
 1157  
             //Process any constraints that may be defined on complex attributes
 1158  0
             if (objectEntry instanceof DataDictionaryEntryBase){
 1159  0
                     List<ComplexAttributeDefinition> complexAttrDefinitions = ((DataDictionaryEntryBase)objectEntry).getComplexAttributes();
 1160  
 
 1161  0
                     if (complexAttrDefinitions != null){
 1162  0
                         for (ComplexAttributeDefinition complexAttrDefinition:complexAttrDefinitions){                                        
 1163  0
                                        DataDictionaryEntry childEntry = complexAttrDefinition.getDataObjectEntry(); 
 1164  
                                
 1165  0
                                 String attributeName = complexAttrDefinition.getName();
 1166  
                                 
 1167  0
                                 attributeValueReader.setAttributeName(attributeName);
 1168  0
                                     Object value = attributeValueReader.getValue();                    
 1169  0
                                     if (value != null){
 1170  0
                                             AttributeValueReader nestedAttributeValueReader = 
 1171  
                                                 new DictionaryObjectAttributeValueReader(value, childEntry.getFullClassName(), childEntry, attributeValueReader.getPath());
 1172  0
                                         validateObject(result, nestedAttributeValueReader, doOptionalProcessing);                    
 1173  
                                     }
 1174  
         
 1175  0
                                     processElementConstraints(result, value, complexAttrDefinition, attributeValueReader, doOptionalProcessing);        
 1176  0
                         }
 1177  
                     }
 1178  
             }
 1179  
 
 1180  
             
 1181  
             //FIXME: I think we may want to use a new CollectionConstrainable interface instead to obtain from 
 1182  
             //DictionaryObjectAttributeValueReader
 1183  0
             DataObjectEntry entry = (DataObjectEntry)attributeValueReader.getEntry();
 1184  0
             if (entry != null) {
 1185  0
             for (CollectionDefinition collectionDefinition : entry.getCollections()){
 1186  
                 //TODO: Do we need to be able to handle simple collections (ie. String, etc)
 1187  
 
 1188  0
                 String childEntryName = collectionDefinition.getDataObjectClass();
 1189  0
                 String attributeName = collectionDefinition.getName();
 1190  0
                 attributeValueReader.setAttributeName(attributeName);
 1191  0
                 Collection<?> collectionObject = attributeValueReader.getValue();
 1192  0
                 DataDictionaryEntry childEntry = childEntryName != null ? getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(childEntryName) : null;
 1193  0
                 if (collectionObject != null){
 1194  0
                     for (Object value:collectionObject){
 1195  
                         //FIXME: It's inefficient to be creating new attribute reader for each item in collection
 1196  0
                         AttributeValueReader nestedAttributeValueReader =
 1197  
                             new DictionaryObjectAttributeValueReader(value, childEntryName, childEntry, attributeValueReader.getPath());
 1198  0
                         validateObject(result, nestedAttributeValueReader, doOptionalProcessing);
 1199  0
                     }
 1200  
                 }
 1201  
 
 1202  0
                 processCollectionConstraints(result, collectionObject, collectionDefinition, attributeValueReader, doOptionalProcessing);
 1203  0
             }
 1204  
         }
 1205  0
     }
 1206  
 
 1207  
     /**
 1208  
      * @return Returns the dataDictionaryService.
 1209  
      */
 1210  
     public DataDictionaryService getDataDictionaryService() {
 1211  0
         return dataDictionaryService;
 1212  
     }
 1213  
 
 1214  
     /**
 1215  
      * @param dataDictionaryService The dataDictionaryService to set.
 1216  
      */
 1217  
     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
 1218  0
         this.dataDictionaryService = dataDictionaryService;
 1219  0
     }
 1220  
 
 1221  
     /**
 1222  
      * Sets the businessObjectService attribute value.
 1223  
      * 
 1224  
      * @param businessObjectService The businessObjectService to set.
 1225  
      */
 1226  
     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
 1227  0
         this.businessObjectService = businessObjectService;
 1228  0
     }
 1229  
 
 1230  
     /**
 1231  
      * Sets the maintenanceDocumentDictionaryService attribute value.
 1232  
      * 
 1233  
      * @param maintenanceDocumentDictionaryService The maintenanceDocumentDictionaryService to set.
 1234  
      */
 1235  
     public void setMaintenanceDocumentDictionaryService(MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
 1236  0
         this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
 1237  0
     }
 1238  
 
 1239  
 
 1240  
     /**
 1241  
          * @param transactionalDocumentDictionaryService the transactionalDocumentDictionaryService to set
 1242  
          */
 1243  
         public void setTransactionalDocumentDictionaryService(
 1244  
                         TransactionalDocumentDictionaryService transactionalDocumentDictionaryService) {
 1245  0
                 this.transactionalDocumentDictionaryService = transactionalDocumentDictionaryService;
 1246  0
         }
 1247  
 
 1248  
 
 1249  
         /**
 1250  
      * Sets the persistenceService attribute value.
 1251  
      * 
 1252  
      * @param persistenceService The persistenceService to set.
 1253  
      */
 1254  
     public void setPersistenceService(PersistenceService persistenceService) {
 1255  0
         this.persistenceService = persistenceService;
 1256  0
     }
 1257  
 
 1258  
     public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
 1259  0
         this.persistenceStructureService = persistenceStructureService;
 1260  0
     }
 1261  
 
 1262  
     private WorkflowAttributePropertyResolutionService getWorkflowAttributePropertyResolutionService() {
 1263  0
             if (workflowAttributePropertyResolutionService == null) {
 1264  0
                     workflowAttributePropertyResolutionService = KNSServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
 1265  
             }
 1266  0
             return workflowAttributePropertyResolutionService;
 1267  
     }
 1268  
 
 1269  
         /**
 1270  
          * @return the collectionConstraintProcessors
 1271  
          */
 1272  
         @SuppressWarnings("unchecked")
 1273  
         public List<CollectionConstraintProcessor> getCollectionConstraintProcessors() {
 1274  0
                 return this.collectionConstraintProcessors;
 1275  
         }
 1276  
 
 1277  
         /**
 1278  
          * @param collectionConstraintProcessors the collectionConstraintProcessors to set
 1279  
          */
 1280  
         @SuppressWarnings("unchecked")
 1281  
         public void setCollectionConstraintProcessors(
 1282  
                         List<CollectionConstraintProcessor> collectionConstraintProcessors) {
 1283  0
                 this.collectionConstraintProcessors = collectionConstraintProcessors;
 1284  0
         }
 1285  
 
 1286  
         /**
 1287  
          * @return the constraintProviders
 1288  
          */
 1289  
         @SuppressWarnings("unchecked")
 1290  
         public List<ConstraintProvider> getConstraintProviders() {
 1291  0
                 return this.constraintProviders;
 1292  
         }
 1293  
 
 1294  
         /**
 1295  
          * @param constraintProviders the constraintProviders to set
 1296  
          */
 1297  
         @SuppressWarnings("unchecked")
 1298  
         public void setConstraintProviders(List<ConstraintProvider> constraintProviders) {
 1299  0
                 this.constraintProviders = constraintProviders;
 1300  0
         }
 1301  
 
 1302  
         /**
 1303  
          * @return the elementConstraintProcessors
 1304  
          */
 1305  
         @SuppressWarnings("unchecked")
 1306  
         public List<ConstraintProcessor> getElementConstraintProcessors() {
 1307  0
                 return this.elementConstraintProcessors;
 1308  
         }
 1309  
 
 1310  
         /**
 1311  
          * @param elementConstraintProcessors the elementConstraintProcessors to set
 1312  
          */
 1313  
         @SuppressWarnings("unchecked")
 1314  
         public void setElementConstraintProcessors(
 1315  
                         List<ConstraintProcessor> elementConstraintProcessors) {
 1316  0
                 this.elementConstraintProcessors = elementConstraintProcessors;
 1317  0
         }
 1318  
 
 1319  
 
 1320  
 
 1321  
 }