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.service.impl;
017:
018: import java.io.File;
019: import java.io.FileNotFoundException;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.util.ArrayList;
024: import java.util.Collections;
025: import java.util.LinkedHashMap;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Set;
029:
030: import org.apache.commons.lang.StringUtils;
031: import org.kuali.core.bo.user.UniversalUser;
032: import org.kuali.core.exceptions.AuthorizationException;
033: import org.kuali.core.util.GlobalVariables;
034: import org.kuali.kfs.KFSConstants;
035: import org.kuali.kfs.KFSKeyConstants;
036: import org.kuali.kfs.KFSConstants.SystemGroupParameterNames;
037: import org.kuali.kfs.batch.BatchInputFileSetType;
038: import org.kuali.kfs.context.SpringContext;
039: import org.kuali.kfs.exceptions.FileStorageException;
040: import org.kuali.kfs.service.BatchInputFileSetService;
041: import org.kuali.kfs.service.ParameterService;
042:
043: /**
044: * Base implementation to manipulate batch input file sets from the batch upload screen
045: */
046: public class BatchInputFileSetServiceImpl implements
047: BatchInputFileSetService {
048: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
049: .getLogger(BatchInputFileSetServiceImpl.class);
050:
051: /**
052: * Generates the file name of a file (not the done file)
053: *
054: * @param user the user who uploaded or will upload the file
055: * @param inputType the file set type
056: * @param fileUserIdentifier the file identifier
057: * @param fileType the file type
058: * @return the file name, starting with the directory path
059: */
060: protected String generateFileName(UniversalUser user,
061: BatchInputFileSetType inputType, String fileUserIdentifier,
062: String fileType) {
063: if (!isFileUserIdentifierProperlyFormatted(fileUserIdentifier)) {
064: throw new IllegalArgumentException(
065: "The file set identifier is not properly formatted: "
066: + fileUserIdentifier);
067: }
068: return inputType.getDirectoryPath(fileType)
069: + File.separator
070: + inputType.getFileName(fileType, user,
071: fileUserIdentifier);
072: }
073:
074: /**
075: * Generates the file name of the done file, if supported by the underlying input type
076: *
077: * @param user the user who uploaded or will upload the file
078: * @param inputType the file set type
079: * @param fileUserIdentifier the file identifier
080: * @param fileType the file type
081: * @return the file name, starting with the directory path
082: */
083: protected String generateDoneFileName(UniversalUser user,
084: BatchInputFileSetType inputType, String fileUserIdentifier) {
085: if (!isFileUserIdentifierProperlyFormatted(fileUserIdentifier)) {
086: throw new IllegalArgumentException(
087: "The file set identifier is not properly formatted: "
088: + fileUserIdentifier);
089: }
090: return inputType.getDoneFileDirectoryPath() + File.separator
091: + inputType.getDoneFileName(user, fileUserIdentifier);
092: }
093:
094: /**
095: * @see org.kuali.kfs.service.BatchInputFileSetService#delete(org.kuali.core.bo.user.UniversalUser,
096: * org.kuali.kfs.batch.BatchInputFileSetType, java.lang.String)
097: */
098: public boolean delete(UniversalUser user,
099: BatchInputFileSetType inputType, String fileUserIdentifier)
100: throws AuthorizationException, FileNotFoundException {
101: if (user == null || inputType == null
102: || StringUtils.isBlank(fileUserIdentifier)) {
103: LOG.error("an invalid(null) argument was given");
104: throw new IllegalArgumentException(
105: "an invalid(null) argument was given");
106: }
107:
108: // check user is authorized to delete a file for the batch type
109: if (!this .isUserAuthorizedForBatchType(inputType, user)) {
110: LOG
111: .error("User "
112: + user.getPersonUserIdentifier()
113: + " is not authorized to delete a file of batch type "
114: + inputType.getFileSetTypeIdentifer());
115: throw new AuthorizationException(user
116: .getPersonUserIdentifier(), "delete", inputType
117: .getFileSetTypeIdentifer());
118: }
119:
120: if (!canDelete(user, inputType, fileUserIdentifier)) {
121: return false;
122: }
123:
124: for (String fileType : inputType.getFileTypes()) {
125: String fileName = generateFileName(user, inputType,
126: fileUserIdentifier, fileType);
127: File file = new File(fileName);
128: if (file.exists()) {
129: file.delete();
130: }
131: }
132: File doneFile = new File(generateDoneFileName(user, inputType,
133: fileUserIdentifier));
134: if (doneFile.exists()) {
135: doneFile.delete();
136: }
137: return true;
138: }
139:
140: /**
141: * Determines whether a file set may be deleted, and if not, it will populate the GlobalVariable's error map with the reason why
142: * not
143: *
144: * @param user
145: * @param inputType
146: * @param fileUserIdentifier
147: * @return
148: * @throws AuthorizationException
149: * @throws FileNotFoundException
150: */
151: protected boolean canDelete(UniversalUser user,
152: BatchInputFileSetType inputType, String fileUserIdentifier)
153: throws AuthorizationException, FileNotFoundException {
154: // we can only delete if we're authorized on each of the files of the file set
155: for (String fileType : inputType.getFileTypes()) {
156: String fileName = generateFileName(user, inputType,
157: fileUserIdentifier, fileType);
158: File file = new File(fileName);
159: if (file.exists()) {
160: if (!inputType.checkAuthorization(user, file)) {
161: GlobalVariables
162: .getErrorMap()
163: .putError(
164: KFSConstants.GLOBAL_ERRORS,
165: KFSKeyConstants.ERROR_BATCH_UPLOAD_DELETE_FAILED_FILE_SET_NOT_AUTHORIZED);
166: return false;
167: }
168: }
169: }
170:
171: // and the file hasn't been processed
172: if (hasBeenProcessed(user, inputType, fileUserIdentifier)) {
173: GlobalVariables
174: .getErrorMap()
175: .putError(
176: KFSConstants.GLOBAL_ERRORS,
177: KFSKeyConstants.ERROR_BATCH_UPLOAD_DELETE_FAILED_FILE_SET_ALREADY_PROCESSED);
178: return false;
179: }
180: return true;
181: }
182:
183: /**
184: * @see org.kuali.kfs.service.BatchInputFileSetService#hasBeenProcessed(org.kuali.core.bo.user.UniversalUser,
185: * org.kuali.kfs.batch.BatchInputFileSetType, java.lang.String)
186: */
187: public boolean hasBeenProcessed(UniversalUser user,
188: BatchInputFileSetType inputType, String fileUserIdentifier) {
189: // if the done file exists, then that means that the file set has not been processed
190: File doneFile = new File(generateDoneFileName(user, inputType,
191: fileUserIdentifier));
192: return !doneFile.exists();
193: }
194:
195: /**
196: * @see org.kuali.kfs.service.BatchInputFileSetService#download(org.kuali.core.bo.user.UniversalUser,
197: * org.kuali.kfs.batch.BatchInputFileSetType, java.lang.String)
198: */
199: public File download(UniversalUser user,
200: BatchInputFileSetType inputType, String fileType,
201: String fileUserIdentifier) throws AuthorizationException,
202: FileNotFoundException {
203: if (!this .isUserAuthorizedForBatchType(inputType, user)) {
204: LOG
205: .error("User "
206: + user.getPersonUserIdentifier()
207: + " is not authorized to download a file of batch type "
208: + inputType.getFileSetTypeIdentifer());
209: throw new AuthorizationException(user
210: .getPersonUserIdentifier(), "download", inputType
211: .getFileSetTypeIdentifer());
212: }
213:
214: String fileName = generateFileName(user, inputType,
215: fileUserIdentifier, fileType);
216: File file = new File(fileName);
217: if (!inputType.checkAuthorization(user, file)) {
218: LOG
219: .error("User "
220: + user.getPersonUserIdentifier()
221: + " is not authorized to download the following file: "
222: + file.getName());
223: throw new AuthorizationException(user
224: .getPersonUserIdentifier(), "download", inputType
225: .getFileSetTypeIdentifer());
226: }
227:
228: if (!file.exists()) {
229: LOG.error("unable to download file " + fileName
230: + " because it doesn not exist.");
231: throw new FileNotFoundException("Unable to download file "
232: + fileName + ". File does not exist on server.");
233: }
234: return file;
235: }
236:
237: /**
238: * @see org.kuali.kfs.service.BatchInputFileSetService#isBatchInputTypeActive(org.kuali.kfs.batch.BatchInputFileSetType)
239: */
240: public boolean isBatchInputTypeActive(
241: BatchInputFileSetType batchInputFileSetType) {
242: if (batchInputFileSetType == null) {
243: LOG.error("an invalid(null) argument was given");
244: throw new IllegalArgumentException(
245: "an invalid(null) argument was given");
246: }
247:
248: List<String> activeInputTypes = SpringContext
249: .getBean(ParameterService.class)
250: .getParameterValues(
251: ParameterConstants.FINANCIAL_SYSTEM_BATCH.class,
252: SystemGroupParameterNames.ACTIVE_INPUT_TYPES_PARAMETER_NAME);
253:
254: boolean activeBatchType = false;
255: if (activeInputTypes.size() > 0
256: && activeInputTypes.contains(batchInputFileSetType
257: .getFileSetTypeIdentifer())) {
258: activeBatchType = true;
259: }
260:
261: return activeBatchType;
262: }
263:
264: /**
265: * @see org.kuali.kfs.service.BatchInputFileSetService#isUserAuthorizedForBatchType(org.kuali.kfs.batch.BatchInputFileSetType,
266: * org.kuali.core.bo.user.UniversalUser)
267: */
268: public boolean isUserAuthorizedForBatchType(
269: BatchInputFileSetType batchInputFileSetType,
270: UniversalUser user) {
271: if (batchInputFileSetType == null || user == null) {
272: LOG.error("an invalid(null) argument was given");
273: throw new IllegalArgumentException(
274: "an invalid(null) argument was given");
275: }
276:
277: String authorizedWorkgroupName = SpringContext
278: .getBean(ParameterService.class)
279: .getParameterValue(
280: batchInputFileSetType
281: .getUploadWorkgroupParameterComponent(),
282: KFSConstants.SystemGroupParameterNames.FILE_TYPE_WORKGROUP_PARAMETER_NAME);
283:
284: return user.isMember(authorizedWorkgroupName);
285: }
286:
287: /**
288: * @see org.kuali.kfs.service.BatchInputFileSetService#listBatchTypeFilesForUser(org.kuali.kfs.batch.BatchInputFileSetType,
289: * org.kuali.core.bo.user.UniversalUser)
290: */
291: public Set<String> listBatchTypeFileUserIdentifiersForUser(
292: BatchInputFileSetType batchInputFileSetType,
293: UniversalUser user) throws AuthorizationException {
294: List<File> files = new ArrayList<File>();
295: for (String fileType : batchInputFileSetType.getFileTypes()) {
296: File fileTypeDirectory = new File(batchInputFileSetType
297: .getDirectoryPath(fileType));
298: File[] filesFromDirectory = fileTypeDirectory.listFiles();
299: Collections.addAll(files, filesFromDirectory);
300: }
301: return batchInputFileSetType.extractFileUserIdentifiers(user,
302: files);
303: }
304:
305: /**
306: * @see org.kuali.kfs.service.BatchInputFileSetService#save(org.kuali.core.bo.user.UniversalUser,
307: * org.kuali.kfs.batch.BatchInputFileSetType, java.lang.String, java.util.Map)
308: */
309: public Map<String, String> save(UniversalUser user,
310: BatchInputFileSetType inputType, String fileUserIdentifer,
311: Map<String, InputStream> typeToStreamMap,
312: boolean suppressDoneFileCreation)
313: throws AuthorizationException, FileStorageException {
314: // check user is authorized to upload a file for the batch type
315: if (!isUserAuthorizedForBatchType(inputType, user)) {
316: LOG
317: .error("User "
318: + user.getPersonUserIdentifier()
319: + " is not authorized to upload a file of batch type "
320: + inputType.getFileSetTypeIdentifer());
321: throw new AuthorizationException(user
322: .getPersonUserIdentifier(), "upload", inputType
323: .getFileSetTypeIdentifer());
324: }
325:
326: assertNoFilesInSetExist(user, inputType, fileUserIdentifer);
327:
328: Map<String, String> typeToFileNames = new LinkedHashMap<String, String>();
329: for (String fileType : inputType.getFileTypes()) {
330: String saveFileName = inputType.getDirectoryPath(fileType)
331: + File.separator
332: + inputType.getFileName(fileType, user,
333: fileUserIdentifer);
334: try {
335: InputStream fileContents = typeToStreamMap
336: .get(fileType);
337:
338: File fileToSave = new File(saveFileName);
339: fileToSave.createNewFile();
340: FileWriter fileWriter = new FileWriter(fileToSave);
341: while (fileContents.available() > 0) {
342: fileWriter.write(fileContents.read());
343: }
344: fileWriter.flush();
345: fileWriter.close();
346:
347: typeToFileNames.put(fileType, saveFileName);
348: } catch (IOException e) {
349: LOG.error("unable to save contents to file "
350: + saveFileName, e);
351: throw new RuntimeException(
352: "errors encountered while writing file "
353: + saveFileName, e);
354: }
355: }
356:
357: if (!suppressDoneFileCreation
358: && inputType.isSupportsDoneFileCreation()) {
359: String doneFileName = inputType.getDoneFileDirectoryPath()
360: + File.separator
361: + inputType
362: .getDoneFileName(user, fileUserIdentifer);
363: File doneFile = new File(doneFileName);
364: try {
365: doneFile.createNewFile();
366: } catch (IOException e) {
367: LOG.error("unable to create done file", e);
368: throw new RuntimeException(
369: "unable to create done file", e);
370: }
371: }
372: return typeToFileNames;
373: }
374:
375: /**
376: * Checks whether files associated with the set are already persisted on the file system or the done file. If so, then an
377: * exception is thrown
378: *
379: * @param user the user who uploaded or will upload the file
380: * @param inputType the file set type
381: * @param fileUserIdentifier the file identifier
382: */
383: protected void assertNoFilesInSetExist(UniversalUser user,
384: BatchInputFileSetType inputType, String fileUserIdentifier)
385: throws FileStorageException {
386: for (String fileType : inputType.getFileTypes()) {
387: String fileName = generateFileName(user, inputType,
388: fileUserIdentifier, fileType);
389: File file = new File(fileName);
390: if (file.exists()) {
391: // only print out the file name itself, no path
392: throw new FileStorageException(
393: "Cannot store file because the name "
394: + file.getName()
395: + " already exists on the file system.");
396: }
397: }
398: File doneFile = new File(generateDoneFileName(user, inputType,
399: fileUserIdentifier));
400: if (doneFile.exists()) {
401: throw new FileStorageException(
402: "Cannot store file because the name "
403: + doneFile.getName()
404: + " already exists on the file system.");
405: }
406:
407: }
408:
409: /**
410: * @see org.kuali.kfs.service.BatchInputFileSetService#isFileUserIdentifierProperlyFormatted(java.lang.String)
411: */
412: public boolean isFileUserIdentifierProperlyFormatted(
413: String fileUserIdentifier) {
414: for (int i = 0; i < fileUserIdentifier.length(); i++) {
415: char c = fileUserIdentifier.charAt(i);
416: if (!(Character.isLetterOrDigit(c))) {
417: return false;
418: }
419: }
420: return true;
421: }
422: }
|