001    /*
002     * Copyright 2011 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.kfs.sys.web.struts;
017    
018    import java.io.File;
019    import java.io.FileInputStream;
020    import java.io.FileNotFoundException;
021    import java.io.InputStream;
022    import java.util.ArrayList;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.Map;
026    import java.util.Set;
027    
028    import javax.servlet.http.HttpServletRequest;
029    import javax.servlet.http.HttpServletResponse;
030    
031    import org.apache.commons.lang.StringUtils;
032    import org.apache.struts.action.ActionForm;
033    import org.apache.struts.action.ActionForward;
034    import org.apache.struts.action.ActionMapping;
035    import org.apache.struts.upload.FormFile;
036    import org.kuali.kfs.sys.KFSConstants;
037    import org.kuali.kfs.sys.KFSKeyConstants;
038    import org.kuali.kfs.sys.batch.BatchInputFileSetType;
039    import org.kuali.kfs.sys.batch.BatchSpringContext;
040    import org.kuali.kfs.sys.batch.service.BatchInputFileSetService;
041    import org.kuali.kfs.sys.businessobject.BatchUpload;
042    import org.kuali.kfs.sys.context.SpringContext;
043    import org.kuali.kfs.sys.exception.FileStorageException;
044    import org.kuali.rice.kim.bo.Person;
045    import org.kuali.rice.kim.bo.impl.KimAttributes;
046    import org.kuali.rice.kim.bo.types.dto.AttributeSet;
047    import org.kuali.rice.kim.service.IdentityManagementService;
048    import org.kuali.rice.kim.util.KimCommonUtils;
049    import org.kuali.rice.kim.util.KimConstants;
050    import org.kuali.rice.kns.exception.AuthorizationException;
051    import org.kuali.rice.kns.exception.ValidationException;
052    import org.kuali.rice.kns.util.GlobalVariables;
053    import org.kuali.rice.kns.util.KNSConstants;
054    import org.kuali.rice.kns.util.WebUtils;
055    import org.kuali.rice.kns.web.struts.action.KualiAction;
056    import org.kuali.rice.core.util.KeyLabelPair;
057    
058    /**
059     * This class is the struts action for the batch upload screen that supports file sets
060     */
061    public class KualiBatchInputFileSetAction extends KualiAction {
062        private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiBatchInputFileSetAction.class);
063        private static IdentityManagementService identityManagementService;
064        private IdentityManagementService getIdentityManagementService() {
065            if (identityManagementService == null) {
066                identityManagementService = SpringContext.getBean(IdentityManagementService.class);
067            }
068            return identityManagementService;
069        }
070    
071        /**
072         * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping,
073         *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
074         */
075        @Override
076        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
077            ActionForward forward = super.execute(mapping, form, request, response);
078            setupForm((KualiBatchInputFileSetForm) form);
079            return forward;
080        }
081    
082        /**
083         * @see org.kuali.rice.kns.web.struts.action.KualiAction#checkAuthorization(org.apache.struts.action.ActionForm, java.lang.String)
084         */
085        @Override
086        protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
087            BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form).getBatchUpload();
088            BatchInputFileSetType batchInputFileType = retrieveBatchInputFileSetTypeImpl(batchUpload.getBatchInputTypeName());
089            AttributeSet permissionDetails = new AttributeSet();
090            permissionDetails.put(KimAttributes.NAMESPACE_CODE, KimCommonUtils.getNamespaceCode(batchInputFileType.getClass()));
091            permissionDetails.put(KimAttributes.BEAN_NAME, batchUpload.getBatchInputTypeName());
092            if (!getIdentityManagementService().isAuthorizedByTemplateName(GlobalVariables.getUserSession().getPrincipalId(), KNSConstants.KNS_NAMESPACE, KFSConstants.PermissionTemplate.UPLOAD_BATCH_INPUT_FILES.name, permissionDetails, null)) {
093                throw new AuthorizationException(GlobalVariables.getUserSession().getPrincipalName(), methodToCall, batchUpload.getBatchInputTypeName());
094            }
095        }
096    
097        /**
098         * Forwards to the batch upload JSP. Initial request.
099         */
100        public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
101            BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form).getBatchUpload();
102            BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload.getBatchInputTypeName());
103            return mapping.findForward(KFSConstants.MAPPING_BASIC);
104        }
105    
106        /**
107         * Sends the uploaded file contents, requested file name, and batch type to the BatchInputTypeService for storage. If errors
108         * were encountered, messages will be in GlobalVariables.errorMap, which is checked and set for display by the request
109         * processor.
110         */
111        public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
112            BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form).getBatchUpload();
113            BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload.getBatchInputTypeName());
114    
115            boolean requiredValuesForFilesMissing = false;
116            if (StringUtils.isBlank(batchUpload.getFileUserIdentifer())) {
117                GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SET_IDENTIFIER_SELECTED, new String[] {});
118                requiredValuesForFilesMissing = true;
119            }
120    
121            BatchInputFileSetService batchInputFileSetService = SpringContext.getBean(BatchInputFileSetService.class);
122            if (!batchInputFileSetService.isFileUserIdentifierProperlyFormatted(batchUpload.getFileUserIdentifer())) {
123                GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SET_IDENTIFIER_BAD_FORMAT);
124                requiredValuesForFilesMissing = true;
125            }
126    
127            Map<String, FormFile> uploadedFiles = ((KualiBatchInputFileSetForm) form).getUploadedFiles();
128            Map<String, InputStream> typeToStreamMap = new HashMap<String, InputStream>();
129    
130            for (String fileType : uploadedFiles.keySet()) {
131                FormFile uploadedFile = uploadedFiles.get(fileType);
132                if (uploadedFile == null || uploadedFile.getInputStream() == null || uploadedFile.getInputStream().available() == 0) {
133                    GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SELECTED_SAVE_FOR_FILE_TYPE, new String[] { batchType.getFileTypeDescription().get(fileType) });
134                    requiredValuesForFilesMissing = true;
135                }
136                else {
137                    typeToStreamMap.put(fileType, uploadedFile.getInputStream());
138                }
139            }
140    
141            if (requiredValuesForFilesMissing) {
142                return mapping.findForward(KFSConstants.MAPPING_BASIC);
143            }
144    
145            try {
146                Map<String, String> typeToSavedFileNames = batchInputFileSetService.save(GlobalVariables.getUserSession().getPerson(), batchType, batchUpload.getFileUserIdentifer(), typeToStreamMap);
147            }
148            catch (FileStorageException e) {
149                LOG.error("Error occured while trying to save file set (probably tried to save a file that already exists).", e);
150                GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SAVE_ERROR, new String[] { e.getMessage() });
151                return mapping.findForward(KFSConstants.MAPPING_BASIC);
152            }
153            catch (ValidationException e) {
154                LOG.error("Error occured while trying to validate file set.", e);
155                GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_VALIDATION_ERROR);
156                return mapping.findForward(KFSConstants.MAPPING_BASIC);
157            }
158            GlobalVariables.getMessageList().add(KFSKeyConstants.MESSAGE_BATCH_UPLOAD_SAVE_SUCCESSFUL);
159    
160            return mapping.findForward(KFSConstants.MAPPING_BASIC);
161        }
162    
163        /**
164         * Retrieves a BatchInputFileType implementation from Spring based on the given name.
165         */
166        public BatchInputFileSetType retrieveBatchInputFileSetTypeImpl(String batchInputTypeName) {
167            BatchInputFileSetType batchInputType = BatchSpringContext.getBatchInputFileSetType(batchInputTypeName);
168            if (batchInputType == null) {
169                LOG.error("Batch input type implementation not found for id " + batchInputTypeName);
170                throw new RuntimeException(("Batch input type implementation not found for id " + batchInputTypeName));
171            }
172    
173            return batchInputType;
174        }
175    
176        /**
177         * Builds list of filenames that the user has permission to manage, and populates the form member. Throws an exception if the
178         * batch file set type is not active. Sets the title key from the batch input type. This method must be called before the action
179         * handler to ensure proper authorization.
180         */
181        public void setupForm(KualiBatchInputFileSetForm form) {
182            BatchInputFileSetType batchInputFileSetType = retrieveBatchInputFileSetTypeImpl(form.getBatchUpload().getBatchInputTypeName());
183    
184            if (batchInputFileSetType == null) {
185                LOG.error("Batch input type implementation not found for id " + form.getBatchUpload().getBatchInputTypeName());
186                throw new RuntimeException("Batch input type implementation not found for id " + form.getBatchUpload().getBatchInputTypeName());
187            }
188    
189            if (!SpringContext.getBean(BatchInputFileSetService.class).isBatchInputTypeActive(batchInputFileSetType)) {
190                throw new RuntimeException("Batch input file set type is not active.");
191            }
192            form.setBatchInputFileSetType(batchInputFileSetType);
193    
194            // set title key
195            form.setTitleKey(batchInputFileSetType.getTitleKey());
196        }
197    
198    }
199