Coverage Report - org.kuali.rice.kim.service.support.impl.KimTypeServiceBase
 
Classes in this File Line Coverage Branch Coverage Complexity
KimTypeServiceBase
0%
0/470
0%
0/302
5.318
 
 1  
 /*
 2  
  * Copyright 2007-2008 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.kim.service.support.impl;
 17  
 
 18  
 import org.apache.commons.beanutils.PropertyUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.util.AttributeSet;
 21  
 import org.kuali.rice.core.util.ClassLoaderUtils;
 22  
 import org.kuali.rice.core.util.KeyValue;
 23  
 import org.kuali.rice.core.util.RiceKeyConstants;
 24  
 import org.kuali.rice.core.util.type.TypeUtils;
 25  
 import org.kuali.rice.core.web.format.Formatter;
 26  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 27  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 28  
 import org.kuali.rice.kim.api.type.KimType;
 29  
 import org.kuali.rice.kim.api.type.KimTypeAttribute;
 30  
 import org.kuali.rice.kim.api.type.KimTypeInfoService;
 31  
 import org.kuali.rice.kim.bo.types.dto.AttributeDefinitionMap;
 32  
 import org.kuali.rice.kim.service.support.KimTypeService;
 33  
 import org.kuali.rice.kns.bo.BusinessObject;
 34  
 import org.kuali.rice.kns.datadictionary.AttributeDefinition;
 35  
 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
 36  
 import org.kuali.rice.kns.datadictionary.KimDataDictionaryAttributeDefinition;
 37  
 import org.kuali.rice.kns.datadictionary.KimNonDataDictionaryAttributeDefinition;
 38  
 import org.kuali.rice.kns.datadictionary.PrimitiveAttributeDefinition;
 39  
 import org.kuali.rice.kns.datadictionary.RelationshipDefinition;
 40  
 import org.kuali.rice.kns.datadictionary.control.ControlDefinition;
 41  
 import org.kuali.rice.kns.datadictionary.validation.ValidationPattern;
 42  
 import org.kuali.rice.kns.lookup.LookupUtils;
 43  
 import org.kuali.rice.kns.lookup.keyvalues.KeyValuesFinder;
 44  
 import org.kuali.rice.kns.lookup.keyvalues.KimAttributeValuesFinder;
 45  
 import org.kuali.rice.kns.lookup.keyvalues.PersistableBusinessObjectValuesFinder;
 46  
 import org.kuali.rice.kns.service.BusinessObjectService;
 47  
 import org.kuali.rice.kns.service.DataDictionaryService;
 48  
 import org.kuali.rice.kns.service.DictionaryValidationService;
 49  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 50  
 import org.kuali.rice.kns.service.KNSServiceLocatorWeb;
 51  
 import org.kuali.rice.kns.util.ErrorMessage;
 52  
 import org.kuali.rice.kns.util.FieldUtils;
 53  
 import org.kuali.rice.kns.util.GlobalVariables;
 54  
 import org.kuali.rice.kns.util.KNSUtils;
 55  
 import org.kuali.rice.kns.util.ObjectUtils;
 56  
 import org.kuali.rice.kns.web.comparator.StringValueComparator;
 57  
 import org.kuali.rice.kns.web.ui.Field;
 58  
 
 59  
 import java.beans.PropertyDescriptor;
 60  
 import java.lang.reflect.Method;
 61  
 import java.lang.reflect.Modifier;
 62  
 import java.math.BigDecimal;
 63  
 import java.util.ArrayList;
 64  
 import java.util.HashMap;
 65  
 import java.util.Iterator;
 66  
 import java.util.List;
 67  
 import java.util.Map;
 68  
 import java.util.Set;
 69  
 import java.util.regex.Pattern;
 70  
 
 71  
 /**
 72  
  * This is a description of what this class does - jonathan don't forget to fill this in.
 73  
  *
 74  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 75  
  *
 76  
  */
 77  0
 public class KimTypeServiceBase implements KimTypeService {
 78  
 
 79  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KimTypeServiceBase.class);
 80  
 
 81  
         private BusinessObjectService businessObjectService;
 82  
         private DictionaryValidationService dictionaryValidationService;
 83  
         private DataDictionaryService dataDictionaryService;
 84  
         private KimTypeInfoService typeInfoService;
 85  
         
 86  0
         protected List<String> workflowRoutingAttributes = new ArrayList<String>();
 87  0
         protected List<String> requiredAttributes = new ArrayList<String>();
 88  0
         protected boolean checkRequiredAttributes = false;
 89  
 
 90  
         protected KimTypeInfoService getTypeInfoService() {
 91  0
                 if ( typeInfoService == null ) {
 92  0
                         typeInfoService = KimApiServiceLocator.getKimTypeInfoService();
 93  
                 }
 94  0
                 return typeInfoService;
 95  
         }
 96  
 
 97  
         protected BusinessObjectService getBusinessObjectService() {
 98  0
                 if ( businessObjectService == null ) {
 99  0
                         businessObjectService = KNSServiceLocator.getBusinessObjectService();
 100  
                 }
 101  0
                 return businessObjectService;
 102  
         }
 103  
 
 104  
         protected DictionaryValidationService getDictionaryValidationService() {
 105  0
                 if ( dictionaryValidationService == null ) {
 106  0
                         dictionaryValidationService = KNSServiceLocatorWeb.getDictionaryValidationService();
 107  
                 }
 108  0
                 return dictionaryValidationService;
 109  
         }
 110  
 
 111  
         protected DataDictionaryService getDataDictionaryService() {
 112  0
                 if ( dataDictionaryService == null ) {
 113  0
                         dataDictionaryService = KNSServiceLocatorWeb.getDataDictionaryService();
 114  
                 }
 115  0
                 return this.dataDictionaryService;
 116  
         }
 117  
 
 118  
         /**
 119  
          * Returns null, to indicate that there is no custom workflow document needed for this type.
 120  
          *
 121  
          * @see org.kuali.rice.kim.service.support.KimTypeService#getWorkflowDocumentTypeName()
 122  
          */
 123  
         @Override
 124  
         public String getWorkflowDocumentTypeName() {
 125  0
                 return null;
 126  
         }
 127  
 
 128  
         /**
 129  
          *
 130  
          * This method matches input attribute set entries and standard attribute set entries using literal string match.
 131  
          *
 132  
          */
 133  
         protected boolean performMatch(AttributeSet inputAttributeSet, AttributeSet storedAttributeSet) {
 134  0
                 if ( storedAttributeSet == null || inputAttributeSet == null ) {
 135  0
                         return true;
 136  
                 }
 137  0
                 for ( Map.Entry<String, String> entry : storedAttributeSet.entrySet() ) {
 138  0
                         if (inputAttributeSet.containsKey(entry.getKey()) && !StringUtils.equals(inputAttributeSet.get(entry.getKey()), entry.getValue()) ) {
 139  0
                                 return false;
 140  
                         }
 141  
                 }
 142  0
                 return true;
 143  
         }
 144  
 
 145  
         public AttributeSet translateInputAttributeSet(AttributeSet qualification){
 146  0
                 return qualification;
 147  
         }
 148  
 
 149  
         /**
 150  
          *
 151  
          * This method ...
 152  
          */
 153  
         public boolean performMatches(AttributeSet inputAttributeSet, List<AttributeSet> storedAttributeSets){
 154  0
                 for ( AttributeSet storedAttributeSet : storedAttributeSets ) {
 155  
                         // if one matches, return true
 156  0
                         if ( performMatch(inputAttributeSet, storedAttributeSet) ) {
 157  0
                                 return true;
 158  
                         }
 159  
                 }
 160  0
                 return false;
 161  
         }
 162  
         
 163  
         /**
 164  
          * This is the default implementation.  It calls into the service for each attribute to
 165  
          * validate it there.  No combination validation is done.  That should be done
 166  
          * by overriding this method.
 167  
          *
 168  
          * @see org.kuali.rice.kim.service.support.KimTypeService#validateAttributes(AttributeSet)
 169  
          */
 170  
         @Override
 171  
         public AttributeSet validateAttributes(String kimTypeId, AttributeSet attributes) {
 172  0
                 AttributeSet validationErrors = new AttributeSet();
 173  0
                 if ( attributes == null ) {
 174  0
                         return validationErrors;
 175  
                 }
 176  0
                 KimType kimType = getTypeInfoService().getKimType(kimTypeId);
 177  
                 
 178  0
                 for ( String attributeName : attributes.keySet() ) {
 179  0
             KimTypeAttribute attr = kimType.getAttributeDefinitionByName(attributeName);
 180  0
                         List<String> attributeErrors = null;
 181  
                         try {
 182  0
                                 if ( attr.getKimAttribute().getComponentName() == null) {
 183  0
                                         attributeErrors = validateNonDataDictionaryAttribute(attributeName, attributes.get( attributeName ), true);
 184  
                                 } else {
 185  
                                         // create an object of the proper type per the component
 186  0
                             Object componentObject = Class.forName( attr.getKimAttribute().getComponentName() ).newInstance();
 187  
                             // get the bean utils descriptor for accessing the attribute on that object
 188  0
                             PropertyDescriptor propertyDescriptor = null;
 189  0
                             if ( attr.getKimAttribute().getAttributeName() != null ) {
 190  0
                                     propertyDescriptor = PropertyUtils.getPropertyDescriptor(componentObject, attr.getKimAttribute().getAttributeName());
 191  0
                                                 if ( propertyDescriptor != null ) {
 192  
                                                         // set the value on the object so that it can be checked
 193  0
                                                         Object attributeValue = getAttributeValue(propertyDescriptor, attributes.get(attributeName));
 194  0
                                                         propertyDescriptor.getWriteMethod().invoke( componentObject, attributeValue);
 195  0
                                                         attributeErrors = validateDataDictionaryAttribute(kimTypeId, attr.getKimAttribute().getComponentName(), componentObject, propertyDescriptor);
 196  
                                                 }
 197  
                             }
 198  0
                                         if ( propertyDescriptor == null ) {
 199  0
                                                 LOG.warn( "Unable to obtain property descriptor for: " + attr.getKimAttribute().getComponentName() + "/" + attr.getKimAttribute().getAttributeName() );
 200  
                                         }
 201  
                                 }
 202  0
                         } catch (Exception e) {
 203  0
                                 LOG.error("Unable to validate attribute: " + attributeName, e);
 204  0
                         }
 205  
 
 206  0
                         if ( attributeErrors != null ) {
 207  0
                                 for ( String err : attributeErrors ) {
 208  0
                                         validationErrors.put(attributeName, err);
 209  
                                 }
 210  
                         }
 211  0
                 }
 212  
                 
 213  0
                 Map<String, List<String>> referenceCheckErrors = validateReferencesExistAndActive(kimType, attributes, validationErrors);
 214  0
                 for ( String attributeName : referenceCheckErrors.keySet() ) {
 215  0
                         List<String> attributeErrors = referenceCheckErrors.get(attributeName);
 216  0
                         for ( String err : attributeErrors ) {
 217  0
                                 validationErrors.put(attributeName, err);
 218  
                         }
 219  0
                 }
 220  
                 
 221  0
                 return validationErrors;
 222  
         }
 223  
 
 224  
         private Object getAttributeValue(PropertyDescriptor propertyDescriptor, String attributeValue){
 225  0
                 Object attributeValueObject = null;
 226  0
                 if(propertyDescriptor!=null && attributeValue!=null){
 227  0
                         Class<?> propertyType = propertyDescriptor.getPropertyType();
 228  0
                         if(propertyType!=String.class){
 229  0
                                 attributeValueObject = KNSUtils.createObject(propertyType, new Class[]{String.class}, new Object[] {attributeValue});
 230  
                         } else {
 231  0
                                 attributeValueObject = attributeValue;
 232  
                         }
 233  
                 }
 234  0
                 return attributeValueObject;
 235  
         }
 236  
         
 237  
         protected Map<String, List<String>> validateReferencesExistAndActive( KimType kimType, AttributeSet attributes, Map<String, String> previousValidationErrors) {
 238  0
                 Map<String, BusinessObject> componentClassInstances = new HashMap<String, BusinessObject>();
 239  0
                 Map<String, List<String>> errors = new HashMap<String, List<String>>();
 240  
                 
 241  0
                 for ( String attributeName : attributes.keySet() ) {
 242  0
                         KimTypeAttribute attr = kimType.getAttributeDefinitionByName(attributeName);
 243  
                         
 244  0
                         if (StringUtils.isNotBlank(attr.getKimAttribute().getComponentName())) {
 245  0
                                 if (!componentClassInstances.containsKey(attr.getKimAttribute().getComponentName())) {
 246  
                                         try {
 247  0
                                                 Class<?> componentClass = Class.forName( attr.getKimAttribute().getComponentName() );
 248  0
                                                 if (!BusinessObject.class.isAssignableFrom(componentClass)) {
 249  0
                                                         LOG.warn("Class " + componentClass.getName() + " does not implement BusinessObject.  Unable to perform reference existence and active validation");
 250  0
                                                         continue;
 251  
                                                 }
 252  0
                                                 BusinessObject componentInstance = (BusinessObject) componentClass.newInstance();
 253  0
                                                 componentClassInstances.put(attr.getKimAttribute().getComponentName(), componentInstance);
 254  0
                                         } catch (Exception e) {
 255  0
                                                 LOG.error("Unable to instantiate class for attribute: " + attributeName, e);
 256  0
                                         }
 257  
                                 }
 258  
                         }
 259  0
                 }
 260  
                 
 261  
                 // now that we have instances for each component class, try to populate them with any attribute we can, assuming there were no other validation errors associated with it
 262  0
                 for ( String attributeName : attributes.keySet() ) {
 263  0
                         if (!previousValidationErrors.containsKey(attributeName)) {
 264  0
                                 for (Object componentInstance : componentClassInstances.values()) {
 265  
                                         try {
 266  0
                                                 ObjectUtils.setObjectProperty(componentInstance, attributeName, attributes.get(attributeName));
 267  0
                                         } catch (NoSuchMethodException e) {
 268  
                                                 // this is expected since not all attributes will be in all components
 269  0
                                         } catch (Exception e) {
 270  0
                                                 LOG.error("Unable to set object property class: " + componentInstance.getClass().getName() + " property: " + attributeName, e);
 271  0
                                         }
 272  
                                 }
 273  
                         }
 274  
                 }
 275  
                 
 276  0
                 for (String componentClass : componentClassInstances.keySet()) {
 277  0
                         BusinessObject componentInstance = componentClassInstances.get(componentClass);
 278  
                         
 279  0
                         List<RelationshipDefinition> relationships = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(componentClass).getRelationships();
 280  0
                         if (relationships == null) {
 281  0
                                 continue;
 282  
                         }
 283  
                         
 284  0
                         for (RelationshipDefinition relationshipDefinition : relationships) {
 285  0
                                 List<PrimitiveAttributeDefinition> primitiveAttributes = relationshipDefinition.getPrimitiveAttributes();
 286  
                                 
 287  
                                 // this code assumes that the last defined primitiveAttribute is the attributeToHighlightOnFail
 288  0
                                 String attributeToHighlightOnFail = primitiveAttributes.get(primitiveAttributes.size() - 1).getSourceName();
 289  
                                 
 290  
                                 // TODO: will this work for user ID attributes?
 291  
                                 
 292  0
                                 if (!attributes.containsKey(attributeToHighlightOnFail)) {
 293  
                                         // if the attribute to highlight wasn't passed in, don't bother validating
 294  0
                                         continue;
 295  
                                 }
 296  
                                 
 297  
                                 String attributeDisplayLabel;
 298  0
                                 KimTypeAttribute attr = kimType.getAttributeDefinitionByName(attributeToHighlightOnFail);
 299  0
                                 if (attr != null) {
 300  0
                                         if (StringUtils.isNotBlank(attr.getKimAttribute().getComponentName())) {
 301  0
                                                 attributeDisplayLabel = getDataDictionaryService().getAttributeLabel(attr.getKimAttribute().getComponentName(), attributeToHighlightOnFail);
 302  
                                         } else {
 303  0
                                                 attributeDisplayLabel = attr.getKimAttribute().getAttributeLabel();
 304  
                                         }
 305  
 
 306  0
                                         getDictionaryValidationService().validateReferenceExistsAndIsActive(componentInstance, relationshipDefinition.getObjectAttributeName(),
 307  
                                                         attributeToHighlightOnFail, attributeDisplayLabel);
 308  
                                 }
 309  
                                 
 310  0
                                 errors.put(attributeToHighlightOnFail, extractErrorsFromGlobalVariablesErrorMap(attributeToHighlightOnFail));
 311  0
                         }
 312  0
                 }
 313  0
                 return errors;
 314  
         }
 315  
         
 316  
     protected void validateAttributeRequired(String kimTypeId, String objectClassName, String attributeName, Object attributeValue, String errorKey) {
 317  
         // check if field is a required field for the business object
 318  0
         if (attributeValue == null || (attributeValue instanceof String && StringUtils.isBlank((String) attributeValue))) {
 319  0
                 AttributeDefinitionMap map = getAttributeDefinitions(kimTypeId);
 320  0
                 AttributeDefinition definition = map.getByAttributeName(attributeName);
 321  
                 
 322  0
             Boolean required = definition.isRequired();
 323  0
             ControlDefinition controlDef = definition.getControl();
 324  
 
 325  0
             if (required != null && required.booleanValue() && !(controlDef != null && controlDef.isHidden())) {
 326  
 
 327  
                 // get label of attribute for message
 328  0
                 String errorLabel = getAttributeErrorLabel(definition);
 329  0
                 GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_REQUIRED, errorLabel);
 330  
             }
 331  
         }
 332  0
     }
 333  
     
 334  
         protected List<String> validateDataDictionaryAttribute(String kimTypeId, String entryName, Object object, PropertyDescriptor propertyDescriptor) {
 335  0
                 validatePrimitiveFromDescriptor(kimTypeId, entryName, object, propertyDescriptor);
 336  0
                 return extractErrorsFromGlobalVariablesErrorMap(propertyDescriptor.getName());
 337  
         }
 338  
 
 339  
     protected void validatePrimitiveFromDescriptor(String kimTypeId, String entryName, Object object, PropertyDescriptor propertyDescriptor) {
 340  
         // validate the primitive attributes if defined in the dictionary
 341  0
         if (null != propertyDescriptor && getDataDictionaryService().isAttributeDefined(entryName, propertyDescriptor.getName())) {
 342  0
             Object value = ObjectUtils.getPropertyValue(object, propertyDescriptor.getName());
 343  0
             Class<? extends Object> propertyType = propertyDescriptor.getPropertyType();
 344  
 
 345  0
             if (TypeUtils.isStringClass(propertyType) || TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType) || TypeUtils.isTemporalClass(propertyType)) {
 346  
 
 347  
                 // check value format against dictionary
 348  0
                 if (value != null && StringUtils.isNotBlank(value.toString())) {
 349  0
                     if (!TypeUtils.isTemporalClass(propertyType)) {
 350  0
                         validateAttributeFormat(kimTypeId, entryName, propertyDescriptor.getName(), value.toString(), propertyDescriptor.getName());
 351  
                     }
 352  
                 }
 353  
                 else {
 354  
                         // if it's blank, then we check whether the attribute should be required
 355  0
                     validateAttributeRequired(kimTypeId, entryName, propertyDescriptor.getName(), value, propertyDescriptor.getName());
 356  
                 }
 357  
             }
 358  
         }
 359  0
     }
 360  
     
 361  
     /**
 362  
      * Constant defines a validation method for an attribute value.
 363  
      * <p>Value is "validate"
 364  
      */
 365  
     public static final String VALIDATE_METHOD="validate";
 366  
     
 367  
     protected String getAttributeErrorLabel(AttributeDefinition definition) {
 368  0
         String longAttributeLabel = definition.getLabel();
 369  0
         String shortAttributeLabel = definition.getShortLabel();
 370  0
         return longAttributeLabel + " (" + shortAttributeLabel + ")";
 371  
     }
 372  
     
 373  
     protected Pattern getAttributeValidatingExpression(AttributeDefinition definition) {
 374  0
             Pattern regex = null;
 375  0
         if (definition != null) {
 376  0
             if (definition.hasValidationPattern()) {
 377  0
                 regex = definition.getValidationPattern().getRegexPattern();
 378  
             } else {
 379  
                 // workaround for existing calls which don't bother checking for null return values
 380  0
                 regex = Pattern.compile(".*");
 381  
             }
 382  
         }
 383  
 
 384  0
         return regex;
 385  
     }
 386  
     
 387  
         protected Class<? extends Formatter> getAttributeFormatter(AttributeDefinition definition) {
 388  0
         Class<? extends Formatter> formatterClass = null;
 389  0
         if (definition != null && definition.hasFormatterClass()) {
 390  
                         try {
 391  0
                                 formatterClass = ClassLoaderUtils.getClass(definition.getFormatterClass(), Formatter.class);
 392  0
                         } catch (ClassNotFoundException e) {
 393  
                                 // supressing the ClassNotFoundException here to keep in consistent in the logic which is
 394  
                                 // calling this code (it's doing a null check) though it really seems like we should
 395  
                                 // be rethrowing this as a RuntimeException!  Either way, will log a WARN here.
 396  0
                                 LOG.warn("Failed to resolve formatter class: " + definition.getFormatterClass(), e);
 397  0
                         }
 398  
         }
 399  0
         return formatterClass;
 400  
     }
 401  
     
 402  
         public String getAttributeValidatingErrorMessageKey(AttributeDefinition definition) {
 403  0
         if (definition != null) {
 404  0
                 if (definition.hasValidationPattern()) {
 405  0
                         ValidationPattern validationPattern = definition.getValidationPattern();
 406  0
                         return validationPattern.getValidationErrorMessageKey();
 407  
                 }
 408  
         }
 409  0
         return null;
 410  
         }
 411  
         
 412  
         public String[] getAttributeValidatingErrorMessageParameters(AttributeDefinition definition) {
 413  0
         if (definition != null) {
 414  0
                 if (definition.hasValidationPattern()) {
 415  0
                         ValidationPattern validationPattern = definition.getValidationPattern();
 416  0
                         String attributeLabel = getAttributeErrorLabel(definition);
 417  0
                         return validationPattern.getValidationErrorMessageParameters(attributeLabel);
 418  
                 }
 419  
         }
 420  0
         return null;
 421  
         }
 422  
     
 423  
         protected String getAttributeExclusiveMin(AttributeDefinition definition) {
 424  0
         return definition == null ? null : definition.getExclusiveMin();
 425  
     }
 426  
 
 427  
         protected String getAttributeInclusiveMax(AttributeDefinition definition) {
 428  0
         return definition == null ? null : definition.getInclusiveMax();
 429  
     }
 430  
         
 431  
     protected void validateAttributeFormat(String kimTypeId, String objectClassName, String attributeName, String attributeValue, String errorKey) {
 432  0
             AttributeDefinitionMap attributeDefinitions = getAttributeDefinitions(kimTypeId);
 433  0
             AttributeDefinition definition = attributeDefinitions.getByAttributeName(attributeName);
 434  
             
 435  0
         String errorLabel = getAttributeErrorLabel(definition);
 436  
 
 437  0
         if ( LOG.isDebugEnabled() ) {
 438  0
                 LOG.debug("(bo, attributeName, attributeValue) = (" + objectClassName + "," + attributeName + "," + attributeValue + ")");
 439  
         }
 440  
 
 441  0
         if (StringUtils.isNotBlank(attributeValue)) {
 442  0
             Integer maxLength = definition.getMaxLength();
 443  0
             if ((maxLength != null) && (maxLength.intValue() < attributeValue.length())) {
 444  0
                 GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_MAX_LENGTH, new String[] { errorLabel, maxLength.toString() });
 445  0
                 return;
 446  
             }
 447  0
             Pattern validationExpression = getAttributeValidatingExpression(definition);
 448  0
             if (validationExpression != null && !validationExpression.pattern().equals(".*")) {
 449  0
                     if ( LOG.isDebugEnabled() ) {
 450  0
                             LOG.debug("(bo, attributeName, validationExpression) = (" + objectClassName + "," + attributeName + "," + validationExpression + ")");
 451  
                     }
 452  
 
 453  0
                 if (!validationExpression.matcher(attributeValue).matches()) {
 454  0
                     boolean isError=true;
 455  
                     // Calling formatter class
 456  0
                     Class<?> formatterClass=getAttributeFormatter(definition);
 457  0
                     if (formatterClass != null) {
 458  
                         try {
 459  0
                             Method validatorMethod=formatterClass.getDeclaredMethod(
 460  
                                     VALIDATE_METHOD, new Class<?>[] {String.class});
 461  0
                             Object o=validatorMethod.invoke(
 462  
                                     formatterClass.newInstance(), attributeValue);
 463  0
                             if (o instanceof Boolean) {
 464  0
                                 isError=!((Boolean)o).booleanValue();
 465  
                             }
 466  0
                         } catch (Exception e) {
 467  0
                             LOG.warn(e.getMessage(), e);
 468  0
                         }
 469  
                     }
 470  0
                     if (isError) {
 471  0
                             String errorMessageKey = getAttributeValidatingErrorMessageKey(definition);
 472  0
                             String[] errorMessageParameters = getAttributeValidatingErrorMessageParameters(definition);
 473  0
                         GlobalVariables.getMessageMap().putError(errorKey, errorMessageKey, errorMessageParameters);
 474  
                     }
 475  0
                     return;
 476  
                 }
 477  
             }
 478  0
             String exclusiveMin = getAttributeExclusiveMin(definition);
 479  0
             if (StringUtils.isNotBlank(exclusiveMin)) {
 480  
                 try {
 481  0
                         BigDecimal exclusiveMinBigDecimal = new BigDecimal(exclusiveMin);
 482  0
                     if (exclusiveMinBigDecimal.compareTo(new BigDecimal(attributeValue)) >= 0) {
 483  0
                         GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_EXCLUSIVE_MIN,
 484  
                         // todo: Formatter for currency?
 485  
                                 new String[] { errorLabel, exclusiveMin.toString() });
 486  0
                         return;
 487  
                     }
 488  
                 }
 489  0
                 catch (NumberFormatException e) {
 490  
                     // quash; this indicates that the DD contained a min for a non-numeric attribute
 491  0
                 }
 492  
             }
 493  0
             String inclusiveMax = getAttributeInclusiveMax(definition);
 494  0
             if (StringUtils.isNotBlank(inclusiveMax)) {
 495  
                 try {
 496  0
                         BigDecimal inclusiveMaxBigDecimal = new BigDecimal(inclusiveMax);
 497  0
                     if (inclusiveMaxBigDecimal.compareTo(new BigDecimal(attributeValue)) < 0) {
 498  0
                         GlobalVariables.getMessageMap().putError(errorKey, RiceKeyConstants.ERROR_INCLUSIVE_MAX,
 499  
                         // todo: Formatter for currency?
 500  
                                 new String[] { errorLabel, inclusiveMax.toString() });
 501  0
                         return;
 502  
                     }
 503  
                 }
 504  0
                 catch (NumberFormatException e) {
 505  
                     // quash; this indicates that the DD contained a max for a non-numeric attribute
 506  0
                 }
 507  
             }
 508  
         }
 509  0
     }
 510  
     
 511  
         protected List<String> extractErrorsFromGlobalVariablesErrorMap(String attributeName) {
 512  0
                 Object results = GlobalVariables.getMessageMap().getErrorMessagesForProperty(attributeName);
 513  0
                 List<String> errors = new ArrayList<String>();
 514  0
         if (results instanceof String) {
 515  0
                 errors.add((String)results);
 516  0
         } else if ( results != null) {
 517  0
                 if (results instanceof List) {
 518  0
                         List<?> errorList = (List<?>)results;
 519  0
                         for (Object msg : errorList) {
 520  0
                                 ErrorMessage errorMessage = (ErrorMessage)msg;
 521  0
                                 String retVal = errorMessage.getErrorKey()+":";
 522  0
                                 for (String param : errorMessage.getMessageParameters()) {
 523  0
                                         retVal = retVal + param +";";
 524  
                                 }
 525  0
                                 errors.add(retVal);
 526  0
                                 }
 527  0
                 } else {
 528  0
                         String [] temp = (String []) results;
 529  0
                         for (String string : temp) {
 530  0
                                         errors.add(string);
 531  
                                 }
 532  
                 }
 533  
         }
 534  0
         GlobalVariables.getMessageMap().removeAllErrorMessagesForProperty(attributeName);
 535  0
         return errors;
 536  
         }
 537  
         
 538  
         protected List<String> validateNonDataDictionaryAttribute(String attributeName, String attributeValue, boolean validateRequired) {
 539  0
                 return new ArrayList<String>();
 540  
         }
 541  
 
 542  
         protected List<KeyValue> getLocalDataDictionaryAttributeValues(KimTypeAttribute attr) throws ClassNotFoundException {
 543  0
                 List<KeyValue> pairs = new ArrayList<KeyValue>();
 544  0
                 BusinessObjectEntry entry = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(attr.getKimAttribute().getComponentName());
 545  0
                 if ( entry == null ) {
 546  0
                         LOG.warn( "Unable to obtain BusinessObjectEntry for component name: " + attr.getKimAttribute().getComponentName() );
 547  0
                         return pairs;
 548  
                 }
 549  0
                 AttributeDefinition definition = entry.getAttributeDefinition(attr.getKimAttribute().getAttributeName());
 550  0
                 if ( definition == null ) {
 551  0
                         LOG.warn( "No attribute named " + attr.getKimAttribute().getAttributeName() + " found on BusinessObjectEntry for: " + attr.getKimAttribute().getComponentName() );
 552  0
                         return pairs;
 553  
                 }
 554  0
                 String keyValuesFinderName = definition.getControl().getValuesFinderClass();
 555  0
                 if ( StringUtils.isNotBlank(keyValuesFinderName)) {
 556  
                         try {
 557  0
                                 KeyValuesFinder finder = (KeyValuesFinder)Class.forName(keyValuesFinderName).newInstance();
 558  0
                                 if (finder instanceof PersistableBusinessObjectValuesFinder) {
 559  0
                         ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass(ClassLoaderUtils.getClass(definition.getControl().getBusinessObjectClass()));
 560  0
                         ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName(definition.getControl().getKeyAttribute());
 561  0
                         ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName(definition.getControl().getLabelAttribute());
 562  0
                         if (definition.getControl().getIncludeBlankRow() != null) {
 563  0
                                 ((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(definition.getControl().getIncludeBlankRow()); 
 564  
                         }
 565  0
                         ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(definition.getControl().getIncludeKeyInLabel());
 566  
                                 }
 567  0
                                 pairs = finder.getKeyValues();
 568  0
                         } catch ( ClassNotFoundException ex ) {
 569  0
                                 LOG.info( "Unable to find class: " + keyValuesFinderName + " in the current context." );
 570  0
                                 throw ex;
 571  0
                         } catch (Exception e) {
 572  0
                                 LOG.error("Unable to build a KeyValuesFinder for " + attr.getKimAttribute().getAttributeName(), e);
 573  0
                         }
 574  
                 } else {
 575  0
                         LOG.warn( "No values finder class defined on the control definition (" + definition.getControl() + ") on BO / attr = " + attr.getKimAttribute().getComponentName() + " / " + attr.getKimAttribute().getAttributeName() );
 576  
                 }
 577  0
                 return pairs;
 578  
         }
 579  
 
 580  
         protected List<KeyValue> getCustomValueFinderValues(KimTypeAttribute attrib) {
 581  0
                 return new ArrayList<KeyValue>(0);
 582  
         }
 583  
 
 584  
         @Override
 585  
         public List<KeyValue> getAttributeValidValues(String kimTypeId, String attributeName) {
 586  0
                 if ( LOG.isDebugEnabled() ) {
 587  0
                         LOG.debug( "getAttributeValidValues(" + kimTypeId + "," + attributeName + ")");                        
 588  
                 }
 589  0
                 KimTypeAttribute attrib = KimApiServiceLocator.getKimTypeInfoService().getKimType(kimTypeId).getAttributeDefinitionByName(attributeName);
 590  0
                 if ( LOG.isDebugEnabled() ) {
 591  0
                         LOG.debug( "Found Attribute definition: " + attrib );
 592  
                 }
 593  0
                 List<KeyValue> pairs = null;
 594  0
                 if ( StringUtils.isNotBlank(attrib.getKimAttribute().getComponentName()) ) {
 595  
                         try {
 596  0
                                 Class.forName(attrib.getKimAttribute().getComponentName());
 597  
                                 try {
 598  0
                                         pairs = getLocalDataDictionaryAttributeValues(attrib);
 599  0
                                 } catch ( ClassNotFoundException ex ) {
 600  0
                                         LOG.error( "Got a ClassNotFoundException resolving a values finder - since this should have been executing in the context of the host system - this should not happen.");
 601  0
                                         pairs = new ArrayList<KeyValue>(0);
 602  0
                                 }
 603  0
                         } catch ( ClassNotFoundException ex ) {
 604  0
                                 LOG.error( "Got a ClassNotFoundException resolving a component name (" + attrib.getKimAttribute().getComponentName() + ") - since this should have been executing in the context of the host system - this should not happen.");
 605  0
                         }
 606  
                 } else {
 607  0
                         pairs = getCustomValueFinderValues(attrib);
 608  
                 }
 609  0
         return pairs;
 610  
         }
 611  
 
 612  
         /**
 613  
          * @param namespaceCode
 614  
          * @param typeAttribute
 615  
          * @return an AttributeDefinition for the given KimTypeAttribute, or null no base AttributeDefinition 
 616  
          * matches the typeAttribute parameter's attributeName.
 617  
          */
 618  
         @SuppressWarnings("unchecked")
 619  
         protected AttributeDefinition getDataDictionaryAttributeDefinition( String namespaceCode, String kimTypeId, KimTypeAttribute typeAttribute) {
 620  
                 // TODO: this method looks like it could use some refactoring
 621  0
                 KimDataDictionaryAttributeDefinition definition = null;
 622  0
                 String componentClassName = typeAttribute.getKimAttribute().getComponentName();
 623  0
                 String attributeName = typeAttribute.getKimAttribute().getAttributeName();
 624  0
                 AttributeDefinition baseDefinition = null;
 625  
                 
 626  
                 // try to resolve the component name - if not possible - try to pull the definition from the app mediation service
 627  
                 try {
 628  0
                         Class.forName(componentClassName);
 629  
                         try {
 630  0
                                 baseDefinition = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(componentClassName).getAttributeDefinition(attributeName);
 631  0
                         } catch ( Exception ex ) {
 632  0
                                 LOG.error( "Unable to get base DD definition for " + componentClassName + "." + attributeName, ex );
 633  0
                                 return definition;
 634  0
                         }
 635  0
                 } catch (ClassNotFoundException ex) {
 636  0
                         if ( LOG.isDebugEnabled() ) {
 637  0
                                 LOG.debug( "Unable to find class " + componentClassName + " in available classloaders. Deferring to the service bus." );
 638  
                         }
 639  0
                         baseDefinition = KNSServiceLocatorWeb.getRiceApplicationConfigurationMediationService().getBusinessObjectAttributeDefinition(componentClassName, attributeName);
 640  0
                 }
 641  
                 
 642  0
                 if (baseDefinition != null) {
 643  
 
 644  0
                         definition = new KimDataDictionaryAttributeDefinition();
 645  
                         // copy all the base attributes
 646  0
                         definition.setName( baseDefinition.getName() );
 647  0
                         definition.setLabel( baseDefinition.getLabel() );
 648  0
                         definition.setShortLabel( baseDefinition.getShortLabel() );
 649  0
                         definition.setMaxLength( baseDefinition.getMaxLength() );
 650  0
                         definition.setRequired( baseDefinition.isRequired() );
 651  
 
 652  0
                         if (baseDefinition.getFormatterClass() != null) {
 653  0
                                 definition.setFormatterClass(baseDefinition.getFormatterClass());
 654  
                         }
 655  0
                         ControlDefinition control = copy(baseDefinition.getControl());
 656  0
                         if ( StringUtils.isNotBlank( control.getValuesFinderClass() ) ) {
 657  
 //                                try {
 658  
 //                                        Class.forName(control.getValuesFinderClass());
 659  
 //                                } catch ( ClassNotFoundException ex ) {
 660  
                                         // not found locally, add the KimAttributeValuesFinder as a proxy
 661  0
                                         control.setValuesFinderClass(KimAttributeValuesFinder.class.getName());
 662  
 //                                }
 663  
                         }
 664  0
                         definition.setControl(control);
 665  0
                         definition.setSortCode(typeAttribute.getSortCode());
 666  0
                         definition.setKimAttrDefnId(typeAttribute.getKimAttribute().getId());
 667  0
                         definition.setKimTypeId(kimTypeId);
 668  
 
 669  0
                         definition.setForceUppercase(baseDefinition.getForceUppercase());
 670  
                         
 671  0
                         Map<String, String> lookupInputPropertyConversionsMap = new HashMap<String, String>();
 672  0
                         Map<String, String> lookupReturnPropertyConversionsMap = new HashMap<String, String>();
 673  
 
 674  
                         try {
 675  0
                                 Class<? extends BusinessObject> componentClass = (Class<? extends BusinessObject>)Class.forName(componentClassName);
 676  0
                                 BusinessObject sampleComponent = componentClass.newInstance();
 677  0
                                 List<String> displayedFieldNames = new ArrayList<String>( 1 );
 678  0
                                 displayedFieldNames.add( attributeName );
 679  0
                                 Field field = FieldUtils.getPropertyField(componentClass, attributeName, false);
 680  0
                                 if ( field != null ) {
 681  0
                                         field = LookupUtils.setFieldQuickfinder( sampleComponent, attributeName, field, displayedFieldNames );
 682  0
                                         if ( StringUtils.isNotBlank( field.getQuickFinderClassNameImpl() ) ) {
 683  0
                                                 Class<? extends BusinessObject> lookupClass = (Class<? extends BusinessObject>)Class.forName( field.getQuickFinderClassNameImpl() );
 684  0
                                                 definition.setLookupBoClass( lookupClass.getName() );
 685  0
                                                 if ( field.getLookupParameters() != null ) {
 686  0
                                                         String [] lookupInputPropertyConversions = field.getLookupParameters().split(",");
 687  0
                                                         for (String string : lookupInputPropertyConversions) {
 688  0
                                                                 String [] keyVal = string.split(":");
 689  0
                                                                 lookupInputPropertyConversionsMap.put(keyVal[0], keyVal[1]);
 690  
                                                         }
 691  0
                                                         definition.setLookupInputPropertyConversions(lookupInputPropertyConversionsMap);
 692  
                                                 }
 693  0
                                                 if ( field.getFieldConversions() != null ) {
 694  0
                                                         String [] lookupReturnPropertyConversions = field.getFieldConversions().split(",");
 695  0
                                                         for (String string : lookupReturnPropertyConversions) {
 696  0
                                                                 String [] keyVal = string.split(":");
 697  0
                                                                 lookupReturnPropertyConversionsMap.put(keyVal[0], keyVal[1]);
 698  
                                                         }
 699  0
                                                         definition.setLookupReturnPropertyConversions(lookupReturnPropertyConversionsMap);
 700  
                                                 }
 701  
                                         }
 702  
                                 }
 703  0
                         } catch (Exception e) {
 704  0
                                 LOG.warn("Unable to get DD data for: " + typeAttribute, e);
 705  0
                         }
 706  
                 }
 707  0
                 return definition;
 708  
         }
 709  
 
 710  
         @SuppressWarnings("unchecked")
 711  
         private <T> T copy(final T original) {
 712  0
                 if ( original == null ) {
 713  0
                         return null;
 714  
                 }
 715  0
                 T copy = null;
 716  
                 try {
 717  0
                         copy = (T) original.getClass().newInstance();
 718  0
                         Class copyClass = copy.getClass();
 719  
                     do {
 720  0
                             for (java.lang.reflect.Field copyField : copyClass.getDeclaredFields()) {
 721  0
                                     copyField.setAccessible(true);
 722  0
                                     int mods = copyField.getModifiers();
 723  0
                                     if (!Modifier.isFinal(mods) && !Modifier.isStatic(mods)) {
 724  0
                                             copyField.set(copy, copyField.get(original));
 725  
                                     }
 726  
                             }
 727  0
                             copyClass = copyClass.getSuperclass();
 728  0
                     } while (copyClass != null && !(copyClass.equals(Object.class)));
 729  0
                 } catch (Exception e) {
 730  0
                         LOG.error("Unable to copy " + original, e);
 731  0
                 }
 732  0
                 return copy;
 733  
         }
 734  
 
 735  
         protected AttributeDefinition getNonDataDictionaryAttributeDefinition(KimTypeAttribute typeAttribute) {
 736  0
                 KimNonDataDictionaryAttributeDefinition definition = new KimNonDataDictionaryAttributeDefinition();
 737  0
                 definition.setName(typeAttribute.getKimAttribute().getAttributeName());
 738  0
                 definition.setLabel(typeAttribute.getKimAttribute().getAttributeLabel());
 739  0
                 definition.setSortCode(typeAttribute.getSortCode());
 740  0
                 definition.setKimAttrDefnId(typeAttribute.getKimAttribute().getId());
 741  0
                 return definition;
 742  
         }
 743  
 
 744  
 //        private Map<String,AttributeDefinitionMap> attributeDefinitionCache = new HashMap<String,AttributeDefinitionMap>();
 745  
 
 746  
         @Override
 747  
         public AttributeDefinitionMap getAttributeDefinitions(String kimTypeId) {
 748  
 //                AttributeDefinitionMap definitions = attributeDefinitionCache.get( kimTypeId );
 749  
 //                if ( definitions == null ) {
 750  0
                         List<String> uniqueAttributes = getUniqueAttributes(kimTypeId);
 751  0
                         AttributeDefinitionMap definitions = new AttributeDefinitionMap();
 752  0
                 KimType kimType = getTypeInfoService().getKimType(kimTypeId);
 753  0
                 if ( kimType != null ) {
 754  0
                                 String nsCode = kimType.getNamespaceCode();                
 755  0
                                 for (KimTypeAttribute typeAttribute : kimType.getAttributeDefinitions()) {
 756  0
                                         AttributeDefinition definition = null;
 757  0
                                         if (typeAttribute.getKimAttribute().getComponentName() == null) {
 758  0
                                                 definition = getNonDataDictionaryAttributeDefinition(typeAttribute);
 759  
                                         } else {
 760  0
                                                 definition = getDataDictionaryAttributeDefinition(nsCode,kimTypeId,typeAttribute);
 761  
                                         }
 762  
 
 763  0
                                         if (definition != null) {
 764  0
                                                 if(uniqueAttributes!=null && uniqueAttributes.contains(definition.getName())){
 765  0
                                                         definition.setUnique(true);
 766  
                                                 }
 767  
                                                 // Perform a parameterized substitution on the applicationUrl
 768  
                                                 //                                        String url = typeAttribute.getApplicationUrl();
 769  
                                                 //                                        url = Utilities.substituteConfigParameters(nsCode, url);
 770  
                                                 //                                        kai.setApplicationUrl(url);
 771  
 
 772  
                                                 // TODO : use id for defnid ?
 773  
                                                 //                definition.setId(typeAttribute.getKimAttributeId());
 774  
                                                 // FIXME: I don't like this - if two attributes have the same sort code, they will overwrite each other
 775  0
                                                 definitions.put(typeAttribute.getSortCode(), definition);
 776  
                                         }
 777  0
                                 }
 778  
                                 // attributeDefinitionCache.put( kimTypeId, definitions );
 779  0
                 } else {
 780  0
                         LOG.warn( "Unable to resolve KIM Type: " + kimTypeId + " - returning an empty AttributeDefinitionMap." );
 781  
                 }
 782  
 //                }
 783  0
                 return definitions;
 784  
         }
 785  
 
 786  0
         protected final String COMMA_SEPARATOR = ", ";
 787  
 
 788  
         protected void validateRequiredAttributesAgainstReceived(AttributeSet receivedAttributes){
 789  
                 // abort if type does not want the qualifiers to be checked
 790  0
                 if ( !isCheckRequiredAttributes() ) {
 791  0
                         return;
 792  
                 }
 793  
                 // abort if the list is empty, no attributes need to be checked
 794  0
                 if ( requiredAttributes == null || requiredAttributes.isEmpty() ) {
 795  0
                         return;
 796  
                 }
 797  0
                 List<String> missingAttributes = new ArrayList<String>();
 798  
                 // if attributes are null or empty, they're all missing
 799  0
                 if ( receivedAttributes == null || receivedAttributes.isEmpty() ) {
 800  0
                         return;                
 801  
                 } else {
 802  0
                         for( String requiredAttribute : requiredAttributes ) {
 803  0
                                 if( !receivedAttributes.containsKey(requiredAttribute) ) {
 804  0
                                         missingAttributes.add(requiredAttribute);
 805  
                                 }
 806  
                         }
 807  
                 }
 808  0
         if(missingAttributes.size()>0) {
 809  0
                 StringBuffer errorMessage = new StringBuffer();
 810  0
                 Iterator<String> attribIter = missingAttributes.iterator();
 811  0
                 while ( attribIter.hasNext() ) {
 812  0
                         errorMessage.append( attribIter.next() );
 813  0
                         if( attribIter.hasNext() ) {
 814  0
                                 errorMessage.append( COMMA_SEPARATOR );
 815  
                         }
 816  
                 }
 817  0
                 errorMessage.append( " not found in required attributes for this type." );
 818  0
             throw new KimTypeAttributeValidationException(errorMessage.toString());
 819  
         }
 820  0
         }
 821  
 
 822  
         /**
 823  
          * Returns an empty list, indicating that no attributes from this
 824  
      * type should be passed to workflow.
 825  
          * 
 826  
          * @see org.kuali.rice.kim.service.support.KimTypeService#getWorkflowRoutingAttributes(java.lang.String)
 827  
          */
 828  
         @Override
 829  
         public List<String> getWorkflowRoutingAttributes(String routeLevel) {
 830  0
                 return workflowRoutingAttributes;
 831  
         }
 832  
         
 833  
         @Override
 834  
         public boolean validateUniqueAttributes(String kimTypeId, AttributeSet newAttributes, AttributeSet oldAttributes){
 835  0
                 boolean areAttributesUnique = true;
 836  0
                 List<String> uniqueAttributes = getUniqueAttributes(kimTypeId);
 837  0
                 if(uniqueAttributes==null || uniqueAttributes.isEmpty()){
 838  0
                         areAttributesUnique = true;
 839  
                 } else{
 840  0
                         if(areAttributesEqual(uniqueAttributes, newAttributes, oldAttributes)){
 841  0
                                 areAttributesUnique = false;
 842  
                         }
 843  
                 }
 844  0
                 return areAttributesUnique;
 845  
         }
 846  
         
 847  
         protected boolean areAttributesEqual(List<String> uniqueAttributeNames, AttributeSet aSet1, AttributeSet aSet2){
 848  
                 String attrVal1;
 849  
                 String attrVal2;
 850  0
                 StringValueComparator comparator = StringValueComparator.getInstance();
 851  0
                 for(String uniqueAttributeName: uniqueAttributeNames){
 852  0
                         attrVal1 = getAttributeValue(aSet1, uniqueAttributeName);
 853  0
                         attrVal2 = getAttributeValue(aSet2, uniqueAttributeName);
 854  0
                         attrVal1 = attrVal1==null?"":attrVal1;
 855  0
                         attrVal2 = attrVal2==null?"":attrVal2;
 856  0
                         if(comparator.compare(attrVal1, attrVal2)!=0){
 857  0
                                 return false;
 858  
                         }
 859  
                 }
 860  0
                 return true;
 861  
         }
 862  
 
 863  
         protected AttributeSet getErrorAttributeSet(String attributeNameKey, String errorKey, String[] errorArguments){
 864  0
                 AttributeSet validationErrors = new AttributeSet();
 865  0
                 GlobalVariables.getMessageMap().putError(attributeNameKey, errorKey, errorArguments);
 866  0
                 List<String> attributeErrors = extractErrorsFromGlobalVariablesErrorMap(attributeNameKey);
 867  0
                 if(attributeErrors!=null){
 868  0
                         for(String err:attributeErrors){
 869  0
                                 validationErrors.put(attributeNameKey, err);
 870  
                         }
 871  
                 }
 872  0
                 return validationErrors;
 873  
         }
 874  
         
 875  
     protected boolean areAllAttributeValuesEmpty(AttributeSet attributes){
 876  0
             boolean areAllAttributesEmpty = true;
 877  0
             if(attributes!=null) {
 878  0
                         for(String attributeNameKey: attributes.keySet()){
 879  0
                                 if(StringUtils.isNotEmpty(attributes.get(attributeNameKey))){
 880  0
                                         areAllAttributesEmpty = false;
 881  0
                                         break;
 882  
                                 }
 883  
                         }
 884  
                 }
 885  0
             return areAllAttributesEmpty;
 886  
     }
 887  
 
 888  
         protected String getAttributeValue(AttributeSet aSet, String attributeName){
 889  0
                 if(StringUtils.isEmpty(attributeName)) {
 890  0
                         return null;
 891  
                 }
 892  0
                 for(String attributeNameKey: aSet.keySet()){
 893  0
                         if(attributeName.equals(attributeNameKey)) {
 894  0
                                 return aSet.get(attributeNameKey);
 895  
                         }
 896  
                 }
 897  0
                 return null;
 898  
         }
 899  
         
 900  
         @Override
 901  
         public List<String> getUniqueAttributes(String kimTypeId){
 902  0
                 KimType kimType = getTypeInfoService().getKimType(kimTypeId);
 903  0
         List<String> uniqueAttributes = new ArrayList<String>();
 904  0
         if ( kimType != null ) {
 905  0
                 for(KimTypeAttribute attributeDefinition: kimType.getAttributeDefinitions()){
 906  0
                         uniqueAttributes.add(attributeDefinition.getKimAttribute().getAttributeName());
 907  
                 }
 908  
         } else {
 909  0
                 LOG.error("Unable to retrieve a KimTypeInfo for a null kimTypeId in getUniqueAttributes()");
 910  
         }
 911  0
         return uniqueAttributes;
 912  
         }
 913  
 
 914  
         @Override
 915  
         public AttributeSet validateUnmodifiableAttributes(String kimTypeId, AttributeSet originalAttributeSet, AttributeSet newAttributeSet){
 916  0
                 AttributeSet validationErrors = new AttributeSet();
 917  0
                 List<String> attributeErrors = null;
 918  0
                 KimType kimType = getTypeInfoService().getKimType(kimTypeId);
 919  0
                 List<String> uniqueAttributes = getUniqueAttributes(kimTypeId);
 920  0
                 for(String attributeNameKey: uniqueAttributes){
 921  0
                         KimTypeAttribute attr = kimType.getAttributeDefinitionByName(attributeNameKey);
 922  0
                         String mainAttributeValue = getAttributeValue(originalAttributeSet, attributeNameKey);
 923  0
                         String delegationAttributeValue = getAttributeValue(newAttributeSet, attributeNameKey);
 924  0
                         attributeErrors = null;
 925  0
                         if(!StringUtils.equals(mainAttributeValue, delegationAttributeValue)){
 926  0
                                 GlobalVariables.getMessageMap().putError(
 927  
                                         attributeNameKey, RiceKeyConstants.ERROR_CANT_BE_MODIFIED, 
 928  
                                         dataDictionaryService.getAttributeLabel(attr.getKimAttribute().getComponentName(), attributeNameKey));
 929  0
                                 attributeErrors = extractErrorsFromGlobalVariablesErrorMap(attributeNameKey);
 930  
                         }
 931  0
                         if(attributeErrors!=null){
 932  0
                                 for(String err:attributeErrors){
 933  0
                                         validationErrors.put(attributeNameKey, err);
 934  
                                 }
 935  
                         }
 936  0
                 }
 937  0
                 return validationErrors;
 938  
         }
 939  
 
 940  
         public boolean isCheckRequiredAttributes() {
 941  0
                 return this.checkRequiredAttributes;
 942  
         }
 943  
 
 944  
         public void setCheckRequiredAttributes(boolean checkRequiredAttributes) {
 945  0
                 this.checkRequiredAttributes = checkRequiredAttributes;
 946  0
         }
 947  
 
 948  
         @Override
 949  
         public AttributeSet validateAttributesAgainstExisting(String kimTypeId, AttributeSet newAttributes, AttributeSet oldAttributes){
 950  0
                 return new AttributeSet();
 951  
         }
 952  
 
 953  
         protected String getClosestParentDocumentTypeName(
 954  
                         DocumentType documentType,
 955  
                         Set<String> potentialParentDocumentTypeNames) {
 956  0
                 if ( potentialParentDocumentTypeNames == null || documentType == null ) {
 957  0
                         return null;
 958  
                 }
 959  0
                 if (potentialParentDocumentTypeNames.contains(documentType.getName())) {
 960  0
                         return documentType.getName();
 961  
                 } 
 962  0
                 if ((documentType.getDocTypeParentId() == null)
 963  
                                 || documentType.getDocTypeParentId().equals(
 964  
                                                 documentType.getDocumentTypeId())) {
 965  0
                         return null;
 966  
                 } 
 967  0
                 return getClosestParentDocumentTypeName(documentType
 968  
                                 .getParentDocType(), potentialParentDocumentTypeNames);
 969  
         }
 970  
 }