001/** 002 * Copyright 2005-2018 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 */ 016package org.kuali.rice.kns.document; 017 018import org.apache.commons.codec.digest.DigestUtils; 019import org.apache.commons.collections.CollectionUtils; 020import org.apache.commons.lang.StringUtils; 021import org.apache.ojb.broker.core.proxy.ProxyHelper; 022import org.apache.struts.upload.FormFile; 023import org.kuali.rice.kns.maintenance.Maintainable; 024import org.kuali.rice.krad.bo.DocumentAttachment; 025import org.kuali.rice.kns.bo.GlobalBusinessObject; 026import org.kuali.rice.krad.bo.MultiDocumentAttachment; 027import org.kuali.rice.krad.bo.PersistableAttachment; 028import org.kuali.rice.krad.bo.PersistableAttachmentBase; 029import org.kuali.rice.krad.bo.PersistableAttachmentList; 030import org.kuali.rice.krad.rules.rule.event.DocumentEvent; 031import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent; 032import org.kuali.rice.krad.service.BusinessObjectSerializerService; 033import org.kuali.rice.krad.service.KRADServiceLocator; 034import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 035import org.kuali.rice.krad.util.KRADUtils; 036import org.kuali.rice.krad.util.ObjectUtils; 037 038import javax.persistence.Transient; 039import java.io.FileNotFoundException; 040import java.io.IOException; 041import java.lang.reflect.Method; 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.HashMap; 045import java.util.List; 046import java.util.Map; 047import java.util.UUID; 048 049/** 050 * @author Kuali Rice Team (rice.collab@kuali.org) 051 * 052 * @deprecated Use {@link org.kuali.rice.krad.maintenance.MaintenanceDocumentBase}. 053 */ 054@Deprecated 055public class MaintenanceDocumentBase extends org.kuali.rice.krad.maintenance.MaintenanceDocumentBase implements MaintenanceDocument { 056 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentBase.class); 057 058 @Transient 059 protected transient FormFile fileAttachment; 060 061 public MaintenanceDocumentBase() { 062 super(); 063 } 064 065 public MaintenanceDocumentBase(String documentTypeName) { 066 super(documentTypeName); 067 } 068 069 @Override 070 public Object getDocumentBusinessObject() { 071 return super.getDocumentDataObject(); 072 } 073 074 /** 075 * Checks old maintainable bo has key values 076 */ 077 public boolean isOldBusinessObjectInDocument() { 078 boolean isOldBusinessObjectInExistence = false; 079 if (getOldMaintainableObject() == null || getOldMaintainableObject().getBusinessObject() == null) { 080 isOldBusinessObjectInExistence = false; 081 } else { 082 isOldBusinessObjectInExistence = getOldMaintainableObject().isOldBusinessObjectInDocument(); 083 } 084 return isOldBusinessObjectInExistence; 085 } 086 087 public Maintainable getNewMaintainableObject() { 088 return (Maintainable) newMaintainableObject; 089 } 090 091 public Maintainable getOldMaintainableObject() { 092 return (Maintainable) oldMaintainableObject; 093 } 094 095 public FormFile getFileAttachment() { 096 return this.fileAttachment; 097 } 098 099 public void setFileAttachment(FormFile fileAttachment) { 100 this.fileAttachment = fileAttachment; 101 } 102 103 /** 104 * The attachment BO is proxied in OJB. For some reason when an attachment does not yet exist, 105 * refreshReferenceObject is not returning null and the proxy cannot be materialized. So, this method exists to 106 * properly handle the proxied attachment BO. This is a hack and should be removed post JPA migration. 107 */ 108 protected void refreshAttachment() { 109 if (KRADUtils.isNull(attachment)) { 110 this.refreshReferenceObject("attachment"); 111 final boolean isProxy = attachment != null && ProxyHelper.isProxy(attachment); 112 if (isProxy && ProxyHelper.getRealObject(attachment) == null) { 113 attachment = null; 114 } 115 } 116 } 117 118 protected void refreshAttachmentList() { 119 if (KRADUtils.isNull(attachments)) { 120 this.refreshReferenceObject("attachments"); 121 final boolean isProxy = attachments != null && ProxyHelper.isProxy(attachments); 122 if (isProxy && ProxyHelper.getRealObject(attachments) == null) { 123 attachments = null; 124 } 125 } 126 } 127 128 @Override 129 public void populateDocumentAttachment() { 130 refreshAttachment(); 131 132 if (fileAttachment != null && StringUtils.isNotEmpty(fileAttachment.getFileName())) { 133 //Populate DocumentAttachment BO 134 if (attachment == null) { 135 attachment = new DocumentAttachment(); 136 } 137 138 byte[] fileContents; 139 try { 140 fileContents = fileAttachment.getFileData(); 141 if (fileContents.length > 0) { 142 attachment.setFileName(fileAttachment.getFileName()); 143 attachment.setContentType(fileAttachment.getContentType()); 144 attachment.setAttachmentContent(fileAttachment.getFileData()); 145 attachment.setObjectId(UUID.randomUUID().toString()); 146 PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject(); 147 boAttachment.setAttachmentContent(null); 148 attachment.setDocumentNumber(getDocumentNumber()); 149 } 150 } catch (FileNotFoundException e) { 151 LOG.error("Error while populating the Document Attachment", e); 152 throw new RuntimeException("Could not populate DocumentAttachment object", e); 153 } catch (IOException e) { 154 LOG.error("Error while populating the Document Attachment", e); 155 throw new RuntimeException("Could not populate DocumentAttachment object", e); 156 } 157 } else { 158 //fileAttachment isn't filled, populate from bo if it exists 159 PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject(); 160 if (attachment == null 161 && boAttachment != null 162 && boAttachment.getAttachmentContent() != null) { 163 DocumentAttachment newAttachment = new DocumentAttachment(); 164 newAttachment.setDocumentNumber(getDocumentNumber()); 165 newAttachment.setAttachmentContent(boAttachment.getAttachmentContent()); 166 newAttachment.setContentType(boAttachment.getContentType()); 167 newAttachment.setFileName(boAttachment.getFileName()); 168 //null out boAttachment file, will be copied back before final save. 169 boAttachment.setAttachmentContent(null); 170 attachment = newAttachment; 171 } 172 } 173 } 174 175 @Override 176 public void populateAttachmentForBO() { 177 refreshAttachment(); 178 179 PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject(); 180 181 if (ObjectUtils.isNotNull(getAttachmentPropertyName())) { 182 String attachmentPropNm = getAttachmentPropertyName(); 183 String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 184 FormFile attachmentFromBusinessObject; 185 186 if((boAttachment.getFileName() == null) && (boAttachment instanceof PersistableAttachment)) { 187 try { 188 Method[] methods = boAttachment.getClass().getMethods(); 189 for (Method method : methods) { 190 if (method.getName().equals(attachmentPropNmSetter)) { 191 attachmentFromBusinessObject = (FormFile)(boAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(boAttachment)); 192 if (attachmentFromBusinessObject != null) { 193 //boAttachment.setAttachmentContent(attachmentFromBusinessObject.getFileData()); 194 boAttachment.setFileName(attachmentFromBusinessObject.getFileName()); 195 boAttachment.setContentType(attachmentFromBusinessObject.getContentType()); 196 } 197 break; 198 } 199 } 200 } catch (Exception e) { 201 LOG.error("Not able to get the attachment " + e.getMessage()); 202 throw new RuntimeException("Not able to get the attachment " + e.getMessage()); 203 } 204 } 205 } 206 207 if((boAttachment.getFileName() == null) && (boAttachment instanceof PersistableAttachment) && (attachment != null)) { 208 //byte[] fileContents; 209 //fileContents = attachment.getAttachmentContent(); 210 if (attachment.getFileName() != null) { 211 boAttachment.setAttachmentContent(null); 212 boAttachment.setFileName(attachment.getFileName()); 213 boAttachment.setContentType(attachment.getContentType()); 214 } 215 } 216 } 217 218 @Override 219 public void populateAttachmentBeforeSave() { 220 PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject(); 221 if (attachment != null 222 && attachment.getAttachmentContent() != null) { 223 boAttachment.setAttachmentContent(attachment.getAttachmentContent()); 224 } else { 225 boAttachment.setAttachmentContent(null); 226 boAttachment.setFileName(null); 227 boAttachment.setContentType(null); 228 } 229 } 230 231 @Override 232 public void populateBoAttachmentListBeforeSave() { 233 234 PersistableAttachmentList<PersistableAttachment> boAttachments = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject(); 235 if (CollectionUtils.isEmpty(attachments)) { 236 //there are no attachments. Clear out Bo Attachments 237 boAttachments.setAttachments(Collections.<PersistableAttachment>emptyList()); 238 return; 239 } 240 Map<String, MultiDocumentAttachment> files = new HashMap<String, MultiDocumentAttachment>(); 241 for (MultiDocumentAttachment multiAttach : attachments) { 242 String key = new StringBuffer(multiAttach.getFileName()).append("|").append(multiAttach.getContentType()).toString(); 243 files.put(key, multiAttach); 244 } 245 246 247 //want to just copy over file if possible, as there can be other fields that are not on PersistableAttachment 248 //these arrays should be somewhat synched by the other populate methods 249 if (CollectionUtils.isNotEmpty(boAttachments.getAttachments())) { 250 for (PersistableAttachment attach : boAttachments.getAttachments()) { 251 //try to get a new instance of the correct object... 252 String key = new StringBuffer(attach.getFileName()).append("|").append(attach.getContentType()).toString(); 253 if (files.containsKey(key)) { 254 attach.setAttachmentContent(files.get(key).getAttachmentContent()); 255 files.remove(key); 256 } 257 } 258 } 259 } 260 261 @Override 262 public void populateAttachmentListForBO() { 263 refreshAttachmentList(); 264 265 PersistableAttachmentList<PersistableAttachment> boAttachments = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject(); 266 267 if (ObjectUtils.isNotNull(getAttachmentListPropertyName())) { 268 //String collectionName = getAttachmentCollectionName(); 269 String attachmentPropNm = getAttachmentListPropertyName(); 270 String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 271 272 273 for (PersistableAttachment persistableAttachment : boAttachments.getAttachments()) { 274 if((persistableAttachment.getFileName() == null)) { 275 try { 276 FormFile attachmentFromBusinessObject = (FormFile)(persistableAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(persistableAttachment)); 277 if (attachmentFromBusinessObject != null) { 278 //persistableAttachment.setAttachmentContent( 279 // attachmentFromBusinessObject.getFileData()); 280 persistableAttachment.setFileName(attachmentFromBusinessObject.getFileName()); 281 persistableAttachment.setContentType(attachmentFromBusinessObject.getContentType()); 282 } 283 } catch (Exception e) { 284 LOG.error("Not able to get the attachment " + e.getMessage()); 285 throw new RuntimeException("Not able to get the attachment " + e.getMessage()); 286 } 287 } 288 } 289 } 290 if((CollectionUtils.isEmpty(boAttachments.getAttachments()) 291 && (CollectionUtils.isNotEmpty(attachments)))) { 292 293 List<PersistableAttachment> attachmentList = new ArrayList<PersistableAttachment>(); 294 for (MultiDocumentAttachment multiAttach : attachments) { 295 296 //try to get a new instance of the correct object... 297 if (multiAttach.getAttachmentContent().length > 0) { 298 PersistableAttachment persistableAttachment = convertDocToBoAttachment(multiAttach, false); 299 attachmentList.add(persistableAttachment); 300 } 301 } 302 boAttachments.setAttachments(attachmentList); 303 } 304 } 305 306 private PersistableAttachment convertDocToBoAttachment(MultiDocumentAttachment multiAttach, boolean copyFile) { 307 PersistableAttachment persistableAttachment = new PersistableAttachmentBase(); 308 309 if (copyFile 310 && multiAttach.getAttachmentContent() != null) { 311 persistableAttachment.setAttachmentContent(multiAttach.getAttachmentContent()); 312 } 313 persistableAttachment.setFileName(multiAttach.getFileName()); 314 persistableAttachment.setContentType(multiAttach.getContentType()); 315 return persistableAttachment; 316 } 317 318 @Override 319 public void populateDocumentAttachmentList() { 320 refreshAttachmentList(); 321 322 String attachmentPropNm = getAttachmentListPropertyName(); 323 String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length()); 324 //don't have form fields to use to fill, but they should be populated on the DataObject. grab them from there. 325 PersistableAttachmentList<PersistableAttachment> boAttachmentList = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject(); 326 327 if (CollectionUtils.isNotEmpty(boAttachmentList.getAttachments())) { 328 329 330 //build map for comparison 331 Map<String, MultiDocumentAttachment> md5Hashes = new HashMap<String, MultiDocumentAttachment>(); 332 if (CollectionUtils.isNotEmpty(attachments)) { 333 for (MultiDocumentAttachment currentAttachment : attachments) { 334 md5Hashes.put(DigestUtils.md5Hex(currentAttachment.getAttachmentContent()), currentAttachment); 335 } 336 } 337 338 //Populate DocumentAttachment BO 339 attachments = new ArrayList<MultiDocumentAttachment>(); 340 341 for (PersistableAttachment persistableAttachment : boAttachmentList.getAttachments()) { 342 try { 343 FormFile attachmentFromBusinessObject = (FormFile)(persistableAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(persistableAttachment)); 344 if (attachmentFromBusinessObject != null) { 345 // 346 //byte[] fileContents = attachmentFromBusinessObject.getFileData(); 347 String md5Hex = DigestUtils.md5Hex(attachmentFromBusinessObject.getInputStream()); 348 if (md5Hashes.containsKey(md5Hex)) { 349 String newFileName = attachmentFromBusinessObject.getFileName(); 350 MultiDocumentAttachment multiAttach = md5Hashes.get(md5Hex); 351 if (multiAttach.getFileName().equals(newFileName)) { 352 attachments.add(multiAttach); 353 } else { 354 multiAttach.setFileName(attachmentFromBusinessObject.getFileName()); 355 multiAttach.setContentType(attachmentFromBusinessObject.getContentType()); 356 multiAttach.setObjectId(UUID.randomUUID().toString()); 357 attachments.add(multiAttach); 358 } 359 md5Hashes.remove(md5Hex); 360 } else { 361 MultiDocumentAttachment attach = new MultiDocumentAttachment(); 362 attach.setFileName(attachmentFromBusinessObject.getFileName()); 363 attach.setContentType(attachmentFromBusinessObject.getContentType()); 364 attach.setAttachmentContent(attachmentFromBusinessObject.getFileData()); 365 attach.setDocumentNumber(getDocumentNumber()); 366 attach.setObjectId(UUID.randomUUID().toString()); 367 attachments.add(attach); 368 } 369 } else { 370 if (persistableAttachment.getFileName() != null 371 && persistableAttachment.getAttachmentContent() != null) { 372 MultiDocumentAttachment attach = new MultiDocumentAttachment(); 373 attach.setFileName(persistableAttachment.getFileName()); 374 attach.setContentType(persistableAttachment.getContentType()); 375 attach.setAttachmentContent(persistableAttachment.getAttachmentContent()); 376 attach.setDocumentNumber(getDocumentNumber()); 377 attach.setObjectId(UUID.randomUUID().toString()); 378 //set Bo's content to null 379 persistableAttachment.setAttachmentContent(null); 380 attachments.add(attach); 381 } 382 } 383 } catch (Exception e) { 384 LOG.error("Not able to get the attachment " + e.getMessage()); 385 throw new RuntimeException("Not able to get the attachment " + e.getMessage()); 386 } 387 } 388 389 } 390 } 391 392 /** 393 * {@inheritDoc} 394 */ 395 @Override 396 protected BusinessObjectSerializerService getBusinessObjectSerializerService() { 397 return KRADServiceLocator.getBusinessObjectSerializerService(); 398 } 399 400 /** 401 * this needs to happen after the document itself is saved, to preserve consistency of the ver_nbr and in the case 402 * of initial save, because this can't be saved until the document is saved initially 403 * 404 * @see org.kuali.rice.krad.document.DocumentBase#postProcessSave(org.kuali.rice.krad.rules.rule.event.DocumentEvent) 405 */ 406 @Override 407 public void postProcessSave(DocumentEvent event) { 408 Object bo = getNewMaintainableObject().getDataObject(); 409 if (bo instanceof GlobalBusinessObject) { 410 bo = KRADServiceLocatorWeb.getLegacyDataAdapter().save(bo); 411 // KRAD/JPA - have to change the handle to object to that just saved 412 getNewMaintainableObject().setDataObject(bo); 413 } 414 415 //currently only global documents could change the list of what they're affecting during routing, 416 //so could restrict this to only happening with them, but who knows if that will change, so safest 417 //to always do the delete and re-add...seems a bit inefficient though if nothing has changed, which is 418 //most of the time...could also try to only add/update/delete what's changed, but this is easier 419 if (!(event instanceof SaveDocumentEvent)) { //don't lock until they route 420 getMaintenanceDocumentService().deleteLocks(MaintenanceDocumentBase.this.getDocumentNumber()); 421 getMaintenanceDocumentService().storeLocks(MaintenanceDocumentBase.this.getNewMaintainableObject().generateMaintenanceLocks()); 422 } 423 } 424 425 426}