Coverage Report - org.kuali.rice.krad.maintenance.KualiMaintainableImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
KualiMaintainableImpl
0%
0/764
0%
0/404
3.614
 
 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.krad.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.Arrays;
 24  
 import java.util.Collection;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 
 32  
 import org.apache.commons.beanutils.PropertyUtils;
 33  
 import org.apache.commons.lang.StringUtils;
 34  
 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
 35  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 36  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 37  
 import org.kuali.rice.core.web.format.FormatException;
 38  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 39  
 import org.kuali.rice.kim.bo.Person;
 40  
 import org.kuali.rice.krad.authorization.FieldRestriction;
 41  
 import org.kuali.rice.krad.bo.BusinessObject;
 42  
 import org.kuali.rice.krad.bo.BusinessObjectRelationship;
 43  
 import org.kuali.rice.krad.bo.DocumentHeader;
 44  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 45  
 import org.kuali.rice.krad.datadictionary.AttributeSecurity;
 46  
 import org.kuali.rice.krad.datadictionary.MaintainableCollectionDefinition;
 47  
 import org.kuali.rice.krad.datadictionary.MaintainableFieldDefinition;
 48  
 import org.kuali.rice.krad.datadictionary.MaintainableItemDefinition;
 49  
 import org.kuali.rice.krad.datadictionary.MaintainableSectionDefinition;
 50  
 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
 51  
 import org.kuali.rice.krad.document.MaintenanceDocument;
 52  
 import org.kuali.rice.krad.document.MaintenanceLock;
 53  
 import org.kuali.rice.krad.document.authorization.MaintenanceDocumentPresentationController;
 54  
 import org.kuali.rice.krad.document.authorization.MaintenanceDocumentRestrictions;
 55  
 import org.kuali.rice.krad.exception.DocumentTypeAuthorizationException;
 56  
 import org.kuali.rice.krad.exception.PessimisticLockingException;
 57  
 import org.kuali.rice.krad.lookup.LookupUtils;
 58  
 import org.kuali.rice.krad.lookup.valuefinder.ValueFinder;
 59  
 import org.kuali.rice.krad.service.BusinessObjectAuthorizationService;
 60  
 import org.kuali.rice.krad.service.BusinessObjectDictionaryService;
 61  
 import org.kuali.rice.krad.service.BusinessObjectMetaDataService;
 62  
 import org.kuali.rice.krad.service.BusinessObjectService;
 63  
 import org.kuali.rice.krad.service.DataDictionaryService;
 64  
 import org.kuali.rice.krad.service.DocumentHelperService;
 65  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 66  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 67  
 import org.kuali.rice.krad.service.LookupService;
 68  
 import org.kuali.rice.krad.service.MaintenanceDocumentDictionaryService;
 69  
 import org.kuali.rice.krad.service.MaintenanceDocumentService;
 70  
 import org.kuali.rice.krad.service.ModuleService;
 71  
 import org.kuali.rice.krad.service.PersistenceStructureService;
 72  
 import org.kuali.rice.krad.uif.container.CollectionGroup;
 73  
 import org.kuali.rice.krad.uif.container.View;
 74  
 import org.kuali.rice.krad.uif.service.impl.DocumentViewHelperServiceImpl;
 75  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 76  
 import org.kuali.rice.krad.util.FieldUtils;
 77  
 import org.kuali.rice.krad.util.GlobalVariables;
 78  
 import org.kuali.rice.krad.util.InactiveRecordsHidingUtils;
 79  
 import org.kuali.rice.krad.util.KRADConstants;
 80  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 81  
 import org.kuali.rice.krad.util.MaintenanceUtils;
 82  
 import org.kuali.rice.krad.util.MessageMap;
 83  
 import org.kuali.rice.krad.util.ObjectUtils;
 84  
 import org.kuali.rice.krad.util.WebUtils;
 85  
 import org.kuali.rice.krad.web.spring.form.MaintenanceForm;
 86  
 import org.kuali.rice.krad.web.ui.Section;
 87  
 import org.kuali.rice.krad.web.ui.SectionBridge;
 88  
 
 89  
 /**
 90  
  * Base Maintainable class to hold things common to all maintainables.
 91  
  */
 92  
 public class KualiMaintainableImpl extends DocumentViewHelperServiceImpl implements Maintainable {
 93  
         private static final long serialVersionUID = 4814145799502207182L;
 94  
 
 95  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMaintainableImpl.class);
 96  
 
 97  
         protected String documentNumber;
 98  
         protected Object dataObject;
 99  
         protected PersistableBusinessObject businessObject;
 100  
         protected Class boClass;
 101  
         protected String maintenanceAction;
 102  
 
 103  0
         protected Map<String, PersistableBusinessObject> newCollectionLines = new HashMap<String, PersistableBusinessObject>();
 104  0
         protected Map<String, Boolean> inactiveRecordDisplay = new HashMap<String, Boolean>();
 105  
 
 106  
         protected String docTypeName;
 107  
 
 108  
     // TODO: rename once 'newCollectionLines' is removed
 109  0
     protected Set<String> newCollectionLineNames = new HashSet<String>();
 110  
 
 111  
         protected transient PersistenceStructureService persistenceStructureService;
 112  
         protected transient MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 113  
         protected transient BusinessObjectService businessObjectService;
 114  
         protected transient BusinessObjectDictionaryService businessObjectDictionaryService;
 115  
         protected transient EncryptionService encryptionService;
 116  
         protected transient org.kuali.rice.kim.service.PersonService personService;
 117  
         protected transient BusinessObjectMetaDataService businessObjectMetaDataService;
 118  
         protected transient BusinessObjectAuthorizationService businessObjectAuthorizationService;
 119  
         protected transient MaintenanceDocumentService maintenanceDocumentService;
 120  
         protected transient DocumentHelperService documentHelperService;
 121  
         protected transient LookupService lookupService;
 122  
 
 123  
         /**
 124  
          * Default empty constructor
 125  
          */
 126  
         public KualiMaintainableImpl() {
 127  0
         super();
 128  0
         }
 129  
 
 130  
         /**
 131  
          * Constructor which initializes the business object to be maintained.
 132  
          * 
 133  
          * @param businessObject
 134  
          */
 135  
         public KualiMaintainableImpl(PersistableBusinessObject businessObject) {
 136  0
                 super();
 137  0
                 this.businessObject = businessObject;
 138  0
                 this.dataObject = businessObject;
 139  0
         }
 140  
 
 141  
         /**
 142  
          * This methods will do the setting of some attributes that might be
 143  
          * necessary if we're creating a new business object using on an existing
 144  
          * business object. For example, create a division Vendor based on an
 145  
          * existing parent Vendor. (Please see VendorMaintainableImpl.java)
 146  
          */
 147  
         public void setupNewFromExisting(MaintenanceDocument document, Map<String, String[]> parameters) {
 148  
 
 149  0
         }
 150  
 
 151  
         public void processAfterPost(MaintenanceDocument document, Map<String, String[]> parameters) {
 152  
 
 153  0
         }
 154  
 
 155  
         /**
 156  
          * This is a hook to allow the document to override the generic document
 157  
          * title.
 158  
          * 
 159  
          * @return String document title
 160  
          */
 161  
         public String getDocumentTitle(MaintenanceDocument document) {
 162  
                 // default implementation is to allow MaintenanceDocumentBase to
 163  
                 // generate the doc title
 164  0
                 return "";
 165  
         }
 166  
 
 167  
         /**
 168  
          * Note: as currently implemented, every key field for a given
 169  
          * BusinessObject subclass must have a visible getter.
 170  
          * 
 171  
          * @return String containing the business object class and key value pairs
 172  
          *         of the current instance that can be used as a unique locking
 173  
          *         representation.
 174  
          */
 175  
         public List<MaintenanceLock> generateMaintenanceLocks() {
 176  
 
 177  
                 // NOTE: KualiGlobalMaintainableImpl overrides this method and forces
 178  
                 // all globals to override that, so they each do their own thing
 179  
 
 180  0
                 List<MaintenanceLock> maintenanceLocks = new ArrayList<MaintenanceLock>();
 181  0
                 StringBuffer lockRepresentation = new StringBuffer(boClass.getName());
 182  0
                 lockRepresentation.append(KRADConstants.Maintenance.AFTER_CLASS_DELIM);
 183  
 
 184  0
                 Object bo = getDataObject();
 185  0
                 List keyFieldNames = getMaintenanceDocumentDictionaryService().getLockingKeys(getDocumentTypeName());
 186  
 
 187  0
                 for (Iterator i = keyFieldNames.iterator(); i.hasNext();) {
 188  0
                         String fieldName = (String) i.next();
 189  0
                         Object fieldValue = ObjectUtils.getPropertyValue(bo, fieldName);
 190  0
                         if (fieldValue == null) {
 191  0
                                 fieldValue = "";
 192  
                         }
 193  
 
 194  
                         // check if field is a secure
 195  0
                         if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(boClass,
 196  
                                         fieldName)) {
 197  
                                 try {
 198  0
                                         fieldValue = getEncryptionService().encrypt(fieldValue);
 199  
                                 }
 200  0
                                 catch (GeneralSecurityException e) {
 201  0
                                         LOG.error("Unable to encrypt secure field for locking representation " + e.getMessage());
 202  0
                                         throw new RuntimeException("Unable to encrypt secure field for locking representation "
 203  
                                                         + e.getMessage());
 204  0
                                 }
 205  
                         }
 206  
 
 207  0
                         lockRepresentation.append(fieldName);
 208  0
                         lockRepresentation.append(KRADConstants.Maintenance.AFTER_FIELDNAME_DELIM);
 209  0
                         lockRepresentation.append(String.valueOf(fieldValue));
 210  0
                         if (i.hasNext()) {
 211  0
                                 lockRepresentation.append(KRADConstants.Maintenance.AFTER_VALUE_DELIM);
 212  
                         }
 213  0
                 }
 214  
 
 215  0
                 MaintenanceLock maintenanceLock = new MaintenanceLock();
 216  0
                 maintenanceLock.setDocumentNumber(documentNumber);
 217  0
                 maintenanceLock.setLockingRepresentation(lockRepresentation.toString());
 218  0
                 maintenanceLocks.add(maintenanceLock);
 219  0
                 return maintenanceLocks;
 220  
         }
 221  
 
 222  
         /**
 223  
          * @see org.kuali.rice.krad.maintenance.Maintainable#populateBusinessObject(java.util.Map,
 224  
          *      org.kuali.rice.krad.document.MaintenanceDocument, String)
 225  
          */
 226  
         @SuppressWarnings("unchecked")
 227  
         public Map populateBusinessObject(Map<String, String> fieldValues, MaintenanceDocument maintenanceDocument,
 228  
                         String methodToCall) {
 229  0
                 fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
 230  0
                 Map newFieldValues = null;
 231  0
                 newFieldValues = getPersonService().resolvePrincipalNamesToPrincipalIds(getBusinessObject(), fieldValues);
 232  
 
 233  0
                 Map cachedValues = FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), newFieldValues);
 234  0
                 performForceUpperCase(newFieldValues);
 235  
 
 236  0
                 return cachedValues;
 237  
         }
 238  
 
 239  
         /**
 240  
          * Special hidden parameters are set on the maintenance jsp starting with a
 241  
          * prefix that tells us which fields have been encrypted. This field finds
 242  
          * the those parameters in the map, whose value gives us the property name
 243  
          * that has an encrypted value. We then need to decrypt the value in the Map
 244  
          * before the business object is populated.
 245  
          * 
 246  
          * @param fieldValues
 247  
          *            - possibly with encrypted values
 248  
          * @return Map fieldValues - with no encrypted values
 249  
          */
 250  
         protected Map<String, String> decryptEncryptedData(Map<String, String> fieldValues,
 251  
                         MaintenanceDocument maintenanceDocument, String methodToCall) {
 252  
                 try {
 253  0
                         MaintenanceDocumentRestrictions auths = KRADServiceLocatorWeb.getBusinessObjectAuthorizationService()
 254  
                                         .getMaintenanceDocumentRestrictions(maintenanceDocument,
 255  
                                                         GlobalVariables.getUserSession().getPerson());
 256  0
                         for (Iterator<String> iter = fieldValues.keySet().iterator(); iter.hasNext();) {
 257  0
                                 String fieldName = iter.next();
 258  0
                                 String fieldValue = (String) fieldValues.get(fieldName);
 259  
 
 260  0
                                 if (fieldValue != null && !"".equals(fieldValue)
 261  
                                                 && fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 262  0
                                         if (shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall)) {
 263  0
                                                 String encryptedValue = fieldValue;
 264  
 
 265  
                                                 // take off the postfix
 266  0
                                                 encryptedValue = StringUtils.stripEnd(encryptedValue, EncryptionService.ENCRYPTION_POST_PREFIX);
 267  0
                                                 String decryptedValue = getEncryptionService().decrypt(encryptedValue);
 268  
 
 269  0
                                                 fieldValues.put(fieldName, decryptedValue);
 270  0
                                         }
 271  
                                         else
 272  0
                                                 throw new RuntimeException("The field value for field name " + fieldName
 273  
                                                                 + " should not be encrypted.");
 274  
                                 }
 275  0
                                 else if (fieldValue != null && !"".equals(fieldValue)
 276  
                                                 && shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall))
 277  0
                                         throw new RuntimeException("The field value for field name " + fieldName + " should be encrypted.");
 278  0
                         }
 279  
                 }
 280  0
                 catch (GeneralSecurityException e) {
 281  0
                         throw new RuntimeException("Unable to decrypt secure data: " + e.getMessage());
 282  0
                 }
 283  
 
 284  0
                 return fieldValues;
 285  
         }
 286  
 
 287  
         /**
 288  
          * Determines whether the field in a request should be encrypted. This base
 289  
          * implementation does not work for properties of collection elements.
 290  
          * 
 291  
          * This base implementation will only return true if the maintenance
 292  
          * document is being refreshed after a lookup (i.e. methodToCall is
 293  
          * "refresh") and the data dictionary-based attribute security definition
 294  
          * has any restriction defined, whether the user would be authorized to view
 295  
          * the field. This assumes that only fields returned from a lookup should be
 296  
          * encrypted in a request. If the user otherwise has no permissions to
 297  
          * view/edit the field, then a request parameter will not be sent back to
 298  
          * the server for population.
 299  
          * 
 300  
          * @param maintenanceDocument
 301  
          * @param fieldName
 302  
          * @param auths
 303  
          * @param methodToCall
 304  
          * @return
 305  
          */
 306  
         protected boolean shouldFieldBeEncrypted(MaintenanceDocument maintenanceDocument, String fieldName,
 307  
                         MaintenanceDocumentRestrictions auths, String methodToCall) {
 308  0
                 if ("refresh".equals(methodToCall) && fieldName != null) {
 309  0
                         fieldName = fieldName.replaceAll("\\[[0-9]*+\\]", "");
 310  0
                         fieldName = fieldName.replaceAll("^add\\.", "");
 311  0
                         Map<String, AttributeSecurity> fieldNameToAttributeSecurityMap = MaintenanceUtils
 312  
                                         .retrievePropertyPathToAttributeSecurityMappings(getDocumentTypeName());
 313  0
                         AttributeSecurity attributeSecurity = fieldNameToAttributeSecurityMap.get(fieldName);
 314  0
                         return attributeSecurity != null && attributeSecurity.hasRestrictionThatRemovesValueFromUI();
 315  
                 }
 316  
                 else {
 317  0
                         return false;
 318  
                 }
 319  
         }
 320  
 
 321  
         /**
 322  
          * Calls method to get all the core sections for the business object defined
 323  
          * in the data dictionary. Then determines if the bo has custom attributes,
 324  
          * if so builds a custom attribute section and adds to the section list.
 325  
          * 
 326  
          * @return List of org.kuali.ui.Section objects
 327  
          */
 328  
         public List getSections(MaintenanceDocument document, Maintainable oldMaintainable) {
 329  0
                 List<Section> sections = new ArrayList<Section>();
 330  0
                 sections.addAll(getCoreSections(document, oldMaintainable));
 331  
 
 332  0
                 return sections;
 333  
         }
 334  
 
 335  
         /**
 336  
          * Gets list of maintenance sections built from the data dictionary. If the
 337  
          * section contains maintenance fields, construct Row/Field UI objects and
 338  
          * place under Section UI. If section contains a maintenance collection,
 339  
          * call method to build a Section UI which contains rows of Container
 340  
          * Fields.
 341  
          * 
 342  
          * @return List of org.kuali.ui.Section objects
 343  
          */
 344  
         public List<Section> getCoreSections(MaintenanceDocument document, Maintainable oldMaintainable) {
 345  0
                 List<Section> sections = new ArrayList<Section>();
 346  0
                 MaintenanceDocumentRestrictions maintenanceRestrictions = KRADServiceLocatorWeb
 347  
                                 .getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(document,
 348  
                                                 GlobalVariables.getUserSession().getPerson());
 349  
 
 350  0
                 MaintenanceDocumentPresentationController maintenanceDocumentPresentationController = (MaintenanceDocumentPresentationController) getDocumentHelperService()
 351  
                                 .getDocumentPresentationController(document);
 352  0
                 Set<String> conditionallyRequiredFields = maintenanceDocumentPresentationController
 353  
                                 .getConditionallyRequiredPropertyNames(document);
 354  
 
 355  0
                 List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
 356  
                                 .getMaintainableSections(docTypeName);
 357  
                 try {
 358  
                         // iterate through section definitions and create Section UI object
 359  0
                         for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
 360  0
                                 MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
 361  
 
 362  0
                                 List<String> displayedFieldNames = new ArrayList<String>();
 363  0
                                 if (!maintenanceRestrictions.isHiddenSectionId(maintSectionDef.getId())) {
 364  
 
 365  0
                                         for (Iterator iter2 = maintSectionDef.getMaintainableItems().iterator(); iter2.hasNext();) {
 366  0
                                                 MaintainableItemDefinition item = (MaintainableItemDefinition) iter2.next();
 367  0
                                                 if (item instanceof MaintainableFieldDefinition) {
 368  0
                                                         displayedFieldNames.add(((MaintainableFieldDefinition) item).getName());
 369  
                                                 }
 370  0
                                         }
 371  
 
 372  0
                                         Section section = SectionBridge.toSection(maintSectionDef, getBusinessObject(), this,
 373  
                                                         oldMaintainable, getMaintenanceAction(), displayedFieldNames, conditionallyRequiredFields);
 374  0
                                         if (maintenanceRestrictions.isReadOnlySectionId(maintSectionDef.getId())) {
 375  0
                                                 section.setReadOnly(true);
 376  
                                         }
 377  
 
 378  
                                         // add to section list
 379  0
                                         sections.add(section);
 380  
                                 }
 381  
 
 382  0
                         }
 383  
 
 384  
                 }
 385  0
                 catch (InstantiationException e) {
 386  0
                         LOG.error("Unable to create instance of object class" + e.getMessage());
 387  0
                         throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
 388  
                 }
 389  0
                 catch (IllegalAccessException e) {
 390  0
                         LOG.error("Unable to create instance of object class" + e.getMessage());
 391  0
                         throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
 392  0
                 }
 393  
 
 394  0
                 return sections;
 395  
         }
 396  
 
 397  
         /**
 398  
          * 
 399  
          * @see org.kuali.rice.krad.maintenance.Maintainable#saveBusinessObject()
 400  
          */
 401  
         public void saveBusinessObject() {
 402  0
                 getBusinessObjectService().linkAndSave(businessObject);
 403  0
         }
 404  
 
 405  
         /**
 406  
          * Retrieves title for maintenance document from data dictionary
 407  
          */
 408  
         public String getMaintainableTitle() {
 409  0
                 return getMaintenanceDocumentDictionaryService().getMaintenanceLabel(getDocumentTypeName());
 410  
         }
 411  
 
 412  
         /**
 413  
          * Retrieves the status of the boNotesEnabled
 414  
          */
 415  
         public boolean isBoNotesEnabled() {
 416  0
             if(BusinessObject.class.isAssignableFrom(boClass)) {
 417  0
                         return getBusinessObjectDictionaryService().areNotesSupported(this.boClass);
 418  
                 }
 419  
 
 420  0
                 return false;
 421  
         }
 422  
 
 423  
         /**
 424  
          * @see org.kuali.rice.krad.maintenance.Maintainable#refresh(java.lang.String,
 425  
          *      java.util.Map) Impls will be needed if custom action is needed on
 426  
          *      refresh.
 427  
          */
 428  
         public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) {
 429  0
                 String referencesToRefresh = (String) fieldValues.get(KRADConstants.REFERENCES_TO_REFRESH);
 430  0
                 refreshReferences(referencesToRefresh);
 431  0
         }
 432  
 
 433  
         protected void refreshReferences(String referencesToRefresh) {
 434  0
                 PersistenceStructureService persistenceStructureService = getPersistenceStructureService();
 435  0
                 if (StringUtils.isNotBlank(referencesToRefresh)) {
 436  0
                         String[] references = StringUtils.split(referencesToRefresh, KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR);
 437  0
                         for (String reference : references) {
 438  0
                                 if (StringUtils.isNotBlank(reference)) {
 439  0
                                         if (reference.startsWith(KRADConstants.ADD_PREFIX + ".")) {
 440  
                                                 // add one for the period
 441  0
                                                 reference = reference.substring(KRADConstants.ADD_PREFIX.length() + 1);
 442  
 
 443  0
                                                 String boToRefreshName = StringUtils.substringBeforeLast(reference, ".");
 444  0
                                                 String propertyToRefresh = StringUtils.substringAfterLast(reference, ".");
 445  0
                                                 if (StringUtils.isNotBlank(propertyToRefresh)) {
 446  0
                                                         PersistableBusinessObject addlineBO = getNewCollectionLine(boToRefreshName);
 447  0
                                                         Class addlineBOClass = addlineBO.getClass();
 448  0
                                                         if (LOG.isDebugEnabled()) {
 449  0
                                                                 LOG.debug("Refresh this \"new\"/add object for the collections:  " + reference);
 450  
                                                         }
 451  0
                                                         if (persistenceStructureService.hasReference(addlineBOClass, propertyToRefresh)
 452  
                                                                         || persistenceStructureService.hasCollection(addlineBOClass, propertyToRefresh)) {
 453  0
                                                                 addlineBO.refreshReferenceObject(propertyToRefresh);
 454  
                                                         }
 455  
                                                         else {
 456  0
                                                                 if (getDataDictionaryService().hasRelationship(addlineBOClass.getName(),
 457  
                                                                                 propertyToRefresh)) {
 458  
                                                                         // a DD mapping, try to go straight to the
 459  
                                                                         // object and refresh it there
 460  0
                                                                         Object possibleBO = ObjectUtils.getPropertyValue(addlineBO, propertyToRefresh);
 461  0
                                                                         if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
 462  0
                                                                                 ((PersistableBusinessObject) possibleBO).refresh();
 463  
                                                                         }
 464  
                                                                 }
 465  
                                                         }
 466  0
                                                 }
 467  
                                                 else {
 468  0
                                                         LOG.error("Error: unable to refresh this \"new\"/add object for the collections:  "
 469  
                                                                         + reference);
 470  
                                                 }
 471  0
                                         }
 472  0
                                         else if (ObjectUtils.isNestedAttribute(reference)) {
 473  0
                                                 Object nestedObject = ObjectUtils.getNestedValue(getBusinessObject(),
 474  
                                                                 ObjectUtils.getNestedAttributePrefix(reference));
 475  0
                                                 if (nestedObject instanceof Collection) {
 476  
                                                         // do nothing, probably because it's not really a
 477  
                                                         // collection reference but a relationship defined
 478  
                                                         // in the DD for a collections lookup
 479  
                                                         // this part will need to be rewritten when the DD
 480  
                                                         // supports true collection references
 481  
                                                 }
 482  0
                                                 else if (nestedObject instanceof PersistableBusinessObject) {
 483  0
                                                         String propertyToRefresh = ObjectUtils.getNestedAttributePrimitive(reference);
 484  0
                                                         if (persistenceStructureService.hasReference(nestedObject.getClass(), propertyToRefresh)
 485  
                                                                         || persistenceStructureService.hasCollection(nestedObject.getClass(),
 486  
                                                                                         propertyToRefresh)) {
 487  0
                                                                 if (LOG.isDebugEnabled()) {
 488  0
                                                                         LOG.debug("Refeshing " + ObjectUtils.getNestedAttributePrefix(reference) + " "
 489  
                                                                                         + ObjectUtils.getNestedAttributePrimitive(reference));
 490  
                                                                 }
 491  0
                                                                 ((PersistableBusinessObject) nestedObject).refreshReferenceObject(propertyToRefresh);
 492  
                                                         }
 493  
                                                         else {
 494  
                                                                 // a DD mapping, try to go straight to the
 495  
                                                                 // object and refresh it there
 496  0
                                                                 Object possibleBO = ObjectUtils.getPropertyValue(nestedObject, propertyToRefresh);
 497  0
                                                                 if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
 498  0
                                                                         if (getDataDictionaryService().hasRelationship(possibleBO.getClass().getName(),
 499  
                                                                                         propertyToRefresh)) {
 500  0
                                                                                 ((PersistableBusinessObject) possibleBO).refresh();
 501  
                                                                         }
 502  
                                                                 }
 503  
                                                         }
 504  0
                                                 }
 505  
                                                 else {
 506  0
                                                         LOG.warn("Expected that a referenceToRefresh ("
 507  
                                                                         + reference
 508  
                                                                         + ")  would be a PersistableBusinessObject or Collection, but instead, it was of class "
 509  
                                                                         + nestedObject.getClass().getName());
 510  
                                                 }
 511  0
                                         }
 512  
                                         else {
 513  0
                                                 if (LOG.isDebugEnabled()) {
 514  0
                                                         LOG.debug("Refreshing " + reference);
 515  
                                                 }
 516  0
                                                 if (persistenceStructureService.hasReference(boClass, reference)
 517  
                                                                 || persistenceStructureService.hasCollection(boClass, reference)) {
 518  0
                                                         getBusinessObject().refreshReferenceObject(reference);
 519  
                                                 }
 520  
                                                 else {
 521  0
                                                         if (getDataDictionaryService().hasRelationship(getBusinessObject().getClass().getName(),
 522  
                                                                         reference)) {
 523  
                                                                 // a DD mapping, try to go straight to the
 524  
                                                                 // object and refresh it there
 525  0
                                                                 Object possibleRelationship = ObjectUtils.getPropertyValue(getBusinessObject(),
 526  
                                                                                 reference);
 527  0
                                                                 if (possibleRelationship != null) {
 528  0
                                                                         if (possibleRelationship instanceof PersistableBusinessObject) {
 529  0
                                                                                 ((PersistableBusinessObject) possibleRelationship).refresh();
 530  
                                                                         }
 531  0
                                                                         else if (possibleRelationship instanceof Collection) {
 532  
                                                                                 // do nothing, probably because it's not
 533  
                                                                                 // really a collection reference but a
 534  
                                                                                 // relationship defined in the DD for a
 535  
                                                                                 // collections lookup
 536  
                                                                                 // this part will need to be rewritten
 537  
                                                                                 // when the DD supports true collection
 538  
                                                                                 // references
 539  
                                                                         }
 540  
                                                                         else {
 541  0
                                                                                 LOG.warn("Expected that a referenceToRefresh ("
 542  
                                                                                                 + reference
 543  
                                                                                                 + ")  would be a PersistableBusinessObject or Collection, but instead, it was of class "
 544  
                                                                                                 + possibleRelationship.getClass().getName());
 545  
                                                                         }
 546  
                                                                 }
 547  
                                                         }
 548  
                                                 }
 549  
                                         }
 550  
                                 }
 551  
                         }
 552  
                 }
 553  0
         }
 554  
 
 555  
         public void addMultipleValueLookupResults(MaintenanceDocument document, String collectionName,
 556  
                         Collection<PersistableBusinessObject> rawValues, boolean needsBlank, PersistableBusinessObject bo) {
 557  0
                 Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(bo, collectionName);
 558  0
                 String docTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
 559  
 
 560  0
                 List<String> duplicateIdentifierFieldsFromDataDictionary = getDuplicateIdentifierFieldsFromDataDictionary(
 561  
                                 docTypeName, collectionName);
 562  
 
 563  0
                 List<String> existingIdentifierList = getMultiValueIdentifierList(maintCollection,
 564  
                                 duplicateIdentifierFieldsFromDataDictionary);
 565  
 
 566  0
                 Class collectionClass = getMaintenanceDocumentDictionaryService().getCollectionBusinessObjectClass(docTypeName,
 567  
                                 collectionName);
 568  
 
 569  0
                 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
 570  
                                 .getMaintainableSections(docTypeName);
 571  0
                 Map<String, String> template = MaintenanceUtils.generateMultipleValueLookupBOTemplate(sections, collectionName);
 572  
                 try {
 573  0
                         for (PersistableBusinessObject nextBo : rawValues) {
 574  
                                 PersistableBusinessObject templatedBo;
 575  0
                                 if (needsBlank) {
 576  0
                                         templatedBo = (PersistableBusinessObject) collectionClass.newInstance();
 577  
                                 }
 578  
                                 else {
 579  
                                         // templatedBo = (PersistableBusinessObject)
 580  
                                         // ObjectUtils.createHybridBusinessObject(collectionClass,
 581  
                                         // nextBo, template);
 582  
                                         try {
 583  0
                                                 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService()
 584  
                                                                 .getResponsibleModuleService(collectionClass);
 585  0
                                                 if (moduleService != null && moduleService.isExternalizable(collectionClass))
 586  0
                                                         templatedBo = (PersistableBusinessObject) moduleService
 587  
                                                                         .createNewObjectFromExternalizableClass(collectionClass);
 588  
                                                 else
 589  0
                                                         templatedBo = (PersistableBusinessObject) collectionClass.newInstance();
 590  
                                         }
 591  0
                                         catch (Exception e) {
 592  0
                                                 throw new RuntimeException("Cannot instantiate " + collectionClass.getName(), e);
 593  0
                                         }
 594  
                                         // first set the default values specified in the DD
 595  0
                                         setNewCollectionLineDefaultValues(collectionName, templatedBo);
 596  
                                         // then set the values from the multiple value lookup result
 597  0
                                         ObjectUtils.createHybridBusinessObject(templatedBo, nextBo, template);
 598  
 
 599  0
                                         prepareBusinessObjectForAdditionFromMultipleValueLookup(collectionName, templatedBo);
 600  
                                 }
 601  0
                                 templatedBo.setNewCollectionRecord(true);
 602  
 
 603  0
                                 if (!hasBusinessObjectExisted(templatedBo, existingIdentifierList,
 604  
                                                 duplicateIdentifierFieldsFromDataDictionary)) {
 605  0
                                         maintCollection.add(templatedBo);
 606  
 
 607  
                                 }
 608  0
                         }
 609  
                 }
 610  0
                 catch (Exception e) {
 611  0
                         LOG.error("Unable to add multiple value lookup results " + e.getMessage());
 612  0
                         throw new RuntimeException("Unable to add multiple value lookup results " + e.getMessage());
 613  0
                 }
 614  0
         }
 615  
 
 616  
         /**
 617  
          * This method is to retrieve a List of fields which are specified in the
 618  
          * maintenance document data dictionary as the
 619  
          * duplicateIdentificationFields. This List is used to determine whether the
 620  
          * new entry being added to the collection is a duplicate entry and if so,
 621  
          * we should not add the new entry to the existing collection
 622  
          * 
 623  
          * @param docTypeName
 624  
          * @param collectionName
 625  
          */
 626  
         public List<String> getDuplicateIdentifierFieldsFromDataDictionary(String docTypeName, String collectionName) {
 627  0
                 List<String> duplicateIdentifierFieldNames = new ArrayList<String>();
 628  0
                 MaintainableCollectionDefinition collDef = getMaintenanceDocumentDictionaryService().getMaintainableCollection(
 629  
                                 docTypeName, collectionName);
 630  0
                 Collection<MaintainableFieldDefinition> fieldDef = collDef.getDuplicateIdentificationFields();
 631  0
                 for (MaintainableFieldDefinition eachFieldDef : fieldDef) {
 632  0
                         duplicateIdentifierFieldNames.add(eachFieldDef.getName());
 633  
                 }
 634  0
                 return duplicateIdentifierFieldNames;
 635  
         }
 636  
 
 637  
         public List<String> getMultiValueIdentifierList(Collection maintCollection, List<String> duplicateIdentifierFields) {
 638  0
                 List<String> identifierList = new ArrayList<String>();
 639  0
                 for (PersistableBusinessObject bo : (Collection<PersistableBusinessObject>) maintCollection) {
 640  0
                         String uniqueIdentifier = new String();
 641  0
                         for (String identifierField : duplicateIdentifierFields) {
 642  0
                                 uniqueIdentifier = uniqueIdentifier + identifierField + "-"
 643  
                                                 + ObjectUtils.getPropertyValue(bo, identifierField);
 644  
                         }
 645  0
                         if (StringUtils.isNotEmpty(uniqueIdentifier)) {
 646  0
                                 identifierList.add(uniqueIdentifier);
 647  
                         }
 648  0
                 }
 649  0
                 return identifierList;
 650  
         }
 651  
 
 652  
         public boolean hasBusinessObjectExisted(BusinessObject bo, List<String> existingIdentifierList,
 653  
                         List<String> duplicateIdentifierFields) {
 654  0
                 String uniqueIdentifier = new String();
 655  0
                 for (String identifierField : duplicateIdentifierFields) {
 656  0
                         uniqueIdentifier = uniqueIdentifier + identifierField + "-"
 657  
                                         + ObjectUtils.getPropertyValue(bo, identifierField);
 658  
                 }
 659  0
                 if (existingIdentifierList.contains(uniqueIdentifier)) {
 660  0
                         return true;
 661  
                 }
 662  
                 else {
 663  0
                         return false;
 664  
                 }
 665  
         }
 666  
 
 667  
         public void prepareBusinessObjectForAdditionFromMultipleValueLookup(String collectionName, BusinessObject bo) {
 668  
                 // default implementation does nothing
 669  0
         }
 670  
 
 671  
         /**
 672  
          * 
 673  
          * @see org.kuali.rice.krad.maintenance.Maintainable#prepareForSave()
 674  
          */
 675  
         public void prepareForSave() {
 676  
 
 677  0
         }
 678  
 
 679  
         /**
 680  
          * 
 681  
          * @see org.kuali.rice.krad.maintenance.Maintainable#processAfterRetrieve()
 682  
          */
 683  
         public void processAfterRetrieve() {
 684  0
         }
 685  
 
 686  
         /**
 687  
          * Set the new collection records back to true so they can be deleted (copy
 688  
          * should act like new)
 689  
          * 
 690  
          * @see org.kuali.rice.krad.maintenance.KualiMaintainableImpl#processAfterCopy()
 691  
          */
 692  
         public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> parameters) {
 693  
                 try {
 694  0
                         ObjectUtils.setObjectPropertyDeep(businessObject, KRADPropertyConstants.NEW_COLLECTION_RECORD,
 695  
                                         boolean.class, true, 2);
 696  
                 }
 697  0
                 catch (Exception e) {
 698  0
                         LOG.error("unable to set newCollectionRecord property: " + e.getMessage(), e);
 699  0
                         throw new RuntimeException("unable to set newCollectionRecord property: " + e.getMessage(), e);
 700  0
                 }
 701  0
         }
 702  
 
 703  
         /**
 704  
          * @see org.kuali.rice.krad.maintenance.Maintainable#processAfterEdit()
 705  
          */
 706  
         public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> parameters) {
 707  0
         }
 708  
 
 709  
         /**
 710  
          * @see org.kuali.rice.krad.maintenance.Maintainable#processAfterNew()
 711  
          */
 712  
         public void processAfterNew(MaintenanceDocument document, Map<String, String[]> parameters) {
 713  0
         }
 714  
 
 715  
         /**
 716  
          * Retrieves the document type name from the data dictionary based on
 717  
          * business object class
 718  
          */
 719  
         protected String getDocumentTypeName() {
 720  0
                 return getMaintenanceDocumentDictionaryService().getDocumentTypeName(boClass);
 721  
         }
 722  
 
 723  
         @Override
 724  
     public Object getDataObject() {
 725  0
         return dataObject;
 726  
     }
 727  
 
 728  
     @Override
 729  
     public void setDataObject(Object object) {
 730  0
         this.dataObject = object;
 731  
         
 732  0
         if(object instanceof PersistableBusinessObject) {
 733  0
             this.businessObject = (PersistableBusinessObject)object;
 734  
         }
 735  0
     }
 736  
 
 737  
     /**
 738  
      * @return Returns the instance of the business object being maintained.
 739  
      */
 740  
     public PersistableBusinessObject getBusinessObject() {
 741  0
         return businessObject;
 742  
     }
 743  
 
 744  
     /**
 745  
      * @param businessObject
 746  
      *            Sets the instance of a business object that will be
 747  
      *            maintained.
 748  
      */
 749  
     public void setBusinessObject(PersistableBusinessObject businessObject) {
 750  0
         this.businessObject = businessObject;
 751  0
         this.dataObject = businessObject;
 752  0
     }
 753  
 
 754  
         /**
 755  
          * @return Returns the boClass.
 756  
          */
 757  
         public Class getBoClass() {
 758  0
                 return boClass;
 759  
         }
 760  
 
 761  
         /**
 762  
          * @param boClass
 763  
          *            The boClass to set.
 764  
          */
 765  
         public void setBoClass(Class boClass) {
 766  0
                 this.boClass = boClass;
 767  0
                 this.docTypeName = getDocumentTypeName();
 768  0
         }
 769  
 
 770  
         /**
 771  
          * @return Returns the maintenanceAction.
 772  
          */
 773  
         public String getMaintenanceAction() {
 774  0
                 return maintenanceAction;
 775  
         }
 776  
 
 777  
         /**
 778  
          * @param maintenanceAction
 779  
          *            The maintenanceAction to set.
 780  
          */
 781  
         public void setMaintenanceAction(String maintenanceAction) {
 782  0
                 this.maintenanceAction = maintenanceAction;
 783  0
         }
 784  
 
 785  
         /**
 786  
          * 
 787  
          * @see org.kuali.rice.krad.maintenance.Maintainable#setGenerateDefaultValues()
 788  
          */
 789  
         public void setGenerateDefaultValues(String docTypeName) {
 790  0
                 List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
 791  
                                 .getMaintainableSections(docTypeName);
 792  0
                 Map defaultValues = new HashMap();
 793  
 
 794  
         // iterate through section definitions
 795  0
         for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
 796  
 
 797  0
             MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
 798  0
             Collection maintItems = maintSectionDef.getMaintainableItems();
 799  0
             for (Iterator iterator = maintItems.iterator(); iterator.hasNext();) {
 800  0
                 MaintainableItemDefinition item = (MaintainableItemDefinition) iterator.next();
 801  
 
 802  0
                 if (item instanceof MaintainableFieldDefinition) {
 803  0
                     MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
 804  
 
 805  0
                     String defaultValue = maintainableFieldDefinition.getDefaultValue();
 806  0
                     if (defaultValue != null) {
 807  0
                         if (defaultValue.equals("true")) {
 808  0
                             defaultValue = "Yes";
 809  
                         }
 810  0
                         else if (defaultValue.equals("false")) {
 811  0
                             defaultValue = "No";
 812  
                         }
 813  
                     }
 814  
 
 815  0
                     Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
 816  0
                     if (defaultValueFinderClass != null) {
 817  
                         try {
 818  0
                             defaultValue = ((ValueFinder) defaultValueFinderClass.newInstance()).getValue();
 819  0
                         } catch (InstantiationException e) {
 820  0
                             throw new RuntimeException("Unable to set default value" + e.getMessage(), e);
 821  0
                         } catch (IllegalAccessException e) {
 822  0
                             throw new RuntimeException("Unable to set default value" + e.getMessage(), e);
 823  0
                         }
 824  
 
 825  
                     }
 826  0
                     if (defaultValue != null) {
 827  0
                         defaultValues.put(item.getName(), defaultValue);
 828  
                     }
 829  
                 }
 830  0
             }
 831  0
         }
 832  0
         FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
 833  
 
 834  0
         }
 835  
 
 836  
         /**
 837  
          * 
 838  
          * @see org.kuali.rice.krad.maintenance.Maintainable#setGenerateBlankRequiredValues()
 839  
          */
 840  
         public void setGenerateBlankRequiredValues(String docTypeName) {
 841  
                 try {
 842  0
                         List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
 843  
                                         .getMaintainableSections(docTypeName);
 844  0
                         Map<String, String> defaultValues = new HashMap<String, String>();
 845  
 
 846  0
                         for (MaintainableSectionDefinition maintSectionDef : sectionDefinitions) {
 847  0
                                 for (MaintainableItemDefinition item : maintSectionDef.getMaintainableItems()) {
 848  0
                                         if (item instanceof MaintainableFieldDefinition) {
 849  0
                                                 MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
 850  0
                                                 if (maintainableFieldDefinition.isRequired()
 851  
                                                                 && maintainableFieldDefinition.isUnconditionallyReadOnly()) {
 852  0
                                                         Object currPropVal = ObjectUtils.getPropertyValue(this.getBusinessObject(), item.getName());
 853  0
                                                         if (currPropVal == null
 854  
                                                                         || (currPropVal instanceof String && StringUtils.isBlank((String) currPropVal))) {
 855  0
                                                                 Class<? extends ValueFinder> defaultValueFinderClass = maintainableFieldDefinition
 856  
                                                                                 .getDefaultValueFinderClass();
 857  0
                                                                 if (defaultValueFinderClass != null) {
 858  0
                                                                         String defaultValue = defaultValueFinderClass.newInstance().getValue();
 859  0
                                                                         if (defaultValue != null) {
 860  0
                                                                                 defaultValues.put(item.getName(), defaultValue);
 861  
                                                                         }
 862  
                                                                 }
 863  
                                                         }
 864  
                                                 }
 865  0
                                         }
 866  
                                 }
 867  
                         }
 868  0
                         FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
 869  
                 }
 870  0
                 catch (Exception e) {
 871  0
                         LOG.error("Unable to set blank required value " + e.getMessage(), e);
 872  0
                         throw new RuntimeException("Unable to set blank required value" + e.getMessage(), e);
 873  0
                 }
 874  0
         }
 875  
 
 876  
         /**
 877  
          * Sets the documentNumber attribute value.
 878  
          * 
 879  
          * @param documentNumber
 880  
          *            The documentNumber to set.
 881  
          */
 882  
         public final void setDocumentNumber(String documentNumber) {
 883  0
                 this.documentNumber = documentNumber;
 884  0
         }
 885  
 
 886  
         @Deprecated
 887  
         public void processAfterAddLine(String colName, Class colClass) {
 888  0
         }
 889  
 
 890  
         /**
 891  
          * @see org.kuali.rice.krad.maintenance.Maintainable#processBeforeAddLine(java.lang.String,
 892  
          *      java.lang.Class, org.kuali.rice.krad.bo.BusinessObject)
 893  
          */
 894  
         public void processBeforeAddLine(String colName, Class colClass, BusinessObject addBO) {
 895  0
         }
 896  
 
 897  
         /**
 898  
          * @see org.kuali.rice.krad.maintenance.Maintainable#getShowInactiveRecords(java.lang.String)
 899  
          */
 900  
         public boolean getShowInactiveRecords(String collectionName) {
 901  0
                 return InactiveRecordsHidingUtils.getShowInactiveRecords(inactiveRecordDisplay, collectionName);
 902  
         }
 903  
 
 904  
         /**
 905  
          * @see org.kuali.rice.krad.maintenance.Maintainable#setShowInactiveRecords(java.lang.String,
 906  
          *      boolean)
 907  
          */
 908  
         public void setShowInactiveRecords(String collectionName, boolean showInactive) {
 909  0
                 InactiveRecordsHidingUtils.setShowInactiveRecords(inactiveRecordDisplay, collectionName, showInactive);
 910  0
         }
 911  
 
 912  
         /**
 913  
          * @return the inactiveRecordDisplay
 914  
          */
 915  
         public Map<String, Boolean> getInactiveRecordDisplay() {
 916  0
                 return inactiveRecordDisplay;
 917  
         }
 918  
 
 919  
         public void addNewLineToCollection(String collectionName) {
 920  
 
 921  0
                 if (LOG.isDebugEnabled()) {
 922  0
                         LOG.debug("addNewLineToCollection( " + collectionName + " )");
 923  
                 }
 924  
                 // get the new line from the map
 925  0
                 PersistableBusinessObject addLine = newCollectionLines.get(collectionName);
 926  0
                 if (addLine != null) {
 927  
                         // mark the isNewCollectionRecord so the option to delete this line
 928  
                         // will be presented
 929  0
                         addLine.setNewCollectionRecord(true);
 930  
 
 931  
                         // if we add back add button on sub collection of an "add line" we
 932  
                         // may need extra logic here
 933  
 
 934  
                         // get the collection from the business object
 935  0
                         Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(getBusinessObject(), collectionName);
 936  
                         // add the line to the collection
 937  0
                         maintCollection.add(addLine);
 938  
                         // refresh parent object since attributes could of changed prior to
 939  
                         // user clicking add
 940  
 
 941  0
                         String referencesToRefresh = LookupUtils
 942  
                                         .convertReferencesToSelectCollectionToString(getAllRefreshableReferences(getBusinessObject()
 943  
                                                         .getClass()));
 944  0
                         if (LOG.isInfoEnabled()) {
 945  0
                                 LOG.info("References to refresh for adding line to collection " + collectionName + ": "
 946  
                                                 + referencesToRefresh);
 947  
                         }
 948  0
                         refreshReferences(referencesToRefresh);
 949  
                 }
 950  
 
 951  0
                 initNewCollectionLine(collectionName);
 952  
 
 953  0
         }
 954  
 
 955  
         public PersistableBusinessObject getNewCollectionLine(String collectionName) {
 956  0
                 if (LOG.isDebugEnabled()) {
 957  
                         // LOG.debug( this + ") getNewCollectionLine( " + collectionName +
 958  
                         // ")", new Exception( "tracing exception") );
 959  0
                         LOG.debug("newCollectionLines: " + newCollectionLines);
 960  
                 }
 961  0
                 PersistableBusinessObject addLine = newCollectionLines.get(collectionName);
 962  0
                 if (addLine == null) {
 963  0
                         addLine = initNewCollectionLine(collectionName);
 964  
                 }
 965  0
                 return addLine;
 966  
         }
 967  
 
 968  
         public PersistableBusinessObject initNewCollectionLine(String collectionName) {
 969  0
                 if (LOG.isDebugEnabled()) {
 970  0
                         LOG.debug("initNewCollectionLine( " + collectionName + " )");
 971  
                 }
 972  
                 // try to get the object from the map
 973  
                 // BusinessObject addLine = newCollectionLines.get( collectionName );
 974  
                 // if ( addLine == null ) {
 975  
                 // if not there, instantiate a new one
 976  
                 PersistableBusinessObject addLine;
 977  
                 try {
 978  0
                         addLine = (PersistableBusinessObject) getMaintenanceDocumentDictionaryService()
 979  
                                         .getCollectionBusinessObjectClass(docTypeName, collectionName).newInstance();
 980  
                 }
 981  0
                 catch (Exception ex) {
 982  0
                         LOG.error("unable to instantiate new collection line", ex);
 983  0
                         throw new RuntimeException("unable to instantiate new collection line", ex);
 984  0
                 }
 985  
                 // and add it to the map
 986  0
                 newCollectionLines.put(collectionName, addLine);
 987  
                 // }
 988  
                 // set its values to the defaults
 989  0
                 setNewCollectionLineDefaultValues(collectionName, addLine);
 990  0
                 return addLine;
 991  
         }
 992  
 
 993  
         /**
 994  
          * 
 995  
          * @see org.kuali.rice.krad.maintenance.Maintainable#populateNewCollectionLines(java.util.Map)
 996  
          */
 997  
         public Map<String, String> populateNewCollectionLines(Map<String, String> fieldValues,
 998  
                         MaintenanceDocument maintenanceDocument, String methodToCall) {
 999  0
                 if (LOG.isDebugEnabled()) {
 1000  0
                         LOG.debug("populateNewCollectionLines: " + fieldValues);
 1001  
                 }
 1002  0
                 fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
 1003  
 
 1004  0
                 Map<String, String> cachedValues = new HashMap<String, String>();
 1005  
 
 1006  
                 // loop over all collections with an enabled add line
 1007  0
                 List<MaintainableCollectionDefinition> collections = getMaintenanceDocumentDictionaryService()
 1008  
                                 .getMaintainableCollections(docTypeName);
 1009  
 
 1010  0
                 for (MaintainableCollectionDefinition coll : collections) {
 1011  
                         // get the collection name
 1012  0
                         String collName = coll.getName();
 1013  0
                         if (LOG.isDebugEnabled()) {
 1014  0
                                 LOG.debug("checking for collection: " + collName);
 1015  
                         }
 1016  
                         // build a map for that collection
 1017  0
                         Map<String, String> collectionValues = new HashMap<String, String>();
 1018  0
                         Map<String, String> subCollectionValues = new HashMap<String, String>();
 1019  
                         // loop over the collection, extracting entries with a matching
 1020  
                         // prefix
 1021  0
                         for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
 1022  0
                                 String key = entry.getKey();
 1023  0
                                 if (key.startsWith(collName)) {
 1024  0
                                         String subStrKey = key.substring(collName.length() + 1);
 1025  
                                         // check for subcoll w/ '[', set collName to propername and
 1026  
                                         // put in correct name for collection values (i.e. strip
 1027  
                                         // '*[x].')
 1028  0
                                         if (key.contains("[")) {
 1029  
 
 1030  
                                                 // collName = StringUtils.substringBeforeLast(key,"[");
 1031  
 
 1032  
                                                 // need the whole thing if subcollection
 1033  0
                                                 subCollectionValues.put(key, entry.getValue());
 1034  
                                         }
 1035  
                                         else {
 1036  0
                                                 collectionValues.put(subStrKey, entry.getValue());
 1037  
                                         }
 1038  
                                 }
 1039  0
                         }
 1040  
                         // send those values to the business object
 1041  0
                         if (LOG.isDebugEnabled()) {
 1042  0
                                 LOG.debug("values for collection: " + collectionValues);
 1043  
                         }
 1044  0
                         cachedValues.putAll(FieldUtils.populateBusinessObjectFromMap(getNewCollectionLine(collName),
 1045  
                                         collectionValues, KRADConstants.MAINTENANCE_ADD_PREFIX + collName + "."));
 1046  0
                         performFieldForceUpperCase(getNewCollectionLine(collName), collectionValues);
 1047  
 
 1048  0
                         cachedValues.putAll(populateNewSubCollectionLines(coll, subCollectionValues));
 1049  0
                 }
 1050  
 
 1051  
                 // cachedValues.putAll( FieldUtils.populateBusinessObjectFromMap( ))
 1052  0
                 return cachedValues;
 1053  
         }
 1054  
 
 1055  
         /*
 1056  
          * Yes, I think this could be merged with the above code - I'm leaving it
 1057  
          * separate until I figure out of there are any issues which would reqire
 1058  
          * that it be separated.
 1059  
          */
 1060  
         protected Map populateNewSubCollectionLines(MaintainableCollectionDefinition parentCollection, Map fieldValues) {
 1061  0
                 if (LOG.isDebugEnabled()) {
 1062  0
                         LOG.debug("populateNewSubCollectionLines: " + fieldValues);
 1063  
                 }
 1064  0
                 Map cachedValues = new HashMap();
 1065  
 
 1066  0
                 for (MaintainableCollectionDefinition coll : parentCollection.getMaintainableCollections()) {
 1067  
                         // get the collection name
 1068  0
                         String collName = coll.getName();
 1069  
 
 1070  0
                         if (LOG.isDebugEnabled()) {
 1071  0
                                 LOG.debug("checking for sub collection: " + collName);
 1072  
                         }
 1073  0
                         Map<String, String> parents = new HashMap<String, String>();
 1074  
                         // get parents from list
 1075  0
                         for (Object entry : fieldValues.entrySet()) {
 1076  0
                                 String key = (String) ((Map.Entry) entry).getKey();
 1077  0
                                 if (key.contains(collName)) {
 1078  0
                                         parents.put(StringUtils.substringBefore(key, "."), "");
 1079  
                                 }
 1080  0
                         }
 1081  
 
 1082  0
                         for (String parent : parents.keySet()) {
 1083  
                                 // build a map for that collection
 1084  0
                                 Map<String, Object> collectionValues = new HashMap<String, Object>();
 1085  
                                 // loop over the collection, extracting entries with a matching
 1086  
                                 // prefix
 1087  0
                                 for (Object entry : fieldValues.entrySet()) {
 1088  0
                                         String key = (String) ((Map.Entry) entry).getKey();
 1089  0
                                         if (key.contains(parent)) {
 1090  0
                                                 String substr = StringUtils.substringAfterLast(key, ".");
 1091  0
                                                 collectionValues.put(substr, ((Map.Entry) entry).getValue());
 1092  
                                         }
 1093  0
                                 }
 1094  
                                 // send those values to the business object
 1095  0
                                 if (LOG.isDebugEnabled()) {
 1096  0
                                         LOG.debug("values for sub collection: " + collectionValues);
 1097  
                                 }
 1098  0
                                 GlobalVariables.getMessageMap().addToErrorPath(
 1099  
                                                 KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName);
 1100  0
                                 cachedValues.putAll(FieldUtils.populateBusinessObjectFromMap(getNewCollectionLine(parent + "."
 1101  
                                                 + collName), collectionValues, KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName
 1102  
                                                 + "."));
 1103  0
                                 performFieldForceUpperCase(getNewCollectionLine(parent + "." + collName), collectionValues);
 1104  0
                                 GlobalVariables.getMessageMap().removeFromErrorPath(
 1105  
                                                 KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName);
 1106  0
                         }
 1107  
 
 1108  0
                         cachedValues.putAll(populateNewSubCollectionLines(coll, fieldValues));
 1109  0
                 }
 1110  
 
 1111  0
                 return cachedValues;
 1112  
         }
 1113  
 
 1114  
         public Collection<String> getAffectedReferencesFromLookup(BusinessObject baseBO, String attributeName,
 1115  
                         String collectionPrefix) {
 1116  0
                 PersistenceStructureService pss = getPersistenceStructureService();
 1117  0
                 String nestedBOPrefix = "";
 1118  0
                 if (ObjectUtils.isNestedAttribute(attributeName)) {
 1119  
                         // if we're performing a lookup on a nested attribute, we need to
 1120  
                         // use the nested BO all the way down the chain
 1121  0
                         nestedBOPrefix = ObjectUtils.getNestedAttributePrefix(attributeName);
 1122  
 
 1123  
                         // renormalize the base BO so that the attribute name is not nested
 1124  
                         // anymore
 1125  0
                         Class reference = ObjectUtils.getPropertyType(baseBO, nestedBOPrefix, pss);
 1126  0
                         if (!(PersistableBusinessObject.class.isAssignableFrom(reference))) {
 1127  0
                                 return new ArrayList<String>();
 1128  
                         }
 1129  
 
 1130  
                         try {
 1131  0
                                 baseBO = (PersistableBusinessObject) reference.newInstance();
 1132  
                         }
 1133  0
                         catch (InstantiationException e) {
 1134  0
                                 LOG.error(e);
 1135  
                         }
 1136  0
                         catch (IllegalAccessException e) {
 1137  0
                                 LOG.error(e);
 1138  0
                         }
 1139  0
                         attributeName = ObjectUtils.getNestedAttributePrimitive(attributeName);
 1140  
                 }
 1141  
 
 1142  0
                 if (baseBO == null) {
 1143  0
                         return new ArrayList<String>();
 1144  
                 }
 1145  
 
 1146  0
                 Map<String, Class> referenceNameToClassFromPSS = LookupUtils.getPrimitiveReference(baseBO, attributeName);
 1147  0
                 if (referenceNameToClassFromPSS.size() > 1) {
 1148  0
                         LOG.error("LookupUtils.getPrimitiveReference return results should only have at most one element");
 1149  
                 }
 1150  
 
 1151  0
                 BusinessObjectMetaDataService businessObjectMetaDataService = getBusinessObjectMetaDataService();
 1152  0
                 BusinessObjectRelationship relationship = businessObjectMetaDataService.getBusinessObjectRelationship(baseBO,
 1153  
                                 attributeName);
 1154  0
                 if (relationship == null) {
 1155  0
                         return new ArrayList<String>();
 1156  
                 }
 1157  
 
 1158  0
                 Map<String, String> fkToPkMappings = relationship.getParentToChildReferences();
 1159  
 
 1160  0
                 Collection<String> affectedReferences = generateAllAffectedReferences(baseBO.getClass(), fkToPkMappings,
 1161  
                                 nestedBOPrefix, collectionPrefix);
 1162  0
                 if (LOG.isDebugEnabled()) {
 1163  0
                         LOG.debug("References affected by a lookup on BO attribute \"" + collectionPrefix + nestedBOPrefix + "."
 1164  
                                         + attributeName + ": " + affectedReferences);
 1165  
                 }
 1166  
 
 1167  0
                 return affectedReferences;
 1168  
         }
 1169  
 
 1170  
         protected boolean isRelationshipRefreshable(Class boClass, String relationshipName) {
 1171  0
                 if (getPersistenceStructureService().isPersistable(boClass)) {
 1172  0
                         if (getPersistenceStructureService().hasCollection(boClass, relationshipName)) {
 1173  0
                                 return !getPersistenceStructureService().isCollectionUpdatable(boClass, relationshipName);
 1174  
                         }
 1175  0
                         else if (getPersistenceStructureService().hasReference(boClass, relationshipName)) {
 1176  0
                                 return !getPersistenceStructureService().isReferenceUpdatable(boClass, relationshipName);
 1177  
                         }
 1178  
                         // else, assume that the relationship is defined in the DD
 1179  
                 }
 1180  
 
 1181  0
                 return true;
 1182  
         }
 1183  
 
 1184  
         protected Collection<String> generateAllAffectedReferences(Class boClass, Map<String, String> fkToPkMappings,
 1185  
                         String nestedBOPrefix, String collectionPrefix) {
 1186  0
                 Set<String> allAffectedReferences = new HashSet<String>();
 1187  0
                 DataDictionaryService dataDictionaryService = getDataDictionaryService();
 1188  0
                 PersistenceStructureService pss = getPersistenceStructureService();
 1189  
 
 1190  0
                 collectionPrefix = StringUtils.isBlank(collectionPrefix) ? "" : collectionPrefix;
 1191  
 
 1192  
                 // retrieve the attributes that are affected by a lookup on
 1193  
                 // attributeName.
 1194  0
                 Collection<String> attributeReferenceFKAttributes = fkToPkMappings.keySet();
 1195  
 
 1196  
                 // a lookup on an attribute may cause other attributes to be updated
 1197  
                 // (e.g. account code lookup would also affect chart code)
 1198  
                 // build a list of all affected FK values via mapKeyFields above, and
 1199  
                 // for each FK, see if there are any non-updatable references with that
 1200  
                 // FK
 1201  
 
 1202  
                 // deal with regular simple references (<reference-descriptor>s in OJB)
 1203  0
                 for (String fkAttribute : attributeReferenceFKAttributes) {
 1204  0
                         for (String affectedReference : pss.getReferencesForForeignKey(boClass, fkAttribute).keySet()) {
 1205  0
                                 if (isRelationshipRefreshable(boClass, affectedReference)) {
 1206  0
                                         if (StringUtils.isBlank(nestedBOPrefix)) {
 1207  0
                                                 allAffectedReferences.add(collectionPrefix + affectedReference);
 1208  
                                         }
 1209  
                                         else {
 1210  0
                                                 allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + affectedReference);
 1211  
                                         }
 1212  
                                 }
 1213  
                         }
 1214  
                 }
 1215  
 
 1216  
                 // now with collection references (<collection-descriptor>s in OJB)
 1217  0
                 for (String collectionName : pss.listCollectionObjectTypes(boClass).keySet()) {
 1218  0
                         if (isRelationshipRefreshable(boClass, collectionName)) {
 1219  0
                                 Map<String, String> keyMappingsForCollection = pss.getInverseForeignKeysForCollection(boClass,
 1220  
                                                 collectionName);
 1221  0
                                 for (String collectionForeignKey : keyMappingsForCollection.keySet()) {
 1222  0
                                         if (attributeReferenceFKAttributes.contains(collectionForeignKey)) {
 1223  0
                                                 if (StringUtils.isBlank(nestedBOPrefix)) {
 1224  0
                                                         allAffectedReferences.add(collectionPrefix + collectionName);
 1225  
                                                 }
 1226  
                                                 else {
 1227  0
                                                         allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + collectionName);
 1228  
                                                 }
 1229  
                                         }
 1230  
                                 }
 1231  0
                         }
 1232  
                 }
 1233  
 
 1234  
                 // now use the DD to compute more affected references
 1235  0
                 List<String> ddDefinedRelationships = dataDictionaryService.getRelationshipNames(boClass.getName());
 1236  0
                 for (String ddRelationship : ddDefinedRelationships) {
 1237  
                         // note that this map is PK (key/target) => FK (value/source)
 1238  0
                         Map<String, String> referencePKtoFKmappings = dataDictionaryService.getRelationshipAttributeMap(
 1239  
                                         boClass.getName(), ddRelationship);
 1240  0
                         for (String sourceAttribute : referencePKtoFKmappings.values()) {
 1241  
                                 // the sourceAttribute is the FK pointing to the target
 1242  
                                 // attribute (PK)
 1243  0
                                 if (attributeReferenceFKAttributes.contains(sourceAttribute)) {
 1244  0
                                         for (String affectedReference : dataDictionaryService.getRelationshipEntriesForSourceAttribute(
 1245  
                                                         boClass.getName(), sourceAttribute)) {
 1246  0
                                                 if (isRelationshipRefreshable(boClass, ddRelationship)) {
 1247  0
                                                         if (StringUtils.isBlank(nestedBOPrefix)) {
 1248  0
                                                                 allAffectedReferences.add(affectedReference);
 1249  
                                                         }
 1250  
                                                         else {
 1251  0
                                                                 allAffectedReferences.add(nestedBOPrefix + "." + affectedReference);
 1252  
                                                         }
 1253  
                                                 }
 1254  
                                         }
 1255  
                                 }
 1256  
                         }
 1257  0
                 }
 1258  0
                 return allAffectedReferences;
 1259  
         }
 1260  
 
 1261  
         protected Collection<String> getAllRefreshableReferences(Class boClass) {
 1262  0
                 HashSet<String> references = new HashSet<String>();
 1263  0
                 for (String referenceName : getPersistenceStructureService().listReferenceObjectFields(boClass).keySet()) {
 1264  0
                         if (isRelationshipRefreshable(boClass, referenceName)) {
 1265  0
                                 references.add(referenceName);
 1266  
                         }
 1267  
                 }
 1268  0
                 for (String collectionName : getPersistenceStructureService().listCollectionObjectTypes(boClass).keySet()) {
 1269  0
                         if (isRelationshipRefreshable(boClass, collectionName)) {
 1270  0
                                 references.add(collectionName);
 1271  
                         }
 1272  
                 }
 1273  0
                 for (String relationshipName : getDataDictionaryService().getRelationshipNames(boClass.getName())) {
 1274  0
                         if (isRelationshipRefreshable(boClass, relationshipName)) {
 1275  0
                                 references.add(relationshipName);
 1276  
                         }
 1277  
                 }
 1278  0
                 return references;
 1279  
         }
 1280  
 
 1281  
         protected void setNewCollectionLineDefaultValues(String collectionName, PersistableBusinessObject addLine) {
 1282  0
                 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(addLine);
 1283  0
                 for (int i = 0; i < descriptors.length; ++i) {
 1284  0
                         PropertyDescriptor propertyDescriptor = descriptors[i];
 1285  
 
 1286  0
                         String fieldName = propertyDescriptor.getName();
 1287  0
                         Class propertyType = propertyDescriptor.getPropertyType();
 1288  0
                         String value = getMaintenanceDocumentDictionaryService().getCollectionFieldDefaultValue(docTypeName,
 1289  
                                         collectionName, fieldName);
 1290  
 
 1291  0
                         if (value != null) {
 1292  
                                 try {
 1293  0
                                         ObjectUtils.setObjectProperty(addLine, fieldName, propertyType, value);
 1294  
                                 }
 1295  0
                                 catch (Exception ex) {
 1296  0
                                         LOG.error("Unable to set default property of collection object: " + "\nobject: " + addLine
 1297  
                                                         + "\nfieldName=" + fieldName + "\npropertyType=" + propertyType + "\nvalue=" + value, ex);
 1298  0
                                 }
 1299  
                         }
 1300  
 
 1301  
                 }
 1302  0
         }
 1303  
 
 1304  
         public void doRouteStatusChange(DocumentHeader documentHeader) {
 1305  0
         }
 1306  
 
 1307  
         public List<Long> getWorkflowEngineDocumentIdsToLock() {
 1308  0
                 return null;
 1309  
         }
 1310  
 
 1311  
         /**
 1312  
          * @see org.kuali.rice.krad.maintenance.Maintainable#clearBusinessObjectOfRestrictedValues(org.kuali.rice.krad.document.authorization.MaintenanceDocumentRestrictions)
 1313  
          */
 1314  
         public void clearBusinessObjectOfRestrictedValues(MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1315  0
                 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
 1316  
                                 .getMaintainableSections(docTypeName);
 1317  0
                 for (MaintainableSectionDefinition sectionDefinition : sections) {
 1318  0
                         for (MaintainableItemDefinition itemDefinition : sectionDefinition.getMaintainableItems()) {
 1319  0
                                 if (itemDefinition instanceof MaintainableFieldDefinition) {
 1320  0
                                         clearFieldRestrictedValues("", businessObject, (MaintainableFieldDefinition) itemDefinition,
 1321  
                                                         maintenanceDocumentRestrictions);
 1322  
                                 }
 1323  0
                                 else if (itemDefinition instanceof MaintainableCollectionDefinition) {
 1324  0
                                         clearCollectionRestrictedValues("", businessObject,
 1325  
                                                         (MaintainableCollectionDefinition) itemDefinition, maintenanceDocumentRestrictions);
 1326  
                                 }
 1327  
                         }
 1328  
                 }
 1329  0
         }
 1330  
 
 1331  
         protected void clearCollectionRestrictedValues(String fieldNamePrefix, BusinessObject businessObject,
 1332  
                         MaintainableCollectionDefinition collectionDefinition,
 1333  
                         MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1334  0
                 String collectionName = fieldNamePrefix + collectionDefinition.getName();
 1335  0
                 Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(
 1336  
                                 businessObject, collectionDefinition.getName());
 1337  
 
 1338  0
                 if (collection != null) {
 1339  0
                         int i = 0;
 1340  
                         // even though it's technically a Collection, we're going to index
 1341  
                         // it like a list
 1342  0
                         for (BusinessObject collectionItem : collection) {
 1343  0
                                 String collectionItemNamePrefix = collectionName + "[" + i + "].";
 1344  0
                                 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition
 1345  
                                                 .getMaintainableCollections()) {
 1346  0
                                         clearCollectionRestrictedValues(collectionItemNamePrefix, collectionItem, subCollectionDefinition,
 1347  
                                                         maintenanceDocumentRestrictions);
 1348  
                                 }
 1349  0
                                 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
 1350  0
                                         clearFieldRestrictedValues(collectionItemNamePrefix, collectionItem, fieldDefinition,
 1351  
                                                         maintenanceDocumentRestrictions);
 1352  
                                 }
 1353  0
                                 i++;
 1354  0
                         }
 1355  
                 }
 1356  0
         }
 1357  
 
 1358  
         protected void clearFieldRestrictedValues(String fieldNamePrefix, BusinessObject businessObject,
 1359  
                         MaintainableFieldDefinition fieldDefinition, MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
 1360  0
                 String fieldName = fieldNamePrefix + fieldDefinition.getName();
 1361  
 
 1362  0
                 FieldRestriction fieldRestriction = maintenanceDocumentRestrictions.getFieldRestriction(fieldName);
 1363  0
                 if (fieldRestriction.isRestricted()) {
 1364  0
                         String defaultValue = null;
 1365  0
                         if (StringUtils.isNotBlank(fieldDefinition.getDefaultValue())) {
 1366  0
                                 defaultValue = fieldDefinition.getDefaultValue();
 1367  
                         }
 1368  0
                         else if (fieldDefinition.getDefaultValueFinderClass() != null) {
 1369  
                                 try {
 1370  0
                                         defaultValue = ((ValueFinder) fieldDefinition.getDefaultValueFinderClass().newInstance())
 1371  
                                                         .getValue();
 1372  
                                 }
 1373  0
                                 catch (Exception e) {
 1374  0
                                         defaultValue = null;
 1375  0
                                         LOG.error("Error trying to instantiate ValueFinder or to determine ValueFinder for doc type: "
 1376  
                                                         + docTypeName + " field name " + fieldDefinition.getName() + " with field prefix: "
 1377  
                                                         + fieldNamePrefix, e);
 1378  0
                                 }
 1379  
                         }
 1380  
                         try {
 1381  0
                                 ObjectUtils.setObjectProperty(businessObject, fieldDefinition.getName(), defaultValue);
 1382  
                         }
 1383  0
                         catch (Exception e) {
 1384  
                                 // throw an exception, because we don't want users to be able to
 1385  
                                 // see the restricted value
 1386  0
                                 LOG.error("Unable to clear maintenance document values for field name: " + fieldName
 1387  
                                                 + " default value: " + defaultValue, e);
 1388  0
                                 throw new RuntimeException("Unable to clear maintenance document values for field name: " + fieldName,
 1389  
                                                 e);
 1390  0
                         }
 1391  
                 }
 1392  0
         }
 1393  
 
 1394  
         protected void performForceUpperCase(Map fieldValues) {
 1395  0
                 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
 1396  
                                 .getMaintainableSections(docTypeName);
 1397  0
                 for (MaintainableSectionDefinition sectionDefinition : sections) {
 1398  0
                         for (MaintainableItemDefinition itemDefinition : sectionDefinition.getMaintainableItems()) {
 1399  0
                                 if (itemDefinition instanceof MaintainableFieldDefinition) {
 1400  0
                                         performFieldForceUpperCase("", businessObject, (MaintainableFieldDefinition) itemDefinition,
 1401  
                                                         fieldValues);
 1402  
                                 }
 1403  0
                                 else if (itemDefinition instanceof MaintainableCollectionDefinition) {
 1404  0
                                         performCollectionForceUpperCase("", businessObject,
 1405  
                                                         (MaintainableCollectionDefinition) itemDefinition, fieldValues);
 1406  
 
 1407  
                                 }
 1408  
                         }
 1409  
                 }
 1410  0
         }
 1411  
 
 1412  
         protected void performFieldForceUpperCase(String fieldNamePrefix, BusinessObject bo,
 1413  
                         MaintainableFieldDefinition fieldDefinition, Map fieldValues) {
 1414  0
                 MessageMap errorMap = GlobalVariables.getMessageMap();
 1415  0
                 String fieldName = fieldDefinition.getName();
 1416  0
                 String mapKey = fieldNamePrefix + fieldName;
 1417  0
                 if (fieldValues != null && fieldValues.get(mapKey) != null) {
 1418  0
                         if (PropertyUtils.isWriteable(bo, fieldName) && ObjectUtils.getNestedValue(bo, fieldName) != null) {
 1419  
 
 1420  
                                 try {
 1421  0
                                         Class type = ObjectUtils.easyGetPropertyType(bo, fieldName);
 1422  
                                         // convert to upperCase based on data dictionary
 1423  0
                                         Class businessObjectClass = bo.getClass();
 1424  0
                                         boolean upperCase = false;
 1425  
                                         try {
 1426  0
                                                 upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass,
 1427  
                                                                 fieldName);
 1428  
                                         }
 1429  0
                                         catch (UnknownBusinessClassAttributeException t) {
 1430  0
                                                 boolean catchme = true;
 1431  
                                                 // throw t;
 1432  0
                                         }
 1433  
 
 1434  0
                                         Object fieldValue = ObjectUtils.getNestedValue(bo, fieldName);
 1435  
 
 1436  0
                                         if (upperCase && fieldValue instanceof String) {
 1437  0
                                                 fieldValue = ((String) fieldValue).toUpperCase();
 1438  
                                         }
 1439  0
                                         ObjectUtils.setObjectProperty(bo, fieldName, type, fieldValue);
 1440  
                                 }
 1441  0
                                 catch (FormatException e) {
 1442  0
                                         errorMap.putError(fieldName, e.getErrorKey(), e.getErrorArgs());
 1443  
                                 }
 1444  0
                                 catch (IllegalAccessException e) {
 1445  0
                                         LOG.error("unable to populate business object" + e.getMessage());
 1446  0
                                         throw new RuntimeException(e.getMessage(), e);
 1447  
                                 }
 1448  0
                                 catch (InvocationTargetException e) {
 1449  0
                                         LOG.error("unable to populate business object" + e.getMessage());
 1450  0
                                         throw new RuntimeException(e.getMessage(), e);
 1451  
                                 }
 1452  0
                                 catch (NoSuchMethodException e) {
 1453  0
                                         LOG.error("unable to populate business object" + e.getMessage());
 1454  0
                                         throw new RuntimeException(e.getMessage(), e);
 1455  0
                                 }
 1456  
                         }
 1457  
                 }
 1458  0
         }
 1459  
 
 1460  
         protected void performCollectionForceUpperCase(String fieldNamePrefix, BusinessObject bo,
 1461  
                         MaintainableCollectionDefinition collectionDefinition, Map fieldValues) {
 1462  0
                 String collectionName = fieldNamePrefix + collectionDefinition.getName();
 1463  0
                 Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(bo,
 1464  
                                 collectionDefinition.getName());
 1465  0
                 if (collection != null) {
 1466  0
                         int i = 0;
 1467  
                         // even though it's technically a Collection, we're going to index
 1468  
                         // it like a list
 1469  0
                         for (BusinessObject collectionItem : collection) {
 1470  0
                                 String collectionItemNamePrefix = collectionName + "[" + i + "].";
 1471  
                                 // String collectionItemNamePrefix = "";
 1472  0
                                 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
 1473  0
                                         performFieldForceUpperCase(collectionItemNamePrefix, collectionItem, fieldDefinition, fieldValues);
 1474  
                                 }
 1475  0
                                 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition
 1476  
                                                 .getMaintainableCollections()) {
 1477  0
                                         performCollectionForceUpperCase(collectionItemNamePrefix, collectionItem, subCollectionDefinition,
 1478  
                                                         fieldValues);
 1479  
                                 }
 1480  0
                                 i++;
 1481  0
                         }
 1482  
                 }
 1483  0
         }
 1484  
 
 1485  
         protected void performFieldForceUpperCase(BusinessObject bo, Map fieldValues) {
 1486  0
                 MessageMap errorMap = GlobalVariables.getMessageMap();
 1487  
 
 1488  
                 try {
 1489  0
                         for (Iterator iter = fieldValues.keySet().iterator(); iter.hasNext();) {
 1490  0
                                 String propertyName = (String) iter.next();
 1491  
 
 1492  0
                                 if (PropertyUtils.isWriteable(bo, propertyName) && fieldValues.get(propertyName) != null) {
 1493  
                                         // if the field propertyName is a valid property on the bo
 1494  
                                         // class
 1495  0
                                         Class type = ObjectUtils.easyGetPropertyType(bo, propertyName);
 1496  
                                         try {
 1497  
                                                 // Keep the convert to upperCase logic here. It will be
 1498  
                                                 // used in populateNewCollectionLines,
 1499  
                                                 // populateNewSubCollectionLines
 1500  
                                                 // convert to upperCase based on data dictionary
 1501  0
                                                 Class businessObjectClass = bo.getClass();
 1502  0
                                                 boolean upperCase = false;
 1503  
                                                 try {
 1504  0
                                                         upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass,
 1505  
                                                                         propertyName);
 1506  
                                                 }
 1507  0
                                                 catch (UnknownBusinessClassAttributeException t) {
 1508  0
                                                         boolean catchme = true;
 1509  
                                                         // throw t;
 1510  0
                                                 }
 1511  
 
 1512  0
                                                 Object fieldValue = fieldValues.get(propertyName);
 1513  
 
 1514  0
                                                 if (upperCase && fieldValue instanceof String) {
 1515  0
                                                         fieldValue = ((String) fieldValue).toUpperCase();
 1516  
                                                 }
 1517  0
                                                 ObjectUtils.setObjectProperty(bo, propertyName, type, fieldValue);
 1518  
                                         }
 1519  0
                                         catch (FormatException e) {
 1520  0
                                                 errorMap.putError(propertyName, e.getErrorKey(), e.getErrorArgs());
 1521  0
                                         }
 1522  
                                 }
 1523  0
                         }
 1524  
                 }
 1525  0
                 catch (IllegalAccessException e) {
 1526  0
                         LOG.error("unable to populate business object" + e.getMessage());
 1527  0
                         throw new RuntimeException(e.getMessage(), e);
 1528  
                 }
 1529  0
                 catch (InvocationTargetException e) {
 1530  0
                         LOG.error("unable to populate business object" + e.getMessage());
 1531  0
                         throw new RuntimeException(e.getMessage(), e);
 1532  
                 }
 1533  0
                 catch (NoSuchMethodException e) {
 1534  0
                         LOG.error("unable to populate business object" + e.getMessage());
 1535  0
                         throw new RuntimeException(e.getMessage(), e);
 1536  0
                 }
 1537  
 
 1538  0
         }
 1539  
 
 1540  
         /**
 1541  
          * By default a maintainable is not external
 1542  
          * 
 1543  
          * @see org.kuali.rice.krad.maintenance.Maintainable#isExternalBusinessObject()
 1544  
          */
 1545  
         public boolean isExternalBusinessObject() {
 1546  0
                 return false;
 1547  
         }
 1548  
 
 1549  
         /**
 1550  
          * @see org.kuali.rice.krad.maintenance.Maintainable#getExternalBusinessObject()
 1551  
          */
 1552  
         public void prepareBusinessObject(BusinessObject businessObject) {
 1553  
                 // Do nothing by default
 1554  0
         }
 1555  
 
 1556  
         /**
 1557  
          * @see org.kuali.rice.krad.maintenance.Maintainable#getLockingDocumentId()
 1558  
          */
 1559  
         public String getLockingDocumentId() {
 1560  0
                 return getMaintenanceDocumentService().getLockingDocumentId(this, documentNumber);
 1561  
         }
 1562  
 
 1563  
         /**
 1564  
          * This default implementation simply returns false to indicate that custom
 1565  
          * lock descriptors are not supported by KualiMaintainableImpl. If custom
 1566  
          * lock descriptors are needed, the appropriate subclasses should override
 1567  
          * this method.
 1568  
          * 
 1569  
          * @see org.kuali.rice.krad.maintenance.Maintainable#useCustomLockDescriptors()
 1570  
          */
 1571  
         public boolean useCustomLockDescriptors() {
 1572  0
                 return false;
 1573  
         }
 1574  
 
 1575  
         /**
 1576  
          * This default implementation just throws a PessimisticLockingException.
 1577  
          * Subclasses of KualiMaintainableImpl that need support for custom lock
 1578  
          * descriptors should override this method.
 1579  
          * 
 1580  
          * @see org.kuali.rice.krad.maintenance.Maintainable#getCustomLockDescriptor(org.kuali.rice.kim.bo.Person)
 1581  
          */
 1582  
         public String getCustomLockDescriptor(Person user) {
 1583  0
                 throw new PessimisticLockingException(
 1584  
                                 "The Maintainable for document "
 1585  
                                                 + documentNumber
 1586  
                                                 + " is using pessimistic locking with custom lock descriptors, but the Maintainable has not overriden the getCustomLockDescriptor method");
 1587  
         }
 1588  
 
 1589  
         // 3070
 1590  
         public void deleteBusinessObject() {
 1591  0
                 if (businessObject == null)
 1592  0
                         return;
 1593  
 
 1594  0
                 KRADServiceLocator.getBusinessObjectService().delete(businessObject);
 1595  0
                 businessObject = null;
 1596  0
         }
 1597  
 
 1598  
         public boolean isOldBusinessObjectInDocument() {
 1599  0
                 boolean isOldBusinessObjectInExistence = false;
 1600  0
                 if (getBusinessObject() == null) {
 1601  0
                         isOldBusinessObjectInExistence = false;
 1602  
                 }
 1603  
                 else {
 1604  0
                         if (KRADServiceLocator.getPersistenceStructureService().isPersistable(getBusinessObject().getClass())) {
 1605  0
                                 isOldBusinessObjectInExistence = KRADServiceLocator.getPersistenceStructureService()
 1606  
                                                 .hasPrimaryKeyFieldValues(getBusinessObject());
 1607  
                         }
 1608  
                 }
 1609  0
                 return isOldBusinessObjectInExistence;
 1610  
 
 1611  
         }
 1612  
 
 1613  
         /**
 1614  
          * @see org.kuali.rice.krad.maintenance.Maintainable#setupMaintenanceObject(org.kuali.rice.krad.document.MaintenanceDocument,
 1615  
          *      java.lang.String, java.util.Map)
 1616  
          */
 1617  
         public void setupMaintenanceObject(MaintenanceDocument document, String maintenanceAction,
 1618  
                         Map<String, String[]> requestParameters) {
 1619  0
                 setMaintenanceAction(maintenanceAction);
 1620  0
                 document.getOldMaintainableObject().setMaintenanceAction(maintenanceAction);
 1621  
 
 1622  
                 // if action is edit or copy first need to retrieve the old record
 1623  0
                 if (!KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)
 1624  
                                 && !KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) {
 1625  0
                         Object oldBusinessObject = retrieveObjectForMaintenance(document, requestParameters);
 1626  
 
 1627  
                         // TODO should we be using ObjectUtils? also, this needs dictionary
 1628  
                         // enhancement to indicate fields to/not to copy
 1629  0
                         Object newBusinessObject = ObjectUtils.deepCopy((Serializable) oldBusinessObject);
 1630  
 
 1631  
                         // process further object preparations for copy action
 1632  0
                         if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) {
 1633  0
                                 processMaintenanceObjectForCopy(document, newBusinessObject, requestParameters);
 1634  
                         }
 1635  
                         else {
 1636  0
                                 checkMaintenanceActionAuthorization(document, oldBusinessObject, requestParameters);
 1637  
                         }
 1638  
 
 1639  
                         // set object instance for editing
 1640  0
                         document.getOldMaintainableObject().setDataObject(oldBusinessObject);
 1641  0
                         document.getNewMaintainableObject().setDataObject(newBusinessObject);
 1642  
                 }
 1643  
 
 1644  
                 // if new with existing we need to populate with passed in parameters
 1645  0
                 if (KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) {
 1646  0
                         Object newBO = document.getNewMaintainableObject().getDataObject();
 1647  0
                         Map<String, String> parameters = buildKeyMapFromRequest(requestParameters);
 1648  0
                         ObjectPropertyUtils.copyPropertiesToObject(parameters, newBO);
 1649  0
                         if(newBO instanceof PersistableBusinessObject) {
 1650  0
                             ((PersistableBusinessObject)newBO).refresh();
 1651  
                         }
 1652  
 
 1653  0
                         setupNewFromExisting(document, requestParameters);
 1654  0
                 }
 1655  0
                 else if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)) {
 1656  0
                         processAfterNew(document, requestParameters);
 1657  
                 }
 1658  0
         }
 1659  
 
 1660  
         /**
 1661  
          * For the edit and delete maintenance actions checks with the
 1662  
          * <code>BusinessObjectAuthorizationService</code> to check whether the
 1663  
          * action is allowed for the record data. In action is allowed invokes the
 1664  
          * custom processing hook on the <code>Maintainble</code>.
 1665  
          * 
 1666  
          * @param document
 1667  
          *            - document instance for the maintenance object
 1668  
          * @param oldBusinessObject
 1669  
          *            - the old maintenance record
 1670  
          * @param requestParameters
 1671  
          *            - map of parameters from the request
 1672  
          */
 1673  
         protected void checkMaintenanceActionAuthorization(MaintenanceDocument document, Object oldBusinessObject,
 1674  
                         Map<String, String[]> requestParameters) {
 1675  0
                 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction)) {
 1676  0
                         boolean allowsEdit = getBusinessObjectAuthorizationService().canMaintain(
 1677  
                                         oldBusinessObject, GlobalVariables.getUserSession().getPerson(),
 1678  
                                         document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
 1679  0
                         if (!allowsEdit) {
 1680  0
                                 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()
 1681  
                                                 + " does not allow edit actions.");
 1682  0
                                 throw new DocumentTypeAuthorizationException(GlobalVariables.getUserSession().getPerson()
 1683  
                                                 .getPrincipalId(), "edit", document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
 1684  
                         }
 1685  
 
 1686  
                         // invoke custom processing method
 1687  0
                         processAfterEdit(document, requestParameters);
 1688  0
                 }
 1689  
                 // 3070
 1690  0
                 else if (KRADConstants.MAINTENANCE_DELETE_ACTION.equals(maintenanceAction)) {
 1691  0
                         boolean allowsDelete = getBusinessObjectAuthorizationService().canMaintain(
 1692  
                                         (BusinessObject) oldBusinessObject, GlobalVariables.getUserSession().getPerson(),
 1693  
                                         document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
 1694  0
                         if (!allowsDelete) {
 1695  0
                                 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()
 1696  
                                                 + " does not allow delete actions.");
 1697  0
                                 throw new DocumentTypeAuthorizationException(GlobalVariables.getUserSession().getPerson()
 1698  
                                                 .getPrincipalId(), "delete", document.getDocumentHeader().getWorkflowDocument()
 1699  
                                                 .getDocumentTypeName());
 1700  
                         }
 1701  
                 }
 1702  0
         }
 1703  
 
 1704  
         /**
 1705  
          * For the edit or copy actions retrieves the record that is to be
 1706  
          * maintained
 1707  
          * 
 1708  
          * <p>
 1709  
          * Based on the persistence metadata for the maintenance object class
 1710  
          * retrieves the primary key values from the given request parameters map
 1711  
          * (if the class is persistable). With those key values attempts to find the
 1712  
          * record using the <code>LookupService</code>.
 1713  
          * </p>
 1714  
          * 
 1715  
          * @param document
 1716  
          *            - document instance for the maintenance object
 1717  
          * @param requestParameters
 1718  
          *            - Map of parameters from the request
 1719  
          * @return Object the retrieved old object
 1720  
          */
 1721  
         protected Object retrieveObjectForMaintenance(MaintenanceDocument document, Map<String, String[]> requestParameters) {
 1722  
             // TODO the logic in this method is very odd, but I don't know how clients
 1723  
             // are extending this impl.  It seems like clients made non persistent objects
 1724  
             // extend PBO in order to not break the framework which requires PBO everywhere,
 1725  
             // KRAD is fixing that.
 1726  
             //
 1727  
             // Would like to see this method get passed keys already parsed from request,
 1728  
             // it seems odd to have entire http request map passed this deep
 1729  
 
 1730  0
                 Map<String, String> keyMap = buildKeyMapFromRequest(requestParameters);
 1731  
                 
 1732  0
                 Object oldBusinessObject = retrieveObjectForEditOrCopy(document, keyMap);
 1733  
                 
 1734  0
                 if (oldBusinessObject == null && !document.getOldMaintainableObject().isExternalBusinessObject()) {
 1735  0
                         throw new RuntimeException(
 1736  
                                         "Cannot retrieve old record for maintenance document, incorrect parameters passed on maint url: "
 1737  
                                                         + requestParameters);
 1738  
                 }
 1739  
 
 1740  0
                 if (document.getOldMaintainableObject().isExternalBusinessObject()) {
 1741  0
                         if (oldBusinessObject == null) {
 1742  
                                 try {
 1743  0
                                         oldBusinessObject = document.getOldMaintainableObject().getBoClass()
 1744  
                                                         .newInstance();
 1745  
                                 }
 1746  0
                                 catch (Exception ex) {
 1747  0
                                         throw new RuntimeException(
 1748  
                                                         "External BO maintainable was null and unable to instantiate for old maintainable object.",
 1749  
                                                         ex);
 1750  0
                                 }
 1751  
                         }
 1752  
 
 1753  0
                         populateMaintenanceObjectWithCopyKeyValues(WebUtils.translateRequestParameterMap(requestParameters),
 1754  
                                         oldBusinessObject, document.getOldMaintainableObject());
 1755  0
                         document.getOldMaintainableObject().prepareBusinessObject((PersistableBusinessObject)oldBusinessObject);
 1756  0
                         oldBusinessObject = document.getOldMaintainableObject().getDataObject();
 1757  
                 }
 1758  
 
 1759  0
                 return oldBusinessObject;
 1760  
         }
 1761  
         
 1762  
 
 1763  
         /**
 1764  
          * @see org.kuali.rice.krad.maintenance.Maintainable#retrieveObjectForEditOrCopy(java.util.Map)
 1765  
          */
 1766  
         @Override
 1767  
     public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
 1768  0
             Object dataObject = null;
 1769  
             
 1770  
             try {
 1771  0
             dataObject = getLookupService().findObjectBySearch(getBoClass(), dataObjectKeys);
 1772  
         }
 1773  0
         catch (ClassNotPersistenceCapableException ex) {
 1774  0
             if (!document.getOldMaintainableObject().isExternalBusinessObject()) {
 1775  0
                 throw new RuntimeException("BO Class: " + getBoClass()
 1776  
                         + " is not persistable and is not externalizable - configuration error");
 1777  
             }
 1778  
             // otherwise, let fall through
 1779  0
         }
 1780  
         
 1781  0
         return dataObject;
 1782  
     }
 1783  
 
 1784  
     /**
 1785  
          * For the copy action clears out primary key values for the old record and
 1786  
          * does authorization checks on the remaining fields. Also invokes the
 1787  
          * custom processing method on the <code>Maintainble</code>
 1788  
          * 
 1789  
          * @param document
 1790  
          *            - document instance for the maintenance object
 1791  
          * @param maintenanceObject
 1792  
          *            - the object instance being maintained
 1793  
          * @param requestParameters
 1794  
          *            - map of parameters from the request
 1795  
          */
 1796  
         protected void processMaintenanceObjectForCopy(MaintenanceDocument document, Object maintenanceObject,
 1797  
                         Map<String, String[]> requestParameters) {
 1798  0
                 if (!document.isFieldsClearedOnCopy()) {
 1799  0
                         if (!maintenanceDocumentDictionaryService.getPreserveLockingKeysOnCopy(getBoClass())) {
 1800  0
                                 clearPrimaryKeyFields(maintenanceObject);
 1801  
                         }
 1802  
 
 1803  0
                         clearUnauthorizedNewFields(document);
 1804  
 
 1805  0
                         Maintainable maintainable = document.getNewMaintainableObject();
 1806  0
                         maintainable.processAfterCopy(document, requestParameters);
 1807  
 
 1808  
                         // mark so that this clearing does not happen again
 1809  0
                         document.setFieldsClearedOnCopy(true);
 1810  
                 }
 1811  0
         }
 1812  
 
 1813  
         /**
 1814  
          * Clears the value of the primary key fields on the maintenance object
 1815  
          * 
 1816  
          * @param document
 1817  
          *            - document to clear the pk fields on
 1818  
          */
 1819  
         protected void clearPrimaryKeyFields(Object maintenanceObject) {
 1820  0
                 List<String> keyFieldNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBoClass());
 1821  0
                 for (String keyFieldName : keyFieldNames) {
 1822  0
                         ObjectPropertyUtils.setPropertyValue(maintenanceObject, keyFieldName, null);
 1823  
                 }
 1824  0
         }
 1825  
 
 1826  
         /**
 1827  
          * Used as part of the Copy functionality, to clear any field values that
 1828  
          * the user making the copy does not have permissions to modify. This will
 1829  
          * prevent authorization errors on a copy.
 1830  
          * 
 1831  
          * @param document
 1832  
          *            - document to be adjusted
 1833  
          */
 1834  
         protected void clearUnauthorizedNewFields(MaintenanceDocument document) {
 1835  
                 // get a reference to the current user
 1836  0
                 Person user = GlobalVariables.getUserSession().getPerson();
 1837  
 
 1838  
                 // get a new instance of MaintenanceDocumentAuthorizations for context
 1839  0
                 MaintenanceDocumentRestrictions maintenanceDocumentRestrictions = getBusinessObjectAuthorizationService()
 1840  
                                 .getMaintenanceDocumentRestrictions(document, user);
 1841  
 
 1842  0
                 clearBusinessObjectOfRestrictedValues(maintenanceDocumentRestrictions);
 1843  0
         }
 1844  
 
 1845  
         /**
 1846  
          * Based on the maintenance object class retrieves the key field names from
 1847  
          * the <code>BusinessObjectMetaDataService</code> (or alternatively from the
 1848  
          * request parameters), then retrieves any matching key value pairs from the
 1849  
          * request parameters
 1850  
          * 
 1851  
          * @param requestParameters
 1852  
          *            - map of parameters from the request
 1853  
          * @return Map<String, String> key value pairs
 1854  
          */
 1855  
         protected Map<String, String> buildKeyMapFromRequest(Map<String, String[]> requestParameters) {
 1856  0
                 List<String> keyFieldNames = null;
 1857  
 
 1858  
                 // translate request parameters
 1859  0
                 Map<String, String> parameters = WebUtils.translateRequestParameterMap(requestParameters);
 1860  
 
 1861  
                 // are override keys listed in the request? If so, then those need to be
 1862  
                 // our keys, not the primary key fields for the BO
 1863  0
                 if (!StringUtils.isBlank(parameters.get(KRADConstants.OVERRIDE_KEYS))) {
 1864  0
                         String[] overrideKeys = parameters.get(KRADConstants.OVERRIDE_KEYS).split(
 1865  
                                         KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 1866  0
                         keyFieldNames = Arrays.asList(overrideKeys);
 1867  0
                 }
 1868  
                 else {
 1869  0
                         keyFieldNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBoClass());
 1870  
                 }
 1871  
 
 1872  0
                 return WebUtils.getParametersFromRequest(keyFieldNames, getBoClass(), parameters);
 1873  
         }
 1874  
 
 1875  
         /**
 1876  
          * Looks for a special request parameters giving the names of the keys that
 1877  
          * should be retrieved from the request parameters and copied to the
 1878  
          * maintenance object
 1879  
          * 
 1880  
          * @param parameters
 1881  
          *            - map of parameters from the request
 1882  
          * @param oldBusinessObject
 1883  
          *            - the old maintenance object
 1884  
          * @param oldMaintainableObject
 1885  
          *            - the old maintainble object (used to get object class for
 1886  
          *            security checks)
 1887  
          */
 1888  
         protected void populateMaintenanceObjectWithCopyKeyValues(Map<String, String> parameters, Object oldBusinessObject,
 1889  
                         Maintainable oldMaintainableObject) {
 1890  0
                 List<String> keyFieldNamesToCopy = null;
 1891  0
                 Map<String, String> parametersToCopy = null;
 1892  
 
 1893  0
                 if (!StringUtils.isBlank(parameters.get(KRADConstants.COPY_KEYS))) {
 1894  0
                         String[] copyKeys = parameters.get(KRADConstants.COPY_KEYS).split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 1895  0
                         keyFieldNamesToCopy = Arrays.asList(copyKeys);
 1896  0
                         parametersToCopy = WebUtils.getParametersFromRequest(keyFieldNamesToCopy,
 1897  
                                         oldMaintainableObject.getBoClass(), parameters);
 1898  
                 }
 1899  
 
 1900  0
                 if (parametersToCopy != null) {
 1901  
                         // TODO: make sure we are doing formatting here eventually
 1902  0
                         ObjectPropertyUtils.copyPropertiesToObject(parametersToCopy, oldBusinessObject);
 1903  
                 }
 1904  0
         }
 1905  
 
 1906  
         /**
 1907  
          * In the case of edit maintenance adds a new blank line to the old side
 1908  
          * 
 1909  
          * TODO: should this write some sort of missing message on the old side
 1910  
          * instead?
 1911  
          * 
 1912  
          * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#processAfterAddLine(org.kuali.rice.krad.uif.container.View,
 1913  
          *      org.kuali.rice.krad.uif.container.CollectionGroup, java.lang.Object,
 1914  
          *      java.lang.Object)
 1915  
          */
 1916  
         @Override
 1917  
         protected void processAfterAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
 1918  0
                 super.processAfterAddLine(view, collectionGroup, model, addLine);
 1919  
 
 1920  0
                 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction)) {
 1921  0
                         MaintenanceForm maintenanceForm = (MaintenanceForm) model;
 1922  0
                         MaintenanceDocument document = maintenanceForm.getDocument();
 1923  
 
 1924  
                         // get the old object's collection
 1925  0
                         Collection<Object> oldCollection = ObjectPropertyUtils.getPropertyValue(document.getOldMaintainableObject()
 1926  
                                         .getBusinessObject(), collectionGroup.getPropertyName());
 1927  
                         try {
 1928  0
                                 Object blankLine = getBoClass().newInstance();
 1929  0
                                 oldCollection.add(blankLine);
 1930  
                         }
 1931  0
                         catch (Exception e) {
 1932  0
                                 throw new RuntimeException("Unable to create new line instance for old maintenance object", e);
 1933  0
                         }
 1934  
                 }
 1935  0
         }
 1936  
 
 1937  
         protected PersistenceStructureService getPersistenceStructureService() {
 1938  0
                 if (persistenceStructureService == null) {
 1939  0
                         persistenceStructureService = KRADServiceLocator.getPersistenceStructureService();
 1940  
                 }
 1941  0
                 return persistenceStructureService;
 1942  
         }
 1943  
 
 1944  
         protected MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
 1945  0
                 if (maintenanceDocumentDictionaryService == null) {
 1946  0
                         maintenanceDocumentDictionaryService = KRADServiceLocatorWeb.getMaintenanceDocumentDictionaryService();
 1947  
                 }
 1948  0
                 return maintenanceDocumentDictionaryService;
 1949  
         }
 1950  
 
 1951  
         protected BusinessObjectService getBusinessObjectService() {
 1952  0
                 if (businessObjectService == null) {
 1953  0
                         businessObjectService = KRADServiceLocator.getBusinessObjectService();
 1954  
                 }
 1955  0
                 return businessObjectService;
 1956  
         }
 1957  
 
 1958  
         protected BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
 1959  0
                 if (businessObjectDictionaryService == null) {
 1960  0
                         businessObjectDictionaryService = KRADServiceLocatorWeb.getBusinessObjectDictionaryService();
 1961  
                 }
 1962  0
                 return businessObjectDictionaryService;
 1963  
         }
 1964  
 
 1965  
         protected EncryptionService getEncryptionService() {
 1966  0
                 if (encryptionService == null) {
 1967  0
                         encryptionService = CoreApiServiceLocator.getEncryptionService();
 1968  
                 }
 1969  0
                 return encryptionService;
 1970  
         }
 1971  
 
 1972  
         protected org.kuali.rice.kim.service.PersonService getPersonService() {
 1973  0
                 if (personService == null) {
 1974  0
                         personService = KimApiServiceLocator.getPersonService();
 1975  
                 }
 1976  0
                 return personService;
 1977  
         }
 1978  
 
 1979  
         protected BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
 1980  0
                 if (businessObjectMetaDataService == null) {
 1981  0
                         businessObjectMetaDataService = KRADServiceLocatorWeb.getBusinessObjectMetaDataService();
 1982  
                 }
 1983  0
                 return businessObjectMetaDataService;
 1984  
         }
 1985  
 
 1986  
         protected BusinessObjectAuthorizationService getBusinessObjectAuthorizationService() {
 1987  0
                 if (businessObjectAuthorizationService == null) {
 1988  0
                         businessObjectAuthorizationService = KRADServiceLocatorWeb.getBusinessObjectAuthorizationService();
 1989  
                 }
 1990  0
                 return businessObjectAuthorizationService;
 1991  
         }
 1992  
 
 1993  
         protected MaintenanceDocumentService getMaintenanceDocumentService() {
 1994  0
                 if (maintenanceDocumentService == null) {
 1995  0
                         maintenanceDocumentService = KRADServiceLocatorWeb.getMaintenanceDocumentService();
 1996  
                 }
 1997  0
                 return maintenanceDocumentService;
 1998  
         }
 1999  
 
 2000  
         protected DocumentHelperService getDocumentHelperService() {
 2001  0
                 if (documentHelperService == null) {
 2002  0
                         documentHelperService = KRADServiceLocatorWeb.getDocumentHelperService();
 2003  
                 }
 2004  0
                 return documentHelperService;
 2005  
         }
 2006  
 
 2007  
         public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
 2008  0
                 this.persistenceStructureService = persistenceStructureService;
 2009  0
         }
 2010  
 
 2011  
         public void setMaintenanceDocumentDictionaryService(
 2012  
                         MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
 2013  0
                 this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
 2014  0
         }
 2015  
 
 2016  
         public void setBusinessObjectService(BusinessObjectService businessObjectService) {
 2017  0
                 this.businessObjectService = businessObjectService;
 2018  0
         }
 2019  
 
 2020  
         public void setBusinessObjectDictionaryService(BusinessObjectDictionaryService businessObjectDictionaryService) {
 2021  0
                 this.businessObjectDictionaryService = businessObjectDictionaryService;
 2022  0
         }
 2023  
 
 2024  
         public void setEncryptionService(EncryptionService encryptionService) {
 2025  0
                 this.encryptionService = encryptionService;
 2026  0
         }
 2027  
 
 2028  
         public void setPersonService(org.kuali.rice.kim.service.PersonService personService) {
 2029  0
                 this.personService = personService;
 2030  0
         }
 2031  
 
 2032  
         public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService businessObjectMetaDataService) {
 2033  0
                 this.businessObjectMetaDataService = businessObjectMetaDataService;
 2034  0
         }
 2035  
 
 2036  
         public void setBusinessObjectAuthorizationService(
 2037  
                         BusinessObjectAuthorizationService businessObjectAuthorizationService) {
 2038  0
                 this.businessObjectAuthorizationService = businessObjectAuthorizationService;
 2039  0
         }
 2040  
 
 2041  
         public void setMaintenanceDocumentService(MaintenanceDocumentService maintenanceDocumentService) {
 2042  0
                 this.maintenanceDocumentService = maintenanceDocumentService;
 2043  0
         }
 2044  
 
 2045  
         public void setDocumentHelperService(DocumentHelperService documentHelperService) {
 2046  0
                 this.documentHelperService = documentHelperService;
 2047  0
         }
 2048  
 
 2049  
         protected LookupService getLookupService() {
 2050  0
                 if (lookupService == null) {
 2051  0
                         lookupService = KRADServiceLocatorWeb.getLookupService();
 2052  
                 }
 2053  0
                 return this.lookupService;
 2054  
         }
 2055  
 
 2056  
         public void setLookupService(LookupService lookupService) {
 2057  0
                 this.lookupService = lookupService;
 2058  0
         }
 2059  
 
 2060  
 }