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.krad.web.service.impl;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.file.FileMeta;
020import org.kuali.rice.krad.uif.UifConstants;
021import org.kuali.rice.krad.uif.UifParameters;
022import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
023import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
024import org.kuali.rice.krad.util.KRADUtils;
025import org.kuali.rice.krad.web.form.DialogResponse;
026import org.kuali.rice.krad.web.form.UifFormBase;
027import org.kuali.rice.krad.web.service.CollectionControllerService;
028import org.kuali.rice.krad.web.service.FileControllerService;
029import org.kuali.rice.krad.web.service.ModelAndViewService;
030import org.springframework.web.multipart.MultipartFile;
031import org.springframework.web.multipart.MultipartHttpServletRequest;
032import org.springframework.web.servlet.ModelAndView;
033
034import javax.servlet.http.HttpServletRequest;
035import javax.servlet.http.HttpServletResponse;
036import java.util.Collection;
037import java.util.Date;
038import java.util.Iterator;
039import java.util.List;
040import java.util.UUID;
041
042/**
043 * Default implementation of the file controller service.
044 *
045 * @author Kuali Rice Team (rice.collab@kuali.org)
046 */
047public class FileControllerServiceImpl implements FileControllerService {
048
049    protected static final String DELETE_FILE_UPLOAD_LINE_DIALOG = "DialogGroup-DeleteFileUploadLine";
050
051    private CollectionControllerService collectionControllerService;
052    private ModelAndViewService modelAndViewService;
053
054    /**
055     * {@inheritDoc}
056     */
057    @Override
058    public ModelAndView addFileUploadLine(final UifFormBase form) {
059        form.setAjaxReturnType(UifConstants.AjaxReturnTypes.UPDATECOMPONENT.getKey());
060        form.setAjaxRequest(true);
061
062        MultipartHttpServletRequest request = (MultipartHttpServletRequest) form.getRequest();
063
064        final String collectionId = request.getParameter(UifParameters.UPDATE_COMPONENT_ID);
065        final String bindingPath = request.getParameter(UifConstants.PostMetadata.BINDING_PATH);
066
067        Class<?> collectionObjectClass = (Class<?>) form.getViewPostMetadata().getComponentPostData(collectionId,
068                UifConstants.PostMetadata.COLL_OBJECT_CLASS);
069
070        Iterator<String> fileNamesItr = request.getFileNames();
071
072        while (fileNamesItr.hasNext()) {
073            String propertyPath = fileNamesItr.next();
074
075            MultipartFile uploadedFile = request.getFile(propertyPath);
076
077            final FileMeta fileObject = (FileMeta) KRADUtils.createNewObjectFromClass(collectionObjectClass);
078            try {
079                fileObject.init(uploadedFile);
080            } catch (Exception e) {
081                throw new RuntimeException("Unable to initialize new file object", e);
082            }
083
084            String id = UUID.randomUUID().toString() + "_" + uploadedFile.getName();
085            fileObject.setId(id);
086
087            fileObject.setDateUploaded(new Date());
088
089            fileObject.setUrl("?methodToCall=getFileFromLine&formKey="
090                    + form.getFormKey()
091                    + "&fileName="
092                    + fileObject.getName()
093                    + "&propertyPath="
094                    + propertyPath);
095
096            ViewLifecycle.encapsulateLifecycle(form.getView(), form, form.getViewPostMetadata(), null, request,
097                    new Runnable() {
098                        @Override
099                        public void run() {
100                            ViewLifecycle.getHelper().processAndAddLineObject(form, fileObject, collectionId,
101                                    bindingPath);
102                        }
103                    });
104        }
105
106        return getModelAndViewService().getModelAndView(form);
107    }
108
109    /**
110     * {@inheritDoc}
111     */
112    @Override
113    public ModelAndView deleteFileUploadLine(UifFormBase form) {
114        DialogResponse deleteFileUploadLineDialogResponse = form.getDialogResponse(DELETE_FILE_UPLOAD_LINE_DIALOG);
115
116        if (deleteFileUploadLineDialogResponse == null) {
117            // no confirmation dialog found, so create one on the form and return it
118            return getModelAndViewService().showDialog(DELETE_FILE_UPLOAD_LINE_DIALOG, true, form);
119        }
120
121        return getCollectionControllerService().deleteLine(form);
122    }
123
124    /**
125     * {@inheritDoc}
126     */
127    @Override
128    public void getFileFromLine(UifFormBase form, HttpServletResponse response) {
129        HttpServletRequest request = form.getRequest();
130
131        String selectedCollectionPath = request.getParameter("propertyPath");
132
133        if (StringUtils.isBlank(selectedCollectionPath)) {
134            throw new RuntimeException("Selected collection was not set for delete line action, cannot delete line");
135        }
136
137        String selectedLine = request.getParameter(UifParameters.SELECTED_LINE_INDEX);
138        int selectedLineIndex;
139        if (StringUtils.isNotBlank(selectedLine)) {
140            selectedLineIndex = Integer.parseInt(selectedLine);
141        } else {
142            selectedLineIndex = -1;
143        }
144
145        if (selectedLineIndex == -1) {
146            throw new RuntimeException("Selected line index was not set for delete line action, cannot delete line");
147        }
148
149        Collection<FileMeta> collection = ObjectPropertyUtils.getPropertyValue(form, selectedCollectionPath);
150
151        if (collection instanceof List) {
152            FileMeta fileLine = ((List<FileMeta>) collection).get(selectedLineIndex);
153            sendFileFromLineResponse(form, response, (List<FileMeta>) collection, fileLine);
154        }
155    }
156
157    /**
158     * Hook controller method to send a response back by using response.flushBuffer() using request/collection/fileLine
159     * information provided.
160     *
161     * <p>A sample implementation may look like:
162     * <code> <pre>
163     * if (fileLine instanceof FileMetaBlob) {
164     * InputStream is = ((FileMetaBlob) fileLine).getBlob().getBinaryStream();
165     * response.setContentType("application/force-download");
166     * response.setHeader("Content-Disposition", "attachment; filename=" + fileLine.getName());
167     *
168     * // copy it to response's OutputStream
169     * FileCopyUtils.copy(is, response.getOutputStream());
170     *
171     * response.flushBuffer();
172     * }
173     * </pre></code></p>
174     *
175     * @param form form instance containing the file request data
176     * @param response Http response object for streaming back the file contents
177     * @param collection collection the file object belongs to
178     * @param fileLine the particular file line instance the contents should be sent back for
179     */
180    protected void sendFileFromLineResponse(UifFormBase form, HttpServletResponse response, List<FileMeta> collection,
181            FileMeta fileLine) {
182        // empty method for overrides
183    }
184
185    protected CollectionControllerService getCollectionControllerService() {
186        return collectionControllerService;
187    }
188
189    public void setCollectionControllerService(CollectionControllerService collectionControllerService) {
190        this.collectionControllerService = collectionControllerService;
191    }
192
193    protected ModelAndViewService getModelAndViewService() {
194        return modelAndViewService;
195    }
196
197    public void setModelAndViewService(ModelAndViewService modelAndViewService) {
198        this.modelAndViewService = modelAndViewService;
199    }
200}