001    /**
002     * Copyright 2005-2013 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.document;
017    
018    import org.apache.commons.codec.digest.DigestUtils;
019    import org.apache.commons.collections.CollectionUtils;
020    import org.apache.commons.lang.StringUtils;
021    import org.apache.struts.upload.FormFile;
022    import org.kuali.rice.kns.maintenance.Maintainable;
023    import org.kuali.rice.krad.bo.DocumentAttachment;
024    import org.kuali.rice.krad.bo.MultiDocumentAttachment;
025    import org.kuali.rice.krad.bo.PersistableAttachment;
026    import org.kuali.rice.krad.bo.PersistableAttachmentBase;
027    import org.kuali.rice.krad.bo.PersistableAttachmentList;
028    import org.kuali.rice.krad.bo.PersistableBusinessObject;
029    import org.kuali.rice.krad.util.ObjectUtils;
030    
031    import javax.persistence.Transient;
032    import java.io.FileNotFoundException;
033    import java.io.IOException;
034    import java.lang.reflect.Method;
035    import java.util.ArrayList;
036    import java.util.Collections;
037    import java.util.HashMap;
038    import java.util.List;
039    import java.util.Map;
040    
041    /**
042     * @author Kuali Rice Team (rice.collab@kuali.org)
043     */
044    public 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    }