001/**
002 * Copyright 2005-2016 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.struts.upload.FormFile;
022import org.kuali.rice.kns.maintenance.Maintainable;
023import org.kuali.rice.krad.bo.DocumentAttachment;
024import org.kuali.rice.krad.bo.MultiDocumentAttachment;
025import org.kuali.rice.krad.bo.PersistableAttachment;
026import org.kuali.rice.krad.bo.PersistableAttachmentBase;
027import org.kuali.rice.krad.bo.PersistableAttachmentList;
028import org.kuali.rice.krad.bo.PersistableBusinessObject;
029import org.kuali.rice.krad.util.ObjectUtils;
030
031import javax.persistence.Transient;
032import java.io.FileNotFoundException;
033import java.io.IOException;
034import java.lang.reflect.Method;
035import java.util.ArrayList;
036import java.util.Collections;
037import java.util.HashMap;
038import java.util.List;
039import java.util.Map;
040
041/**
042 * @author Kuali Rice Team (rice.collab@kuali.org)
043 */
044public class MaintenanceDocumentBase extends org.kuali.rice.krad.maintenance.MaintenanceDocumentBase implements MaintenanceDocument {
045    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentBase.class);
046
047    @Transient
048    protected transient FormFile fileAttachment;
049
050    public MaintenanceDocumentBase() {
051        super();
052    }
053
054    public MaintenanceDocumentBase(String documentTypeName) {
055        super(documentTypeName);
056    }
057
058    @Override
059    public PersistableBusinessObject getDocumentBusinessObject() {
060        return (PersistableBusinessObject) super.getDocumentDataObject();
061    }
062
063    /**
064     * Checks old maintainable bo has key values
065     */
066    public boolean isOldBusinessObjectInDocument() {
067        boolean isOldBusinessObjectInExistence = false;
068        if (getOldMaintainableObject() == null || getOldMaintainableObject().getBusinessObject() == null) {
069            isOldBusinessObjectInExistence = false;
070        } else {
071            isOldBusinessObjectInExistence = getOldMaintainableObject().isOldBusinessObjectInDocument();
072        }
073        return isOldBusinessObjectInExistence;
074    }
075
076    public Maintainable getNewMaintainableObject() {
077        return (Maintainable) newMaintainableObject;
078    }
079
080    public Maintainable getOldMaintainableObject() {
081        return (Maintainable) oldMaintainableObject;
082    }
083
084    public FormFile getFileAttachment() {
085        return this.fileAttachment;
086    }
087
088    public void setFileAttachment(FormFile fileAttachment) {
089        this.fileAttachment = fileAttachment;
090    }
091
092    @Override
093    public void populateDocumentAttachment() {
094        refreshAttachment();
095
096        if (fileAttachment != null && StringUtils.isNotEmpty(fileAttachment.getFileName())) {
097            //Populate DocumentAttachment BO
098            if (attachment == null) {
099                attachment = new DocumentAttachment();
100            }
101
102            byte[] fileContents;
103            try {
104                fileContents = fileAttachment.getFileData();
105                if (fileContents.length > 0) {
106                    attachment.setFileName(fileAttachment.getFileName());
107                    attachment.setContentType(fileAttachment.getContentType());
108                    attachment.setAttachmentContent(fileAttachment.getFileData());
109                    PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject();
110                    boAttachment.setAttachmentContent(null);
111                    attachment.setDocumentNumber(getDocumentNumber());
112                }
113            } catch (FileNotFoundException e) {
114                LOG.error("Error while populating the Document Attachment", e);
115                throw new RuntimeException("Could not populate DocumentAttachment object", e);
116            } catch (IOException e) {
117                LOG.error("Error while populating the Document Attachment", e);
118                throw new RuntimeException("Could not populate DocumentAttachment object", e);
119            }
120        } else {
121            //fileAttachment isn't filled, populate from bo if it exists
122            PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject();
123            if (attachment == null
124                    && boAttachment != null
125                    && boAttachment.getAttachmentContent() != null) {
126                DocumentAttachment newAttachment = new DocumentAttachment();
127                newAttachment.setDocumentNumber(getDocumentNumber());
128                newAttachment.setAttachmentContent(boAttachment.getAttachmentContent());
129                newAttachment.setContentType(boAttachment.getContentType());
130                newAttachment.setFileName(boAttachment.getFileName());
131                //null out boAttachment file, will be copied back before final save.
132                boAttachment.setAttachmentContent(null);
133                attachment = newAttachment;
134            }
135        }
136    }
137
138    @Override
139    public void populateAttachmentForBO() {
140        refreshAttachment();
141
142        PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject();
143
144        if (ObjectUtils.isNotNull(getAttachmentPropertyName())) {
145                String attachmentPropNm = getAttachmentPropertyName();
146                String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length());
147                FormFile attachmentFromBusinessObject;
148
149                if((boAttachment.getFileName() == null) && (boAttachment instanceof PersistableAttachment)) {
150                        try {
151                                Method[] methods = boAttachment.getClass().getMethods();
152                                for (Method method : methods) {
153                                        if (method.getName().equals(attachmentPropNmSetter)) {
154                                                attachmentFromBusinessObject =  (FormFile)(boAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(boAttachment));
155                                                if (attachmentFromBusinessObject != null) {
156                                                        //boAttachment.setAttachmentContent(attachmentFromBusinessObject.getFileData());
157                                                        boAttachment.setFileName(attachmentFromBusinessObject.getFileName());
158                                                        boAttachment.setContentType(attachmentFromBusinessObject.getContentType());
159                                                }
160                                                break;
161                                        }
162                                }
163                   } catch (Exception e) {
164                                LOG.error("Not able to get the attachment " + e.getMessage());
165                                throw new RuntimeException("Not able to get the attachment " + e.getMessage());
166                   }
167          }
168      }
169
170      if((boAttachment.getFileName() == null) && (boAttachment instanceof PersistableAttachment) && (attachment != null)) {
171          //byte[] fileContents;
172          //fileContents = attachment.getAttachmentContent();
173          if (attachment.getFileName() != null) {
174              boAttachment.setAttachmentContent(null);
175              boAttachment.setFileName(attachment.getFileName());
176              boAttachment.setContentType(attachment.getContentType());
177          }
178       }
179    }
180
181    @Override
182    public void populateAttachmentBeforeSave() {
183        PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getDataObject();
184        if (attachment != null
185                && attachment.getAttachmentContent() != null) {
186            boAttachment.setAttachmentContent(attachment.getAttachmentContent());
187        } else {
188            boAttachment.setAttachmentContent(null);
189            boAttachment.setFileName(null);
190            boAttachment.setContentType(null);
191        }
192    }
193
194    @Override
195    public void populateBoAttachmentListBeforeSave() {
196
197        PersistableAttachmentList<PersistableAttachment> boAttachments = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject();
198        if (CollectionUtils.isEmpty(attachments)) {
199            //there are no attachments.  Clear out Bo Attachments
200            boAttachments.setAttachments(Collections.<PersistableAttachment>emptyList());
201            return;
202        }
203        Map<String, MultiDocumentAttachment> files = new HashMap<String, MultiDocumentAttachment>();
204        for (MultiDocumentAttachment multiAttach : attachments) {
205            String key = new StringBuffer(multiAttach.getFileName()).append("|").append(multiAttach.getContentType()).toString();
206            files.put(key, multiAttach);
207        }
208
209
210        //want to just copy over file if possible, as there can be other fields that are not on PersistableAttachment
211        //these arrays should be somewhat synched by the other populate methods
212        if (CollectionUtils.isNotEmpty(boAttachments.getAttachments())) {
213            for (PersistableAttachment attach : boAttachments.getAttachments()) {
214                //try to get a new instance of the correct object...
215                String key = new StringBuffer(attach.getFileName()).append("|").append(attach.getContentType()).toString();
216                if (files.containsKey(key)) {
217                    attach.setAttachmentContent(files.get(key).getAttachmentContent());
218                    files.remove(key);
219                }
220            }
221        }
222    }
223
224    @Override
225    public void populateAttachmentListForBO() {
226        refreshAttachmentList();
227
228        PersistableAttachmentList<PersistableAttachment> boAttachments = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject();
229
230        if (ObjectUtils.isNotNull(getAttachmentListPropertyName())) {
231            //String collectionName = getAttachmentCollectionName();
232            String attachmentPropNm = getAttachmentListPropertyName();
233            String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length());
234
235
236            for (PersistableAttachment persistableAttachment : boAttachments.getAttachments()) {
237                if((persistableAttachment.getFileName() == null)) {
238                    try {
239                        FormFile attachmentFromBusinessObject =  (FormFile)(persistableAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(persistableAttachment));
240                        if (attachmentFromBusinessObject != null) {
241                            //persistableAttachment.setAttachmentContent(
242                            //        attachmentFromBusinessObject.getFileData());
243                            persistableAttachment.setFileName(attachmentFromBusinessObject.getFileName());
244                            persistableAttachment.setContentType(attachmentFromBusinessObject.getContentType());
245                        }
246                    } catch (Exception e) {
247                        LOG.error("Not able to get the attachment " + e.getMessage());
248                        throw new RuntimeException("Not able to get the attachment " + e.getMessage());
249                    }
250                }
251            }
252        }
253        if((CollectionUtils.isEmpty(boAttachments.getAttachments())
254                && (CollectionUtils.isNotEmpty(attachments)))) {
255
256            List<PersistableAttachment> attachmentList = new ArrayList<PersistableAttachment>();
257            for (MultiDocumentAttachment multiAttach : attachments) {
258
259                //try to get a new instance of the correct object...
260                if (multiAttach.getAttachmentContent().length > 0) {
261                    PersistableAttachment persistableAttachment = convertDocToBoAttachment(multiAttach, false);
262                    attachmentList.add(persistableAttachment);
263                }
264            }
265            boAttachments.setAttachments(attachmentList);
266        }
267    }
268
269    private PersistableAttachment convertDocToBoAttachment(MultiDocumentAttachment multiAttach, boolean copyFile) {
270        PersistableAttachment persistableAttachment = new PersistableAttachmentBase();
271
272        if (copyFile
273                && multiAttach.getAttachmentContent() != null) {
274            persistableAttachment.setAttachmentContent(multiAttach.getAttachmentContent());
275        }
276        persistableAttachment.setFileName(multiAttach.getFileName());
277        persistableAttachment.setContentType(multiAttach.getContentType());
278        return persistableAttachment;
279    }
280
281    @Override
282    public void populateDocumentAttachmentList() {
283        refreshAttachmentList();
284
285        String attachmentPropNm = getAttachmentListPropertyName();
286        String attachmentPropNmSetter = "get" + attachmentPropNm.substring(0, 1).toUpperCase() + attachmentPropNm.substring(1, attachmentPropNm.length());
287        //don't have form fields to use to fill, but they should be populated on the DataObject.  grab them from there.
288        PersistableAttachmentList<PersistableAttachment> boAttachmentList = (PersistableAttachmentList<PersistableAttachment>) newMaintainableObject.getDataObject();
289
290        if (CollectionUtils.isNotEmpty(boAttachmentList.getAttachments())) {
291
292
293            //build map for comparison
294            Map<String, MultiDocumentAttachment> md5Hashes = new HashMap<String, MultiDocumentAttachment>();
295            if (CollectionUtils.isNotEmpty(attachments)) {
296                for (MultiDocumentAttachment currentAttachment : attachments) {
297                    md5Hashes.put(DigestUtils.md5Hex(currentAttachment.getAttachmentContent()), currentAttachment);
298                }
299            }
300
301            //Populate DocumentAttachment BO
302            attachments = new ArrayList<MultiDocumentAttachment>();
303
304            for (PersistableAttachment persistableAttachment : boAttachmentList.getAttachments()) {
305                try {
306                    FormFile attachmentFromBusinessObject =  (FormFile)(persistableAttachment.getClass().getDeclaredMethod(attachmentPropNmSetter).invoke(persistableAttachment));
307                    if (attachmentFromBusinessObject != null) {
308                        //
309                        //byte[] fileContents = attachmentFromBusinessObject.getFileData();
310                        String md5Hex = DigestUtils.md5Hex(attachmentFromBusinessObject.getInputStream());
311                        if (md5Hashes.containsKey(md5Hex)) {
312                            String newFileName = attachmentFromBusinessObject.getFileName();
313                            MultiDocumentAttachment multiAttach = md5Hashes.get(md5Hex);
314                            if (multiAttach.getFileName().equals(newFileName)) {
315                                attachments.add(multiAttach);
316                            } else {
317                                multiAttach.setFileName(attachmentFromBusinessObject.getFileName());
318                                multiAttach.setContentType(attachmentFromBusinessObject.getContentType());
319                                attachments.add(multiAttach);
320                            }
321                            md5Hashes.remove(md5Hex);
322                        } else {
323                            MultiDocumentAttachment attach = new MultiDocumentAttachment();
324                            attach.setFileName(attachmentFromBusinessObject.getFileName());
325                            attach.setContentType(attachmentFromBusinessObject.getContentType());
326                            attach.setAttachmentContent(attachmentFromBusinessObject.getFileData());
327                            attach.setDocumentNumber(getDocumentNumber());
328                            attachments.add(attach);
329                        }
330                    } else {
331                        if (persistableAttachment.getFileName() != null
332                                && persistableAttachment.getAttachmentContent() != null) {
333                            MultiDocumentAttachment attach = new MultiDocumentAttachment();
334                            attach.setFileName(persistableAttachment.getFileName());
335                            attach.setContentType(persistableAttachment.getContentType());
336                            attach.setAttachmentContent(persistableAttachment.getAttachmentContent());
337                            attach.setDocumentNumber(getDocumentNumber());
338
339                            //set Bo's content to null
340                            persistableAttachment.setAttachmentContent(null);
341                            attachments.add(attach);
342                        }
343                    }
344                } catch (Exception e) {
345                    LOG.error("Not able to get the attachment " + e.getMessage());
346                    throw new RuntimeException("Not able to get the attachment " + e.getMessage());
347                }
348            }
349
350        }
351    }
352
353}