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