001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.module.bc.util;
017
018 import java.util.ArrayList;
019 import java.util.Arrays;
020 import java.util.List;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.kuali.kfs.module.bc.BCConstants;
024 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionRequestMove;
025 import org.kuali.rice.kns.util.KualiInteger;
026
027 /**
028 * This class contains methods to help parse budget construction import request files
029 *
030 */
031 public class ImportRequestFileParsingHelper {
032
033
034 /**
035 * Parses line and creates BudgetConstructionRequestMove object.
036 *
037 * @param lineToParse
038 * @param fieldSeperator
039 * @param textDelimiter
040 * @return the BudgetConstructionRequestMove or null if there was an error parsing the line
041 */
042 public static BudgetConstructionRequestMove parseLine(String lineToParse, String fieldSeperator, String textDelimiter, boolean isAnnual) {
043 List<String> attributes = new ArrayList<String>();
044 BudgetConstructionRequestMove budgetConstructionRequestMove = new BudgetConstructionRequestMove();
045
046 int expectedNumberOfSeparators = isAnnual ? 5 : 16;
047
048 lineToParse = lineToParse.trim();
049
050 //check if line is in correct format
051 if (!isLineCorrectlyFormatted(lineToParse, fieldSeperator, textDelimiter, isAnnual)) return null;
052
053 if (textDelimiter.equalsIgnoreCase(BCConstants.RequestImportTextFieldDelimiter.NOTHING.getDelimiter())) {
054 attributes.addAll(Arrays.asList(lineToParse.split(isFieldSeparatorSpecialCharacter(fieldSeperator) ? "\\" + fieldSeperator : fieldSeperator)));
055 } else if ( getEscapedFieldSeparatorCount(lineToParse, fieldSeperator, textDelimiter, isAnnual) == 0) {
056 lineToParse = StringUtils.remove(lineToParse, textDelimiter);
057 attributes.addAll(Arrays.asList(lineToParse.split(isFieldSeparatorSpecialCharacter(fieldSeperator) ? "\\" + fieldSeperator : fieldSeperator)));
058 } else {
059 int firstIndexOfTextDelimiter = 0;
060 int nextIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, firstIndexOfTextDelimiter + 1);
061 int expectedNumberOfTextDelimiters = 10;
062
063 for (int i = 0; i < expectedNumberOfTextDelimiters/2; i++) {
064 attributes.add(lineToParse.substring(firstIndexOfTextDelimiter, nextIndexOfTextDelimiter).replaceAll(textDelimiter, ""));
065 firstIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, nextIndexOfTextDelimiter + 1);
066 nextIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, firstIndexOfTextDelimiter + 1);
067 }
068
069 String remainingNonStringValuesToParse = lineToParse.substring(lineToParse.lastIndexOf(textDelimiter + 1));
070 attributes.addAll(Arrays.asList(remainingNonStringValuesToParse.split(isFieldSeparatorSpecialCharacter(fieldSeperator) ? "\\" + fieldSeperator : fieldSeperator)));
071 }
072
073 budgetConstructionRequestMove.setChartOfAccountsCode(attributes.get(0));
074 budgetConstructionRequestMove.setAccountNumber(attributes.get(1));
075 budgetConstructionRequestMove.setSubAccountNumber(attributes.get(2));
076 budgetConstructionRequestMove.setFinancialObjectCode(attributes.get(3));
077 budgetConstructionRequestMove.setFinancialSubObjectCode(attributes.get(4));
078
079 try {
080 if (isAnnual) {
081 budgetConstructionRequestMove.setAccountLineAnnualBalanceAmount(new KualiInteger(Integer.parseInt(attributes.get(5))));
082
083 } else {
084 budgetConstructionRequestMove.setFinancialDocumentMonth1LineAmount(new KualiInteger(Integer.parseInt(attributes.get(5))));
085 budgetConstructionRequestMove.setFinancialDocumentMonth2LineAmount(new KualiInteger(Integer.parseInt(attributes.get(6))));
086 budgetConstructionRequestMove.setFinancialDocumentMonth3LineAmount(new KualiInteger(Integer.parseInt(attributes.get(7))));
087 budgetConstructionRequestMove.setFinancialDocumentMonth4LineAmount(new KualiInteger(Integer.parseInt(attributes.get(8))));
088 budgetConstructionRequestMove.setFinancialDocumentMonth5LineAmount(new KualiInteger(Integer.parseInt(attributes.get(9))));
089 budgetConstructionRequestMove.setFinancialDocumentMonth6LineAmount(new KualiInteger(Integer.parseInt(attributes.get(10))));
090 budgetConstructionRequestMove.setFinancialDocumentMonth7LineAmount(new KualiInteger(Integer.parseInt(attributes.get(11))));
091 budgetConstructionRequestMove.setFinancialDocumentMonth8LineAmount(new KualiInteger(Integer.parseInt(attributes.get(12))));
092 budgetConstructionRequestMove.setFinancialDocumentMonth9LineAmount(new KualiInteger(Integer.parseInt(attributes.get(13))));
093 budgetConstructionRequestMove.setFinancialDocumentMonth10LineAmount(new KualiInteger(Integer.parseInt(attributes.get(14))));
094 budgetConstructionRequestMove.setFinancialDocumentMonth11LineAmount(new KualiInteger(Integer.parseInt(attributes.get(15))));
095 budgetConstructionRequestMove.setFinancialDocumentMonth12LineAmount(new KualiInteger(Integer.parseInt(attributes.get(16))));
096
097 }
098 }
099 catch (NumberFormatException e) {
100 return null;
101 }
102
103 return budgetConstructionRequestMove;
104 }
105
106 /**
107 * Checks for the correct number of field separators and text delimiters on line (either annual or monthly file). Does not check if the correct field separator and text delimiter are being used (form level validation should do this)
108 *
109 * @param lineToParse
110 * @param fieldSeperator
111 * @param textDelimiter
112 * @param isAnnual
113 * @return
114 */
115 public static boolean isLineCorrectlyFormatted(String lineToParse, String fieldSeperator, String textDelimiter, boolean isAnnual) {
116 int fieldSeparatorCount = StringUtils.countMatches(lineToParse, fieldSeperator);
117 int expectedNumberOfSeparators = isAnnual ? 5 : 16;
118
119 if (textDelimiter.equalsIgnoreCase(BCConstants.RequestImportTextFieldDelimiter.NOTHING.getDelimiter())) {
120
121 if (isAnnual) {
122 if (fieldSeparatorCount != 5) {
123 return false;
124 }
125 } else {
126 if (fieldSeparatorCount != 16) {
127 return false;
128 }
129 }
130 } else if (StringUtils.countMatches(lineToParse, textDelimiter) != 10) {
131 return false;
132 } else if ( getEscapedFieldSeparatorCount(lineToParse, fieldSeperator, textDelimiter, isAnnual) == -1 || ( fieldSeparatorCount - getEscapedFieldSeparatorCount(lineToParse, fieldSeperator, textDelimiter, isAnnual) != expectedNumberOfSeparators ) ) {
133 return false;
134 }
135
136 return true;
137 }
138
139 /**
140 * Checks if a line of an annual file contains an escaped field separator (convience method to aid in file parsing)
141 * Will not work correctly if text delimiters are not correctly placed in lineToParse (method does not check file formatting)
142 *
143 * @param lineToParse
144 * @param fieldSeperator
145 * @param textDelimiter
146 * @return number of escaped separators or -1 if file is incorrectly formatted
147 */
148 private static int getEscapedFieldSeparatorCount(String lineToParse, String fieldSeperator, String textDelimiter, boolean isAnnual) {
149 int firstIndexOfTextDelimiter = 0;
150 int nextIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, firstIndexOfTextDelimiter + 1);
151 int expectedNumberOfSeparators = isAnnual ? 5 : 16;
152 int expectedTextDelimitersCount = 10;
153 int actualNumberOfTextDelimiters = StringUtils.countMatches(lineToParse, textDelimiter);
154 int totalSeparatorsInLineToParse = StringUtils.countMatches(lineToParse, fieldSeperator);
155 int escapedSeparatorsCount = 0;
156
157 //line does not use text delimiters
158 if (textDelimiter.equalsIgnoreCase(BCConstants.RequestImportTextFieldDelimiter.NOTHING.getDelimiter())) return 0;
159
160 //line does not contain escaped field separators
161 if (totalSeparatorsInLineToParse == expectedNumberOfSeparators) return 0;
162
163 //line is incorrectly formatted
164 if ( actualNumberOfTextDelimiters != expectedTextDelimitersCount) return -1;
165
166 for (int i = 0; i < expectedTextDelimitersCount/2; i++) {
167 String escapedString = lineToParse.substring(firstIndexOfTextDelimiter, nextIndexOfTextDelimiter);
168 escapedSeparatorsCount += StringUtils.countMatches(escapedString, fieldSeperator);
169 firstIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, nextIndexOfTextDelimiter + 1);
170 nextIndexOfTextDelimiter = lineToParse.indexOf(textDelimiter, firstIndexOfTextDelimiter + 1);
171 }
172
173 return escapedSeparatorsCount;
174 }
175
176 /**
177 * Determines if the field delimiter is a regular expression special character
178 *
179 * @param delimiter
180 * @return true if special character
181 */
182 private static boolean isFieldSeparatorSpecialCharacter(String delimiter) {
183 if (delimiter.equals(".")) return true;
184 if (delimiter.equals("[")) return true;
185 if (delimiter.equals("\\")) return true;
186 if (delimiter.equals("*")) return true;
187 if (delimiter.equals("^")) return true;
188 if (delimiter.equals("$")) return true;
189
190 return false;
191 }
192
193 // private static ImportRequestLine createImportRequestLine(boolean isAnnual, int lineNumber) {
194 // ImportRequestLine line = isAnnual ? new ImportRequestAnnualLine(lineNumber) : new ImportRequestMonthlyLine(lineNumber);
195 //
196 // return line;
197 // }
198 }