Coverage Report - org.kuali.rice.kns.maintenance.KualiMaintainableImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiMaintainableImpl
0%
0/634
0%
0/358
3.936
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.maintenance;
 17  
 
 18  
 import java.beans.PropertyDescriptor;
 19  
 import java.io.Serializable;
 20  
 import java.lang.reflect.InvocationTargetException;
 21  
 import java.security.GeneralSecurityException;
 22  
 import java.util.ArrayList;
 23  
 import java.util.Collection;
 24  
 import java.util.HashMap;
 25  
 import java.util.HashSet;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 
 31  
 import org.apache.commons.beanutils.PropertyUtils;
 32  
 import org.apache.commons.lang.StringUtils;
 33  
 import org.kuali.rice.core.service.EncryptionService;
 34  
 import org.kuali.rice.kim.bo.Person;
 35  
 import org.kuali.rice.kns.authorization.FieldRestriction;
 36  
 import org.kuali.rice.kns.bo.BusinessObject;
 37  
 import org.kuali.rice.kns.bo.BusinessObjectRelationship;
 38  
 import org.kuali.rice.kns.bo.DocumentHeader;
 39  
 import org.kuali.rice.kns.bo.PersistableBusinessObject;
 40  
 import org.kuali.rice.kns.datadictionary.AttributeSecurity;
 41  
 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
 42  
 import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
 43  
 import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
 44  
 import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
 45  
 import org.kuali.rice.kns.document.MaintenanceDocument;
 46  
 import org.kuali.rice.kns.document.MaintenanceLock;
 47  
 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentPresentationController;
 48  
 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions;
 49  
 import org.kuali.rice.kns.exception.PessimisticLockingException;
 50  
 import org.kuali.rice.kns.exception.UnknownBusinessClassAttributeException;
 51  
 import org.kuali.rice.kns.lookup.LookupUtils;
 52  
 import org.kuali.rice.kns.lookup.valueFinder.ValueFinder;
 53  
 import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
 54  
 import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
 55  
 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
 56  
 import org.kuali.rice.kns.service.BusinessObjectService;
 57  
 import org.kuali.rice.kns.service.DataDictionaryService;
 58  
 import org.kuali.rice.kns.service.DocumentHelperService;
 59  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 60  
 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
 61  
 import org.kuali.rice.kns.service.MaintenanceDocumentService;
 62  
 import org.kuali.rice.kns.service.ModuleService;
 63  
 import org.kuali.rice.kns.service.PersistenceStructureService;
 64  
 import org.kuali.rice.kns.util.FieldUtils;
 65  
 import org.kuali.rice.kns.util.GlobalVariables;
 66  
 import org.kuali.rice.kns.util.InactiveRecordsHidingUtils;
 67  
 import org.kuali.rice.kns.util.KNSConstants;
 68  
 import org.kuali.rice.kns.util.KNSPropertyConstants;
 69  
 import org.kuali.rice.kns.util.MaintenanceUtils;
 70  
 import org.kuali.rice.kns.util.MessageMap;
 71  
 import org.kuali.rice.kns.util.ObjectUtils;
 72  
 import org.kuali.rice.kns.web.format.FormatException;
 73  
 import org.kuali.rice.kns.web.ui.Section;
 74  
 import org.kuali.rice.kns.web.ui.SectionBridge;
 75  
 
 76  
 /**
 77  
  * Base Maintainable class to hold things common to all maintainables.
 78  
  */
 79  
 public class KualiMaintainableImpl implements Maintainable, Serializable {
 80  
     private static final long serialVersionUID = 4814145799502207182L;
 81  
 
 82  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMaintainableImpl.class);
 83  
 
 84  
     protected String documentNumber;
 85  
     protected PersistableBusinessObject businessObject;
 86  
     protected Class boClass;
 87  
     protected String maintenanceAction;
 88  
     
 89  0
     protected Map<String,PersistableBusinessObject> newCollectionLines = new HashMap<String,PersistableBusinessObject>();
 90  0
     protected Map<String, Boolean> inactiveRecordDisplay = new HashMap<String, Boolean>();
 91  
     
 92  
     protected String docTypeName;
 93  
 
 94  
     protected static PersistenceStructureService persistenceStructureService;
 95  
     
 96  
     protected static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 97  
     protected static DataDictionaryService dataDictionaryService;
 98  
     protected static BusinessObjectService businessObjectService;
 99  
     protected static BusinessObjectDictionaryService businessObjectDictionaryService;
 100  
     protected static EncryptionService encryptionService;
 101  
     protected static org.kuali.rice.kim.service.PersonService personService;
 102  
     protected static BusinessObjectMetaDataService businessObjectMetaDataService;
 103  
     protected static BusinessObjectAuthorizationService businessObjectAuthorizationService;
 104  
     protected static MaintenanceDocumentService maintenanceDocumentService;
 105  
     protected static DocumentHelperService documentHelperService;
 106  
     
 107  
     /**
 108  
      * Default empty constructor
 109  
      */
 110  0
     public KualiMaintainableImpl() {
 111  0
     }
 112  
 
 113  
     /**
 114  
      * Constructor which initializes the business object to be maintained.
 115  
      * 
 116  
      * @param businessObject
 117  
      */
 118  
     public KualiMaintainableImpl(PersistableBusinessObject businessObject) {
 119  0
         this();
 120  0
         this.businessObject = businessObject;
 121  0
     }
 122  
 
 123  
     public void setupNewFromExisting( MaintenanceDocument document, Map<String,String[]> parameters ) {
 124  
         
 125  0
     }
 126  
 
 127  
     public void processAfterPost( MaintenanceDocument document, Map<String,String[]> parameters ) {
 128  
         
 129  0
     }
 130  
     
 131  
     /**
 132  
      * This is a hook to allow the document to override the generic document title.
 133  
      * 
 134  
      * @return String   document title
 135  
      */
 136  
     public String getDocumentTitle(MaintenanceDocument document) {
 137  
         //default implementation is to allow MaintenanceDocumentBase to generate the doc title
 138  0
         return "";
 139  
     }
 140  
 
 141  
     /**
 142  
      * Note: as currently implemented, every key field for a given BusinessObject subclass must have a visible getter.
 143  
      * 
 144  
      * @return String containing the business object class and key value pairs of the current instance that can be used as a unique
 145  
      *         locking representation.
 146  
      */
 147  
     public List<MaintenanceLock> generateMaintenanceLocks() {
 148  
 
 149  
         //NOTE: KualiGlobalMaintainableImpl overrides this method and forces all globals to override that, so they each do their own thing
 150  
         
 151  0
         List<MaintenanceLock> maintenanceLocks = new ArrayList<MaintenanceLock>();
 152  0
         StringBuffer lockRepresentation = new StringBuffer(boClass.getName());
 153  0
         lockRepresentation.append(KNSConstants.Maintenance.AFTER_CLASS_DELIM);
 154  
 
 155  0
         PersistableBusinessObject bo = getBusinessObject();
 156  0
         List keyFieldNames = getMaintenanceDocumentDictionaryService().getLockingKeys(getDocumentTypeName());
 157  
 
 158  0
         for (Iterator i = keyFieldNames.iterator(); i.hasNext();) {
 159  0
             String fieldName = (String) i.next();
 160  0
             Object fieldValue = ObjectUtils.getPropertyValue(bo, fieldName);
 161  0
             if (fieldValue == null) {
 162  0
                 fieldValue = "";
 163  
             }
 164  
             
 165  
             // check if field is a secure
 166  0
             if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(boClass, fieldName)) {
 167  
                 try {
 168  0
                     fieldValue = getEncryptionService().encrypt(fieldValue);
 169  
                 }
 170  0
                 catch (GeneralSecurityException e) {
 171  0
                     LOG.error("Unable to encrypt secure field for locking representation " + e.getMessage());
 172  0
                     throw new RuntimeException("Unable to encrypt secure field for locking representation " + e.getMessage());
 173  0
                 }
 174  
             }
 175  
 
 176  0
             lockRepresentation.append(fieldName);
 177  0
             lockRepresentation.append(KNSConstants.Maintenance.AFTER_FIELDNAME_DELIM);
 178  0
             lockRepresentation.append(String.valueOf(fieldValue));
 179  0
             if (i.hasNext()) {
 180  0
                 lockRepresentation.append(KNSConstants.Maintenance.AFTER_VALUE_DELIM);
 181  
             }
 182  0
         }
 183  
 
 184  0
         MaintenanceLock maintenanceLock = new MaintenanceLock();
 185  0
         maintenanceLock.setDocumentNumber(documentNumber);
 186  0
         maintenanceLock.setLockingRepresentation(lockRepresentation.toString());
 187  0
         maintenanceLocks.add(maintenanceLock);
 188  0
         return maintenanceLocks;
 189  
     }
 190  
 
 191  
     /**
 192  
      * @see org.kuali.rice.kns.maintenance.Maintainable#populateBusinessObject(java.util.Map, org.kuali.rice.kns.document.MaintenanceDocument, String)
 193  
      */
 194  
     @SuppressWarnings("unchecked")
 195  
         public Map populateBusinessObject(Map<String, String> fieldValues, MaintenanceDocument maintenanceDocument, String methodToCall) {
 196  0
         fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
 197  0
         Map newFieldValues = null;
 198  0
         newFieldValues = getPersonService().resolvePrincipalNamesToPrincipalIds(getBusinessObject(), fieldValues);
 199  
    
 200  0
         Map cachedValues = FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), newFieldValues);
 201  0
         performForceUpperCase(newFieldValues);
 202  
         
 203  0
         return cachedValues;
 204  
     }
 205  
     
 206  
     /**
 207  
      * Special hidden parameters are set on the maintenance jsp starting with a prefix that tells us which fields have been
 208  
      * encrypted. This field finds the those parameters in the map, whose value gives us the property name that has an encrypted
 209  
      * value. We then need to decrypt the value in the Map before the business object is populated.
 210  
      * 
 211  
      * @param fieldValues - possibly with encrypted values
 212  
      * @return Map fieldValues - with no encrypted values
 213  
      */
 214  
     protected Map<String, String> decryptEncryptedData(Map<String, String> fieldValues, MaintenanceDocument maintenanceDocument, String methodToCall) {
 215  
             try {
 216  0
                     MaintenanceDocumentRestrictions auths = KNSServiceLocator.getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(maintenanceDocument, GlobalVariables.getUserSession().getPerson());
 217  0
                 for (Iterator<String> iter = fieldValues.keySet().iterator(); iter.hasNext();) {
 218  0
                 String fieldName = iter.next();
 219  0
                 String fieldValue = (String) fieldValues.get(fieldName);
 220  
 
 221  0
                 if (fieldValue != null &&!"".equals(fieldValue) && fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)){
 222  0
                         if(shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall)){
 223  0
                             String encryptedValue = fieldValue;
 224  
         
 225  
                             // take off the postfix
 226  0
                             encryptedValue = StringUtils.stripEnd(encryptedValue, EncryptionService.ENCRYPTION_POST_PREFIX);
 227  0
                             String decryptedValue = getEncryptionService().decrypt(encryptedValue);
 228  
         
 229  0
                             fieldValues.put(fieldName, decryptedValue);
 230  0
                         } else
 231  0
                                 throw new RuntimeException(
 232  
                                         "The field value for field name "+fieldName+" should not be encrypted.");
 233  0
                     } else if(fieldValue != null &&!"".equals(fieldValue)  && shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall))
 234  0
                             throw new RuntimeException(
 235  
                                     "The field value for field name "+fieldName+" should be encrypted.");
 236  0
                         } 
 237  
                 }
 238  0
         catch (GeneralSecurityException e) {
 239  0
             throw new RuntimeException("Unable to decrypt secure data: " + e.getMessage());
 240  0
         }
 241  
        
 242  0
         return fieldValues;
 243  
     }
 244  
 
 245  
     /**
 246  
      * Determines whether the field in a request should be encrypted.  This base implementation does not work for properties of collection elements.
 247  
      * 
 248  
      * This base implementation will only return true if the maintenance document is being refreshed after a lookup (i.e. methodToCall is "refresh") and 
 249  
      * the data dictionary-based attribute security definition has any restriction defined, whether the user would be authorized to view the field.  This
 250  
      * assumes that only fields returned from a lookup should be encrypted in a request.  If the user otherwise has no permissions to view/edit the field,
 251  
      * then a request parameter will not be sent back to the server for population.
 252  
      * 
 253  
      * @param maintenanceDocument
 254  
      * @param fieldName
 255  
      * @param auths
 256  
      * @param methodToCall
 257  
      * @return
 258  
      */
 259  
     protected boolean shouldFieldBeEncrypted(MaintenanceDocument maintenanceDocument, String fieldName, MaintenanceDocumentRestrictions auths, String methodToCall){
 260  0
             if ("refresh".equals(methodToCall) && fieldName != null) {
 261  0
                     fieldName = fieldName.replaceAll("\\[[0-9]*+\\]", "");
 262  0
                     fieldName = fieldName.replaceAll("^add\\.", "");
 263  0
                     Map<String, AttributeSecurity> fieldNameToAttributeSecurityMap = MaintenanceUtils.retrievePropertyPathToAttributeSecurityMappings(getDocumentTypeName());
 264  0
                     AttributeSecurity attributeSecurity = fieldNameToAttributeSecurityMap.get(fieldName);
 265  0
                     return attributeSecurity != null && attributeSecurity.hasRestrictionThatRemovesValueFromUI();
 266  
             }
 267  
             else {
 268  0
             return false;
 269  
                }
 270  
     }
 271  
     
 272  
     /**
 273  
      * Calls method to get all the core sections for the business object defined in the data dictionary. Then determines if the bo
 274  
      * has custom attributes, if so builds a custom attribute section and adds to the section list.
 275  
      * 
 276  
      * @return List of org.kuali.ui.Section objects
 277  
      */
 278  
     public List getSections(MaintenanceDocument document, Maintainable oldMaintainable) {
 279  0
         List<Section> sections = new ArrayList<Section>();
 280  0
         sections.addAll(getCoreSections(document, oldMaintainable));
 281  
         
 282  0
         return sections;
 283  
     }
 284  
     
 285  
 
 286  
     /**
 287  
      * Gets list of maintenance sections built from the data dictionary. If the section contains maintenance fields, construct
 288  
      * Row/Field UI objects and place under Section UI. If section contains a maintenance collection, call method to build a Section
 289  
      * UI which contains rows of Container Fields.
 290  
      * 
 291  
      * @return List of org.kuali.ui.Section objects
 292  
      */
 293  
     public List<Section> getCoreSections(MaintenanceDocument document, Maintainable oldMaintainable) {
 294  0
         List<Section> sections = new ArrayList<Section>();
 295  0
         MaintenanceDocumentRestrictions maintenanceRestrictions = KNSServiceLocator.getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(document, GlobalVariables.getUserSession().getPerson());
 296  
         
 297  0
         MaintenanceDocumentPresentationController maintenanceDocumentPresentationController = (MaintenanceDocumentPresentationController) getDocumentHelperService()
 298  
                 .getDocumentPresentationController(document);
 299  0
         Set<String> conditionallyRequiredFields = maintenanceDocumentPresentationController.getConditionallyRequiredPropertyNames(document);
 300  
         
 301  0
         List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 302  
         try {
 303  
             // iterate through section definitions and create Section UI object
 304  0
             for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
 305  0
                 MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
 306  
 
 307  0
                 List<String> displayedFieldNames = new ArrayList<String>();
 308  0
                 if (!maintenanceRestrictions.isHiddenSectionId(maintSectionDef.getId())) {
 309  
                         
 310  0
                         for (Iterator iter2 = maintSectionDef.getMaintainableItems().iterator(); iter2.hasNext();) {
 311  0
                                 MaintainableItemDefinition item = (MaintainableItemDefinition) iter2.next();
 312  0
                                 if (item instanceof MaintainableFieldDefinition) {
 313  0
                                     displayedFieldNames.add(((MaintainableFieldDefinition) item).getName());
 314  
                                 }
 315  0
                         }
 316  
                         
 317  0
                         Section section = SectionBridge.toSection(maintSectionDef, getBusinessObject(), this, oldMaintainable, getMaintenanceAction(), displayedFieldNames, conditionallyRequiredFields);
 318  0
                         if(maintenanceRestrictions.isReadOnlySectionId(maintSectionDef.getId())){
 319  0
                                 section.setReadOnly(true);
 320  
                         }
 321  
                 
 322  
                         // add to section list
 323  0
                         sections.add(section);
 324  
                 }
 325  
                 
 326  0
             }
 327  
             
 328  0
         } catch (InstantiationException e) {
 329  0
             LOG.error("Unable to create instance of object class" + e.getMessage());
 330  0
             throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
 331  0
         } catch (IllegalAccessException e) {
 332  0
             LOG.error("Unable to create instance of object class" + e.getMessage());
 333  0
             throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
 334  0
         }
 335  
 
 336  0
         return sections;
 337  
     }
 338  
     
 339  
     /**
 340  
      * 
 341  
      * @see org.kuali.rice.kns.maintenance.Maintainable#saveBusinessObject()
 342  
      */
 343  
     public void saveBusinessObject() {
 344  0
         getBusinessObjectService().linkAndSave(businessObject);
 345  0
     }
 346  
     
 347  
     /**
 348  
      * Retrieves title for maintenance document from data dictionary
 349  
      */
 350  
     public String getMaintainableTitle() {        
 351  0
         return getMaintenanceDocumentDictionaryService().getMaintenanceLabel(getDocumentTypeName());
 352  
     }
 353  
 
 354  
     /**
 355  
      * Retrieves the status of the boNotesEnabled
 356  
      */
 357  
     public boolean isBoNotesEnabled() {
 358  0
             return getBusinessObjectDictionaryService().areNotesSupported(this.boClass);
 359  
     }
 360  
     
 361  
     /**
 362  
      * @see org.kuali.rice.kns.maintenance.Maintainable#refresh(java.lang.String, java.util.Map) Impls will be needed if custom action
 363  
      *      is needed on refresh.
 364  
      */
 365  
     public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) {
 366  0
         String referencesToRefresh = (String) fieldValues.get(KNSConstants.REFERENCES_TO_REFRESH);
 367  0
         refreshReferences(referencesToRefresh);
 368  0
     }
 369  
 
 370  
     
 371  
     protected void refreshReferences(String referencesToRefresh) {
 372  0
         PersistenceStructureService persistenceStructureService = getPersistenceStructureService();
 373  0
         if (StringUtils.isNotBlank(referencesToRefresh)) {
 374  0
             String[] references = StringUtils.split(referencesToRefresh, KNSConstants.REFERENCES_TO_REFRESH_SEPARATOR);
 375  0
             for (String reference : references) {
 376  0
                 if (StringUtils.isNotBlank(reference)) {
 377  0
                     if (reference.startsWith(KNSConstants.ADD_PREFIX + ".")) {
 378  
                         // add one for the period
 379  0
                         reference = reference.substring(KNSConstants.ADD_PREFIX.length() + 1);
 380  
                         
 381  0
                         String boToRefreshName = StringUtils.substringBeforeLast(reference, ".");
 382  0
                         String propertyToRefresh = StringUtils.substringAfterLast(reference, ".");
 383  0
                         if (StringUtils.isNotBlank(propertyToRefresh)) {
 384  0
                             PersistableBusinessObject addlineBO = getNewCollectionLine(boToRefreshName);
 385  0
                             Class addlineBOClass = addlineBO.getClass();
 386  0
                             if ( LOG.isDebugEnabled() ) {
 387  0
                                 LOG.debug("Refresh this \"new\"/add object for the collections:  " + reference);
 388  
                             }
 389  0
                             if (persistenceStructureService.hasReference(addlineBOClass, propertyToRefresh) ||
 390  
                                     persistenceStructureService.hasCollection(addlineBOClass, propertyToRefresh)) {
 391  0
                                 addlineBO.refreshReferenceObject(propertyToRefresh);
 392  
                             }
 393  
                             else {
 394  0
                                 if (getDataDictionaryService().hasRelationship(addlineBOClass.getName(), propertyToRefresh)) {
 395  
                                     // a DD mapping, try to go straight to the object and refresh it there
 396  0
                                     Object possibleBO = ObjectUtils.getPropertyValue(addlineBO, propertyToRefresh);
 397  0
                                     if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
 398  0
                                         ((PersistableBusinessObject) possibleBO).refresh();
 399  
                                     }
 400  
                                 }
 401  
                             }
 402  0
                         }
 403  
                         else {
 404  0
                             LOG.error("Error: unable to refresh this \"new\"/add object for the collections:  " + reference);
 405  
                         }
 406  0
                     }
 407  0
                     else if (ObjectUtils.isNestedAttribute(reference)) {
 408  0
                         Object nestedObject = ObjectUtils.getNestedValue(getBusinessObject(), ObjectUtils.getNestedAttributePrefix(reference));
 409  0
                         if (nestedObject instanceof Collection) {
 410  
                             // do nothing, probably because it's not really a collection reference but a relationship defined in the DD for a collections lookup
 411  
                             // this part will need to be rewritten when the DD supports true collection references   
 412  
                         }
 413  0
                         else if (nestedObject instanceof PersistableBusinessObject) {
 414  0
                             String propertyToRefresh = ObjectUtils.getNestedAttributePrimitive(reference);
 415  0
                             if (persistenceStructureService.hasReference(nestedObject.getClass(), propertyToRefresh) ||
 416  
                                     persistenceStructureService.hasCollection(nestedObject.getClass(), propertyToRefresh)) {
 417  0
                                 if ( LOG.isDebugEnabled() ) {
 418  0
                                     LOG.debug("Refeshing " + ObjectUtils.getNestedAttributePrefix(reference) + " " + ObjectUtils.getNestedAttributePrimitive(reference));
 419  
                                 }
 420  0
                                 ((PersistableBusinessObject) nestedObject).refreshReferenceObject(propertyToRefresh);
 421  
                             }
 422  
                             else {
 423  
                                 // a DD mapping, try to go straight to the object and refresh it there
 424  0
                                 Object possibleBO = ObjectUtils.getPropertyValue(nestedObject, propertyToRefresh);
 425  0
                                 if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
 426  0
                                     if (getDataDictionaryService().hasRelationship(possibleBO.getClass().getName(), propertyToRefresh)) {
 427  0
                                         ((PersistableBusinessObject) possibleBO).refresh();
 428  
                                     }
 429  
                                 }
 430  
                             }
 431  0
                         }
 432  
                         else {
 433  0
                             LOG.warn("Expected that a referenceToRefresh (" + reference + ")  would be a PersistableBusinessObject or Collection, but instead, it was of class " + nestedObject.getClass().getName());
 434  
                         }
 435  0
                     }
 436  
                     else {
 437  0
                         if ( LOG.isDebugEnabled() ) {
 438  0
                             LOG.debug("Refreshing " + reference);
 439  
                         }
 440  0
                         if (persistenceStructureService.hasReference(boClass, reference) ||
 441  
                                 persistenceStructureService.hasCollection(boClass, reference)) {
 442  0
                             getBusinessObject().refreshReferenceObject(reference);
 443  
                         }
 444  
                         else {
 445  0
                                                         if (getDataDictionaryService().hasRelationship(getBusinessObject().getClass().getName(), reference)) {
 446  
                                 // a DD mapping, try to go straight to the object and refresh it there
 447  0
                                 Object possibleRelationship = ObjectUtils.getPropertyValue(getBusinessObject(), reference);
 448  0
                                 if (possibleRelationship != null) {
 449  0
                                     if (possibleRelationship instanceof PersistableBusinessObject) {
 450  0
                                         ((PersistableBusinessObject) possibleRelationship).refresh();
 451  
                                     }
 452  0
                                     else if (possibleRelationship instanceof Collection) {
 453  
                                         // do nothing, probably because it's not really a collection reference but a relationship defined in the DD for a collections lookup
 454  
                                         // this part will need to be rewritten when the DD supports true collection references   
 455  
                                     }
 456  
                                     else {
 457  0
                                         LOG.warn("Expected that a referenceToRefresh (" + reference + 
 458  
                                                 ")  would be a PersistableBusinessObject or Collection, but instead, it was of class " + 
 459  
                                                 possibleRelationship.getClass().getName());
 460  
                                     }
 461  
                                 }
 462  
                             }
 463  
                         }
 464  
                     }
 465  
                 }
 466  
             }
 467  
         }
 468  0
     }
 469  
     
 470  
 
 471  
     public void addMultipleValueLookupResults(MaintenanceDocument document, String collectionName, Collection<PersistableBusinessObject> rawValues, boolean needsBlank, PersistableBusinessObject bo) {
 472  0
         Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(bo, collectionName);
 473  0
         String docTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentType();
 474  
         
 475  0
         List<String> duplicateIdentifierFieldsFromDataDictionary = getDuplicateIdentifierFieldsFromDataDictionary(docTypeName, collectionName);
 476  
         
 477  0
         List<String> existingIdentifierList = getMultiValueIdentifierList(maintCollection, duplicateIdentifierFieldsFromDataDictionary);
 478  
         
 479  0
         Class collectionClass = getMaintenanceDocumentDictionaryService().getCollectionBusinessObjectClass(docTypeName, collectionName);
 480  
 
 481  0
         List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 482  0
         Map<String, String> template = MaintenanceUtils.generateMultipleValueLookupBOTemplate(sections, collectionName);
 483  
         try {
 484  0
             for (PersistableBusinessObject nextBo : rawValues) {
 485  
                 PersistableBusinessObject templatedBo;
 486  0
                 if(needsBlank) {
 487  0
                     templatedBo = (PersistableBusinessObject) collectionClass.newInstance();                    
 488  
                 } else {
 489  
                     //templatedBo = (PersistableBusinessObject) ObjectUtils.createHybridBusinessObject(collectionClass, nextBo, template);
 490  
                         try {
 491  0
                                 ModuleService moduleService = KNSServiceLocator.getKualiModuleService().getResponsibleModuleService(collectionClass);
 492  0
                                 if (moduleService != null && moduleService.isExternalizable(collectionClass))
 493  0
                                         templatedBo = (PersistableBusinessObject)moduleService.createNewObjectFromExternalizableClass(collectionClass);
 494  
                                 else
 495  0
                                         templatedBo = (PersistableBusinessObject) collectionClass.newInstance();
 496  
                     }
 497  0
                     catch (Exception e) {
 498  0
                         throw new RuntimeException("Cannot instantiate " + collectionClass.getName(), e);
 499  0
                     }
 500  
                     // first set the default values specified in the DD
 501  0
                         setNewCollectionLineDefaultValues(collectionName, templatedBo);
 502  
                          // then set the values from the multiple value lookup result
 503  0
                         ObjectUtils.createHybridBusinessObject(templatedBo, nextBo, template);
 504  
                         
 505  0
                     prepareBusinessObjectForAdditionFromMultipleValueLookup(collectionName, templatedBo);
 506  
                 }
 507  0
                     templatedBo.setNewCollectionRecord(true);
 508  
                 
 509  0
                 if (!hasBusinessObjectExisted(templatedBo, existingIdentifierList, duplicateIdentifierFieldsFromDataDictionary)) {   
 510  0
                     maintCollection.add(templatedBo);
 511  
 
 512  
                 }
 513  0
             }
 514  
         } 
 515  0
         catch (Exception e) {
 516  0
                 LOG.error("Unable to add multiple value lookup results " + e.getMessage());
 517  0
             throw new RuntimeException("Unable to add multiple value lookup results " + e.getMessage());
 518  0
         }
 519  0
     }
 520  
     
 521  
     /**
 522  
      * This method is to retrieve a List of fields which are specified in the maintenance document
 523  
      * data dictionary as the duplicateIdentificationFields. This List is used to determine whether
 524  
      * the new entry being added to the collection is a duplicate entry and if so, we should not
 525  
      * add the new entry to the existing collection
 526  
      * 
 527  
      * @param docTypeName
 528  
      * @param collectionName
 529  
      */
 530  
     public List<String> getDuplicateIdentifierFieldsFromDataDictionary(String docTypeName, String collectionName) {
 531  0
             List<String> duplicateIdentifierFieldNames = new ArrayList<String>();
 532  0
             MaintainableCollectionDefinition collDef = getMaintenanceDocumentDictionaryService().getMaintainableCollection(docTypeName, collectionName);
 533  0
             Collection<MaintainableFieldDefinition> fieldDef = collDef.getDuplicateIdentificationFields();
 534  0
             for (MaintainableFieldDefinition eachFieldDef : fieldDef) {
 535  0
                     duplicateIdentifierFieldNames.add(eachFieldDef.getName());
 536  
             }
 537  0
             return duplicateIdentifierFieldNames;
 538  
     }
 539  
     
 540  
 
 541  
     public List<String> getMultiValueIdentifierList(Collection maintCollection, List<String> duplicateIdentifierFields) {
 542  0
         List<String> identifierList = new ArrayList<String>();
 543  0
         for (PersistableBusinessObject bo : (Collection<PersistableBusinessObject>)maintCollection) {
 544  0
                 String uniqueIdentifier = new String();
 545  0
                 for (String identifierField : duplicateIdentifierFields) {
 546  0
                     uniqueIdentifier = uniqueIdentifier + identifierField + "-" + ObjectUtils.getPropertyValue(bo, identifierField);
 547  
                 }
 548  0
                 if (StringUtils.isNotEmpty(uniqueIdentifier)) {
 549  0
                 identifierList.add(uniqueIdentifier);
 550  
                 }
 551  0
         }
 552  0
         return identifierList;
 553  
     } 
 554  
     
 555  
     public boolean hasBusinessObjectExisted(BusinessObject bo, List<String> existingIdentifierList, List<String> duplicateIdentifierFields) {
 556  0
             String uniqueIdentifier = new String();
 557  0
         for (String identifierField : duplicateIdentifierFields) {
 558  0
             uniqueIdentifier = uniqueIdentifier + identifierField + "-" + ObjectUtils.getPropertyValue(bo, identifierField);
 559  
         }
 560  0
         if (existingIdentifierList.contains(uniqueIdentifier)) {
 561  0
             return true; 
 562  
         }
 563  
         else {
 564  0
             return false;
 565  
         }
 566  
     } 
 567  
     
 568  
     public void prepareBusinessObjectForAdditionFromMultipleValueLookup(String collectionName, BusinessObject bo) {
 569  
         // default implementation does nothing
 570  0
     }
 571  
     
 572  
     /**
 573  
      * 
 574  
      * @see org.kuali.rice.kns.maintenance.Maintainable#prepareForSave()
 575  
      */
 576  
     public void prepareForSave() {
 577  0
         if ( businessObject != null ) {
 578  0
             businessObject.prepareForWorkflow();
 579  
         }
 580  0
     }
 581  
 
 582  
     /**
 583  
      * 
 584  
      * @see org.kuali.rice.kns.maintenance.Maintainable#processAfterRetrieve()
 585  
      */
 586  
     public void processAfterRetrieve() {
 587  0
     }
 588  
     
 589  
         /** 
 590  
      * Set the new collection records back to true so they can be deleted (copy should act like new)
 591  
      * 
 592  
          * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#processAfterCopy()
 593  
          */
 594  
         public void processAfterCopy( MaintenanceDocument document, Map<String,String[]> parameters ) {
 595  
         try {
 596  0
             ObjectUtils.setObjectPropertyDeep(businessObject, KNSPropertyConstants.NEW_COLLECTION_RECORD, boolean.class, true, 2);
 597  
         }
 598  0
         catch (Exception e) {
 599  0
             LOG.error("unable to set newCollectionRecord property: " + e.getMessage(), e);
 600  0
             throw new RuntimeException("unable to set newCollectionRecord property: " + e.getMessage(), e);
 601  0
         }
 602  0
         }
 603  
     
 604  
     /**
 605  
      * @see org.kuali.rice.kns.maintenance.Maintainable#processAfterEdit()
 606  
      */
 607  
     public void processAfterEdit( MaintenanceDocument document, Map<String,String[]> parameters ) {
 608  0
     }
 609  
 
 610  
     /**
 611  
      * @see org.kuali.rice.kns.maintenance.Maintainable#processAfterNew()
 612  
      */
 613  
     public void processAfterNew( MaintenanceDocument document, Map<String,String[]> parameters ) {
 614  0
     }
 615  
     
 616  
     /**
 617  
      * Retrieves the document type name from the data dictionary based on business object class
 618  
      */
 619  
     protected String getDocumentTypeName() {
 620  0
         return getMaintenanceDocumentDictionaryService().getDocumentTypeName(boClass);
 621  
     }
 622  
 
 623  
     /**
 624  
      * @return Returns the instance of the business object being maintained.
 625  
      */
 626  
     public PersistableBusinessObject getBusinessObject() {
 627  0
         return businessObject;
 628  
     }
 629  
 
 630  
     /**
 631  
      * @param businessObject Sets the instance of a business object that will be maintained.
 632  
      */
 633  
     public void setBusinessObject(PersistableBusinessObject businessObject) {
 634  0
         this.businessObject = businessObject;
 635  0
     }
 636  
 
 637  
 
 638  
     /**
 639  
      * @return Returns the boClass.
 640  
      */
 641  
     public Class getBoClass() {
 642  0
         return boClass;
 643  
     }
 644  
 
 645  
 
 646  
     /**
 647  
      * @param boClass The boClass to set.
 648  
      */
 649  
     public void setBoClass(Class boClass) {
 650  0
         this.boClass = boClass;
 651  0
         this.docTypeName = getDocumentTypeName();
 652  0
     }
 653  
 
 654  
     /**
 655  
      * @return Returns the maintenanceAction.
 656  
      */
 657  
     public String getMaintenanceAction() {
 658  0
         return maintenanceAction;
 659  
     }
 660  
 
 661  
     /**
 662  
      * @param maintenanceAction The maintenanceAction to set.
 663  
      */
 664  
     public void setMaintenanceAction(String maintenanceAction) {
 665  0
         this.maintenanceAction = maintenanceAction;
 666  0
     }
 667  
 
 668  
 
 669  
     /**
 670  
      * 
 671  
      * @see org.kuali.rice.kns.maintenance.Maintainable#setGenerateDefaultValues()
 672  
      */
 673  
     public void setGenerateDefaultValues(String docTypeName) {
 674  0
      List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 675  0
      Map defaultValues = new HashMap();
 676  
 
 677  
      try {
 678  
          // iterate through section definitions
 679  0
          for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
 680  
              
 681  0
              MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
 682  0
              Collection maintItems = maintSectionDef.getMaintainableItems();
 683  0
              for (Iterator iterator = maintItems.iterator(); iterator.hasNext();) {
 684  0
                  MaintainableItemDefinition item = (MaintainableItemDefinition) iterator.next();
 685  
 
 686  0
                  if (item instanceof MaintainableFieldDefinition) {
 687  0
                      MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
 688  
                      
 689  0
                      String defaultValue = maintainableFieldDefinition.getDefaultValue();
 690  0
                      if (defaultValue != null) {
 691  0
                              if (defaultValue.equals("true")) {
 692  0
                                      defaultValue = "Yes";
 693  
                          }
 694  0
                          else if (defaultValue.equals("false")) {
 695  0
                               defaultValue = "No";
 696  
                              }
 697  
                       }
 698  
 
 699  0
                       Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
 700  0
                       if (defaultValueFinderClass != null) {
 701  0
                               defaultValue = ((ValueFinder) defaultValueFinderClass.newInstance()).getValue();
 702  
                             
 703  
                       }
 704  0
                       if (defaultValue != null) {
 705  0
                               defaultValues.put(item.getName(), defaultValue);
 706  
                       }
 707  
                   }
 708  0
              }   
 709  0
          }
 710  0
          Map cachedValues = FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
 711  0
      } catch(Exception e){
 712  0
              LOG.error("Unable to set default value " + e.getMessage(), e);
 713  0
              throw new RuntimeException("Unable to set default value" + e.getMessage(), e);
 714  0
      }
 715  
     
 716  0
     }
 717  
 
 718  
 
 719  
     /**
 720  
      * 
 721  
      * @see org.kuali.rice.kns.maintenance.Maintainable#setGenerateBlankRequiredValues()
 722  
      */
 723  
     public void setGenerateBlankRequiredValues(String docTypeName) {
 724  
          try {
 725  0
              List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 726  0
                  Map<String,String> defaultValues = new HashMap<String,String>();
 727  
              
 728  0
                  for ( MaintainableSectionDefinition maintSectionDef : sectionDefinitions ) {
 729  0
                          for ( MaintainableItemDefinition item : maintSectionDef.getMaintainableItems() ) {
 730  0
                      if (item instanceof MaintainableFieldDefinition) {
 731  0
                          MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
 732  0
                          if (maintainableFieldDefinition.isRequired() 
 733  
                                          && maintainableFieldDefinition.isUnconditionallyReadOnly() ) {
 734  0
                                  Object currPropVal = ObjectUtils.getPropertyValue(this.getBusinessObject(), item.getName()); 
 735  0
                                  if ( currPropVal == null
 736  
                                                 || (currPropVal instanceof String && StringUtils.isBlank( (String)currPropVal ) ) 
 737  
                                                  ) {
 738  0
                                          Class<? extends ValueFinder> defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
 739  0
                                          if (defaultValueFinderClass != null) {
 740  0
                                                  String defaultValue = defaultValueFinderClass.newInstance().getValue();
 741  0
                                                   if (defaultValue != null) {
 742  0
                                                           defaultValues.put(item.getName(), defaultValue);
 743  
                                                   }    
 744  
                                  }
 745  
                                  }
 746  
                          }
 747  0
                      }
 748  
                  }   
 749  
              }
 750  0
              FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
 751  0
          } catch(Exception e){
 752  0
                  LOG.error("Unable to set blank required value " + e.getMessage(), e);
 753  0
                  throw new RuntimeException("Unable to set blank required value" + e.getMessage(), e);
 754  0
          }
 755  0
     }
 756  
 
 757  
 
 758  
     /**
 759  
      * Sets the documentNumber attribute value.
 760  
      * 
 761  
      * @param documentNumber The documentNumber to set.
 762  
      */
 763  
     public final void setDocumentNumber(String documentNumber) {
 764  0
         this.documentNumber = documentNumber;
 765  0
     }
 766  
 
 767  
     @Deprecated
 768  
     public void processAfterAddLine(String colName, Class colClass) {
 769  0
     }
 770  
     
 771  
     /**
 772  
      * @see org.kuali.rice.kns.maintenance.Maintainable#processBeforeAddLine(java.lang.String, java.lang.Class, org.kuali.rice.kns.bo.BusinessObject)
 773  
      */
 774  
     public void processBeforeAddLine(String colName, Class colClass, BusinessObject addBO) {
 775  0
     }
 776  
 
 777  
     /**
 778  
      * @see org.kuali.rice.kns.maintenance.Maintainable#getShowInactiveRecords(java.lang.String)
 779  
      */
 780  
     public boolean getShowInactiveRecords(String collectionName) {
 781  0
         return InactiveRecordsHidingUtils.getShowInactiveRecords(inactiveRecordDisplay, collectionName);
 782  
     }
 783  
         
 784  
     /**
 785  
      * @see org.kuali.rice.kns.maintenance.Maintainable#setShowInactiveRecords(java.lang.String, boolean)
 786  
      */
 787  
     public void setShowInactiveRecords(String collectionName, boolean showInactive) {
 788  0
         InactiveRecordsHidingUtils.setShowInactiveRecords(inactiveRecordDisplay, collectionName, showInactive);
 789  0
     }
 790  
         
 791  
     /**
 792  
      * @return the inactiveRecordDisplay
 793  
      */
 794  
     public Map<String, Boolean> getInactiveRecordDisplay() {
 795  0
         return inactiveRecordDisplay;
 796  
     }
 797  
 
 798  
     public void addNewLineToCollection( String collectionName ) {
 799  
         
 800  0
         if ( LOG.isDebugEnabled() ) {
 801  0
             LOG.debug( "addNewLineToCollection( " + collectionName + " )" );
 802  
         }
 803  
         // get the new line from the map
 804  0
         PersistableBusinessObject addLine = newCollectionLines.get( collectionName );
 805  0
         if ( addLine != null ) {
 806  
             // mark the isNewCollectionRecord so the option to delete this line will be presented
 807  0
             addLine.setNewCollectionRecord(true);
 808  
 
 809  
             //if we add back add button on sub collection of an "add line" we may need extra logic here
 810  
 
 811  
             // get the collection from the business object
 812  0
             Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(getBusinessObject(), collectionName);
 813  
             // add the line to the collection
 814  0
             maintCollection.add( addLine );
 815  
             //refresh parent object since attributes could of changed prior to user clicking add
 816  
             
 817  0
             String referencesToRefresh = LookupUtils.convertReferencesToSelectCollectionToString(getAllRefreshableReferences(getBusinessObject().getClass()));
 818  0
             if (LOG.isInfoEnabled()) {
 819  0
                 LOG.info("References to refresh for adding line to collection " + collectionName + ": " + referencesToRefresh);
 820  
             }
 821  0
             refreshReferences(referencesToRefresh);
 822  
         }
 823  
         
 824  0
         initNewCollectionLine( collectionName );
 825  
         
 826  0
     }
 827  
     
 828  
     public PersistableBusinessObject getNewCollectionLine( String collectionName ) {
 829  0
         if ( LOG.isDebugEnabled() ) {
 830  
             //LOG.debug( this + ") getNewCollectionLine( " + collectionName + ")", new Exception( "tracing exception") );
 831  0
             LOG.debug( "newCollectionLines: " + newCollectionLines );
 832  
         }
 833  0
         PersistableBusinessObject addLine = newCollectionLines.get( collectionName );
 834  0
         if ( addLine == null ) {
 835  0
             addLine = initNewCollectionLine( collectionName );            
 836  
         }
 837  0
         return addLine;
 838  
     }
 839  
     
 840  
     public PersistableBusinessObject initNewCollectionLine( String collectionName ) {
 841  0
         if ( LOG.isDebugEnabled() ) {
 842  0
             LOG.debug( "initNewCollectionLine( " + collectionName + " )" );
 843  
         }
 844  
         // try to get the object from the map
 845  
         //BusinessObject addLine = newCollectionLines.get( collectionName );
 846  
         //if ( addLine == null ) {
 847  
             // if not there, instantiate a new one
 848  
         PersistableBusinessObject addLine;
 849  
         try {
 850  0
             addLine = (PersistableBusinessObject)getMaintenanceDocumentDictionaryService().getCollectionBusinessObjectClass( docTypeName, collectionName ).newInstance();
 851  0
         } catch ( Exception ex ) {
 852  0
             LOG.error( "unable to instantiate new collection line", ex );
 853  0
             throw new RuntimeException( "unable to instantiate new collection line", ex );
 854  0
         }
 855  
         // and add it to the map
 856  0
         newCollectionLines.put( collectionName, addLine );            
 857  
         //}
 858  
         // set its values to the defaults
 859  0
         setNewCollectionLineDefaultValues(collectionName, addLine);
 860  0
         return addLine;
 861  
     }
 862  
     
 863  
    
 864  
     /**
 865  
      * 
 866  
      * @see org.kuali.rice.kns.maintenance.Maintainable#populateNewCollectionLines(java.util.Map)
 867  
      */
 868  
     public Map<String, String> populateNewCollectionLines( Map<String, String> fieldValues, MaintenanceDocument maintenanceDocument, String methodToCall ) {
 869  0
         if ( LOG.isDebugEnabled() ) {
 870  0
             LOG.debug( "populateNewCollectionLines: " + fieldValues );
 871  
         }
 872  0
         fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
 873  
         
 874  0
         Map<String, String> cachedValues = new HashMap<String, String>();
 875  
         
 876  
         // loop over all collections with an enabled add line
 877  0
         List<MaintainableCollectionDefinition> collections = 
 878  
                 getMaintenanceDocumentDictionaryService().getMaintainableCollections( docTypeName );
 879  
                 
 880  0
         for ( MaintainableCollectionDefinition coll : collections ) {
 881  
             // get the collection name
 882  0
             String collName = coll.getName();
 883  0
             if ( LOG.isDebugEnabled() ) {
 884  0
                 LOG.debug( "checking for collection: " + collName );
 885  
             }
 886  
             // build a map for that collection
 887  0
             Map<String, String> collectionValues = new HashMap<String, String>();
 888  0
             Map<String, String> subCollectionValues = new HashMap<String,String>();
 889  
             // loop over the collection, extracting entries with a matching prefix
 890  0
             for ( Map.Entry<String, String> entry : fieldValues.entrySet() ) {
 891  0
                 String key = entry.getKey(); 
 892  0
                 if ( key.startsWith( collName ) ) {
 893  0
                     String subStrKey = key.substring( collName.length() + 1 );
 894  
                     //check for subcoll w/ '[', set collName to propername and put in correct name for collection values (i.e. strip '*[x].')
 895  0
                     if(key.contains("[")) {
 896  
                         
 897  
                         //collName = StringUtils.substringBeforeLast(key,"[");
 898  
                         
 899  
                         //need the whole thing if subcollection
 900  0
                         subCollectionValues.put( key, entry.getValue() );
 901  
                     } else {
 902  0
                         collectionValues.put( subStrKey, entry.getValue() );
 903  
                     }
 904  
                 }
 905  0
             }
 906  
             // send those values to the business object
 907  0
             if ( LOG.isDebugEnabled() ) {
 908  0
                 LOG.debug( "values for collection: " + collectionValues );
 909  
             }
 910  0
             cachedValues.putAll( FieldUtils.populateBusinessObjectFromMap( getNewCollectionLine( collName ), collectionValues, KNSConstants.MAINTENANCE_ADD_PREFIX + collName + "." ) );
 911  0
             performFieldForceUpperCase(getNewCollectionLine( collName ), collectionValues);
 912  
             
 913  0
             cachedValues.putAll( populateNewSubCollectionLines( coll, subCollectionValues ) );
 914  0
         }
 915  
         
 916  
         //cachedValues.putAll( FieldUtils.populateBusinessObjectFromMap( ))
 917  0
         return cachedValues;
 918  
     }
 919  
 
 920  
     /* Yes, I think this could be merged with the above code - I'm 
 921  
      * leaving it separate until I figure out of there are any issues which would reqire
 922  
      * that it be separated.
 923  
      */
 924  
     protected Map populateNewSubCollectionLines( MaintainableCollectionDefinition parentCollection, Map fieldValues) {
 925  0
         if ( LOG.isDebugEnabled() ) {
 926  0
             LOG.debug( "populateNewSubCollectionLines: " + fieldValues );
 927  
         }
 928  0
         Map cachedValues = new HashMap();
 929  
         
 930  0
         for ( MaintainableCollectionDefinition coll : parentCollection.getMaintainableCollections() ) {
 931  
             // get the collection name
 932  0
             String collName = coll.getName();
 933  
             
 934  
 
 935  0
             if ( LOG.isDebugEnabled() ) {
 936  0
                 LOG.debug( "checking for sub collection: " + collName );
 937  
             }
 938  0
             Map<String,String> parents = new HashMap<String,String>();
 939  
             //get parents from list
 940  0
             for ( Object entry : fieldValues.entrySet() ) {
 941  0
                 String key = (String)((Map.Entry)entry).getKey(); 
 942  0
                 if ( key.contains( collName ) ) {
 943  0
                     parents.put(StringUtils.substringBefore(key,"."),"");
 944  
                 }
 945  0
             }
 946  
             
 947  0
             for (String parent : parents.keySet()) {
 948  
                 // build a map for that collection
 949  0
                 Map<String,Object> collectionValues = new HashMap<String,Object>();
 950  
                 // loop over the collection, extracting entries with a matching prefix
 951  0
                 for ( Object entry : fieldValues.entrySet() ) {
 952  0
                     String key = (String)((Map.Entry)entry).getKey(); 
 953  0
                     if ( key.contains( parent ) ) {
 954  0
                         String substr = StringUtils.substringAfterLast(key,".");
 955  0
                         collectionValues.put( substr, ((Map.Entry)entry).getValue() );                                        
 956  
                     }
 957  0
                 }
 958  
                 // send those values to the business object
 959  0
                 if ( LOG.isDebugEnabled() ) {
 960  0
                     LOG.debug( "values for sub collection: " + collectionValues );
 961  
                 }
 962  0
                 GlobalVariables.getMessageMap().addToErrorPath( KNSConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName );
 963  0
                 cachedValues.putAll( FieldUtils.populateBusinessObjectFromMap( getNewCollectionLine( parent+"."+collName ), collectionValues, KNSConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName + "." ) );
 964  0
                 performFieldForceUpperCase(getNewCollectionLine( parent+"."+collName ), collectionValues);
 965  0
                 GlobalVariables.getMessageMap().removeFromErrorPath( KNSConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName );
 966  0
             }
 967  
             
 968  0
             cachedValues.putAll( populateNewSubCollectionLines( coll, fieldValues ) );
 969  0
         }
 970  
         
 971  0
         return cachedValues;
 972  
     }
 973  
     
 974  
 
 975  
     public Collection<String> getAffectedReferencesFromLookup(BusinessObject baseBO, String attributeName, String collectionPrefix) {
 976  0
         PersistenceStructureService pss = getPersistenceStructureService();
 977  0
         String nestedBOPrefix = "";
 978  0
         if (ObjectUtils.isNestedAttribute(attributeName)) {
 979  
             // if we're performing a lookup on a nested attribute, we need to use the nested BO all the way down the chain
 980  0
             nestedBOPrefix = ObjectUtils.getNestedAttributePrefix(attributeName);
 981  
             
 982  
             // renormalize the base BO so that the attribute name is not nested anymore 
 983  0
             Class reference = ObjectUtils.getPropertyType(baseBO, nestedBOPrefix, pss);
 984  0
             if (!(PersistableBusinessObject.class.isAssignableFrom(reference))) {
 985  0
                 return new ArrayList<String>();
 986  
             }
 987  
 
 988  
             try {
 989  0
                 baseBO = (PersistableBusinessObject) reference.newInstance();
 990  
             }
 991  0
             catch (InstantiationException e) {
 992  0
                 LOG.error(e);
 993  
             }
 994  0
             catch (IllegalAccessException e) {
 995  0
                 LOG.error(e);
 996  0
             }
 997  0
             attributeName = ObjectUtils.getNestedAttributePrimitive(attributeName);
 998  
         }
 999  
         
 1000  0
         if (baseBO == null) {
 1001  0
             return new ArrayList<String>();
 1002  
         }
 1003  
         
 1004  0
         Map<String, Class> referenceNameToClassFromPSS = LookupUtils.getPrimitiveReference(baseBO, attributeName);
 1005  0
         if (referenceNameToClassFromPSS.size() > 1) {
 1006  0
             LOG.error("LookupUtils.getPrimitiveReference return results should only have at most one element");
 1007  
         }
 1008  
         
 1009  0
         BusinessObjectMetaDataService businessObjectMetaDataService = getBusinessObjectMetaDataService();
 1010  0
         BusinessObjectRelationship relationship = businessObjectMetaDataService.getBusinessObjectRelationship(baseBO, attributeName);
 1011  0
         if (relationship == null) {
 1012  0
             return new ArrayList<String>();
 1013  
         }
 1014  
         
 1015  0
         Map<String, String> fkToPkMappings = relationship.getParentToChildReferences();
 1016  
         
 1017  0
         Collection<String> affectedReferences = generateAllAffectedReferences(baseBO.getClass(), fkToPkMappings, nestedBOPrefix, collectionPrefix);
 1018  0
         if (LOG.isDebugEnabled()) {
 1019  0
             LOG.debug("References affected by a lookup on BO attribute \"" + collectionPrefix + nestedBOPrefix + "." + attributeName + ": " + affectedReferences);
 1020  
         }
 1021  
         
 1022  0
         return affectedReferences;
 1023  
     }
 1024  
     
 1025  
     protected boolean isRelationshipRefreshable(Class boClass, String relationshipName) {
 1026  0
         if (getPersistenceStructureService().isPersistable(boClass)) {
 1027  0
             if (getPersistenceStructureService().hasCollection(boClass, relationshipName)) {
 1028  0
                 return !getPersistenceStructureService().isCollectionUpdatable(boClass, relationshipName);
 1029  
             }
 1030  0
             else if (getPersistenceStructureService().hasReference(boClass, relationshipName)) {
 1031  0
                 return !getPersistenceStructureService().isReferenceUpdatable(boClass, relationshipName);
 1032  
             }
 1033  
             // else, assume that the relationship is defined in the DD
 1034  
         }
 1035  
 
 1036  0
         return true;
 1037  
     }
 1038  
     
 1039  
     protected Collection<String> generateAllAffectedReferences(Class boClass, 
 1040  
             Map<String, String> fkToPkMappings, String nestedBOPrefix, String collectionPrefix) {
 1041  0
         Set<String> allAffectedReferences = new HashSet<String>();
 1042  0
         DataDictionaryService dataDictionaryService = getDataDictionaryService();
 1043  0
         PersistenceStructureService pss = getPersistenceStructureService();
 1044  
         
 1045  0
         collectionPrefix = StringUtils.isBlank(collectionPrefix) ? "" : collectionPrefix;
 1046  
         
 1047  
         // retrieve the attributes that are affected by a lookup on attributeName.
 1048  0
         Collection<String> attributeReferenceFKAttributes = fkToPkMappings.keySet();
 1049  
         
 1050  
         // a lookup on an attribute may cause other attributes to be updated (e.g. account code lookup would also affect chart code)
 1051  
         // build a list of all affected FK values via mapKeyFields above, and for each FK, see if there are any non-updatable references with that FK
 1052  
         
 1053  
         // deal with regular simple references (<reference-descriptor>s in OJB)
 1054  0
         for (String fkAttribute : attributeReferenceFKAttributes) {
 1055  0
             for (String affectedReference : pss.getReferencesForForeignKey(boClass, fkAttribute).keySet()) {
 1056  0
                 if (isRelationshipRefreshable(boClass, affectedReference)) {
 1057  0
                     if (StringUtils.isBlank(nestedBOPrefix)) {
 1058  0
                         allAffectedReferences.add(collectionPrefix+ affectedReference);
 1059  
                     }
 1060  
                     else {
 1061  0
                         allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + affectedReference);
 1062  
                     }
 1063  
                 }
 1064  
             }
 1065  
         }
 1066  
     
 1067  
         // now with collection references (<collection-descriptor>s in OJB)
 1068  0
         for (String collectionName : pss.listCollectionObjectTypes(boClass).keySet()) {
 1069  0
             if (isRelationshipRefreshable(boClass, collectionName)) {
 1070  0
                 Map<String, String> keyMappingsForCollection = pss.getInverseForeignKeysForCollection(boClass, collectionName);
 1071  0
                 for (String collectionForeignKey : keyMappingsForCollection.keySet()) {
 1072  0
                     if (attributeReferenceFKAttributes.contains(collectionForeignKey)) {
 1073  0
                         if (StringUtils.isBlank(nestedBOPrefix)) {
 1074  0
                             allAffectedReferences.add(collectionPrefix + collectionName);
 1075  
                         }
 1076  
                         else {
 1077  0
                             allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + collectionName);
 1078  
                         }
 1079  
                     }
 1080  
                 }
 1081  0
             }
 1082  
         }
 1083  
         
 1084  
         // now use the DD to compute more affected references
 1085  0
         List<String> ddDefinedRelationships = dataDictionaryService.getRelationshipNames(boClass.getName());
 1086  0
         for (String ddRelationship : ddDefinedRelationships) {
 1087  
             // note that this map is PK (key/target) => FK (value/source)
 1088  0
             Map<String, String> referencePKtoFKmappings = dataDictionaryService.getRelationshipAttributeMap(boClass.getName(), ddRelationship);
 1089  0
             for (String sourceAttribute : referencePKtoFKmappings.values()) {
 1090  
                 // the sourceAttribute is the FK pointing to the target attribute (PK)
 1091  0
                 if (attributeReferenceFKAttributes.contains(sourceAttribute)) {
 1092  0
                     for (String affectedReference : dataDictionaryService.getRelationshipEntriesForSourceAttribute(boClass.getName(), sourceAttribute)) {
 1093  0
                         if (isRelationshipRefreshable(boClass, ddRelationship)) {
 1094  0
                             if (StringUtils.isBlank(nestedBOPrefix)) {
 1095  0
                                 allAffectedReferences.add(affectedReference);
 1096  
                             }
 1097  
                             else {
 1098  0
                                 allAffectedReferences.add(nestedBOPrefix + "." + affectedReference);
 1099  
                             }
 1100  
                         }
 1101  
                     }
 1102  
                 }
 1103  
             }
 1104  0
         }
 1105  0
         return allAffectedReferences;
 1106  
     }
 1107  
     
 1108  
     protected Collection<String> getAllRefreshableReferences(Class boClass) {
 1109  0
         HashSet<String> references = new HashSet<String>();
 1110  0
         for (String referenceName : getPersistenceStructureService().listReferenceObjectFields(boClass).keySet()) {
 1111  0
             if (isRelationshipRefreshable(boClass, referenceName)) {
 1112  0
                 references.add(referenceName);
 1113  
             }
 1114  
         }
 1115  0
         for (String collectionName : getPersistenceStructureService().listCollectionObjectTypes(boClass).keySet()) {
 1116  0
             if (isRelationshipRefreshable(boClass, collectionName)) {
 1117  0
                 references.add(collectionName);
 1118  
             }
 1119  
         }
 1120  0
         for (String relationshipName : getDataDictionaryService().getRelationshipNames(boClass.getName())) {
 1121  0
             if (isRelationshipRefreshable(boClass, relationshipName)) {
 1122  0
                 references.add(relationshipName);
 1123  
             }
 1124  
         }
 1125  0
         return references;
 1126  
     }
 1127  
     
 1128  
     protected void setNewCollectionLineDefaultValues(String collectionName, PersistableBusinessObject addLine) {
 1129  0
         PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors( addLine );
 1130  0
         for (int i = 0; i < descriptors.length; ++i) {
 1131  0
             PropertyDescriptor propertyDescriptor = descriptors[i];
 1132  
 
 1133  0
             String fieldName = propertyDescriptor.getName();
 1134  0
             Class propertyType = propertyDescriptor.getPropertyType();
 1135  0
             String value = getMaintenanceDocumentDictionaryService().getCollectionFieldDefaultValue(docTypeName, collectionName, fieldName);
 1136  
 
 1137  0
             if (value != null) {
 1138  
                 try {                   
 1139  0
                     ObjectUtils.setObjectProperty( addLine, fieldName, propertyType, value);
 1140  0
                 } catch ( Exception ex ) {
 1141  0
                     LOG.error( "Unable to set default property of collection object: "
 1142  
                             + "\nobject: " 
 1143  
                             + addLine 
 1144  
                             + "\nfieldName=" + fieldName 
 1145  
                             + "\npropertyType=" + propertyType 
 1146  
                             + "\nvalue=" + value, ex );
 1147  0
                 }
 1148  
             }
 1149  
 
 1150  
         }
 1151  0
     }
 1152  
 
 1153  
         public void doRouteStatusChange(DocumentHeader documentHeader) {
 1154  0
         }
 1155  
 
 1156  
         public List<Long> getWorkflowEngineDocumentIdsToLock() {
 1157  0
                 return null;
 1158  
         }
 1159  
 
 1160  
         public static PersistenceStructureService getPersistenceStructureService() {
 1161  0
             if ( persistenceStructureService == null ) {
 1162  0
                 persistenceStructureService = KNSServiceLocator.getPersistenceStructureService();
 1163  
             }
 1164  0
             return persistenceStructureService;
 1165  
         }
 1166  
 
 1167  
     public static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
 1168  0
         if ( maintenanceDocumentDictionaryService == null ) {
 1169  0
             maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
 1170  
         }
 1171  0
         return maintenanceDocumentDictionaryService;
 1172  
     }
 1173  
 
 1174  
     public static DataDictionaryService getDataDictionaryService() {
 1175  0
         if ( dataDictionaryService == null ) {
 1176  0
             dataDictionaryService = KNSServiceLocator.getDataDictionaryService();
 1177  
         }
 1178  0
         return dataDictionaryService;
 1179  
     }
 1180  
 
 1181  
     public static BusinessObjectService getBusinessObjectService() {
 1182  0
         if ( businessObjectService == null ) {
 1183  0
             businessObjectService = KNSServiceLocator.getBusinessObjectService();
 1184  
         }
 1185  0
         return businessObjectService;
 1186  
     }
 1187  
 
 1188  
     public static BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
 1189  0
         if ( businessObjectDictionaryService == null ) {
 1190  0
             businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService();
 1191  
         }
 1192  0
         return businessObjectDictionaryService;
 1193  
     }
 1194  
 
 1195  
     public static EncryptionService getEncryptionService() {
 1196  0
         if ( encryptionService == null ) {
 1197  0
             encryptionService = KNSServiceLocator.getEncryptionService();
 1198  
         }
 1199  0
         return encryptionService;
 1200  
     }
 1201  
 
 1202  
     public static org.kuali.rice.kim.service.PersonService getPersonService() {
 1203  0
         if ( personService == null ) {
 1204  0
             personService = org.kuali.rice.kim.service.KIMServiceLocator.getPersonService();
 1205  
         }
 1206  0
         return personService;
 1207  
     }
 1208  
 
 1209  
     public static BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
 1210  0
         if ( businessObjectMetaDataService == null ) {
 1211  0
             businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService();
 1212  
         }
 1213  0
         return businessObjectMetaDataService;
 1214  
     }
 1215  
 
 1216  
     public static BusinessObjectAuthorizationService getBusinessObjectAuthorizationService() {
 1217  0
             if (businessObjectAuthorizationService == null) {
 1218  0
                     businessObjectAuthorizationService = KNSServiceLocator.getBusinessObjectAuthorizationService();
 1219  
             }
 1220  0
             return businessObjectAuthorizationService;
 1221  
     }
 1222  
     
 1223  
     public static MaintenanceDocumentService getMaintenanceDocumentService() {
 1224  0
             if (maintenanceDocumentService == null) {
 1225  0
                     maintenanceDocumentService = KNSServiceLocator.getMaintenanceDocumentService();
 1226  
             }
 1227  0
             return maintenanceDocumentService;
 1228  
     }
 1229  
     
 1230  
     public static DocumentHelperService getDocumentHelperService() {
 1231  0
             if (documentHelperService == null) {
 1232  0
                     documentHelperService = KNSServiceLocator.getDocumentHelperService();
 1233  
             }
 1234  0
             return documentHelperService;
 1235  
     }
 1236  
     
 1237  
         /**
 1238  
          * @see org.kuali.rice.kns.maintenance.Maintainable#clearBusinessObjectOfRestrictedValues(org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions)
 1239  
          */
 1240  
         public void clearBusinessObjectOfRestrictedValues(MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1241  0
                 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 1242  0
                 for (MaintainableSectionDefinition sectionDefinition : sections) {
 1243  0
                         for (MaintainableItemDefinition itemDefinition : sectionDefinition.getMaintainableItems()) {
 1244  0
                                 if (itemDefinition instanceof MaintainableFieldDefinition) {
 1245  0
                                         clearFieldRestrictedValues("", businessObject, (MaintainableFieldDefinition) itemDefinition, maintenanceDocumentRestrictions);
 1246  
                                 }
 1247  0
                                 else if (itemDefinition instanceof MaintainableCollectionDefinition) {
 1248  0
                                         clearCollectionRestrictedValues("", businessObject, (MaintainableCollectionDefinition) itemDefinition, maintenanceDocumentRestrictions);
 1249  
                                 }
 1250  
                         }
 1251  
                 }
 1252  0
         }
 1253  
         
 1254  
         protected void clearCollectionRestrictedValues(String fieldNamePrefix, BusinessObject businessObject, MaintainableCollectionDefinition collectionDefinition, MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1255  0
                 String collectionName = fieldNamePrefix + collectionDefinition.getName();
 1256  0
                 Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(businessObject, collectionDefinition.getName());
 1257  
                 
 1258  0
                 if (collection != null) {
 1259  0
                         int i = 0;
 1260  
                         // even though it's technically a Collection, we're going to index it like a list
 1261  0
                         for (BusinessObject collectionItem : collection) {
 1262  0
                                 String collectionItemNamePrefix = collectionName + "[" + i + "].";
 1263  0
                                 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition.getMaintainableCollections()) {
 1264  0
                                         clearCollectionRestrictedValues(collectionItemNamePrefix, collectionItem, subCollectionDefinition, maintenanceDocumentRestrictions);
 1265  
                                 }
 1266  0
                                 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
 1267  0
                                         clearFieldRestrictedValues(collectionItemNamePrefix, collectionItem, fieldDefinition, maintenanceDocumentRestrictions);
 1268  
                                 }
 1269  0
                                 i++;
 1270  0
                         }
 1271  
                 }
 1272  0
         }
 1273  
         
 1274  
         protected void clearFieldRestrictedValues(String fieldNamePrefix, BusinessObject businessObject, MaintainableFieldDefinition fieldDefinition, MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1275  0
                 String fieldName = fieldNamePrefix + fieldDefinition.getName();
 1276  
                 
 1277  0
                 FieldRestriction fieldRestriction = maintenanceDocumentRestrictions.getFieldRestriction(fieldName);
 1278  0
                 if (fieldRestriction.isRestricted()) {
 1279  0
                         String defaultValue = null;
 1280  0
                         if (StringUtils.isNotBlank(fieldDefinition.getDefaultValue())) {
 1281  0
                                 defaultValue = fieldDefinition.getDefaultValue();
 1282  
                         }
 1283  0
                         else if (fieldDefinition.getDefaultValueFinderClass() != null) {
 1284  
                                 try {
 1285  0
                                         defaultValue = ((ValueFinder) fieldDefinition.getDefaultValueFinderClass().newInstance()).getValue();
 1286  0
                                 } catch (Exception e) {
 1287  0
                                         defaultValue = null;
 1288  0
                                         LOG.error("Error trying to instantiate ValueFinder or to determine ValueFinder for doc type: " + docTypeName + " field name " + fieldDefinition.getName() + " with field prefix: " + fieldNamePrefix, e);
 1289  0
                                 }
 1290  
                         }
 1291  
                         try {
 1292  0
                                 ObjectUtils.setObjectProperty(businessObject, fieldDefinition.getName(), defaultValue);
 1293  0
                         } catch (Exception e) {
 1294  
                                 // throw an exception, because we don't want users to be able to see the restricted value
 1295  0
                                 LOG.error("Unable to clear maintenance document values for field name: " + fieldName + " default value: " + defaultValue, e);
 1296  0
                                 throw new RuntimeException("Unable to clear maintenance document values for field name: " + fieldName, e);
 1297  0
                         }
 1298  
                 }
 1299  0
         }
 1300  
         
 1301  
         protected void performForceUpperCase(Map fieldValues) {
 1302  0
                     List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService().getMaintainableSections(docTypeName);
 1303  0
                 for (MaintainableSectionDefinition sectionDefinition : sections) {
 1304  0
                         for (MaintainableItemDefinition itemDefinition :  sectionDefinition.getMaintainableItems()) {
 1305  0
                                 if (itemDefinition instanceof MaintainableFieldDefinition) {
 1306  0
                                         performFieldForceUpperCase("", businessObject, (MaintainableFieldDefinition) itemDefinition, fieldValues);
 1307  
                         }
 1308  0
                         else if (itemDefinition instanceof MaintainableCollectionDefinition) {
 1309  0
                                 performCollectionForceUpperCase("", businessObject,(MaintainableCollectionDefinition) itemDefinition, fieldValues);
 1310  
            
 1311  
                         }
 1312  
                     }
 1313  
                 }
 1314  0
           }
 1315  
             
 1316  
         protected void performFieldForceUpperCase(String fieldNamePrefix, BusinessObject bo, MaintainableFieldDefinition fieldDefinition, Map fieldValues) {
 1317  0
                     MessageMap errorMap = GlobalVariables.getMessageMap();
 1318  0
                     String fieldName = fieldDefinition.getName();
 1319  0
                     String mapKey = fieldNamePrefix + fieldName; 
 1320  0
                     if(fieldValues != null && fieldValues.get(mapKey) != null){
 1321  0
                       if (PropertyUtils.isWriteable(bo, fieldName) && ObjectUtils.getNestedValue(bo, fieldName) != null ) {
 1322  
                             
 1323  
                     try {
 1324  0
                                 Class type = ObjectUtils.easyGetPropertyType(bo, fieldName);
 1325  
                             //convert to upperCase based on data dictionary
 1326  0
                             Class businessObjectClass = bo.getClass();
 1327  0
                         boolean upperCase = false;
 1328  
                         try {
 1329  0
                                 upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass, fieldName);
 1330  
                         }
 1331  0
                         catch (UnknownBusinessClassAttributeException t) {
 1332  0
                                 boolean catchme = true;
 1333  
                             // throw t;
 1334  0
                         }
 1335  
                                         
 1336  0
                         Object fieldValue = ObjectUtils.getNestedValue(bo, fieldName);
 1337  
                                         
 1338  0
                         if(upperCase && fieldValue instanceof String){
 1339  0
                                 fieldValue = ((String) fieldValue).toUpperCase(); 
 1340  
                         }
 1341  0
                         ObjectUtils.setObjectProperty(bo, fieldName, type, fieldValue);
 1342  0
                    }catch (FormatException e){
 1343  0
                            errorMap.putError(fieldName, e.getErrorKey(), e.getErrorArgs());
 1344  0
                    }catch (IllegalAccessException e) {
 1345  0
                        LOG.error("unable to populate business object" + e.getMessage());
 1346  0
                        throw new RuntimeException(e.getMessage(), e);
 1347  
                    }
 1348  0
                    catch (InvocationTargetException e) {
 1349  0
                        LOG.error("unable to populate business object" + e.getMessage());
 1350  0
                        throw new RuntimeException(e.getMessage(), e);
 1351  
                    }
 1352  0
                    catch (NoSuchMethodException e) {
 1353  0
                        LOG.error("unable to populate business object" + e.getMessage());
 1354  0
                        throw new RuntimeException(e.getMessage(), e);
 1355  0
                    }
 1356  
                     }
 1357  
               }
 1358  0
           }
 1359  
 
 1360  
         protected void performCollectionForceUpperCase(String fieldNamePrefix, BusinessObject bo, MaintainableCollectionDefinition collectionDefinition, Map fieldValues) {
 1361  0
                     String collectionName = fieldNamePrefix + collectionDefinition.getName();
 1362  0
                     Collection<BusinessObject> collection = (Collection<BusinessObject>)ObjectUtils.getPropertyValue(bo, collectionDefinition.getName());
 1363  0
                     if (collection != null) {
 1364  0
                             int i = 0;
 1365  
                             // even though it's technically a Collection, we're going to index it like a list
 1366  0
                             for (BusinessObject collectionItem : collection) {
 1367  0
                                     String collectionItemNamePrefix = collectionName + "[" + i + "].";
 1368  
                                     //String collectionItemNamePrefix = "";
 1369  0
                                 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
 1370  0
                                         performFieldForceUpperCase(collectionItemNamePrefix, collectionItem, fieldDefinition, fieldValues);
 1371  
                                 }
 1372  0
                                 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition.getMaintainableCollections()) {                
 1373  0
                                         performCollectionForceUpperCase(collectionItemNamePrefix, collectionItem, subCollectionDefinition, fieldValues);
 1374  
                                 }
 1375  0
                                 i++;
 1376  0
                             }
 1377  
                 }
 1378  0
           }
 1379  
           
 1380  
         protected void performFieldForceUpperCase(BusinessObject bo, Map fieldValues) {
 1381  0
               MessageMap errorMap = GlobalVariables.getMessageMap();
 1382  
 
 1383  
               try {
 1384  0
                       for (Iterator iter = fieldValues.keySet().iterator(); iter.hasNext();) {
 1385  0
                               String propertyName = (String) iter.next();
 1386  
 
 1387  0
                       if (PropertyUtils.isWriteable(bo, propertyName) && fieldValues.get(propertyName) != null ) {
 1388  
                             // if the field propertyName is a valid property on the bo class
 1389  0
                             Class type = ObjectUtils.easyGetPropertyType(bo, propertyName);
 1390  
                             try {
 1391  
                                     //Keep the convert to upperCase logic here. It will be used in populateNewCollectionLines, populateNewSubCollectionLines
 1392  
                                     //convert to upperCase based on data dictionary
 1393  0
                                     Class businessObjectClass = bo.getClass();
 1394  0
                                     boolean upperCase = false;
 1395  
                                  try {
 1396  0
                                          upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass, propertyName);
 1397  
                                  }
 1398  0
                                  catch (UnknownBusinessClassAttributeException t) {
 1399  0
                                      boolean catchme = true;
 1400  
                                      // throw t;
 1401  0
                                  }
 1402  
                                     
 1403  0
                                     Object fieldValue = fieldValues.get(propertyName);
 1404  
                                     
 1405  0
                                     if(upperCase && fieldValue instanceof String){
 1406  0
                                             fieldValue = ((String) fieldValue).toUpperCase(); 
 1407  
                                     }
 1408  0
                                 ObjectUtils.setObjectProperty(bo, propertyName, type, fieldValue);
 1409  
                             }
 1410  0
                             catch (FormatException e) {
 1411  0
                                 errorMap.putError(propertyName, e.getErrorKey(), e.getErrorArgs());
 1412  0
                             }
 1413  
                         }
 1414  0
                     }
 1415  
                 }
 1416  0
                 catch (IllegalAccessException e) {
 1417  0
                     LOG.error("unable to populate business object" + e.getMessage());
 1418  0
                     throw new RuntimeException(e.getMessage(), e);
 1419  
                 }
 1420  0
                 catch (InvocationTargetException e) {
 1421  0
                     LOG.error("unable to populate business object" + e.getMessage());
 1422  0
                     throw new RuntimeException(e.getMessage(), e);
 1423  
                 }
 1424  0
                 catch (NoSuchMethodException e) {
 1425  0
                     LOG.error("unable to populate business object" + e.getMessage());
 1426  0
                     throw new RuntimeException(e.getMessage(), e);
 1427  0
                 }
 1428  
 
 1429  0
           }
 1430  
 
 1431  
 
 1432  
         /**
 1433  
          * By default a maintainable is not external 
 1434  
          * 
 1435  
          * @see org.kuali.rice.kns.maintenance.Maintainable#isExternalBusinessObject()
 1436  
          */
 1437  
         public boolean isExternalBusinessObject(){
 1438  0
                 return false;
 1439  
         }
 1440  
         
 1441  
         /**
 1442  
          * @see org.kuali.rice.kns.maintenance.Maintainable#getExternalBusinessObject()
 1443  
          */
 1444  
         public void prepareBusinessObject(BusinessObject businessObject){
 1445  
                 //Do nothing by default
 1446  0
         }
 1447  
 
 1448  
         /**
 1449  
          * @see org.kuali.rice.kns.maintenance.Maintainable#getLockingDocumentId()
 1450  
          */
 1451  
         public String getLockingDocumentId() {
 1452  0
                 return getMaintenanceDocumentService().getLockingDocumentId(this, documentNumber);
 1453  
         }
 1454  
         
 1455  
                 /**
 1456  
      * This default implementation simply returns false to indicate that custom lock descriptors are not supported by KualiMaintainableImpl.
 1457  
      * If custom lock descriptors are needed, the appropriate subclasses should override this method.
 1458  
          * 
 1459  
          * @see org.kuali.rice.kns.maintenance.Maintainable#useCustomLockDescriptors()
 1460  
          */
 1461  
         public boolean useCustomLockDescriptors() {
 1462  0
                 return false;
 1463  
         }
 1464  
 
 1465  
         /**
 1466  
      * This default implementation just throws a PessimisticLockingException. Subclasses of KualiMaintainableImpl that need support for
 1467  
      * custom lock descriptors should override this method.
 1468  
          * 
 1469  
          * @see org.kuali.rice.kns.maintenance.Maintainable#getCustomLockDescriptor(org.kuali.rice.kim.bo.Person)
 1470  
          */
 1471  
         public String getCustomLockDescriptor(Person user) {
 1472  0
             throw new PessimisticLockingException("The Maintainable for document " + documentNumber +
 1473  
                             " is using pessimistic locking with custom lock descriptors, but the Maintainable has not overriden the getCustomLockDescriptor method");
 1474  
     }
 1475  
         
 1476  
         //3070
 1477  
         public void deleteBusinessObject(){
 1478  0
                 if(businessObject == null)
 1479  0
                         return;
 1480  
                 
 1481  0
                 KNSServiceLocator.getBusinessObjectService().delete(businessObject);
 1482  0
                 businessObject = null;        
 1483  0
         }
 1484  
 
 1485  
         public boolean isOldBusinessObjectInDocument() {
 1486  0
         boolean isOldBusinessObjectInExistence = false;
 1487  0
         if (getBusinessObject() == null) {
 1488  0
             isOldBusinessObjectInExistence = false;
 1489  
         } else {
 1490  0
             if ( KNSServiceLocator.getPersistenceStructureService().isPersistable( getBusinessObject().getClass() ) ) {
 1491  0
                 isOldBusinessObjectInExistence = KNSServiceLocator.getPersistenceStructureService().hasPrimaryKeyFieldValues(getBusinessObject());
 1492  
             }
 1493  
         }
 1494  0
         return isOldBusinessObjectInExistence;
 1495  
         
 1496  
     }
 1497  
 }