0001: /*
0002: * Copyright 2006-2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.module.gl.service.impl;
0017:
0018: import java.io.BufferedOutputStream;
0019: import java.io.BufferedReader;
0020: import java.io.File;
0021: import java.io.FileInputStream;
0022: import java.io.FileOutputStream;
0023: import java.io.FileReader;
0024: import java.io.IOException;
0025: import java.io.OutputStream;
0026: import java.sql.Date;
0027: import java.util.ArrayList;
0028: import java.util.Collection;
0029: import java.util.Collections;
0030: import java.util.Iterator;
0031: import java.util.List;
0032:
0033: import org.apache.log4j.Logger;
0034: import org.kuali.core.dao.DocumentDao;
0035: import org.kuali.core.service.KualiConfigurationService;
0036: import org.kuali.core.web.comparator.NumericValueComparator;
0037: import org.kuali.core.web.comparator.StringValueComparator;
0038: import org.kuali.core.web.comparator.TemporalValueComparator;
0039: import org.kuali.core.web.ui.Column;
0040: import org.kuali.core.workflow.service.KualiWorkflowDocument;
0041: import org.kuali.kfs.KFSPropertyConstants;
0042: import org.kuali.module.gl.bo.CorrectionChangeGroup;
0043: import org.kuali.module.gl.bo.OriginEntryFull;
0044: import org.kuali.module.gl.bo.OriginEntryGroup;
0045: import org.kuali.module.gl.dao.CorrectionChangeDao;
0046: import org.kuali.module.gl.dao.CorrectionChangeGroupDao;
0047: import org.kuali.module.gl.dao.CorrectionCriteriaDao;
0048: import org.kuali.module.gl.dao.CorrectionDocumentDao;
0049: import org.kuali.module.gl.document.CorrectionDocument;
0050: import org.kuali.module.gl.service.CorrectionDocumentService;
0051: import org.kuali.module.gl.service.OriginEntryGroupService;
0052: import org.kuali.module.gl.service.OriginEntryService;
0053: import org.kuali.module.gl.util.CorrectionDocumentEntryMetadata;
0054: import org.kuali.module.gl.util.CorrectionDocumentUtils;
0055: import org.kuali.module.gl.util.OriginEntryFileIterator;
0056: import org.kuali.module.gl.util.OriginEntryStatistics;
0057: import org.springframework.transaction.annotation.Transactional;
0058:
0059: /**
0060: * The base implementaiton of CorrectionDocumentService
0061: */
0062: @Transactional
0063: public class CorrectionDocumentServiceImpl implements
0064: CorrectionDocumentService {
0065: protected static Logger LOG = Logger
0066: .getLogger(CorrectionDocumentServiceImpl.class);
0067:
0068: protected CorrectionChangeGroupDao correctionChangeGroupDao;
0069: protected CorrectionChangeDao correctionChangeDao;
0070: protected CorrectionCriteriaDao correctionCriteriaDao;
0071: protected DocumentDao documentDao;
0072: protected KualiConfigurationService kualiConfigurationService;
0073: private OriginEntryService originEntryService;
0074: private String glcpDirectoryName;
0075: protected OriginEntryGroupService originEntryGroupService;
0076:
0077: protected static final String INPUT_ORIGIN_ENTRIES_FILE_SUFFIX = "-input.txt";
0078: protected static final String OUTPUT_ORIGIN_ENTRIES_FILE_SUFFIX = "-output.txt";
0079:
0080: protected CorrectionDocumentDao correctionDocumentDao;
0081:
0082: /**
0083: * Returns a specific correction change group for a GLCP document. Defers to DAO.
0084: *
0085: * @param docId the document id of a GLCP document
0086: * @param i the number of the correction group within the document
0087: * @return a CorrectionChangeGroup
0088: * @see org.kuali.module.gl.service.CorrectionDocumentService#findByDocumentNumberAndCorrectionChangeGroupNumber(java.lang.String,
0089: * int)
0090: */
0091: public CorrectionChangeGroup findByDocumentNumberAndCorrectionChangeGroupNumber(
0092: String docId, int i) {
0093:
0094: return correctionChangeGroupDao
0095: .findByDocumentNumberAndCorrectionChangeGroupNumber(
0096: docId, i);
0097: }
0098:
0099: /**
0100: * Finds CollectionChange records associated with a given document id and correction change group. Defers to DAO
0101: *
0102: * @param docId the document id of a GLCP document
0103: * @param i the number of the correction group within the document
0104: * @return a List of qualifying CorrectionChange records
0105: * @see org.kuali.module.gl.service.CorrectionDocumentService#findByDocumentHeaderIdAndCorrectionGroupNumber(java.lang.String,
0106: * int)
0107: */
0108: public List findByDocumentHeaderIdAndCorrectionGroupNumber(
0109: String docId, int i) {
0110:
0111: return correctionChangeDao
0112: .findByDocumentHeaderIdAndCorrectionGroupNumber(docId,
0113: i);
0114: }
0115:
0116: /**
0117: * Finds Collection Criteria associated with the given GLCP document and group. Defers to DAO.
0118: *
0119: * @param docId the document id of a GLCP document
0120: * @param i the number of the correction group within the document
0121: * @return a List of qualifying CorrectionCriteria
0122: * @see org.kuali.module.gl.service.CorrectionDocumentService#findByDocumentNumberAndCorrectionGroupNumber(java.lang.String,
0123: * int)
0124: */
0125: public List findByDocumentNumberAndCorrectionGroupNumber(
0126: String docId, int i) {
0127:
0128: return correctionCriteriaDao
0129: .findByDocumentNumberAndCorrectionGroupNumber(docId, i);
0130: }
0131:
0132: /**
0133: * Retrieves a correction document by the document id
0134: *
0135: * @param docId the document id of the GLCP to find
0136: * @return a CorrectionDocument if found
0137: * @see org.kuali.module.gl.service.CorrectionDocumentService#findByCorrectionDocumentHeaderId(java.lang.String)
0138: */
0139: public CorrectionDocument findByCorrectionDocumentHeaderId(
0140: String docId) {
0141:
0142: return (CorrectionDocument) documentDao.findByDocumentHeaderId(
0143: CorrectionDocument.class, docId);
0144: }
0145:
0146: public void setCorrectionChangeDao(
0147: CorrectionChangeDao correctionChangeDao) {
0148: this .correctionChangeDao = correctionChangeDao;
0149: }
0150:
0151: public void setCorrectionChangeGroupDao(
0152: CorrectionChangeGroupDao correctionChangeGroupDao) {
0153: this .correctionChangeGroupDao = correctionChangeGroupDao;
0154: }
0155:
0156: public void setCorrectionCriteriaDao(
0157: CorrectionCriteriaDao correctionCriteriaDao) {
0158: this .correctionCriteriaDao = correctionCriteriaDao;
0159: }
0160:
0161: public void setDocumentDao(DocumentDao documentDao) {
0162: this .documentDao = documentDao;
0163: }
0164:
0165: private List<Column> cachedColumns = null;
0166:
0167: /**
0168: * Returns metadata to help render columns in the GLCP. Do not modify this list or the contents in this list.
0169: *
0170: * @param docId the document id of a GLCP document
0171: * @return a List of Columns to render
0172: * @see org.kuali.module.gl.service.CorrectionDocumentService#getTableRenderColumnMetadata(java.lang.String)
0173: */
0174: public List<Column> getTableRenderColumnMetadata(String docId) {
0175: synchronized (this ) {
0176: if (cachedColumns == null) {
0177: cachedColumns = new ArrayList<Column>();
0178: Column columnToAdd;
0179:
0180: columnToAdd = new Column();
0181: columnToAdd.setColumnTitle("Fiscal Year");
0182: columnToAdd
0183: .setPropertyName(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR);
0184: columnToAdd.setValueComparator(NumericValueComparator
0185: .getInstance());
0186: cachedColumns.add(columnToAdd);
0187:
0188: columnToAdd = new Column();
0189: columnToAdd.setColumnTitle("Chart Code");
0190: columnToAdd
0191: .setPropertyName(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE);
0192: columnToAdd.setValueComparator(StringValueComparator
0193: .getInstance());
0194: cachedColumns.add(columnToAdd);
0195:
0196: columnToAdd = new Column();
0197: columnToAdd.setColumnTitle("Account Number");
0198: columnToAdd
0199: .setPropertyName(KFSPropertyConstants.ACCOUNT_NUMBER);
0200: columnToAdd.setValueComparator(StringValueComparator
0201: .getInstance());
0202: cachedColumns.add(columnToAdd);
0203:
0204: columnToAdd = new Column();
0205: columnToAdd.setColumnTitle("Sub Account Number");
0206: columnToAdd
0207: .setPropertyName(KFSPropertyConstants.SUB_ACCOUNT_NUMBER);
0208: columnToAdd.setValueComparator(StringValueComparator
0209: .getInstance());
0210: cachedColumns.add(columnToAdd);
0211:
0212: columnToAdd = new Column();
0213: columnToAdd.setColumnTitle("Object Code");
0214: columnToAdd
0215: .setPropertyName(KFSPropertyConstants.FINANCIAL_OBJECT_CODE);
0216: columnToAdd.setValueComparator(StringValueComparator
0217: .getInstance());
0218: cachedColumns.add(columnToAdd);
0219:
0220: columnToAdd = new Column();
0221: columnToAdd.setColumnTitle("Sub Object Code");
0222: columnToAdd
0223: .setPropertyName(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE);
0224: columnToAdd.setValueComparator(StringValueComparator
0225: .getInstance());
0226: cachedColumns.add(columnToAdd);
0227:
0228: columnToAdd = new Column();
0229: columnToAdd.setColumnTitle("Balance Type");
0230: columnToAdd
0231: .setPropertyName(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE);
0232: columnToAdd.setValueComparator(StringValueComparator
0233: .getInstance());
0234: cachedColumns.add(columnToAdd);
0235:
0236: columnToAdd = new Column();
0237: columnToAdd.setColumnTitle("Object Type");
0238: columnToAdd
0239: .setPropertyName(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE);
0240: columnToAdd.setValueComparator(StringValueComparator
0241: .getInstance());
0242: cachedColumns.add(columnToAdd);
0243:
0244: columnToAdd = new Column();
0245: columnToAdd.setColumnTitle("Fiscal Period");
0246: columnToAdd
0247: .setPropertyName(KFSPropertyConstants.UNIVERSITY_FISCAL_PERIOD_CODE);
0248: columnToAdd.setValueComparator(StringValueComparator
0249: .getInstance());
0250: cachedColumns.add(columnToAdd);
0251:
0252: columnToAdd = new Column();
0253: columnToAdd.setColumnTitle("Document Type");
0254: columnToAdd
0255: .setPropertyName(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE);
0256: columnToAdd.setValueComparator(StringValueComparator
0257: .getInstance());
0258: cachedColumns.add(columnToAdd);
0259:
0260: columnToAdd = new Column();
0261: columnToAdd.setColumnTitle("Origin Code");
0262: columnToAdd
0263: .setPropertyName(KFSPropertyConstants.FINANCIAL_SYSTEM_ORIGINATION_CODE);
0264: columnToAdd.setValueComparator(StringValueComparator
0265: .getInstance());
0266: cachedColumns.add(columnToAdd);
0267:
0268: columnToAdd = new Column();
0269: columnToAdd.setColumnTitle("Document Number");
0270: columnToAdd
0271: .setPropertyName(KFSPropertyConstants.DOCUMENT_NUMBER);
0272: columnToAdd.setValueComparator(StringValueComparator
0273: .getInstance());
0274: cachedColumns.add(columnToAdd);
0275:
0276: columnToAdd = new Column();
0277: columnToAdd.setColumnTitle("Sequence Number");
0278: columnToAdd.setValueComparator(NumericValueComparator
0279: .getInstance());
0280: columnToAdd
0281: .setPropertyName(KFSPropertyConstants.TRANSACTION_ENTRY_SEQUENCE_NUMBER);
0282: cachedColumns.add(columnToAdd);
0283:
0284: columnToAdd = new Column();
0285: columnToAdd.setColumnTitle("Description");
0286: columnToAdd
0287: .setPropertyName(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_DESC);
0288: columnToAdd.setValueComparator(StringValueComparator
0289: .getInstance());
0290: cachedColumns.add(columnToAdd);
0291:
0292: columnToAdd = new Column();
0293: columnToAdd.setColumnTitle("Amount");
0294: columnToAdd.setValueComparator(NumericValueComparator
0295: .getInstance());
0296: columnToAdd
0297: .setPropertyName(KFSPropertyConstants.TRANSACTION_LEDGER_ENTRY_AMOUNT);
0298: cachedColumns.add(columnToAdd);
0299:
0300: columnToAdd = new Column();
0301: columnToAdd.setColumnTitle("Debit Credit Indicator");
0302: columnToAdd
0303: .setPropertyName(KFSPropertyConstants.TRANSACTION_DEBIT_CREDIT_CODE);
0304: columnToAdd.setValueComparator(StringValueComparator
0305: .getInstance());
0306: cachedColumns.add(columnToAdd);
0307:
0308: columnToAdd = new Column();
0309: columnToAdd.setColumnTitle("Transaction Date");
0310: columnToAdd
0311: .setPropertyName(KFSPropertyConstants.TRANSACTION_DATE);
0312: columnToAdd.setValueComparator(TemporalValueComparator
0313: .getInstance());
0314: cachedColumns.add(columnToAdd);
0315:
0316: columnToAdd = new Column();
0317: columnToAdd.setColumnTitle("Org Doc Number");
0318: columnToAdd
0319: .setPropertyName(KFSPropertyConstants.ORGANIZATION_DOCUMENT_NUMBER);
0320: columnToAdd.setValueComparator(StringValueComparator
0321: .getInstance());
0322: cachedColumns.add(columnToAdd);
0323:
0324: columnToAdd = new Column();
0325: columnToAdd.setColumnTitle("Project Code");
0326: columnToAdd
0327: .setPropertyName(KFSPropertyConstants.PROJECT_CODE);
0328: columnToAdd.setValueComparator(StringValueComparator
0329: .getInstance());
0330: cachedColumns.add(columnToAdd);
0331:
0332: columnToAdd = new Column();
0333: columnToAdd.setColumnTitle("Org Ref ID");
0334: columnToAdd
0335: .setPropertyName(KFSPropertyConstants.ORGANIZATION_REFERENCE_ID);
0336: columnToAdd.setValueComparator(StringValueComparator
0337: .getInstance());
0338: cachedColumns.add(columnToAdd);
0339:
0340: columnToAdd = new Column();
0341: columnToAdd.setColumnTitle("Ref Doc Type");
0342: columnToAdd
0343: .setPropertyName(KFSPropertyConstants.REFERENCE_FIN_DOCUMENT_TYPE_CODE);
0344: columnToAdd.setValueComparator(StringValueComparator
0345: .getInstance());
0346: cachedColumns.add(columnToAdd);
0347:
0348: columnToAdd = new Column();
0349: columnToAdd.setColumnTitle("Ref Origin Code");
0350: columnToAdd
0351: .setPropertyName(KFSPropertyConstants.REFERENCE_FINANCIAL_SYSTEM_ORIGINATION_CODE);
0352: columnToAdd.setValueComparator(StringValueComparator
0353: .getInstance());
0354: cachedColumns.add(columnToAdd);
0355:
0356: columnToAdd = new Column();
0357: columnToAdd.setColumnTitle("Ref Doc Number");
0358: columnToAdd
0359: .setPropertyName(KFSPropertyConstants.FINANCIAL_DOCUMENT_REFERENCE_NBR);
0360: columnToAdd.setValueComparator(StringValueComparator
0361: .getInstance());
0362: cachedColumns.add(columnToAdd);
0363:
0364: columnToAdd = new Column();
0365: columnToAdd.setColumnTitle("Reversal Date");
0366: columnToAdd
0367: .setPropertyName(KFSPropertyConstants.FINANCIAL_DOCUMENT_REVERSAL_DATE);
0368: columnToAdd.setValueComparator(TemporalValueComparator
0369: .getInstance());
0370: cachedColumns.add(columnToAdd);
0371:
0372: columnToAdd = new Column();
0373: columnToAdd.setColumnTitle("Enc Update Code");
0374: columnToAdd
0375: .setPropertyName(KFSPropertyConstants.TRANSACTION_ENCUMBRANCE_UPDT_CD);
0376: columnToAdd.setValueComparator(StringValueComparator
0377: .getInstance());
0378: cachedColumns.add(columnToAdd);
0379:
0380: cachedColumns = Collections
0381: .unmodifiableList(cachedColumns);
0382: }
0383: }
0384: return cachedColumns;
0385: }
0386:
0387: /**
0388: * Generates the file name that input origin entries should be retrieved from
0389: *
0390: * @param document a GLCP document
0391: * @return the name of the file to read
0392: */
0393: protected String generateInputOriginEntryFileName(
0394: CorrectionDocument document) {
0395: String docId = document.getDocumentHeader().getDocumentNumber();
0396: return generateInputOriginEntryFileName(docId);
0397: }
0398:
0399: /**
0400: * Generates the file name that output origin entries should be written to
0401: *
0402: * @param document a GLCP document
0403: * @return the name of the file to write to
0404: */
0405: protected String generateOutputOriginEntryFileName(
0406: CorrectionDocument document) {
0407: String docId = document.getDocumentHeader().getDocumentNumber();
0408: return generateOutputOriginEntryFileName(docId);
0409: }
0410:
0411: /**
0412: * Generates the file name that input origin entries should be retrieved from
0413: *
0414: * @param docId the document id of a GLCP document
0415: * @return the name of the file to read input origin entries in from
0416: */
0417: protected String generateInputOriginEntryFileName(String docId) {
0418: return getOriginEntryStagingDirectoryPath() + File.separator
0419: + docId + INPUT_ORIGIN_ENTRIES_FILE_SUFFIX;
0420: }
0421:
0422: /**
0423: * Generates the file name that output origin entries should be written to
0424: *
0425: * @param docId the document id of a GLCP document
0426: * @return the name of the file to write output origin entries to
0427: */
0428: protected String generateOutputOriginEntryFileName(String docId) {
0429: return getOriginEntryStagingDirectoryPath() + File.separator
0430: + docId + OUTPUT_ORIGIN_ENTRIES_FILE_SUFFIX;
0431: }
0432:
0433: /**
0434: * This method persists an Iterator of input origin entries for a document that is in the initiated or saved state
0435: *
0436: * @param document an initiated or saved document
0437: * @param entries an Iterator of origin entries
0438: * @see org.kuali.module.gl.service.CorrectionDocumentService#persistOriginEntriesToFile(java.lang.String, java.util.Iterator)
0439: */
0440: public void persistInputOriginEntriesForInitiatedOrSavedDocument(
0441: CorrectionDocument document,
0442: Iterator<OriginEntryFull> entries) {
0443: KualiWorkflowDocument workflowDocument = document
0444: .getDocumentHeader().getWorkflowDocument();
0445: if (!workflowDocument.stateIsInitiated()
0446: && !workflowDocument.stateIsSaved()) {
0447: LOG
0448: .error("This method may only be called when the document is in the initiated or saved state.");
0449: }
0450: String fullPathUniqueFileName = generateInputOriginEntryFileName(document);
0451: persistOriginEntries(fullPathUniqueFileName, entries);
0452: }
0453:
0454: /**
0455: * This method persists an Iterator of output origin entries for a document that is in the initiated or saved state
0456: *
0457: * @param document an initiated or saved document
0458: * @param entries an Iterator of origin entries
0459: * @see org.kuali.module.gl.service.CorrectionDocumentService#persistOutputOriginEntriesForInitiatedOrSavedDocument(org.kuali.module.gl.document.CorrectionDocument,
0460: * java.util.Iterator)
0461: */
0462: public void persistOutputOriginEntriesForInitiatedOrSavedDocument(
0463: CorrectionDocument document,
0464: Iterator<OriginEntryFull> entries) {
0465: KualiWorkflowDocument workflowDocument = document
0466: .getDocumentHeader().getWorkflowDocument();
0467: if (!workflowDocument.stateIsInitiated()
0468: && !workflowDocument.stateIsSaved()) {
0469: LOG
0470: .error("This method may only be called when the document is in the initiated or saved state.");
0471: }
0472: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0473: persistOriginEntries(fullPathUniqueFileName, entries);
0474: }
0475:
0476: /**
0477: * Saves an interator of Origin Entry records to the given file name
0478: *
0479: * @param fullPathUniqueFileName the name of the file to write entries to
0480: * @param entries entries to write
0481: */
0482: protected void persistOriginEntries(String fullPathUniqueFileName,
0483: Iterator<OriginEntryFull> entries) {
0484: File fileOut = new File(fullPathUniqueFileName);
0485: FileOutputStream streamOut = null;
0486: BufferedOutputStream bufferedStreamOut = null;
0487: try {
0488: streamOut = new FileOutputStream(fileOut);
0489: bufferedStreamOut = new BufferedOutputStream(streamOut);
0490:
0491: byte[] newLine = "\n".getBytes();
0492: while (entries.hasNext()) {
0493: OriginEntryFull entry = entries.next();
0494: bufferedStreamOut.write(entry.getLine().getBytes());
0495: bufferedStreamOut.write(newLine);
0496: }
0497: } catch (IOException e) {
0498: LOG.error("unable to persist origin entries to file: "
0499: + fullPathUniqueFileName, e);
0500: throw new RuntimeException(
0501: "unable to persist origin entries to file.");
0502: } finally {
0503: try {
0504: bufferedStreamOut.close();
0505: streamOut.close();
0506: } catch (IOException e) {
0507: LOG.error("unable to close output streams for file: "
0508: + fullPathUniqueFileName, e);
0509: throw new RuntimeException(
0510: "unable to close output streams");
0511: }
0512: }
0513: }
0514:
0515: /**
0516: * Opens an Output Stream to write Origin Entries to
0517: *
0518: * @param document the GLCP document which has the origin entries to write
0519: * @return an OutputStream to write to
0520: * @throws IOException if the file cannot be successfully opened
0521: */
0522: protected BufferedOutputStream openEntryOutputStreamForOutputGroup(
0523: CorrectionDocument document) throws IOException {
0524: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0525: return new BufferedOutputStream(new FileOutputStream(
0526: fullPathUniqueFileName));
0527: }
0528:
0529: /**
0530: * Removes input origin entries that were saved to the database associated with the given document
0531: *
0532: * @param document a GLCP document
0533: * @see org.kuali.module.gl.service.CorrectionDocumentService#removePersistedInputOriginEntriesForInitiatedOrSavedDocument(org.kuali.module.gl.document.CorrectionDocument)
0534: */
0535: public void removePersistedInputOriginEntries(
0536: CorrectionDocument document) {
0537: String fullPathUniqueFileName = generateInputOriginEntryFileName(document);
0538: removePersistedOriginEntries(fullPathUniqueFileName);
0539: }
0540:
0541: /**
0542: * Removes all output origin entries persisted in the database created by the given document
0543: *
0544: * @param document a GLCP document
0545: * @see org.kuali.module.gl.service.CorrectionDocumentService#removePersistedOutputOriginEntriesForInitiatedOrSavedDocument(org.kuali.module.gl.document.CorrectionDocument)
0546: */
0547: public void removePersistedOutputOriginEntries(
0548: CorrectionDocument document) {
0549: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0550: removePersistedOriginEntries(fullPathUniqueFileName);
0551: }
0552:
0553: /**
0554: * Removes input origin entries that were saved to the database associated with the given document
0555: *
0556: * @param docId the document id of a GLCP document
0557: * @see org.kuali.module.gl.service.CorrectionDocumentService#removePersistedInputOriginEntries(java.lang.String)
0558: */
0559: public void removePersistedInputOriginEntries(String docId) {
0560: removePersistedOriginEntries(generateInputOriginEntryFileName(docId));
0561: }
0562:
0563: /**
0564: * Removes all output origin entries persisted in the database created by the given document
0565: *
0566: * @param docId the document id of a GLCP document
0567: * @see org.kuali.module.gl.service.CorrectionDocumentService#removePersistedOutputOriginEntries(java.lang.String)
0568: */
0569: public void removePersistedOutputOriginEntries(String docId) {
0570: removePersistedOriginEntries(generateOutputOriginEntryFileName(docId));
0571: }
0572:
0573: /**
0574: * Removes a file of origin entries. Just deletes the whole thing!
0575: *
0576: * @param fullPathUniqueFileName the file name of the file holding origin entries
0577: */
0578: protected void removePersistedOriginEntries(
0579: String fullPathUniqueFileName) {
0580: File fileOut = new File(fullPathUniqueFileName);
0581: if (fileOut.exists() && fileOut.isFile()) {
0582: fileOut.delete();
0583: }
0584: }
0585:
0586: /**
0587: * retrieves input origin entries that have been persisted for this document
0588: *
0589: * @param document the document
0590: * @param abortThreshold if the file exceeds this number of rows, then null is returned. {@link UNLIMITED_ABORT_THRESHOLD}
0591: * signifies that there is no limit
0592: * @return the list, or null if there are too many origin entries
0593: * @throws RuntimeException several reasons, primarily relating to underlying persistence layer problems
0594: * @see org.kuali.module.gl.service.CorrectionDocumentService#retrievePersistedInputOriginEntries(org.kuali.module.gl.document.CorrectionDocument,
0595: * int)
0596: */
0597: public List<OriginEntryFull> retrievePersistedInputOriginEntries(
0598: CorrectionDocument document, int abortThreshold) {
0599: return retrievePersistedOriginEntries(
0600: generateInputOriginEntryFileName(document),
0601: abortThreshold);
0602: }
0603:
0604: /**
0605: * retrieves output origin entries that have been persisted for this document
0606: *
0607: * @param document the document
0608: * @param abortThreshold if the file exceeds this number of rows, then null is returned. {@link UNLIMITED_ABORT_THRESHOLD}
0609: * signifies that there is no limit
0610: * @return the list, or null if there are too many origin entries
0611: * @throws RuntimeException several reasons, primarily relating to underlying persistence layer problems
0612: * @see org.kuali.module.gl.service.CorrectionDocumentService#retrievePersistedOutputOriginEntries(org.kuali.module.gl.document.CorrectionDocument,
0613: * int)
0614: */
0615: public List<OriginEntryFull> retrievePersistedOutputOriginEntries(
0616: CorrectionDocument document, int abortThreshold) {
0617: return retrievePersistedOriginEntries(
0618: generateOutputOriginEntryFileName(document),
0619: abortThreshold);
0620: }
0621:
0622: /**
0623: * Reads a file of origin entries and returns a List of those entry records
0624: *
0625: * @param fullPathUniqueFileName the file name of the file to read
0626: * @param abortThreshold if more entries than this need to be read...well, they just won't get read
0627: * @return a List of OriginEntryFulls
0628: */
0629: protected List<OriginEntryFull> retrievePersistedOriginEntries(
0630: String fullPathUniqueFileName, int abortThreshold) {
0631: File fileIn = new File(fullPathUniqueFileName);
0632: if (!fileIn.exists()) {
0633: LOG.error("File " + fullPathUniqueFileName
0634: + " does not exist.");
0635: throw new RuntimeException("File does not exist");
0636: }
0637: BufferedReader reader = null;
0638: FileReader fReader = null;
0639:
0640: List<OriginEntryFull> entries = new ArrayList<OriginEntryFull>();
0641: int lineNumber = 0;
0642: try {
0643: fReader = new FileReader(fileIn);
0644: reader = new BufferedReader(fReader);
0645: String line;
0646: while ((line = reader.readLine()) != null) {
0647: OriginEntryFull entry = new OriginEntryFull();
0648: entry.setFromTextFile(line, lineNumber);
0649: if (abortThreshold != UNLIMITED_ABORT_THRESHOLD
0650: && lineNumber >= abortThreshold) {
0651: return null;
0652: }
0653: lineNumber++;
0654: entries.add(entry);
0655: }
0656: } catch (IOException e) {
0657: LOG.error(
0658: "retrievePersistedOriginEntries() Error reading file "
0659: + fileIn.getAbsolutePath(), e);
0660: throw new RuntimeException("Error reading file");
0661: } finally {
0662: try {
0663: if (fReader != null) {
0664: fReader.close();
0665: }
0666: if (reader != null) {
0667: reader.close();
0668: }
0669: } catch (IOException e) {
0670: LOG.error("Unable to close file "
0671: + fileIn.getAbsolutePath(), e);
0672: throw new RuntimeException("Error closing file");
0673: }
0674: }
0675: return entries;
0676: }
0677:
0678: /**
0679: * Retrieves input origin entries that have been persisted for this document in an iterator. Implementations of this method may
0680: * choose to implement this method in a way that consumes very little memory.
0681: *
0682: * @param document the document
0683: * @return the iterator
0684: * @see org.kuali.module.gl.service.CorrectionDocumentService#retrievePersistedInputOriginEntriesAsIterator(org.kuali.module.gl.document.CorrectionDocument)
0685: */
0686: public Iterator<OriginEntryFull> retrievePersistedInputOriginEntriesAsIterator(
0687: CorrectionDocument document) {
0688: String fullPathUniqueFileName = generateInputOriginEntryFileName(document);
0689: return retrievePersistedOriginEntriesAsIterator(fullPathUniqueFileName);
0690: }
0691:
0692: /**
0693: * Retrieves output origin entries that have been persisted for this document in an iterator. Implementations of this method may
0694: * choose to implement this method in a way that consumes very little memory.
0695: *
0696: * @param document the document
0697: * @return the iterator
0698: * @throws RuntimeException several reasons, primarily relating to underlying persistence layer problems
0699: * @see org.kuali.module.gl.service.CorrectionDocumentService#retrievePersistedOutputOriginEntriesAsIterator(org.kuali.module.gl.document.CorrectionDocument)
0700: */
0701: public Iterator<OriginEntryFull> retrievePersistedOutputOriginEntriesAsIterator(
0702: CorrectionDocument document) {
0703: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0704: return retrievePersistedOriginEntriesAsIterator(fullPathUniqueFileName);
0705: }
0706:
0707: /**
0708: * Reads origin entries from a file to an iterator
0709: *
0710: * @param fullPathUniqueFileName the file name to read from
0711: * @return an Iterator of OriginEntries
0712: */
0713: protected Iterator<OriginEntryFull> retrievePersistedOriginEntriesAsIterator(
0714: String fullPathUniqueFileName) {
0715: File fileIn = new File(fullPathUniqueFileName);
0716: if (!fileIn.exists()) {
0717: LOG.error("File " + fullPathUniqueFileName
0718: + " does not exist.");
0719: throw new RuntimeException("File does not exist");
0720: }
0721: BufferedReader reader = null;
0722: FileReader fReader = null;
0723:
0724: try {
0725: fReader = new FileReader(fileIn);
0726: reader = new BufferedReader(fReader);
0727:
0728: return new OriginEntryFileIterator(reader);
0729: } catch (IOException e) {
0730: LOG.error(
0731: "retrievePersistedOriginEntries() Error opening file "
0732: + fileIn.getAbsolutePath(), e);
0733: throw new RuntimeException("Error opening file");
0734: }
0735: // don't close the reader, the iterator will take care of that
0736: }
0737:
0738: /**
0739: * Returns true if and only if the file corresponding to this document's input origin entries are on the file system.
0740: *
0741: * @see org.kuali.module.gl.service.CorrectionDocumentService#areInputOriginEntriesPersisted(org.kuali.module.gl.document.CorrectionDocument)
0742: */
0743: public boolean areInputOriginEntriesPersisted(
0744: CorrectionDocument document) {
0745: String fullPathUniqueFileName = generateInputOriginEntryFileName(document);
0746: File file = new File(fullPathUniqueFileName);
0747: return file.exists();
0748: }
0749:
0750: /**
0751: * Returns true if and only if the file corresponding to this document's output origin entries are on the file system.
0752: * @param document a GLCP document to query
0753: * @return true if origin entries are stored to the system, false otherwise
0754: * @see org.kuali.module.gl.service.CorrectionDocumentService#areOutputOriginEntriesPersisted(org.kuali.module.gl.document.CorrectionDocument)
0755: */
0756: public boolean areOutputOriginEntriesPersisted(
0757: CorrectionDocument document) {
0758: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0759: File file = new File(fullPathUniqueFileName);
0760: return file.exists();
0761: }
0762:
0763: /**
0764: * Writes out the persisted input origin entries in an {@link OutputStream} in a flat file format\
0765: *
0766: * @param document a GLCP document
0767: * @param out axn open and ready output stream
0768: * @throws IOException thrown if IOExceptions occurred in writing the persisted origin entries
0769: * @see org.kuali.module.gl.service.CorrectionDocumentService#writePersistedInputOriginEntriesToStream(java.io.OutputStream)
0770: */
0771: public void writePersistedInputOriginEntriesToStream(
0772: CorrectionDocument document, OutputStream out)
0773: throws IOException {
0774: String fullPathUniqueFileName = generateInputOriginEntryFileName(document);
0775: writePersistedOriginEntriesToStream(fullPathUniqueFileName, out);
0776: }
0777:
0778: /**
0779: * Writes out the persisted output origin entries in an {@link OutputStream} in a flat file format\
0780: *
0781: * @param document a GLCP document
0782: * @param out axn open and ready output stream
0783: * @throws IOException thrown if IOExceptions occurred in writing the persisted origin entries
0784: * @see org.kuali.module.gl.service.CorrectionDocumentService#writePersistedOutputOriginEntriesToStream(java.io.OutputStream)
0785: */
0786: public void writePersistedOutputOriginEntriesToStream(
0787: CorrectionDocument document, OutputStream out)
0788: throws IOException {
0789: String fullPathUniqueFileName = generateOutputOriginEntryFileName(document);
0790: writePersistedOriginEntriesToStream(fullPathUniqueFileName, out);
0791: }
0792:
0793: /**
0794: * Writes origin entries to an output stream
0795: *
0796: * @param fullPathUniqueFileName the name of the file to write to
0797: * @param out an output stream to write to
0798: * @throws IOException thrown if problems occur during writing
0799: */
0800: protected void writePersistedOriginEntriesToStream(
0801: String fullPathUniqueFileName, OutputStream out)
0802: throws IOException {
0803: FileInputStream fileIn = new FileInputStream(
0804: fullPathUniqueFileName);
0805:
0806: try {
0807: byte[] buf = new byte[1000];
0808: int bytesRead;
0809:
0810: while ((bytesRead = fileIn.read(buf)) != -1) {
0811: out.write(buf, 0, bytesRead);
0812: }
0813: } finally {
0814: fileIn.close();
0815: }
0816: }
0817:
0818: /**
0819: * Saves the input and output origin entry groups for a document prior to saving the document
0820: *
0821: * @param document a GLCP document
0822: * @param correctionDocumentEntryMetadata metadata about this GLCP document
0823: * @see org.kuali.module.gl.service.CorrectionDocumentService#persistOriginEntryGroupsForDocumentSave(org.kuali.module.gl.document.CorrectionDocument, org.kuali.module.gl.util.CorrectionDocumentEntryMetadata)
0824: */
0825: public void persistOriginEntryGroupsForDocumentSave(
0826: CorrectionDocument document,
0827: CorrectionDocumentEntryMetadata correctionDocumentEntryMetadata) {
0828: if (correctionDocumentEntryMetadata.getAllEntries() == null
0829: && !correctionDocumentEntryMetadata
0830: .isRestrictedFunctionalityMode()) {
0831: // if we don't have origin entries loaded and not in restricted functionality mode, then there's nothing worth
0832: // persisting
0833: removePersistedInputOriginEntries(document);
0834: removePersistedOutputOriginEntries(document);
0835: return;
0836: }
0837:
0838: if (!correctionDocumentEntryMetadata.getDataLoadedFlag()
0839: && !correctionDocumentEntryMetadata
0840: .isRestrictedFunctionalityMode()) {
0841: // data is not loaded (maybe user selected a new group with no rows)
0842: // clear out existing data
0843: removePersistedInputOriginEntries(document);
0844: removePersistedOutputOriginEntries(document);
0845: return;
0846: }
0847:
0848: // reload the group from the origin entry service
0849: Iterator<OriginEntryFull> inputGroupEntries;
0850: KualiWorkflowDocument workflowDocument = document
0851: .getDocumentHeader().getWorkflowDocument();
0852: if ((workflowDocument.stateIsSaved() && !(correctionDocumentEntryMetadata
0853: .getInputGroupIdFromLastDocumentLoad() != null && correctionDocumentEntryMetadata
0854: .getInputGroupIdFromLastDocumentLoad().equals(
0855: document.getCorrectionInputGroupId())))
0856: || workflowDocument.stateIsInitiated()) {
0857: // we haven't saved the origin entry group yet, so let's load the entries from the DB and persist them for the document
0858: // this could be because we've previously saved the doc, but now we are now using a new input group, so we have to
0859: // repersist the input group
0860: OriginEntryGroup group = originEntryGroupService
0861: .getExactMatchingEntryGroup(document
0862: .getCorrectionInputGroupId());
0863: inputGroupEntries = originEntryService
0864: .getEntriesByGroup(group);
0865: persistInputOriginEntriesForInitiatedOrSavedDocument(
0866: document, inputGroupEntries);
0867:
0868: // we've exhausted the iterator for the origin entries group
0869: // reload the iterator from the file
0870: inputGroupEntries = retrievePersistedInputOriginEntriesAsIterator(document);
0871: } else if (workflowDocument.stateIsSaved()
0872: && correctionDocumentEntryMetadata
0873: .getInputGroupIdFromLastDocumentLoad().equals(
0874: document.getCorrectionInputGroupId())) {
0875: // we've saved the origin entries before, so just retrieve them
0876: inputGroupEntries = retrievePersistedInputOriginEntriesAsIterator(document);
0877: } else {
0878: LOG
0879: .error("Unexpected state while trying to persist/retrieve GLCP origin entries during document save: document status is "
0880: + workflowDocument.getStatusDisplayValue()
0881: + " selected input group: "
0882: + document.getCorrectionInputGroupId()
0883: + " last saved input group: "
0884: + correctionDocumentEntryMetadata
0885: .getInputGroupIdFromLastDocumentLoad());
0886: throw new RuntimeException(
0887: "Error persisting GLCP document origin entries.");
0888: }
0889:
0890: OriginEntryStatistics statistics;
0891: if (CorrectionDocumentService.CORRECTION_TYPE_MANUAL
0892: .equals(correctionDocumentEntryMetadata.getEditMethod())) {
0893: // persist the allEntries element as the output group, since it has all of the modifications made by during the manual
0894: // edits
0895: persistOutputOriginEntriesForInitiatedOrSavedDocument(
0896: document, correctionDocumentEntryMetadata
0897: .getAllEntries().iterator());
0898:
0899: // even though the struts action handler may have computed the doc totals, let's recompute them
0900: statistics = CorrectionDocumentUtils
0901: .getStatistics(correctionDocumentEntryMetadata
0902: .getAllEntries());
0903: } else if (CorrectionDocumentService.CORRECTION_TYPE_CRITERIA
0904: .equals(correctionDocumentEntryMetadata.getEditMethod())) {
0905: // we want to persist the values of the output group. So reapply all of the criteria on each entry, one at a time
0906:
0907: BufferedOutputStream bufferedOutputStream = null;
0908: try {
0909: bufferedOutputStream = openEntryOutputStreamForOutputGroup(document);
0910: statistics = new OriginEntryStatistics();
0911: byte[] newLine = "\n".getBytes();
0912:
0913: while (inputGroupEntries.hasNext()) {
0914: OriginEntryFull entry = inputGroupEntries.next();
0915:
0916: entry = CorrectionDocumentUtils
0917: .applyCriteriaToEntry(entry,
0918: correctionDocumentEntryMetadata
0919: .getMatchCriteriaOnly(),
0920: document.getCorrectionChangeGroup());
0921: if (entry != null) {
0922: CorrectionDocumentUtils
0923: .updateStatisticsWithEntry(entry,
0924: statistics);
0925: bufferedOutputStream.write(entry.getLine()
0926: .getBytes());
0927: bufferedOutputStream.write(newLine);
0928: }
0929: // else it was null, which means that the match criteria only flag was set, and the entry didn't match the
0930: // criteria
0931: }
0932: } catch (IOException e) {
0933: LOG
0934: .error(
0935: "Unable to persist persisted output entry",
0936: e);
0937: throw new RuntimeException(
0938: "Unable to persist output entry");
0939: } finally {
0940: if (bufferedOutputStream != null) {
0941: try {
0942: bufferedOutputStream.close();
0943: } catch (IOException e) {
0944: LOG
0945: .error(
0946: "Unable to close output stream for persisted output entries",
0947: e);
0948: throw new RuntimeException(
0949: "Unable to close output entry file");
0950: }
0951: }
0952: }
0953: } else if (CorrectionDocumentService.CORRECTION_TYPE_REMOVE_GROUP_FROM_PROCESSING
0954: .equals(correctionDocumentEntryMetadata.getEditMethod())) {
0955: // just wipe out the previous output entries
0956: removePersistedOutputOriginEntries(document);
0957: statistics = new OriginEntryStatistics();
0958: } else {
0959: throw new RuntimeException("Unrecognized edit method: "
0960: + correctionDocumentEntryMetadata.getEditMethod());
0961: }
0962:
0963: CorrectionDocumentUtils.copyStatisticsToDocument(statistics,
0964: document);
0965: }
0966:
0967: /**
0968: * Gets the name of the directory to save all these temporary files in
0969: *
0970: * @return the name of a directory path
0971: */
0972: protected String getOriginEntryStagingDirectoryPath() {
0973: return getGlcpDirectoryName();
0974: }
0975:
0976: /**
0977: * Gets the kualiConfigurationService attribute.
0978: *
0979: * @return Returns the kualiConfigurationService.
0980: */
0981: public KualiConfigurationService getKualiConfigurationService() {
0982: return kualiConfigurationService;
0983: }
0984:
0985: /**
0986: * Sets the kualiConfigurationService attribute value.
0987: *
0988: * @param kualiConfigurationService The kualiConfigurationService to set.
0989: */
0990: public void setKualiConfigurationService(
0991: KualiConfigurationService kualiConfigurationService) {
0992: this .kualiConfigurationService = kualiConfigurationService;
0993: }
0994:
0995: /**
0996: * Gets the originEntryService attribute.
0997: *
0998: * @return Returns the originEntryService.
0999: */
1000: public OriginEntryService getOriginEntryService() {
1001: return originEntryService;
1002: }
1003:
1004: /**
1005: * Sets the originEntryService attribute value.
1006: *
1007: * @param originEntryService The originEntryService to set.
1008: */
1009: public void setOriginEntryService(
1010: OriginEntryService originEntryService) {
1011: this .originEntryService = originEntryService;
1012: }
1013:
1014: /**
1015: * Gets the glcpDirectoryName attribute.
1016: *
1017: * @return Returns the glcpDirectoryName.
1018: */
1019: public String getGlcpDirectoryName() {
1020: return glcpDirectoryName;
1021: }
1022:
1023: /**
1024: * Sets the glcpDirectoryName attribute value.
1025: *
1026: * @param glcpDirectoryName The glcpDirectoryName to set.
1027: */
1028: public void setGlcpDirectoryName(String glcpDirectoryName) {
1029: this .glcpDirectoryName = glcpDirectoryName;
1030: }
1031:
1032: /**
1033: * Gets the originEntryGroupService attribute.
1034: *
1035: * @return Returns the originEntryGroupService.
1036: */
1037: public OriginEntryGroupService getOriginEntryGroupService() {
1038: return originEntryGroupService;
1039: }
1040:
1041: /**
1042: * Sets the originEntryGroupService attribute value.
1043: *
1044: * @param originEntryGroupService The originEntryGroupService to set.
1045: */
1046: public void setOriginEntryGroupService(
1047: OriginEntryGroupService originEntryGroupService) {
1048: this .originEntryGroupService = originEntryGroupService;
1049: }
1050:
1051: /**
1052: * @see org.kuali.module.gl.service.CorrectionDocumentService#getCorrectionDocumentsFinalizedOn(java.sql.Date)
1053: */
1054: public Collection<CorrectionDocument> getCorrectionDocumentsFinalizedOn(
1055: Date date) {
1056: return correctionDocumentDao
1057: .getCorrectionDocumentsFinalizedOn(date);
1058: }
1059:
1060: public void setCorrectionDocumentDao(
1061: CorrectionDocumentDao correctionDocumentDao) {
1062: this.correctionDocumentDao = correctionDocumentDao;
1063: }
1064: }
|