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 }