001 /** 002 * Copyright 2005-2014 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.web.struts.action; 017 018 import org.apache.commons.beanutils.PropertyUtils; 019 import org.apache.commons.collections.CollectionUtils; 020 import org.apache.commons.lang.StringUtils; 021 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; 022 import org.apache.struts.action.ActionForm; 023 import org.apache.struts.action.ActionForward; 024 import org.apache.struts.action.ActionMapping; 025 import org.apache.struts.upload.FormFile; 026 import org.kuali.rice.core.api.CoreApiServiceLocator; 027 import org.kuali.rice.core.api.encryption.EncryptionService; 028 import org.kuali.rice.core.api.util.ClassLoaderUtils; 029 import org.kuali.rice.core.api.util.RiceConstants; 030 import org.kuali.rice.core.api.util.RiceKeyConstants; 031 import org.kuali.rice.core.web.format.Formatter; 032 import org.kuali.rice.kew.api.KewApiConstants; 033 import org.kuali.rice.kim.api.identity.Person; 034 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition; 035 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry; 036 import org.kuali.rice.kns.document.MaintenanceDocument; 037 import org.kuali.rice.kns.document.MaintenanceDocumentBase; 038 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentAuthorizer; 039 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions; 040 import org.kuali.rice.kns.lookup.LookupResultsService; 041 import org.kuali.rice.kns.maintenance.Maintainable; 042 import org.kuali.rice.kns.rule.event.KualiAddLineEvent; 043 import org.kuali.rice.kns.service.KNSServiceLocator; 044 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 045 import org.kuali.rice.kns.util.KNSGlobalVariables; 046 import org.kuali.rice.kns.util.MaintenanceUtils; 047 import org.kuali.rice.kns.util.WebUtils; 048 import org.kuali.rice.kns.web.struts.form.InquiryForm; 049 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 050 import org.kuali.rice.kns.web.struts.form.KualiForm; 051 import org.kuali.rice.kns.web.struts.form.KualiMaintenanceForm; 052 import org.kuali.rice.kns.web.ui.Field; 053 import org.kuali.rice.kns.web.ui.Row; 054 import org.kuali.rice.kns.web.ui.Section; 055 import org.kuali.rice.krad.bo.DocumentAttachment; 056 import org.kuali.rice.krad.bo.MultiDocumentAttachment; 057 import org.kuali.rice.krad.bo.PersistableAttachment; 058 import org.kuali.rice.krad.bo.PersistableAttachmentList; 059 import org.kuali.rice.krad.bo.PersistableBusinessObject; 060 import org.kuali.rice.krad.exception.DocumentTypeAuthorizationException; 061 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 062 import org.kuali.rice.krad.service.LookupService; 063 import org.kuali.rice.krad.util.GlobalVariables; 064 import org.kuali.rice.krad.util.KRADConstants; 065 import org.kuali.rice.krad.util.KRADPropertyConstants; 066 import org.kuali.rice.krad.util.ObjectUtils; 067 068 import javax.servlet.http.HttpServletRequest; 069 import javax.servlet.http.HttpServletResponse; 070 import java.lang.reflect.InvocationTargetException; 071 import java.lang.reflect.Method; 072 import java.security.GeneralSecurityException; 073 import java.util.ArrayList; 074 import java.util.Collection; 075 import java.util.Enumeration; 076 import java.util.HashMap; 077 import java.util.Iterator; 078 import java.util.List; 079 import java.util.Map; 080 081 /** 082 * This class handles actions for maintenance documents. These include creating new edit, and copying of maintenance records. 083 */ 084 public class KualiMaintenanceDocumentAction extends KualiDocumentActionBase { 085 protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMaintenanceDocumentAction.class); 086 087 protected MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService = null; 088 protected EncryptionService encryptionService; 089 protected LookupService lookupService; 090 protected LookupResultsService lookupResultsService; 091 092 public KualiMaintenanceDocumentAction() { 093 super(); 094 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService(); 095 encryptionService = CoreApiServiceLocator.getEncryptionService(); 096 } 097 098 @Override 099 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 100 request.setAttribute(KRADConstants.PARAM_MAINTENANCE_VIEW_MODE, KRADConstants.PARAM_MAINTENANCE_VIEW_MODE_MAINTENANCE); 101 return super.execute(mapping, form, request, response); 102 } 103 104 /** 105 * Calls setup Maintenance for new action. 106 */ 107 public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 108 request.setAttribute(KRADConstants.MAINTENANCE_ACTN, KRADConstants.MAINTENANCE_NEW_ACTION); 109 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_NEW_ACTION); 110 } 111 112 /** 113 * Calls setupMaintenance for copy action. 114 */ 115 public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 116 // check for copy document number 117 if (request.getParameter("document." + KRADPropertyConstants.DOCUMENT_NUMBER) == null) { // object copy 118 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_COPY_ACTION); 119 } 120 else { // document copy 121 throw new UnsupportedOperationException("System does not support copying of maintenance documents."); 122 } 123 } 124 125 /** 126 * Calls setupMaintenance for edit action. 127 */ 128 public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 129 130 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_EDIT_ACTION); 131 } 132 133 /** 134 * KUALRice 3070 Calls setupMaintenance for delete action. 135 */ 136 public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 137 if (isFormRepresentingLockObject((KualiDocumentFormBase)form)) { 138 return super.delete(mapping, form, request, response); 139 } 140 KNSGlobalVariables.getMessageList().add(RiceKeyConstants.MESSAGE_DELETE); 141 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_DELETE_ACTION); 142 } 143 144 /** 145 * Calls setupMaintenance for new object that have existing objects attributes. 146 */ 147 public ActionForward newWithExisting(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 148 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION); 149 } 150 151 /** 152 * Gets a new document for a maintenance record. The maintainable is specified with the documentTypeName or business object 153 * class request parameter and request parameters are parsed for key values for retrieving the business object. Forward to the 154 * maintenance jsp which renders the page based on the maintainable's field specifications. Retrieves an existing business 155 * object for edit and copy. Checks locking on edit. 156 */ 157 protected ActionForward setupMaintenance(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String maintenanceAction) throws Exception { 158 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) form; 159 MaintenanceDocument document = null; 160 161 // create a new document object, if required (on NEW object, or other reasons) 162 if (maintenanceForm.getDocument() == null) { 163 if (StringUtils.isEmpty(maintenanceForm.getBusinessObjectClassName()) && StringUtils.isEmpty(maintenanceForm.getDocTypeName())) { 164 throw new IllegalArgumentException("Document type name or bo class not given!"); 165 } 166 167 String documentTypeName = maintenanceForm.getDocTypeName(); 168 // get document type if not passed 169 if (StringUtils.isEmpty(documentTypeName)) { 170 documentTypeName = maintenanceDocumentDictionaryService.getDocumentTypeName(Class.forName(maintenanceForm.getBusinessObjectClassName())); 171 maintenanceForm.setDocTypeName(documentTypeName); 172 } 173 174 if (StringUtils.isEmpty(documentTypeName)) { 175 throw new RuntimeException("documentTypeName is empty; does this Business Object have a maintenance document definition? " + maintenanceForm.getBusinessObjectClassName()); 176 } 177 178 // check doc type allows new or copy if that action was requested 179 if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { 180 Class boClass = maintenanceDocumentDictionaryService.getDataObjectClass(documentTypeName); 181 boolean allowsNewOrCopy = getBusinessObjectAuthorizationService().canCreate(boClass, GlobalVariables.getUserSession().getPerson(), documentTypeName); 182 if (!allowsNewOrCopy) { 183 LOG.error("Document type " + documentTypeName + " does not allow new or copy actions."); 184 throw new DocumentTypeAuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalId(), "newOrCopy", documentTypeName); 185 } 186 } 187 188 // get new document from service 189 document = (MaintenanceDocument) getDocumentService().getNewDocument(maintenanceForm.getDocTypeName()); 190 // Check for an auto-incrementing PK and set it if needed 191 // if (document.getNewMaintainableObject().getBoClass().isAnnotationPresent(Sequence.class)) { 192 // Sequence sequence = (Sequence) document.getNewMaintainableObject().getBoClass().getAnnotation(Sequence.class); 193 // Long pk = OrmUtils.getNextAutoIncValue(sequence); 194 // OrmUtils.populateAutoIncValue(document.getOldMaintainableObject().getBusinessObject(), pk); 195 // OrmUtils.populateAutoIncValue(document.getNewMaintainableObject().getBusinessObject(), pk); 196 // document.getOldMaintainableObject().getBusinessObject().setAutoIncrementSet(true); 197 // document.getNewMaintainableObject().getBusinessObject().setAutoIncrementSet(true); 198 // } 199 maintenanceForm.setDocument(document); 200 } 201 else { 202 document = (MaintenanceDocument) maintenanceForm.getDocument(); 203 } 204 205 // retrieve business object from request parameters 206 if (!(KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)) 207 && !(KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction))) { 208 Map requestParameters = buildKeyMapFromRequest(document.getNewMaintainableObject(), request); 209 PersistableBusinessObject oldBusinessObject = null; 210 try { 211 oldBusinessObject = (PersistableBusinessObject) getLookupService().findObjectBySearch(Class.forName(maintenanceForm.getBusinessObjectClassName()), requestParameters); 212 } catch ( ClassNotPersistenceCapableException ex ) { 213 if ( !document.getOldMaintainableObject().isExternalBusinessObject() ) { 214 throw new RuntimeException( "BO Class: " + maintenanceForm.getBusinessObjectClassName() + " is not persistable and is not externalizable - configuration error" ); 215 } 216 // otherwise, let fall through 217 } 218 if (oldBusinessObject == null && !document.getOldMaintainableObject().isExternalBusinessObject()) { 219 throw new RuntimeException("Cannot retrieve old record for maintenance document, incorrect parameters passed on maint url: " + requestParameters ); 220 } 221 222 if(document.getOldMaintainableObject().isExternalBusinessObject()){ 223 if ( oldBusinessObject == null ) { 224 try { 225 oldBusinessObject = (PersistableBusinessObject)document.getOldMaintainableObject().getBoClass().newInstance(); 226 } catch ( Exception ex ) { 227 throw new RuntimeException( "External BO maintainable was null and unable to instantiate for old maintainable object.", ex ); 228 } 229 } 230 populateBOWithCopyKeyValues(request, oldBusinessObject, document.getOldMaintainableObject()); 231 document.getOldMaintainableObject().prepareBusinessObject(oldBusinessObject); 232 oldBusinessObject = document.getOldMaintainableObject().getBusinessObject(); 233 } 234 //KULRICE-6985 Commented out because of StringIndexOutOfBoundsException for some classnames and since we are not using JPA at the moment. 235 // Temp solution for loading extension objects - need to find a better way 236 // final String TMP_NM = oldBusinessObject.getClass().getName(); 237 // final int START_INDEX = TMP_NM.indexOf('.', TMP_NM.indexOf('.') + 1) + 1; 238 // if ( ( OrmUtils.isJpaEnabled() || OrmUtils.isJpaEnabled(TMP_NM.substring(START_INDEX, TMP_NM.indexOf('.', TMP_NM.indexOf('.', START_INDEX) + 1))) ) && 239 // OrmUtils.isJpaAnnotated(oldBusinessObject.getClass()) && oldBusinessObject.getExtension() != null && OrmUtils.isJpaAnnotated(oldBusinessObject.getExtension().getClass())) { 240 // if (oldBusinessObject.getExtension() != null) { 241 // PersistableBusinessObjectExtension boe = oldBusinessObject.getExtension(); 242 // EntityDescriptor entity = MetadataManager.getEntityDescriptor(oldBusinessObject.getExtension().getClass()); 243 // Criteria extensionCriteria = new Criteria(boe.getClass().getName()); 244 // for (FieldDescriptor fieldDescriptor : entity.getPrimaryKeys()) { 245 // try { 246 // Field field = oldBusinessObject.getClass().getDeclaredField(fieldDescriptor.getName()); 247 // field.setAccessible(true); 248 // extensionCriteria.eq(fieldDescriptor.getName(), field.get(oldBusinessObject)); 249 // } catch (Exception e) { 250 // LOG.error(e.getMessage(),e); 251 // } 252 // } 253 // try { 254 // boe = (PersistableBusinessObjectExtension) new QueryByCriteria(getEntityManagerFactory().createEntityManager(), extensionCriteria).toQuery().getSingleResult(); 255 // } catch (PersistenceException e) {} 256 // oldBusinessObject.setExtension(boe); 257 // } 258 // } 259 260 PersistableBusinessObject newBusinessObject = (PersistableBusinessObject) ObjectUtils.deepCopy(oldBusinessObject); 261 262 // set business object instance for editing 263 Class<? extends PersistableBusinessObject> businessObjectClass = ClassLoaderUtils.getClass(maintenanceForm.getBusinessObjectClassName(), PersistableBusinessObject.class); 264 document.getOldMaintainableObject().setBusinessObject(oldBusinessObject); 265 document.getOldMaintainableObject().setBoClass(businessObjectClass); 266 document.getNewMaintainableObject().setBusinessObject(newBusinessObject); 267 document.getNewMaintainableObject().setBoClass(businessObjectClass); 268 269 270 // on a COPY, clear any fields that this user isnt authorized for, and also 271 // clear the primary key fields and the version number and objectId 272 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { 273 if (!document.isFieldsClearedOnCopy()) { 274 //for issue KULRice 3072 275 Class boClass = maintenanceDocumentDictionaryService.getDataObjectClass( 276 maintenanceForm.getDocTypeName()); 277 if (!maintenanceDocumentDictionaryService.getPreserveLockingKeysOnCopy(boClass)) { 278 clearPrimaryKeyFields(document); 279 } 280 281 clearUnauthorizedNewFields(document); 282 283 Maintainable maintainable = document.getNewMaintainableObject(); 284 285 maintainable.processAfterCopy( document, request.getParameterMap() ); 286 287 // mark so that this clearing doesnt happen again 288 document.setFieldsClearedOnCopy(true); 289 290 // mark so that blank required fields will be populated with default values 291 maintainable.setGenerateBlankRequiredValues(maintenanceForm.getDocTypeName()); 292 } 293 } 294 else if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction)) { 295 boolean allowsEdit = getBusinessObjectAuthorizationService().canMaintain(oldBusinessObject, GlobalVariables.getUserSession().getPerson(), document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 296 if (!allowsEdit) { 297 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName() + " does not allow edit actions."); 298 throw new DocumentTypeAuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalId(), "edit", document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 299 } 300 document.getNewMaintainableObject().processAfterEdit( document, request.getParameterMap() ); 301 } 302 //3070 303 else if (KRADConstants.MAINTENANCE_DELETE_ACTION.equals(maintenanceAction)) { 304 boolean allowsDelete = getBusinessObjectAuthorizationService().canMaintain(oldBusinessObject, GlobalVariables.getUserSession().getPerson(), document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 305 if (!allowsDelete) { 306 LOG.error("Document type " + document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName() + " does not allow delete actions."); 307 throw new DocumentTypeAuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalId(), "delete", document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 308 } 309 //document.getNewMaintainableObject().processAfterEdit( document, request.getParameterMap() ); 310 } 311 // Check for an auto-incrementing PK and set it if needed 312 // if (document.getNewMaintainableObject().getBoClass().isAnnotationPresent(Sequence.class)) { 313 // Sequence sequence = (Sequence) document.getNewMaintainableObject().getBoClass().getAnnotation(Sequence.class); 314 // Long pk = OrmUtils.getNextAutoIncValue(sequence); 315 // OrmUtils.populateAutoIncValue(document.getNewMaintainableObject().getBusinessObject(), pk); 316 // document.getNewMaintainableObject().getBusinessObject().setAutoIncrementSet(true); 317 // } 318 } 319 // if new with existing we need to populate we need to populate with passed in parameters 320 if (KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) { 321 // TODO: this code should be abstracted out into a helper 322 // also is it a problem that we're not calling setGenerateDefaultValues? it blanked out the below values when I did 323 // maybe we need a new generateDefaultValues that doesn't overwrite? 324 PersistableBusinessObject newBO = document.getNewMaintainableObject().getBusinessObject(); 325 Map<String, String> parameters = buildKeyMapFromRequest(document.getNewMaintainableObject(), request); 326 copyParametersToBO(parameters, newBO); 327 newBO.refresh(); 328 document.getNewMaintainableObject().setupNewFromExisting( document, request.getParameterMap() ); 329 } 330 331 // for new maintainble need to pick up default values 332 if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)) { 333 document.getNewMaintainableObject().setGenerateDefaultValues(maintenanceForm.getDocTypeName()); 334 document.getNewMaintainableObject().processAfterNew( document, request.getParameterMap() ); 335 336 // If a maintenance lock exists, warn the user. 337 MaintenanceUtils.checkForLockingDocument(document.getNewMaintainableObject(), false); 338 } 339 340 // set maintenance action state 341 document.getNewMaintainableObject().setMaintenanceAction(maintenanceAction); 342 maintenanceForm.setMaintenanceAction(maintenanceAction); 343 344 // attach any extra JS from the data dictionary 345 MaintenanceDocumentEntry entry = maintenanceDocumentDictionaryService.getMaintenanceDocumentEntry(document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 346 if (LOG.isDebugEnabled()) { 347 LOG.debug("maintenanceForm.getAdditionalScriptFiles(): " + maintenanceForm.getAdditionalScriptFiles()); 348 } 349 if (maintenanceForm.getAdditionalScriptFiles().isEmpty()) { 350 maintenanceForm.getAdditionalScriptFiles().addAll(entry.getWebScriptFiles()); 351 } 352 353 // Retrieve notes topic display flag from data dictionary and add to document 354 document.setDisplayTopicFieldInNotes(entry.getDisplayTopicFieldInNotes()); 355 356 return mapping.findForward(RiceConstants.MAPPING_BASIC); 357 } 358 359 protected void populateBOWithCopyKeyValues(HttpServletRequest request, PersistableBusinessObject oldBusinessObject, Maintainable oldMaintainableObject) throws Exception{ 360 List keyFieldNamesToCopy = new ArrayList(); 361 Map<String, String> parametersToCopy; 362 if (!StringUtils.isBlank(request.getParameter(KRADConstants.COPY_KEYS))) { 363 String[] copyKeys = request.getParameter(KRADConstants.COPY_KEYS).split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR); 364 for (String copyKey: copyKeys) { 365 keyFieldNamesToCopy.add(copyKey); 366 } 367 } 368 parametersToCopy = getRequestParameters(keyFieldNamesToCopy, oldMaintainableObject, request); 369 if(parametersToCopy!=null && parametersToCopy.size()>0){ 370 copyParametersToBO(parametersToCopy, oldBusinessObject); 371 } 372 } 373 374 protected void copyParametersToBO(Map<String, String> parameters, PersistableBusinessObject newBO) throws Exception{ 375 for (String parmName : parameters.keySet()) { 376 String propertyValue = parameters.get(parmName); 377 378 if (StringUtils.isNotBlank(propertyValue)) { 379 String propertyName = parmName; 380 // set value of property in bo 381 if (PropertyUtils.isWriteable(newBO, propertyName)) { 382 Class type = ObjectUtils.easyGetPropertyType(newBO, propertyName); 383 if (type != null && Formatter.getFormatter(type) != null) { 384 Formatter formatter = Formatter.getFormatter(type); 385 Object obj = formatter.convertFromPresentationFormat(propertyValue); 386 ObjectUtils.setObjectProperty(newBO, propertyName, obj.getClass(), obj); 387 } 388 else { 389 ObjectUtils.setObjectProperty(newBO, propertyName, String.class, propertyValue); 390 } 391 } 392 } 393 } 394 } 395 396 /** 397 * Downloads the attachment to the user's browser 398 * 399 * @param mapping 400 * @param form 401 * @param request 402 * @param response 403 * @return ActionForward 404 * @throws Exception 405 */ 406 public ActionForward downloadAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 407 KualiDocumentFormBase documentForm = (KualiDocumentFormBase) form; 408 MaintenanceDocumentBase document = (MaintenanceDocumentBase) documentForm.getDocument(); 409 410 int line = getSelectedLine(request); 411 if (line < 0) { 412 DocumentAttachment documentAttachment = document.getAttachment(); 413 if (documentAttachment != null 414 && documentAttachment.getAttachmentContent() != null) { 415 416 streamToResponse(documentAttachment.getAttachmentContent(), documentAttachment.getFileName(), documentAttachment.getContentType(), response); 417 return null; 418 } 419 PersistableAttachment attachment = (PersistableAttachment) document.getNewMaintainableObject().getBusinessObject(); 420 String attachmentPropNm = document.getAttachmentPropertyName(); 421 FormFile attachmentFromBusinessObject = null; 422 byte[] attachmentContent; 423 String fileName = attachment.getFileName(); 424 String contentType = attachment.getContentType(); 425 if (StringUtils.isNotBlank(attachmentPropNm)) { 426 String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 427 attachmentFromBusinessObject = (FormFile)(attachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(attachment)); 428 } 429 if (attachmentFromBusinessObject != null 430 && attachmentFromBusinessObject.getInputStream() != null) { 431 attachmentContent = attachmentFromBusinessObject.getFileData(); 432 fileName = attachmentFromBusinessObject.getFileName(); 433 contentType = attachmentFromBusinessObject.getContentType(); 434 } else { 435 attachmentContent = attachment.getAttachmentContent(); 436 } 437 if (StringUtils.isNotBlank(fileName) 438 && contentType != null 439 && attachmentContent != null) { 440 streamToResponse(attachmentContent, fileName, contentType, response); 441 } 442 } else { 443 444 // attachment is part of a collection 445 PersistableAttachmentList<PersistableAttachment> attachmentsBo = (PersistableAttachmentList<PersistableAttachment>) document.getNewMaintainableObject().getBusinessObject(); 446 if (CollectionUtils.isEmpty(attachmentsBo.getAttachments())) { 447 document.populateAttachmentListForBO(); 448 } 449 450 List<? extends PersistableAttachment> attachments = attachmentsBo.getAttachments(); 451 if (CollectionUtils.isNotEmpty(attachments) 452 && attachments.size() > line) { 453 PersistableAttachment attachment = attachmentsBo.getAttachments().get(line); 454 455 //it is possible that document hasn't been saved (attachment just added) and the attachment content is still in the FormFile 456 //need to grab it if that is the case. 457 byte[] attachmentContent; // = attachment.getAttachmentContent(); 458 String fileName = attachment.getFileName(); 459 String contentType = attachment.getContentType(); 460 String attachmentPropNm = document.getAttachmentListPropertyName(); 461 FormFile attachmentFromBusinessObject = null; 462 if (StringUtils.isNotBlank(attachmentPropNm)) { 463 String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 464 attachmentFromBusinessObject = (FormFile)(attachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(attachment)); 465 } 466 //Use form file data if it exists 467 //if (attachmentContent == null) { 468 469 if (attachmentFromBusinessObject != null 470 && attachmentFromBusinessObject.getInputStream() != null) { 471 attachmentContent = attachmentFromBusinessObject.getFileData(); 472 fileName = attachmentFromBusinessObject.getFileName(); 473 contentType = attachmentFromBusinessObject.getContentType(); 474 } else { 475 attachmentContent = attachment.getAttachmentContent(); 476 } 477 478 if (attachmentContent != null) { 479 streamToResponse(attachmentContent, fileName, contentType, response); 480 } else { 481 // last ditch effort to find the correct attachment 482 //check to see if attachment is populated on document first, so no copying done unless necessary 483 List<MultiDocumentAttachment> multiDocumentAttachs = document.getAttachments(); 484 if (CollectionUtils.isNotEmpty(multiDocumentAttachs)) { 485 for (MultiDocumentAttachment multiAttach : multiDocumentAttachs) { 486 if (multiAttach.getFileName().equals(fileName) 487 && multiAttach.getContentType().equals(contentType)) { 488 streamToResponse(multiAttach.getAttachmentContent(), multiAttach.getFileName(), multiAttach.getContentType(), response); 489 break; 490 } 491 } 492 } 493 } 494 } 495 } 496 return null; 497 } 498 499 500 /** 501 * 502 * This method used to replace the attachment 503 * @param mapping 504 * @param form 505 * @param request 506 * @param response 507 * @return 508 * @throws Exception 509 */ 510 public ActionForward replaceAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, 511 HttpServletResponse response) throws Exception { 512 KualiDocumentFormBase documentForm = (KualiDocumentFormBase) form; 513 MaintenanceDocumentBase document = (MaintenanceDocumentBase) documentForm.getDocument(); 514 515 int lineNum = getSelectedLine(request); 516 517 if (lineNum < 0) { 518 519 document.refreshReferenceObject("attachment"); 520 documentForm.setAttachmentFile(null); 521 document.setFileAttachment(null); 522 getBusinessObjectService().delete(document.getAttachment()); 523 document.setAttachment(null); 524 525 PersistableAttachment attachment = (PersistableAttachment) document.getNewMaintainableObject().getBusinessObject(); 526 527 attachment.setAttachmentContent(null); 528 attachment.setContentType(null); 529 attachment.setFileName(null); 530 //pBo.setAttachmentFile(null); 531 532 String attachmentPropNm = document.getAttachmentPropertyName(); 533 String attachmentPropNmSetter = "set" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 534 Class propNameSetterSig = null; 535 536 try { 537 Method[] methods = attachment.getClass().getMethods(); 538 for (Method method : methods) { 539 if (method.getName().equals(attachmentPropNmSetter)) { 540 propNameSetterSig = method.getParameterTypes()[0]; 541 attachment.getClass().getDeclaredMethod(attachmentPropNmSetter, propNameSetterSig).invoke(attachment, (Object) null); 542 break; 543 } 544 } 545 } catch (Exception e) { 546 LOG.error("Not able to get the attachment " + e.getMessage()); 547 throw new RuntimeException( 548 "Not able to get the attachment " + e.getMessage()); 549 } 550 } else { 551 document.refreshReferenceObject("attachments"); 552 getBusinessObjectService().delete(document.getAttachment()); 553 554 PersistableAttachmentList<PersistableAttachment> attachmentListBo = (PersistableAttachmentList<PersistableAttachment>) document.getNewMaintainableObject().getBusinessObject(); 555 556 PersistableAttachment attachment = (PersistableAttachment)attachmentListBo.getAttachments().get(lineNum); 557 attachment.setAttachmentContent(null); 558 attachment.setContentType(null); 559 attachment.setFileName(null); 560 561 String attachmentPropNm = document.getAttachmentListPropertyName(); 562 String attachmentPropNmSetter = "set" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 563 Class propNameSetterSig = null; 564 565 try { 566 Method[] methods = attachment.getClass().getMethods(); 567 for (Method method : methods) { 568 if (method.getName().equals(attachmentPropNmSetter)) { 569 propNameSetterSig = method.getParameterTypes()[0]; 570 attachment.getClass().getDeclaredMethod(attachmentPropNmSetter, propNameSetterSig).invoke(attachment, (Object) null); 571 break; 572 } 573 } 574 } catch (Exception e) { 575 LOG.error("Not able to get the attachment " + e.getMessage()); 576 throw new RuntimeException( 577 "Not able to get the attachment " + e.getMessage()); 578 } 579 } 580 581 return mapping.findForward(RiceConstants.MAPPING_BASIC); 582 } 583 584 /** 585 * route the document using the document service 586 * 587 * @param mapping 588 * @param form 589 * @param request 590 * @param response 591 * @return ActionForward 592 * @throws Exception 593 */ 594 @Override 595 public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 596 KualiDocumentFormBase documentForm = (KualiDocumentFormBase) form; 597 MaintenanceDocumentBase document = (MaintenanceDocumentBase) documentForm.getDocument(); 598 599 ActionForward forward = super.route(mapping, form, request, response); 600 PersistableBusinessObject businessObject = document.getNewMaintainableObject().getBusinessObject(); 601 if(businessObject instanceof PersistableAttachment) { 602 document.populateAttachmentForBO(); 603 String fileName = ((PersistableAttachment) businessObject).getFileName(); 604 if(StringUtils.isEmpty(fileName)) { 605 PersistableAttachment existingBO = (PersistableAttachment) getBusinessObjectService().retrieve(document.getNewMaintainableObject().getBusinessObject()); 606 if (existingBO == null) { 607 if (document.getAttachment() != null) { 608 fileName = document.getAttachment().getFileName(); 609 } else { 610 fileName = ""; 611 } 612 } else { 613 fileName = (existingBO != null ? existingBO.getFileName() : ""); 614 } 615 request.setAttribute("fileName", fileName); 616 } 617 } 618 return forward; 619 } 620 621 /** 622 * Handles creating and loading of documents. 623 */ 624 @Override 625 public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 626 ActionForward af = super.docHandler(mapping, form, request, response); 627 if (af.getName().equals(KRADConstants.KRAD_INITIATED_DOCUMENT_VIEW_NAME)) 628 { 629 return af; 630 } 631 KualiMaintenanceForm kualiMaintenanceForm = (KualiMaintenanceForm) form; 632 633 if (KewApiConstants.ACTIONLIST_COMMAND.equals(kualiMaintenanceForm.getCommand()) || KewApiConstants.DOCSEARCH_COMMAND.equals(kualiMaintenanceForm.getCommand()) || KewApiConstants.SUPERUSER_COMMAND.equals(kualiMaintenanceForm.getCommand()) || KewApiConstants.HELPDESK_ACTIONLIST_COMMAND.equals(kualiMaintenanceForm.getCommand()) && kualiMaintenanceForm.getDocId() != null) { 634 if (kualiMaintenanceForm.getDocument() instanceof MaintenanceDocument) { 635 kualiMaintenanceForm.setReadOnly(true); 636 kualiMaintenanceForm.setMaintenanceAction(((MaintenanceDocument) kualiMaintenanceForm.getDocument()).getNewMaintainableObject().getMaintenanceAction()); 637 638 //Retrieving the FileName from BO table 639 Maintainable tmpMaintainable = ((MaintenanceDocument) kualiMaintenanceForm.getDocument()).getNewMaintainableObject(); 640 if(tmpMaintainable.getBusinessObject() instanceof PersistableAttachment) { 641 PersistableAttachment bo = (PersistableAttachment) getBusinessObjectService().retrieve(tmpMaintainable.getBusinessObject()); 642 if (bo != null) { 643 request.setAttribute("fileName", bo.getFileName()); 644 } 645 } 646 } 647 else { 648 LOG.error("Illegal State: document is not a maintenance document"); 649 throw new IllegalArgumentException("Document is not a maintenance document"); 650 } 651 } 652 else if (KewApiConstants.INITIATE_COMMAND.equals(kualiMaintenanceForm.getCommand())) { 653 kualiMaintenanceForm.setReadOnly(false); 654 return setupMaintenance(mapping, form, request, response, KRADConstants.MAINTENANCE_NEW_ACTION); 655 } 656 else { 657 LOG.error("We should never have gotten to here"); 658 throw new IllegalArgumentException("docHandler called with invalid parameters"); 659 } 660 return mapping.findForward(RiceConstants.MAPPING_BASIC); 661 } 662 663 /** 664 * Called on return from a lookup. 665 */ 666 @Override 667 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 668 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) form; 669 670 WebUtils.reuseErrorMapFromPreviousRequest(maintenanceForm); 671 maintenanceForm.setDerivedValuesOnForm(request); 672 673 refreshAdHocRoutingWorkgroupLookups(request, maintenanceForm); 674 MaintenanceDocument document = (MaintenanceDocument) maintenanceForm.getDocument(); 675 676 // call refresh on new maintainable 677 Map<String, String> requestParams = new HashMap<String, String>(); 678 for (Enumeration i = request.getParameterNames(); i.hasMoreElements();) { 679 String requestKey = (String) i.nextElement(); 680 String requestValue = request.getParameter(requestKey); 681 requestParams.put(requestKey, requestValue); 682 } 683 684 // Add multiple values from Lookup 685 Collection<PersistableBusinessObject> rawValues = null; 686 if (StringUtils.equals(KRADConstants.MULTIPLE_VALUE, maintenanceForm.getRefreshCaller())) { 687 String lookupResultsSequenceNumber = maintenanceForm.getLookupResultsSequenceNumber(); 688 if (StringUtils.isNotBlank(lookupResultsSequenceNumber)) { 689 // actually returning from a multiple value lookup 690 String lookupResultsBOClassName = maintenanceForm.getLookupResultsBOClassName(); 691 Class lookupResultsBOClass = Class.forName(lookupResultsBOClassName); 692 693 rawValues = getLookupResultsService().retrieveSelectedResultBOs(lookupResultsSequenceNumber, lookupResultsBOClass, GlobalVariables.getUserSession().getPerson().getPrincipalId()); 694 } 695 } 696 697 if (rawValues != null) { // KULCOA-1073 - caused by this block running unnecessarily? 698 // we need to run the business rules on all the newly added items to the collection 699 // KULCOA-1000, KULCOA-1004 removed business rule validation on multiple value return 700 // (this was running before the objects were added anyway) 701 // getKualiRuleService().applyRules(new SaveDocumentEvent(document)); 702 String collectionName = maintenanceForm.getLookedUpCollectionName(); 703 //TODO: Cathy remember to delete this block of comments after I've tested. 704 // PersistableBusinessObject bo = document.getNewMaintainableObject().getBusinessObject(); 705 // Collection maintCollection = this.extractCollection(bo, collectionName); 706 // String docTypeName = ((MaintenanceDocument) maintenanceForm.getDocument()).getDocumentHeader().getWorkflowDocument().getDocumentType(); 707 // Class collectionClass = extractCollectionClass(docTypeName, collectionName); 708 // 709 // List<MaintainableSectionDefinition> sections = maintenanceDocumentDictionaryService.getMaintainableSections(docTypeName); 710 // Map<String, String> template = MaintenanceUtils.generateMultipleValueLookupBOTemplate(sections, collectionName); 711 // for (PersistableBusinessObject nextBo : rawValues) { 712 // PersistableBusinessObject templatedBo = (PersistableBusinessObject) ObjectUtils.createHybridBusinessObject(collectionClass, nextBo, template); 713 // templatedBo.setNewCollectionRecord(true); 714 // maintCollection.add(templatedBo); 715 // } 716 document.getNewMaintainableObject().addMultipleValueLookupResults(document, collectionName, rawValues, false, document.getNewMaintainableObject().getBusinessObject()); 717 if (LOG.isInfoEnabled()) { 718 LOG.info("********************doing editing 3 in refersh()***********************."); 719 } 720 boolean isEdit = KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceForm.getMaintenanceAction()); 721 boolean isCopy = KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceForm.getMaintenanceAction()); 722 723 if (isEdit || isCopy) { 724 document.getOldMaintainableObject().addMultipleValueLookupResults(document, collectionName, rawValues, true, document.getOldMaintainableObject().getBusinessObject()); 725 document.getOldMaintainableObject().refresh(maintenanceForm.getRefreshCaller(), requestParams, document); 726 } 727 } 728 729 document.getNewMaintainableObject().refresh(maintenanceForm.getRefreshCaller(), requestParams, document); 730 731 //pass out customAction from methodToCall parameter. Call processAfterPost 732 String fullParameter = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); 733 if(StringUtils.contains(fullParameter, KRADConstants.CUSTOM_ACTION)){ 734 String customAction = StringUtils.substringBetween(fullParameter, KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL); 735 String[] actionValue = new String[1]; 736 actionValue[0]= StringUtils.substringAfter(customAction, "."); 737 Map<String,String[]> paramMap = new HashMap<String,String[]>(request.getParameterMap()); 738 paramMap.put(KRADConstants.CUSTOM_ACTION, actionValue); 739 doProcessingAfterPost( (KualiMaintenanceForm) form, paramMap ); 740 } 741 742 return mapping.findForward(RiceConstants.MAPPING_BASIC); 743 } 744 745 /** 746 * Gets keys for the maintainable business object from the persistence metadata explorer. Checks for existence of key property 747 * names as request parameters, if found adds them to the returned hash map. 748 */ 749 protected Map buildKeyMapFromRequest(Maintainable maintainable, HttpServletRequest request) { 750 List keyFieldNames = null; 751 // are override keys listed in the request? If so, then those need to be our keys, 752 // not the primary keye fields for the BO 753 if (!StringUtils.isBlank(request.getParameter(KRADConstants.OVERRIDE_KEYS))) { 754 String[] overrideKeys = request.getParameter(KRADConstants.OVERRIDE_KEYS).split(KRADConstants.FIELD_CONVERSIONS_SEPARATOR); 755 keyFieldNames = new ArrayList(); 756 for (String overrideKey : overrideKeys) { 757 keyFieldNames.add(overrideKey); 758 } 759 } 760 else { 761 keyFieldNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(maintainable.getBusinessObject().getClass()); 762 } 763 return getRequestParameters(keyFieldNames, maintainable, request); 764 } 765 766 protected Map<String, String> getRequestParameters(List keyFieldNames, Maintainable maintainable, HttpServletRequest request){ 767 768 Map<String, String> requestParameters = new HashMap<String, String>(); 769 770 771 for (Iterator iter = keyFieldNames.iterator(); iter.hasNext();) { 772 String keyPropertyName = (String) iter.next(); 773 774 if (request.getParameter(keyPropertyName) != null) { 775 String keyValue = request.getParameter(keyPropertyName); 776 777 // Check if this element was encrypted, if it was decrypt it 778 if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(maintainable.getBoClass(), keyPropertyName)) { 779 try { 780 keyValue = StringUtils.removeEnd(keyValue, EncryptionService.ENCRYPTION_POST_PREFIX); 781 if(CoreApiServiceLocator.getEncryptionService().isEnabled()) { 782 keyValue = encryptionService.decrypt(keyValue); 783 } 784 } 785 catch (GeneralSecurityException e) { 786 throw new RuntimeException(e); 787 } 788 } 789 790 791 requestParameters.put(keyPropertyName, keyValue); 792 } 793 } 794 795 return requestParameters; 796 797 } 798 799 /** 800 * Convert a Request into a Map<String,String>. Technically, Request parameters do not neatly translate into a Map of Strings, 801 * because a given parameter may legally appear more than once (so a Map of String[] would be more accurate.) This method should 802 * be safe for business objects, but may not be reliable for more general uses. 803 */ 804 String extractCollectionName(HttpServletRequest request, String methodToCall) { 805 // collection name and underlying object type from request parameter 806 String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); 807 String collectionName = null; 808 if (StringUtils.isNotBlank(parameterName)) { 809 collectionName = StringUtils.substringBetween(parameterName, methodToCall + ".", ".("); 810 } 811 return collectionName; 812 } 813 814 Collection extractCollection(PersistableBusinessObject bo, String collectionName) { 815 // retrieve the collection from the business object 816 Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(bo, collectionName); 817 return maintCollection; 818 } 819 820 Class extractCollectionClass(String docTypeName, String collectionName) { 821 return maintenanceDocumentDictionaryService.getCollectionBusinessObjectClass(docTypeName, collectionName); 822 } 823 824 /** 825 * Adds a line to a collection being maintained in a many section. 826 */ 827 public ActionForward addLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 828 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) form; 829 MaintenanceDocument document = (MaintenanceDocument) maintenanceForm.getDocument(); 830 Maintainable oldMaintainable = document.getOldMaintainableObject(); 831 Maintainable newMaintainable = document.getNewMaintainableObject(); 832 833 String collectionName = extractCollectionName(request, KRADConstants.ADD_LINE_METHOD); 834 if (collectionName == null) { 835 LOG.error("Unable to get find collection name and class in request."); 836 throw new RuntimeException("Unable to get find collection name and class in request."); 837 } 838 839 // if dealing with sub collection it will have a "[" 840 if ((StringUtils.lastIndexOf(collectionName, "]") + 1) == collectionName.length()) { 841 collectionName = StringUtils.substringBeforeLast(collectionName, "["); 842 } 843 844 PersistableBusinessObject bo = newMaintainable.getBusinessObject(); 845 Collection maintCollection = extractCollection(bo, collectionName); 846 Class collectionClass = extractCollectionClass(((MaintenanceDocument) maintenanceForm.getDocument()).getDocumentHeader().getWorkflowDocument().getDocumentTypeName(), collectionName); 847 848 // TODO: sort of collection, new instance should be first 849 850 // get the BO from the new collection line holder 851 PersistableBusinessObject addBO = newMaintainable.getNewCollectionLine(collectionName); 852 if (LOG.isDebugEnabled()) { 853 LOG.debug("obtained addBO from newCollectionLine: " + addBO); 854 } 855 856 // link up the user fields, if any 857 getBusinessObjectService().linkUserFields(addBO); 858 859 //KULRICE-4264 - a hook to change the state of the business object, which is the "new line" of a collection, before it is validated 860 newMaintainable.processBeforeAddLine(collectionName, collectionClass, addBO); 861 862 // apply rules to the addBO 863 boolean rulePassed = false; 864 if (LOG.isDebugEnabled()) { 865 LOG.debug("about to call AddLineEvent applyRules: document=" + document + "\ncollectionName=" + collectionName + "\nBO=" + addBO); 866 } 867 rulePassed = getKualiRuleService().applyRules(new KualiAddLineEvent(document, collectionName, addBO)); 868 869 // if the rule evaluation passed, let's add it 870 if (rulePassed) { 871 if (LOG.isInfoEnabled()) { 872 LOG.info("********************doing editing 4 in addline()***********************."); 873 } 874 // if edit or copy action, just add empty instance to old maintainable 875 boolean isEdit = KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceForm.getMaintenanceAction()); 876 boolean isCopy = KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceForm.getMaintenanceAction()); 877 878 879 if (isEdit || isCopy) { 880 PersistableBusinessObject oldBo = oldMaintainable.getBusinessObject(); 881 Collection oldMaintCollection = (Collection) ObjectUtils.getPropertyValue(oldBo, collectionName); 882 883 if (oldMaintCollection == null) { 884 oldMaintCollection = new ArrayList(); 885 } 886 if (PersistableBusinessObject.class.isAssignableFrom(collectionClass)) { 887 PersistableBusinessObject placeholder = (PersistableBusinessObject) collectionClass.newInstance(); 888 // KULRNE-4538: must set it as a new collection record, because the maintainable will set the BO that gets added 889 // to the new maintainable as a new collection record 890 891 // if not set, then the subcollections of the newly added object will appear as read only 892 // see FieldUtils.getContainerRows on how the delete button is rendered 893 placeholder.setNewCollectionRecord(true); 894 ((List) oldMaintCollection).add(placeholder); 895 } 896 else { 897 LOG.warn("Should be a instance of PersistableBusinessObject"); 898 ((List) oldMaintCollection).add(collectionClass.newInstance()); 899 } 900 // update collection in maintenance business object 901 ObjectUtils.setObjectProperty(oldBo, collectionName, List.class, oldMaintCollection); 902 } 903 904 newMaintainable.addNewLineToCollection(collectionName); 905 int subCollectionIndex = 0; 906 for (Object aSubCollection : maintCollection) { 907 subCollectionIndex += getSubCollectionIndex(aSubCollection, maintenanceForm.getDocTypeName()); 908 } 909 //TODO: Should we keep this logic and continue using currentTabIndex as the key in the tabStates HashMap ? 910 // 911 // String parameter = (String) request.getAttribute(Constants.METHOD_TO_CALL_ATTRIBUTE); 912 // String indexStr = StringUtils.substringBetween(parameter, Constants.METHOD_TO_CALL_PARM13_LEFT_DEL, Constants.METHOD_TO_CALL_PARM13_RIGHT_DEL); 913 // // + 1 is for the fact that the first element of a collection is on the next tab 914 // int index = Integer.parseInt(indexStr) + subCollectionIndex + 1; 915 // Map<String, String> tabStates = maintenanceForm.getTabStates(); 916 // Map<String, String> copyOfTabStates = new HashMap<String, String>(); 917 // 918 // int incrementor = 0; 919 // for (String tabState : tabStates.keySet()) { 920 // String originalValue = maintenanceForm.getTabState(Integer.toString(incrementor)); 921 // copyOfTabStates.put(Integer.toString(incrementor), originalValue); 922 // incrementor++; 923 // } 924 // 925 // int i = index; 926 // if (tabStates.containsKey(Integer.toString(i-1))) { 927 // tabStates.remove(Integer.toString(i-1)); 928 // } 929 // while (i < copyOfTabStates.size() + 1) { 930 // String originalValue = copyOfTabStates.get(Integer.toString(i-1)); 931 // if (tabStates.containsKey(Integer.toString(i))) { 932 // tabStates.remove(Integer.toString(i)); 933 // } 934 // tabStates.put(Integer.toString(i), originalValue); 935 // i++; 936 // } 937 938 939 // End of whether we should continue to keep this logic and use currentTabIndex as the key 940 } 941 doProcessingAfterPost( (KualiMaintenanceForm) form, request ); 942 943 return mapping.findForward(RiceConstants.MAPPING_BASIC); 944 } 945 946 protected int getSubCollectionIndex(Object object, String documentTypeName) { 947 int index = 1; 948 MaintainableCollectionDefinition theCollectionDefinition = null; 949 for (MaintainableCollectionDefinition maintainableCollectionDefinition : maintenanceDocumentDictionaryService.getMaintainableCollections(documentTypeName)) { 950 if (maintainableCollectionDefinition.getBusinessObjectClass().equals(object.getClass())) { 951 // we've found the collection we were looking for, so let's find all of its subcollections 952 theCollectionDefinition = maintainableCollectionDefinition; 953 break; 954 } 955 } 956 if (theCollectionDefinition != null) { 957 for (MaintainableCollectionDefinition subCollDef : theCollectionDefinition.getMaintainableCollections()) { 958 String name = subCollDef.getName(); 959 String capitalFirst = name.substring(0, 1).toUpperCase(); 960 String methodName = "get" + capitalFirst + name.substring(1); 961 List subCollectionList = new ArrayList(); 962 try { 963 subCollectionList = (List) object.getClass().getMethod(methodName).invoke(object); 964 } 965 catch (InvocationTargetException ite) { 966 // this shouldn't happen 967 } 968 catch (IllegalAccessException iae) { 969 // this shouldn't happen 970 } 971 catch (NoSuchMethodException nme) { 972 // this shouldn't happen 973 } 974 index += subCollectionList.size(); 975 } 976 } 977 return index; 978 } 979 980 /** 981 * Deletes a collection line that is pending by this document. The collection name and the index to delete is embedded into the 982 * delete button name. These parameters are extracted, the collection pulled out of the parent business object, and finally the 983 * collection record at the specified index is removed for the new maintainable, and the old if we are dealing with an edit. 984 */ 985 public ActionForward deleteLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 986 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) form; 987 MaintenanceDocument document = (MaintenanceDocument) maintenanceForm.getDocument(); 988 Maintainable oldMaintainable = document.getOldMaintainableObject(); 989 Maintainable newMaintainable = document.getNewMaintainableObject(); 990 991 String collectionName = extractCollectionName(request, KRADConstants.DELETE_LINE_METHOD); 992 if (collectionName == null) { 993 LOG.error("Unable to get find collection name in request."); 994 throw new RuntimeException("Unable to get find collection class in request."); 995 } 996 997 PersistableBusinessObject bo = newMaintainable.getBusinessObject(); 998 Collection maintCollection = extractCollection(bo, collectionName); 999 if (collectionName == null) { 1000 LOG.error("Collection is null in parent business object."); 1001 throw new RuntimeException("Collection is null in parent business object."); 1002 } 1003 1004 int deleteRecordIndex = getLineToDelete(request); 1005 if (deleteRecordIndex < 0 || deleteRecordIndex > maintCollection.size() - 1) { 1006 if (collectionName == null) { 1007 LOG.error("Invalid index for deletion of collection record: " + deleteRecordIndex); 1008 throw new RuntimeException("Invalid index for deletion of collection record: " + deleteRecordIndex); 1009 } 1010 } 1011 1012 ((List) maintCollection).remove(deleteRecordIndex); 1013 1014 // if it's either an edit or a copy, need to remove the collection from the old maintainable as well 1015 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceForm.getMaintenanceAction()) || 1016 KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceForm.getMaintenanceAction())) { 1017 bo = oldMaintainable.getBusinessObject(); 1018 maintCollection = extractCollection(bo, collectionName); 1019 1020 if (collectionName == null) { 1021 LOG.error("Collection is null in parent business object."); 1022 throw new RuntimeException("Collection is null in parent business object."); 1023 } 1024 1025 ((List) maintCollection).remove(deleteRecordIndex); 1026 } 1027 1028 // remove the tab state information of the tab that the deleted element originally occupied, so that it will keep tab states 1029 // consistent 1030 // String parameter = (String) request.getAttribute(Constants.METHOD_TO_CALL_ATTRIBUTE); 1031 // String indexStr = StringUtils.substringBetween(parameter, Constants.METHOD_TO_CALL_PARM13_LEFT_DEL, Constants.METHOD_TO_CALL_PARM13_RIGHT_DEL); 1032 // int index = Integer.parseInt(indexStr); 1033 // maintenanceForm.removeTabState(index); 1034 1035 1036 // TODO: Should we keep this logic and continue using currentTabIndex as the key in the tabStates HashMap ? 1037 // 1038 // String parameter = (String) request.getAttribute(Constants.METHOD_TO_CALL_ATTRIBUTE); 1039 // String indexStr = StringUtils.substringBetween(parameter, Constants.METHOD_TO_CALL_PARM13_LEFT_DEL, Constants.METHOD_TO_CALL_PARM13_RIGHT_DEL); 1040 // // + 1 is for the fact that the first element of a collection is on the next tab 1041 // int index = Integer.parseInt(indexStr) + 1; 1042 // Map<String, String> tabStates = maintenanceForm.getTabStates(); 1043 // Map<String, String> copyOfTabStates = new HashMap<String, String>(); 1044 // 1045 // int incrementor = 0; 1046 // for (String tabState : tabStates.keySet()) { 1047 // String originalValue = maintenanceForm.getTabState(Integer.toString(incrementor)); 1048 // copyOfTabStates.put(Integer.toString(incrementor), originalValue); 1049 // incrementor++; 1050 // } 1051 // 1052 // int i = index; 1053 // 1054 // while (i < copyOfTabStates.size() ) { 1055 // String originalValue = copyOfTabStates.get(Integer.toString(i)); 1056 // if (tabStates.containsKey(Integer.toString(i-1))) { 1057 // tabStates.remove(Integer.toString(i-1)); 1058 // } 1059 // tabStates.put(Integer.toString(i-1), originalValue); 1060 // i++; 1061 // } 1062 // 1063 // 1064 //End of whether we should continue to keep this logic and use currentTabIndex as the key 1065 1066 doProcessingAfterPost( (KualiMaintenanceForm) form, request ); 1067 1068 return mapping.findForward(RiceConstants.MAPPING_BASIC); 1069 } 1070 1071 /** 1072 * Turns on (or off) the inactive record display for a maintenance collection. 1073 */ 1074 public ActionForward toggleInactiveRecordDisplay(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 1075 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) form; 1076 MaintenanceDocument document = (MaintenanceDocument) maintenanceForm.getDocument(); 1077 Maintainable oldMaintainable = document.getOldMaintainableObject(); 1078 Maintainable newMaintainable = document.getNewMaintainableObject(); 1079 1080 String collectionName = extractCollectionName(request, KRADConstants.TOGGLE_INACTIVE_METHOD); 1081 if (collectionName == null) { 1082 LOG.error("Unable to get find collection name in request."); 1083 throw new RuntimeException("Unable to get find collection class in request."); 1084 } 1085 1086 String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE); 1087 boolean showInactive = Boolean.parseBoolean(StringUtils.substringBetween(parameterName, KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL, ".")); 1088 1089 oldMaintainable.setShowInactiveRecords(collectionName, showInactive); 1090 newMaintainable.setShowInactiveRecords(collectionName, showInactive); 1091 1092 return mapping.findForward(RiceConstants.MAPPING_BASIC); 1093 } 1094 1095 /** 1096 * This method clears the value of the primary key fields on a Business Object. 1097 * 1098 * @param document - document to clear the pk fields on 1099 */ 1100 protected void clearPrimaryKeyFields(MaintenanceDocument document) { 1101 // get business object being maintained and its keys 1102 PersistableBusinessObject bo = document.getNewMaintainableObject().getBusinessObject(); 1103 List<String> keyFieldNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(bo.getClass()); 1104 1105 for (String keyFieldName : keyFieldNames) { 1106 try { 1107 ObjectUtils.setObjectProperty(bo, keyFieldName, null); 1108 } 1109 catch (Exception e) { 1110 LOG.error("Unable to clear primary key field: " + e.getMessage()); 1111 throw new RuntimeException("Unable to clear primary key field: " + e.getMessage()); 1112 } 1113 } 1114 bo.setObjectId(null); 1115 bo.setVersionNumber(new Long(1)); 1116 } 1117 1118 /** 1119 * This method is used as part of the Copy functionality, to clear any field values that the user making the copy does not have 1120 * permissions to modify. This will prevent authorization errors on a copy. 1121 * 1122 * @param document - document to be adjusted 1123 */ 1124 protected void clearUnauthorizedNewFields(MaintenanceDocument document) { 1125 // get a reference to the current user 1126 Person user = GlobalVariables.getUserSession().getPerson(); 1127 1128 // get the correct documentAuthorizer for this document 1129 MaintenanceDocumentAuthorizer documentAuthorizer = (MaintenanceDocumentAuthorizer) getDocumentHelperService().getDocumentAuthorizer(document); 1130 1131 // get a new instance of MaintenanceDocumentAuthorizations for this context 1132 MaintenanceDocumentRestrictions maintenanceDocumentRestrictions = getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(document, user); 1133 1134 // get a reference to the newBo 1135 PersistableBusinessObject newBo = document.getNewMaintainableObject().getBusinessObject(); 1136 1137 document.getNewMaintainableObject().clearBusinessObjectOfRestrictedValues(maintenanceDocumentRestrictions); 1138 } 1139 1140 /** 1141 * This method does all special processing on a document that should happen on each HTTP post (ie, save, route, approve, etc). 1142 * 1143 * @param form 1144 */ 1145 @SuppressWarnings("unchecked") 1146 protected void doProcessingAfterPost( KualiForm form, HttpServletRequest request ) { 1147 MaintenanceDocument document = (MaintenanceDocument) ((KualiMaintenanceForm)form).getDocument(); 1148 Maintainable maintainable = document.getNewMaintainableObject(); 1149 PersistableBusinessObject bo = maintainable.getBusinessObject(); 1150 1151 getBusinessObjectService().linkUserFields(bo); 1152 1153 maintainable.processAfterPost(document, request.getParameterMap() ); 1154 } 1155 1156 protected void doProcessingAfterPost( KualiForm form, Map<String,String[]> parameters ) { 1157 MaintenanceDocument document = (MaintenanceDocument) ((KualiMaintenanceForm)form).getDocument(); 1158 Maintainable maintainable = document.getNewMaintainableObject(); 1159 PersistableBusinessObject bo = maintainable.getBusinessObject(); 1160 1161 getBusinessObjectService().linkUserFields(bo); 1162 1163 maintainable.processAfterPost(document, parameters ); 1164 } 1165 1166 protected void populateAuthorizationFields(KualiDocumentFormBase formBase){ 1167 super.populateAuthorizationFields(formBase); 1168 1169 KualiMaintenanceForm maintenanceForm = (KualiMaintenanceForm) formBase; 1170 MaintenanceDocument maintenanceDocument = (MaintenanceDocument) maintenanceForm.getDocument(); 1171 MaintenanceDocumentAuthorizer maintenanceDocumentAuthorizer = (MaintenanceDocumentAuthorizer) getDocumentHelperService().getDocumentAuthorizer(maintenanceDocument); 1172 Person user = GlobalVariables.getUserSession().getPerson(); 1173 maintenanceForm.setReadOnly(!formBase.getDocumentActions().containsKey(KRADConstants.KUALI_ACTION_CAN_EDIT)); 1174 MaintenanceDocumentRestrictions maintenanceDocumentAuthorizations = getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(maintenanceDocument, user); 1175 maintenanceForm.setAuthorizations(maintenanceDocumentAuthorizations); 1176 } 1177 1178 public LookupService getLookupService() { 1179 if ( lookupService == null ) { 1180 lookupService = KRADServiceLocatorWeb.getLookupService(); 1181 } 1182 return this.lookupService; 1183 } 1184 1185 public LookupResultsService getLookupResultsService() { 1186 if ( lookupResultsService == null ) { 1187 lookupResultsService = KNSServiceLocator.getLookupResultsService(); 1188 } 1189 return this.lookupResultsService; 1190 } 1191 1192 }