001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.web.struts.action;
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.core.authorization.AuthorizationType;
037: import org.kuali.core.bo.user.UniversalUser;
038: import org.kuali.core.exceptions.AuthorizationException;
039: import org.kuali.core.exceptions.ModuleAuthorizationException;
040: import org.kuali.core.util.GlobalVariables;
041: import org.kuali.core.util.WebUtils;
042: import org.kuali.core.web.struts.action.KualiAction;
043: import org.kuali.core.web.ui.KeyLabelPair;
044: import org.kuali.kfs.KFSConstants;
045: import org.kuali.kfs.KFSKeyConstants;
046: import org.kuali.kfs.batch.BatchInputFileSetType;
047: import org.kuali.kfs.batch.BatchSpringContext;
048: import org.kuali.kfs.bo.BatchUpload;
049: import org.kuali.kfs.context.SpringContext;
050: import org.kuali.kfs.exceptions.FileStorageException;
051: import org.kuali.kfs.service.BatchInputFileSetService;
052: import org.kuali.kfs.web.struts.form.KualiBatchInputFileSetForm;
053:
054: /**
055: * This class is the struts action for the batch upload screen that supports file sets
056: */
057: public class KualiBatchInputFileSetAction extends KualiAction {
058: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
059: .getLogger(KualiBatchInputFileSetAction.class);
060:
061: /**
062: * @see org.kuali.core.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping,
063: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
064: */
065: @Override
066: public ActionForward execute(ActionMapping mapping,
067: ActionForm form, HttpServletRequest request,
068: HttpServletResponse response) throws Exception {
069: ActionForward forward = super .execute(mapping, form, request,
070: response);
071: setupForm((KualiBatchInputFileSetForm) form);
072: return forward;
073: }
074:
075: /**
076: * First verifies the user is active for the module in which the batch input type is in, then calls batch input service to
077: * authorize the user for the specific batch input type.
078: *
079: * @see org.kuali.core.web.struts.action.KualiAction#checkAuthorization(org.apache.struts.action.ActionForm, java.lang.String)
080: */
081: @Override
082: protected void checkAuthorization(ActionForm form,
083: String methodToCall) throws AuthorizationException {
084: BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form)
085: .getBatchUpload();
086: BatchInputFileSetType batchInputFileType = retrieveBatchInputFileSetTypeImpl(batchUpload
087: .getBatchInputTypeName());
088:
089: AuthorizationType defaultAuthorizationType = new AuthorizationType.Default(
090: batchInputFileType.getClass());
091: if (!getKualiModuleService().isAuthorized(
092: GlobalVariables.getUserSession().getUniversalUser(),
093: defaultAuthorizationType)) {
094: LOG
095: .error("User not authorized for lookup action for this object: "
096: + batchInputFileType.getClass().getName());
097: throw new ModuleAuthorizationException(GlobalVariables
098: .getUserSession().getUniversalUser()
099: .getPersonUserIdentifier(),
100: defaultAuthorizationType, getKualiModuleService()
101: .getResponsibleModule(
102: batchInputFileType.getClass()));
103: }
104:
105: boolean isAuthorizedForType = SpringContext.getBean(
106: BatchInputFileSetService.class)
107: .isUserAuthorizedForBatchType(
108: batchInputFileType,
109: GlobalVariables.getUserSession()
110: .getUniversalUser());
111: if (!isAuthorizedForType) {
112: LOG.error("User "
113: + GlobalVariables.getUserSession()
114: .getUniversalUser()
115: .getPersonUserIdentifier()
116: + " is not authorized for batch type "
117: + batchInputFileType.getFileSetTypeIdentifer());
118: throw new AuthorizationException(GlobalVariables
119: .getUserSession().getUniversalUser()
120: .getPersonUserIdentifier(), "upload",
121: batchInputFileType.getFileSetTypeIdentifer());
122: }
123: }
124:
125: /**
126: * Forwards to the batch upload JSP. Initial request.
127: */
128: public ActionForward start(ActionMapping mapping, ActionForm form,
129: HttpServletRequest request, HttpServletResponse response)
130: throws Exception {
131: BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form)
132: .getBatchUpload();
133: BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload
134: .getBatchInputTypeName());
135: if (batchType.isSupportsDoneFileCreation()) {
136:
137: }
138: return mapping.findForward(KFSConstants.MAPPING_BASIC);
139: }
140:
141: /**
142: * Sends the uploaded file contents, requested file name, and batch type to the BatchInputTypeService for storage. If errors
143: * were encountered, messages will be in GlobalVariables.errorMap, which is checked and set for display by the request
144: * processor.
145: */
146: public ActionForward save(ActionMapping mapping, ActionForm form,
147: HttpServletRequest request, HttpServletResponse response)
148: throws Exception {
149: BatchUpload batchUpload = ((KualiBatchInputFileSetForm) form)
150: .getBatchUpload();
151: BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload
152: .getBatchInputTypeName());
153:
154: boolean requiredValuesForFilesMissing = false;
155: if (StringUtils.isBlank(batchUpload.getFileUserIdentifer())) {
156: GlobalVariables
157: .getErrorMap()
158: .putError(
159: KFSConstants.GLOBAL_ERRORS,
160: KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SET_IDENTIFIER_SELECTED,
161: new String[] {});
162: requiredValuesForFilesMissing = true;
163: }
164:
165: BatchInputFileSetService batchInputFileSetService = SpringContext
166: .getBean(BatchInputFileSetService.class);
167: if (!batchInputFileSetService
168: .isFileUserIdentifierProperlyFormatted(batchUpload
169: .getFileUserIdentifer())) {
170: GlobalVariables
171: .getErrorMap()
172: .putError(
173: KFSConstants.GLOBAL_ERRORS,
174: KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SET_IDENTIFIER_BAD_FORMAT);
175: requiredValuesForFilesMissing = true;
176: }
177:
178: Map<String, FormFile> uploadedFiles = ((KualiBatchInputFileSetForm) form)
179: .getUploadedFiles();
180: Map<String, InputStream> typeToStreamMap = new HashMap<String, InputStream>();
181:
182: for (String fileType : uploadedFiles.keySet()) {
183: FormFile uploadedFile = uploadedFiles.get(fileType);
184: if (uploadedFile == null
185: || uploadedFile.getInputStream() == null
186: || uploadedFile.getInputStream().available() == 0) {
187: GlobalVariables
188: .getErrorMap()
189: .putError(
190: KFSConstants.GLOBAL_ERRORS,
191: KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SELECTED_SAVE_FOR_FILE_TYPE,
192: new String[] { batchType
193: .getFileTypeDescription().get(
194: fileType) });
195: requiredValuesForFilesMissing = true;
196: } else {
197: typeToStreamMap.put(fileType, uploadedFile
198: .getInputStream());
199: }
200: }
201:
202: if (requiredValuesForFilesMissing) {
203: return mapping.findForward(KFSConstants.MAPPING_BASIC);
204: }
205:
206: try {
207: Map<String, String> typeToSavedFileNames = batchInputFileSetService
208: .save(GlobalVariables.getUserSession()
209: .getUniversalUser(), batchType, batchUpload
210: .getFileUserIdentifer(), typeToStreamMap,
211: ((KualiBatchInputFileSetForm) form)
212: .isSupressDoneFileCreation());
213: } catch (FileStorageException e) {
214: LOG
215: .error(
216: "Error occured while trying to save file set (probably tried to save a file that already exists).",
217: e);
218: GlobalVariables.getErrorMap().putError(
219: KFSConstants.GLOBAL_ERRORS,
220: KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SAVE_ERROR,
221: new String[] { e.getMessage() });
222: return mapping.findForward(KFSConstants.MAPPING_BASIC);
223: }
224: GlobalVariables.getMessageList().add(
225: KFSKeyConstants.MESSAGE_BATCH_UPLOAD_SAVE_SUCCESSFUL);
226:
227: return mapping.findForward(KFSConstants.MAPPING_BASIC);
228: }
229:
230: /**
231: * Deletes an existing batch file set. If errors were encountered, messages will be in GlobalVariables.errorMap, which is
232: * checked and set for display by the request processor.
233: */
234: public ActionForward delete(ActionMapping mapping, ActionForm form,
235: HttpServletRequest request, HttpServletResponse response)
236: throws Exception {
237: KualiBatchInputFileSetForm kualiBatchInputFileSetForm = (KualiBatchInputFileSetForm) form;
238: BatchUpload batchUpload = kualiBatchInputFileSetForm
239: .getBatchUpload();
240:
241: if (StringUtils.isBlank(batchUpload.getExistingFileName())) {
242: GlobalVariables
243: .getErrorMap()
244: .putError(
245: KFSConstants.GLOBAL_ERRORS,
246: KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SELECTED_DELETE,
247: new String[] {});
248: return mapping.findForward(KFSConstants.MAPPING_BASIC);
249: }
250:
251: BatchInputFileSetService batchInputFileSetService = SpringContext
252: .getBean(BatchInputFileSetService.class);
253: if (!batchInputFileSetService
254: .isFileUserIdentifierProperlyFormatted(batchUpload
255: .getExistingFileName())) {
256: GlobalVariables
257: .getErrorMap()
258: .putError(
259: KFSConstants.GLOBAL_ERRORS,
260: KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SET_IDENTIFIER_BAD_FORMAT);
261: return mapping.findForward(KFSConstants.MAPPING_BASIC);
262: }
263:
264: BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload
265: .getBatchInputTypeName());
266: try {
267: boolean deleteSuccessful = batchInputFileSetService
268: .delete(GlobalVariables.getUserSession()
269: .getUniversalUser(), batchType, batchUpload
270: .getExistingFileName());
271:
272: if (deleteSuccessful) {
273: GlobalVariables
274: .getMessageList()
275: .add(
276: KFSKeyConstants.MESSAGE_BATCH_UPLOAD_DELETE_SUCCESSFUL);
277: }
278: } catch (FileNotFoundException e1) {
279: LOG.error("errors deleting file " + e1.getMessage(), e1);
280: GlobalVariables.getErrorMap().putError(
281: KFSConstants.GLOBAL_ERRORS,
282: KFSKeyConstants.ERROR_BATCH_UPLOAD_DELETE,
283: new String[] { e1.getMessage() });
284: }
285:
286: return mapping.findForward(KFSConstants.MAPPING_BASIC);
287: }
288:
289: /**
290: * Retrieves the contents of an uploaded batch file. If errors were encountered, messages will be in GlobalVariables.errorMap,
291: * which is checked and set for display by the request processor.
292: */
293: public ActionForward download(ActionMapping mapping,
294: ActionForm form, HttpServletRequest request,
295: HttpServletResponse response) throws Exception {
296: KualiBatchInputFileSetForm kualiBatchInputFileSetForm = (KualiBatchInputFileSetForm) form;
297: BatchUpload batchUpload = kualiBatchInputFileSetForm
298: .getBatchUpload();
299:
300: if (StringUtils.isBlank(batchUpload.getExistingFileName())) {
301: GlobalVariables
302: .getErrorMap()
303: .putError(
304: KFSConstants.GLOBAL_ERRORS,
305: KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_SELECTED_DOWNLOAD,
306: new String[] {});
307: return mapping.findForward(KFSConstants.MAPPING_BASIC);
308: }
309:
310: if (StringUtils.isBlank(kualiBatchInputFileSetForm
311: .getDownloadFileType())) {
312: GlobalVariables
313: .getErrorMap()
314: .putError(
315: KFSConstants.GLOBAL_ERRORS,
316: KFSKeyConstants.ERROR_BATCH_UPLOAD_NO_FILE_TYPE_SELECTED_DOWNLOAD,
317: new String[] {});
318: return mapping.findForward(KFSConstants.MAPPING_BASIC);
319: }
320:
321: BatchInputFileSetService batchInputFileSetService = SpringContext
322: .getBean(BatchInputFileSetService.class);
323: if (!batchInputFileSetService
324: .isFileUserIdentifierProperlyFormatted(batchUpload
325: .getExistingFileName())) {
326: GlobalVariables
327: .getErrorMap()
328: .putError(
329: KFSConstants.GLOBAL_ERRORS,
330: KFSKeyConstants.ERROR_BATCH_UPLOAD_FILE_SET_IDENTIFIER_BAD_FORMAT);
331: return mapping.findForward(KFSConstants.MAPPING_BASIC);
332: }
333:
334: BatchInputFileSetType batchType = retrieveBatchInputFileSetTypeImpl(batchUpload
335: .getBatchInputTypeName());
336: File batchInputFile = null;
337: try {
338: batchInputFile = batchInputFileSetService
339: .download(GlobalVariables.getUserSession()
340: .getUniversalUser(), batchType,
341: kualiBatchInputFileSetForm
342: .getDownloadFileType(), batchUpload
343: .getExistingFileName());
344: } catch (FileNotFoundException e1) {
345: LOG.error("errors downloading file " + e1.getMessage(), e1);
346: GlobalVariables.getErrorMap().putError(
347: KFSConstants.GLOBAL_ERRORS,
348: KFSKeyConstants.ERROR_BATCH_UPLOAD_DOWNLOAD,
349: new String[] { e1.getMessage() });
350:
351: return mapping.findForward(KFSConstants.MAPPING_BASIC);
352: }
353:
354: WebUtils.saveMimeInputStreamAsFile(response, "text/plain",
355: new FileInputStream(batchInputFile), batchInputFile
356: .getName(), new Long(batchInputFile.length())
357: .intValue());
358:
359: return null;
360: }
361:
362: /**
363: * Retrieves a BatchInputFileType implementation from Spring based on the given name.
364: */
365: private BatchInputFileSetType retrieveBatchInputFileSetTypeImpl(
366: String batchInputTypeName) {
367: BatchInputFileSetType batchInputType = BatchSpringContext
368: .getBatchInputFileSetType(batchInputTypeName);
369: if (batchInputType == null) {
370: LOG
371: .error("Batch input type implementation not found for id "
372: + batchInputTypeName);
373: throw new RuntimeException(
374: ("Batch input type implementation not found for id " + batchInputTypeName));
375: }
376:
377: return batchInputType;
378: }
379:
380: /**
381: * Builds list of filenames that the user has permission to manage, and populates the form member. Throws an exception if the
382: * batch file set type is not active. Sets the title key from the batch input type. This method must be called before the action
383: * handler to ensure proper authorization.
384: */
385: private void setupForm(KualiBatchInputFileSetForm form) {
386: List<KeyLabelPair> userFiles = new ArrayList<KeyLabelPair>();
387:
388: UniversalUser user = GlobalVariables.getUserSession()
389: .getUniversalUser();
390: BatchInputFileSetType batchInputFileSetType = retrieveBatchInputFileSetTypeImpl(form
391: .getBatchUpload().getBatchInputTypeName());
392:
393: if (batchInputFileSetType == null) {
394: LOG
395: .error("Batch input type implementation not found for id "
396: + form.getBatchUpload()
397: .getBatchInputTypeName());
398: throw new RuntimeException(
399: "Batch input type implementation not found for id "
400: + form.getBatchUpload()
401: .getBatchInputTypeName());
402: }
403:
404: if (!SpringContext.getBean(BatchInputFileSetService.class)
405: .isBatchInputTypeActive(batchInputFileSetType)) {
406: throw new RuntimeException(
407: "Batch input file set type is not active.");
408: }
409: form.setBatchInputFileSetType(batchInputFileSetType);
410:
411: BatchInputFileSetService batchInputFileSetService = SpringContext
412: .getBean(BatchInputFileSetService.class);
413: Set<String> fileUserIdentifiers = batchInputFileSetService
414: .listBatchTypeFileUserIdentifiersForUser(
415: batchInputFileSetType, user);
416:
417: userFiles.add(new KeyLabelPair("",
418: "Select a File Set Identifier"));
419: for (String fileUserIdentifier : fileUserIdentifiers) {
420: String label = fileUserIdentifier;
421: if (batchInputFileSetService.hasBeenProcessed(user,
422: batchInputFileSetType, fileUserIdentifier)) {
423: label = label + " (processed)";
424: } else {
425: label = label + " (ready to process)";
426: }
427: userFiles.add(new KeyLabelPair(fileUserIdentifier, label));
428: }
429: form.setFileUserIdentifiers(userFiles);
430:
431: List<KeyLabelPair> fileTypes = new ArrayList<KeyLabelPair>();
432: fileTypes.add(new KeyLabelPair("",
433: "Select a file type to download"));
434: for (String fileAlias : batchInputFileSetType.getFileTypes()) {
435: fileTypes.add(new KeyLabelPair(fileAlias,
436: batchInputFileSetType.getFileTypeDescription().get(
437: fileAlias)));
438: }
439: form.setFileTypes(fileTypes);
440:
441: // set title key
442: form.setTitleKey(batchInputFileSetType.getTitleKey());
443: }
444:
445: }
|