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