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.ByteArrayInputStream;
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.io.FileWriter;
022: import java.io.FilenameFilter;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.net.URL;
026: import java.util.ArrayList;
027: import java.util.List;
028:
029: import javax.xml.XMLConstants;
030: import javax.xml.transform.Source;
031: import javax.xml.transform.stream.StreamSource;
032: import javax.xml.validation.Schema;
033: import javax.xml.validation.SchemaFactory;
034: import javax.xml.validation.Validator;
035:
036: import org.apache.commons.digester.Digester;
037: import org.apache.commons.digester.Rules;
038: import org.apache.commons.digester.xmlrules.DigesterLoader;
039: import org.apache.commons.lang.StringUtils;
040: import org.kuali.core.bo.user.UniversalUser;
041: import org.kuali.core.datadictionary.exception.InitException;
042: import org.kuali.core.exceptions.AuthorizationException;
043: import org.kuali.core.util.GlobalVariables;
044: import org.kuali.kfs.KFSConstants;
045: import org.kuali.kfs.KFSKeyConstants;
046: import org.kuali.kfs.KFSConstants.SystemGroupParameterNames;
047: import org.kuali.kfs.batch.BatchInputFileType;
048: import org.kuali.kfs.context.SpringContext;
049: import org.kuali.kfs.exceptions.FileStorageException;
050: import org.kuali.kfs.exceptions.XMLParseException;
051: import org.kuali.kfs.exceptions.XmlErrorHandler;
052: import org.kuali.kfs.service.BatchInputFileService;
053: import org.kuali.kfs.service.ParameterService;
054: import org.springframework.core.io.ClassPathResource;
055: import org.xml.sax.SAXException;
056:
057: /**
058: * Provides batch input file management, including listing files, parsing, downloading, storing, and deleting.
059: */
060: public class BatchInputFileServiceImpl implements BatchInputFileService {
061: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
062: .getLogger(BatchInputFileServiceImpl.class);
063:
064: /**
065: * Uses the apache commons digestor to unmarshell the xml. The BatchInputFileType specifies the location of the digestor rules
066: * xml which tells the digestor how to build the object graph from the xml.
067: *
068: * @see org.kuali.kfs.service.BatchInputFileService#parse(org.kuali.kfs.batch.BatchInputFileType, byte[])
069: */
070: public Object parse(BatchInputFileType batchInputFileType,
071: byte[] fileByteContent) throws XMLParseException {
072: if (batchInputFileType == null || fileByteContent == null) {
073: LOG.error("an invalid(null) argument was given");
074: throw new IllegalArgumentException(
075: "an invalid(null) argument was given");
076: }
077:
078: // handle zero byte contents, xml parsers don't deal with them well
079: if (fileByteContent.length == 0) {
080: LOG
081: .error("an invalid argument was given, empty input stream");
082: throw new IllegalArgumentException(
083: "an invalid argument was given, empty input stream");
084: }
085:
086: // validate contents against schema
087: ByteArrayInputStream validateFileContents = new ByteArrayInputStream(
088: fileByteContent);
089: validateContentsAgainstSchema(batchInputFileType
090: .getSchemaLocation(), validateFileContents);
091:
092: // setup digester for parsing the xml file
093: Digester digester = buildDigester(batchInputFileType
094: .getSchemaLocation(), batchInputFileType
095: .getDigestorRulesFileName());
096:
097: Object parsedContents = null;
098: try {
099: ByteArrayInputStream parseFileContents = new ByteArrayInputStream(
100: fileByteContent);
101: parsedContents = digester.parse(parseFileContents);
102: } catch (Exception e) {
103: LOG.error("Error parsing xml contents", e);
104: throw new XMLParseException("Error parsing xml contents: "
105: + e.getMessage(), e);
106: }
107:
108: return parsedContents;
109: }
110:
111: /**
112: * Validates the xml contents against the batch input type schema using the java 1.5 validation package.
113: *
114: * @param schemaLocation - location of the schema file
115: * @param fileContents - xml contents to validate against the schema
116: */
117: private void validateContentsAgainstSchema(String schemaLocation,
118: InputStream fileContents) throws XMLParseException {
119:
120: // create a SchemaFactory capable of understanding WXS schemas
121: SchemaFactory factory = SchemaFactory
122: .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
123:
124: // get schemaFile from classpath
125: ClassPathResource resource = new ClassPathResource(
126: schemaLocation);
127: File schemaFile;
128: try {
129: schemaFile = resource.getFile();
130: } catch (IOException e2) {
131: LOG.error("unable to get schema file: " + e2.getMessage());
132: throw new RuntimeException("unable to get schema file: "
133: + e2.getMessage());
134: }
135:
136: // load a WXS schema, represented by a Schema instance
137: Source schemaSource = new StreamSource(schemaFile);
138: Schema schema = null;
139: try {
140: schema = factory.newSchema(schemaSource);
141: } catch (SAXException e) {
142: LOG.error("error occured while setting schema file: "
143: + e.getMessage());
144: throw new RuntimeException(
145: "error occured while setting schema file: "
146: + e.getMessage(), e);
147: }
148:
149: // create a Validator instance, which can be used to validate an instance document
150: Validator validator = schema.newValidator();
151: validator.setErrorHandler(new XmlErrorHandler());
152:
153: // validate
154: try {
155: validator.validate(new StreamSource(fileContents));
156: } catch (SAXException e) {
157: LOG.error("error encountered while parsing xml "
158: + e.getMessage());
159: throw new XMLParseException(
160: "Schema validation error occured while processing file: "
161: + e.getMessage(), e);
162: } catch (IOException e1) {
163: LOG.error("error occured while validating file contents: "
164: + e1.getMessage());
165: throw new RuntimeException(
166: "error occured while validating file contents: "
167: + e1.getMessage(), e1);
168: }
169: }
170:
171: /**
172: * Defers to batch type to do any validation on the parsed contents.
173: *
174: * @see org.kuali.kfs.service.BatchInputFileService#validate(org.kuali.kfs.batch.BatchInputFileType, java.lang.Object)
175: */
176: public boolean validate(BatchInputFileType batchInputFileType,
177: Object parsedObject) {
178: if (batchInputFileType == null || parsedObject == null) {
179: LOG.error("an invalid(null) argument was given");
180: throw new IllegalArgumentException(
181: "an invalid(null) argument was given");
182: }
183:
184: boolean contentsValid = true;
185: contentsValid = batchInputFileType.validate(parsedObject);
186:
187: return contentsValid;
188: }
189:
190: /**
191: * @see org.kuali.kfs.service.BatchInputFileService#save(org.kuali.core.bo.user.UniversalUser,
192: * org.kuali.kfs.batch.BatchInputFileType, java.lang.String, java.io.InputStream)
193: */
194: public String save(UniversalUser user,
195: BatchInputFileType batchInputFileType,
196: String fileUserIdentifier, InputStream fileContents,
197: Object parsedObject) throws AuthorizationException,
198: FileStorageException {
199: if (user == null || batchInputFileType == null
200: || fileContents == null) {
201: LOG.error("an invalid(null) argument was given");
202: throw new IllegalArgumentException(
203: "an invalid(null) argument was given");
204: }
205:
206: if (!isFileUserIdentifierProperlyFormatted(fileUserIdentifier)) {
207: LOG
208: .error("The following file user identifer was not properly formatted: "
209: + fileUserIdentifier);
210: throw new IllegalArgumentException(
211: "The following file user identifer was not properly formatted: "
212: + fileUserIdentifier);
213: }
214: // check user is authorized to upload a file for the batch type
215: if (!isUserAuthorizedForBatchType(batchInputFileType, user)) {
216: LOG
217: .error("User "
218: + user.getPersonUserIdentifier()
219: + " is not authorized to upload a file of batch type "
220: + batchInputFileType.getFileTypeIdentifer());
221: throw new AuthorizationException(user
222: .getPersonUserIdentifier(), "upload",
223: batchInputFileType.getFileTypeIdentifer());
224: }
225:
226: // defer to batch input type to add any security or other needed information to the file name
227: String saveFileName = batchInputFileType.getDirectoryPath()
228: + "/"
229: + batchInputFileType.getFileName(user, parsedObject,
230: fileUserIdentifier);
231: saveFileName += "." + batchInputFileType.getFileExtension();
232:
233: // consruct the file object and check for existence
234: File fileToSave = new File(saveFileName);
235: if (fileToSave.exists()) {
236: LOG.error("cannot store file, name already exists "
237: + saveFileName);
238: throw new FileStorageException(
239: "Cannot store file because the name "
240: + saveFileName
241: + " already exists on the file system.");
242: }
243:
244: try {
245: FileWriter fileWriter = new FileWriter(fileToSave);
246: while (fileContents.available() > 0) {
247: fileWriter.write(fileContents.read());
248: }
249: fileWriter.flush();
250: fileWriter.close();
251:
252: createDoneFile(fileToSave);
253: } catch (IOException e) {
254: LOG.error(
255: "unable to save contents to file " + saveFileName,
256: e);
257: throw new RuntimeException(
258: "errors encountered while writing file "
259: + saveFileName, e);
260: }
261:
262: return saveFileName;
263: }
264:
265: /**
266: * Creates a '.done' file with the name of the batch file.
267: */
268: private void createDoneFile(File batchFile) {
269: File doneFile = generateDoneFileObject(batchFile);
270: String doneFileName = doneFile.getName();
271:
272: if (!doneFile.exists()) {
273: boolean doneFileCreated = false;
274: try {
275: doneFileCreated = doneFile.createNewFile();
276: } catch (IOException e) {
277: LOG.error("unable to create done file " + doneFileName,
278: e);
279: throw new RuntimeException(
280: "Errors encountered while saving the file: Unable to create .done file "
281: + doneFileName, e);
282: }
283:
284: if (!doneFileCreated) {
285: LOG.error("unable to create done file " + doneFileName);
286: throw new RuntimeException(
287: "Errors encountered while saving the file: Unable to create .done file "
288: + doneFileName);
289: }
290: }
291: }
292:
293: /**
294: * @see org.kuali.kfs.service.BatchInputFileService#delete(org.kuali.core.bo.user.UniversalUser,
295: * org.kuali.kfs.batch.BatchInputFileType, java.lang.String)
296: */
297: public boolean delete(UniversalUser user,
298: BatchInputFileType batchInputFileType,
299: String deleteFileNameWithNoPath)
300: throws AuthorizationException, FileNotFoundException {
301: if (user == null || batchInputFileType == null
302: || StringUtils.isBlank(deleteFileNameWithNoPath)) {
303: LOG.error("an invalid(null) argument was given");
304: throw new IllegalArgumentException(
305: "an invalid(null) argument was given");
306: }
307:
308: // check user is authorized to delete a file for the batch type
309: if (!this
310: .isUserAuthorizedForBatchType(batchInputFileType, user)) {
311: LOG
312: .error("User "
313: + user.getPersonUserIdentifier()
314: + " is not authorized to delete a file of batch type "
315: + batchInputFileType.getFileTypeIdentifer());
316: throw new AuthorizationException(user
317: .getPersonUserIdentifier(), "delete",
318: batchInputFileType.getFileTypeIdentifer());
319: }
320:
321: File fileToDelete = retrieveFileToDownloadOrDelete(
322: batchInputFileType, user, deleteFileNameWithNoPath);
323: if (fileToDelete != null) {
324: if (canDelete(user, batchInputFileType, fileToDelete)) {
325: fileToDelete.delete();
326:
327: // check for associated .done file and remove as well
328: File doneFile = generateDoneFileObject(fileToDelete);
329: if (doneFile.exists()) {
330: doneFile.delete();
331: }
332: return true;
333: } else {
334: return false;
335: }
336: } else {
337: LOG.error("unable to delete file "
338: + deleteFileNameWithNoPath
339: + " because it doesn not exist.");
340: throw new FileNotFoundException("Unable to delete file "
341: + deleteFileNameWithNoPath
342: + ". File does not exist on server.");
343: }
344: }
345:
346: /**
347: * This method indicates whether a file can be deleted. It will also place an error in the GlobalVariables error map to indicate
348: * to the UI the reason that the file could not be deleted.
349: *
350: * @param user
351: * @param inputType
352: * @param deleteFileNameWithNoPath
353: * @return
354: * @throws AuthorizationException
355: * @throws FileNotFoundException
356: */
357: protected boolean canDelete(UniversalUser user,
358: BatchInputFileType inputType, File fileToDelete) {
359: if (!inputType.checkAuthorization(user, fileToDelete)) {
360: GlobalVariables
361: .getErrorMap()
362: .putError(
363: KFSConstants.GLOBAL_ERRORS,
364: KFSKeyConstants.ERROR_BATCH_UPLOAD_DELETE_FAILED_NOT_AUTHORIZED);
365: return false;
366: }
367: if (hasBeenProcessed(inputType, fileToDelete.getName())) {
368: GlobalVariables
369: .getErrorMap()
370: .putError(
371: KFSConstants.GLOBAL_ERRORS,
372: KFSKeyConstants.ERROR_BATCH_UPLOAD_DELETE_FAILED_FILE_ALREADY_PROCESSED);
373: return false;
374: }
375: return true;
376: }
377:
378: public boolean hasBeenProcessed(BatchInputFileType inputType,
379: String fileName) {
380: List<String> fileNamesWithDoneFile = listInputFileNamesWithDoneFile(inputType);
381: // except during the short time during which the data file is written to disk,
382: // the absence of a done file means that the file has been processed
383: for (String fileNameWithDoneFile : fileNamesWithDoneFile) {
384: File fileWithDone = new File(fileNameWithDoneFile);
385: if (fileWithDone.getName().equals(fileName)) {
386: return false;
387: }
388: }
389: return true;
390: }
391:
392: /**
393: * @see org.kuali.kfs.service.BatchInputFileService#download(org.kuali.core.bo.user.UniversalUser,
394: * org.kuali.kfs.batch.BatchInputFileType, java.lang.String)
395: */
396: public File download(UniversalUser user,
397: BatchInputFileType batchInputFileType,
398: String downloadFileNameWithNoPath)
399: throws AuthorizationException, FileNotFoundException {
400: if (user == null || batchInputFileType == null
401: || StringUtils.isBlank(downloadFileNameWithNoPath)) {
402: LOG.error("an invalid(null) argument was given");
403: throw new IllegalArgumentException(
404: "an invalid(null) argument was given");
405: }
406:
407: // check user is authorized to download a file for the batch type
408: if (!this
409: .isUserAuthorizedForBatchType(batchInputFileType, user)) {
410: LOG
411: .error("User "
412: + user.getPersonUserIdentifier()
413: + " is not authorized to download a file of batch type "
414: + batchInputFileType.getFileTypeIdentifer());
415: throw new AuthorizationException(user
416: .getPersonUserIdentifier(), "download",
417: batchInputFileType.getFileTypeIdentifer());
418: }
419:
420: File fileToDownload = retrieveFileToDownloadOrDelete(
421: batchInputFileType, user, downloadFileNameWithNoPath);
422: if (fileToDownload == null) {
423: LOG.error("unable to download file "
424: + downloadFileNameWithNoPath
425: + " because it doesn not exist.");
426: throw new FileNotFoundException("Unable to download file "
427: + downloadFileNameWithNoPath
428: + ". File does not exist on server.");
429: }
430:
431: return fileToDownload;
432: }
433:
434: /**
435: * This method will attempt to find the File object representing the file to download or delete. USE EXTREME CAUTION when
436: * overridding this method, as a badly implemented method may cause a security vulnerability.
437: *
438: * @param batchInputFileType
439: * @param user
440: * @param fileName the file name, WITHOUT any path components
441: * @return the File object, if a file exists in the directory specified by the batchInputFileType. null if no file can be found
442: * in the directory specified by batchInputFileType.
443: */
444: protected File retrieveFileToDownloadOrDelete(
445: BatchInputFileType batchInputFileType, UniversalUser user,
446: String fileName) {
447: // retrieve a list of files from the appropriate directory for the batch input file type for the user
448: List<File> userFileList = listBatchTypeFilesForUserAsFiles(
449: batchInputFileType, user);
450:
451: // make sure that we have the right file extension
452: if (!fileName.toLowerCase().endsWith(
453: batchInputFileType.getFileExtension().toLowerCase())) {
454: throw new IllegalArgumentException("Filename " + fileName
455: + " does not end with the proper extension: ("
456: + batchInputFileType.getFileExtension() + ")");
457: }
458:
459: // the file must exist, and the file's name must match completely with the filesystem file
460: File theFile = null;
461: for (File userFile : userFileList) {
462: if (userFile.exists()
463: && userFile.getName().equals(fileName)) {
464: theFile = userFile;
465: break;
466: }
467: }
468: return theFile;
469: }
470:
471: /**
472: * This method is responsible for creating a File object that represents the done file. The real file represented on disk may
473: * not exist
474: *
475: * @param batchInputFile
476: * @return a File object representing the done file. The real file may not exist on disk, but the return value can be used to
477: * create that file.
478: */
479: protected File generateDoneFileObject(File batchInputFile) {
480: String doneFileName = StringUtils.substringBeforeLast(
481: batchInputFile.getPath(), ".")
482: + ".done";
483: File doneFile = new File(doneFileName);
484: return doneFile;
485: }
486:
487: /**
488: * @see org.kuali.kfs.service.BatchInputFileService#isBatchInputTypeActive(org.kuali.kfs.batch.BatchInputFileType)
489: */
490: public boolean isBatchInputTypeActive(
491: BatchInputFileType batchInputFileType) {
492: if (batchInputFileType == null) {
493: LOG.error("an invalid(null) argument was given");
494: throw new IllegalArgumentException(
495: "an invalid(null) argument was given");
496: }
497:
498: List<String> activeInputTypes = SpringContext
499: .getBean(ParameterService.class)
500: .getParameterValues(
501: ParameterConstants.FINANCIAL_SYSTEM_BATCH.class,
502: SystemGroupParameterNames.ACTIVE_INPUT_TYPES_PARAMETER_NAME);
503:
504: boolean activeBatchType = false;
505: if (activeInputTypes.size() > 0
506: && activeInputTypes.contains(batchInputFileType
507: .getFileTypeIdentifer())) {
508: activeBatchType = true;
509: }
510:
511: return activeBatchType;
512: }
513:
514: /**
515: * @see org.kuali.kfs.service.BatchInputFileService#isUserAuthorizedForBatchType(org.kuali.kfs.batch.BatchInputFileType,
516: * org.kuali.core.bo.user.UniversalUser)
517: */
518: public boolean isUserAuthorizedForBatchType(
519: BatchInputFileType batchInputFileType, UniversalUser user) {
520: if (batchInputFileType == null || user == null) {
521: LOG.error("an invalid(null) argument was given");
522: throw new IllegalArgumentException(
523: "an invalid(null) argument was given");
524: }
525: String authorizedWorkgroupName = SpringContext
526: .getBean(ParameterService.class)
527: .getParameterValue(
528: batchInputFileType
529: .getUploadWorkgroupParameterComponent(),
530: KFSConstants.SystemGroupParameterNames.FILE_TYPE_WORKGROUP_PARAMETER_NAME);
531: return user.isMember(authorizedWorkgroupName);
532: }
533:
534: /**
535: * Fetches workgroup for batch type from system parameter and verifies user is a member. Then a list of all files for the batch
536: * type are retrieved. For each file, the file and user is sent through the checkAuthorization method of the batch input type
537: * implementation for finer grained security. If the method returns true, the filename is added to the user's list.
538: *
539: * @see org.kuali.kfs.service.BatchInputFileService#listBatchTypeFilesForUser(org.kuali.kfs.batch.BatchInputFileType,
540: * org.kuali.core.bo.user.UniversalUser)
541: */
542: public List<String> listBatchTypeFilesForUser(
543: BatchInputFileType batchInputFileType, UniversalUser user)
544: throws AuthorizationException {
545: if (batchInputFileType == null || user == null) {
546: LOG.error("an invalid(null) argument was given");
547: throw new IllegalArgumentException(
548: "an invalid(null) argument was given");
549: }
550:
551: if (!this
552: .isUserAuthorizedForBatchType(batchInputFileType, user)) {
553: LOG
554: .error("User "
555: + user.getPersonUserIdentifier()
556: + " is not authorized to list a file of batch type "
557: + batchInputFileType.getFileTypeIdentifer());
558: throw new AuthorizationException(user
559: .getPersonUserIdentifier(), "list",
560: batchInputFileType.getFileTypeIdentifer());
561: }
562:
563: File[] filesInBatchDirectory = listFilesInBatchTypeDirectory(batchInputFileType);
564:
565: List<String> userFileNamesList = new ArrayList<String>();
566: List<File> userFileList = listBatchTypeFilesForUserAsFiles(
567: batchInputFileType, user);
568:
569: for (File userFile : userFileList) {
570: userFileNamesList.add(userFile.getName());
571: }
572:
573: return userFileNamesList;
574: }
575:
576: protected List<File> listBatchTypeFilesForUserAsFiles(
577: BatchInputFileType batchInputFileType, UniversalUser user)
578: throws AuthorizationException {
579: File[] filesInBatchDirectory = listFilesInBatchTypeDirectory(batchInputFileType);
580:
581: List<File> userFileList = new ArrayList<File>();
582: if (filesInBatchDirectory != null) {
583: for (int i = 0; i < filesInBatchDirectory.length; i++) {
584: File batchFile = filesInBatchDirectory[i];
585: String fileExtension = StringUtils.substringAfterLast(
586: batchFile.getName(), ".");
587: if (batchInputFileType.getFileExtension().equals(
588: fileExtension)) {
589: boolean userAuthorizedForFile = batchInputFileType
590: .checkAuthorization(user, batchFile);
591: if (userAuthorizedForFile) {
592: userFileList.add(batchFile);
593: }
594: }
595: }
596: }
597: return userFileList;
598: }
599:
600: /**
601: * Returns List of filenames for existing files in the directory given by the batch input type.
602: */
603: private File[] listFilesInBatchTypeDirectory(
604: BatchInputFileType batchInputFileType) {
605: File batchTypeDirectory = new File(batchInputFileType
606: .getDirectoryPath());
607: return batchTypeDirectory.listFiles();
608: }
609:
610: /**
611: * @see org.kuali.kfs.service.BatchInputFileService#listInputFileNamesWithDoneFile(org.kuali.kfs.batch.BatchInputFileType)
612: */
613: public List<String> listInputFileNamesWithDoneFile(
614: BatchInputFileType batchInputFileType) {
615: if (batchInputFileType == null) {
616: LOG.error("an invalid(null) argument was given");
617: throw new IllegalArgumentException(
618: "an invalid(null) argument was given");
619: }
620:
621: File batchTypeDirectory = new File(batchInputFileType
622: .getDirectoryPath());
623: File[] doneFiles = batchTypeDirectory
624: .listFiles(new DoneFilenameFilter());
625:
626: List<String> batchInputFiles = new ArrayList();
627: for (int i = 0; i < doneFiles.length; i++) {
628: File doneFile = doneFiles[i];
629: File dataFile = new File(StringUtils.substringBeforeLast(
630: doneFile.getPath(), ".")
631: + "." + batchInputFileType.getFileExtension());
632: if (dataFile.exists()) {
633: batchInputFiles.add(dataFile.getPath());
634: }
635: }
636:
637: return batchInputFiles;
638: }
639:
640: /**
641: * Retrieves files in a directory with the .done extension.
642: */
643: private class DoneFilenameFilter implements FilenameFilter {
644: /**
645: * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
646: */
647: public boolean accept(File dir, String name) {
648: return name.endsWith(".done");
649: }
650: }
651:
652: /**
653: * @return fully-initialized Digester used to process entry XML files
654: */
655: private Digester buildDigester(String schemaLocation,
656: String digestorRulesFileName) {
657: Digester digester = new Digester();
658: digester.setNamespaceAware(false);
659: digester.setValidating(true);
660: digester.setErrorHandler(new XmlErrorHandler());
661: digester.setSchema(schemaLocation);
662:
663: Rules rules = loadRules(digestorRulesFileName);
664:
665: digester.setRules(rules);
666:
667: return digester;
668: }
669:
670: /**
671: * @return Rules loaded from the appropriate XML file
672: */
673: private final Rules loadRules(String digestorRulesFileName) {
674: // locate Digester rules
675: ClassLoader classLoader = Thread.currentThread()
676: .getContextClassLoader();
677: URL rulesUrl = classLoader.getResource(digestorRulesFileName);
678: if (rulesUrl == null) {
679: throw new InitException(
680: "unable to locate digester rules file "
681: + digestorRulesFileName);
682: }
683:
684: // create and init digester
685: Digester digester = DigesterLoader.createDigester(rulesUrl);
686:
687: return digester.getRules();
688: }
689:
690: /**
691: * For this implementation, a file user identifier must consist of letters and digits
692: *
693: * @see org.kuali.kfs.service.BatchInputFileService#isFileUserIdentifierProperlyFormatted(java.lang.String)
694: */
695: public boolean isFileUserIdentifierProperlyFormatted(
696: String fileUserIdentifier) {
697: for (int i = 0; i < fileUserIdentifier.length(); i++) {
698: char c = fileUserIdentifier.charAt(i);
699: if (!(Character.isLetterOrDigit(c))) {
700: return false;
701: }
702: }
703: return true;
704: }
705: }
|