View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kns.document;
17  
18  import org.apache.commons.codec.digest.DigestUtils;
19  import org.apache.commons.collections.CollectionUtils;
20  import org.apache.commons.lang.StringUtils;
21  import org.apache.ojb.broker.core.proxy.ProxyHelper;
22  import org.apache.struts.upload.FormFile;
23  import org.kuali.rice.kns.maintenance.Maintainable;
24  import org.kuali.rice.krad.bo.DocumentAttachment;
25  import org.kuali.rice.kns.bo.GlobalBusinessObject;
26  import org.kuali.rice.krad.bo.MultiDocumentAttachment;
27  import org.kuali.rice.krad.bo.PersistableAttachment;
28  import org.kuali.rice.krad.bo.PersistableAttachmentBase;
29  import org.kuali.rice.krad.bo.PersistableAttachmentList;
30  import org.kuali.rice.krad.rules.rule.event.DocumentEvent;
31  import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent;
32  import org.kuali.rice.krad.service.BusinessObjectSerializerService;
33  import org.kuali.rice.krad.service.KRADServiceLocator;
34  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
35  import org.kuali.rice.krad.util.KRADUtils;
36  import org.kuali.rice.krad.util.ObjectUtils;
37  
38  import javax.persistence.Transient;
39  import java.io.FileNotFoundException;
40  import java.io.IOException;
41  import java.lang.reflect.Method;
42  import java.util.ArrayList;
43  import java.util.Collections;
44  import java.util.HashMap;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.UUID;
48  
49  /**
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   *
52   * @deprecated Use {@link org.kuali.rice.krad.maintenance.MaintenanceDocumentBase}.
53   */
54  @Deprecated
55  public class MaintenanceDocumentBase extends org.kuali.rice.krad.maintenance.MaintenanceDocumentBase implements MaintenanceDocument {
56      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentBase.class);
57  
58      @Transient
59      protected transient FormFile fileAttachment;
60  
61      public MaintenanceDocumentBase() {
62          super();
63      }
64  
65      public MaintenanceDocumentBase(String documentTypeName) {
66          super(documentTypeName);
67      }
68  
69      @Override
70      public Object getDocumentBusinessObject() {
71          return super.getDocumentDataObject();
72      }
73  
74      /**
75       * Checks old maintainable bo has key values
76       */
77      public boolean isOldBusinessObjectInDocument() {
78          boolean isOldBusinessObjectInExistence = false;
79          if (getOldMaintainableObject() == null || getOldMaintainableObject().getBusinessObject() == null) {
80              isOldBusinessObjectInExistence = false;
81          } else {
82              isOldBusinessObjectInExistence = getOldMaintainableObject().isOldBusinessObjectInDocument();
83          }
84          return isOldBusinessObjectInExistence;
85      }
86  
87      public Maintainable getNewMaintainableObject() {
88          return (Maintainable) newMaintainableObject;
89      }
90  
91      public Maintainable getOldMaintainableObject() {
92          return (Maintainable) oldMaintainableObject;
93      }
94  
95      public FormFile getFileAttachment() {
96          return this.fileAttachment;
97      }
98  
99      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 }