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 }