001: /*
002: *
003: * The DbUnit Database Testing Framework
004: * Copyright (C)2002-2004, DbUnit.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: */
021:
022: package org.dbunit.dataset.csv;
023:
024: import org.slf4j.Logger;
025: import org.slf4j.LoggerFactory;
026:
027: import org.dbunit.dataset.csv.handlers.*;
028:
029: import java.io.*;
030: import java.net.URL;
031: import java.text.CharacterIterator;
032: import java.text.StringCharacterIterator;
033: import java.util.ArrayList;
034: import java.util.List;
035:
036: public class CsvParserImpl implements CsvParser {
037:
038: /**
039: * Logger for this class
040: */
041: private static final Logger logger = LoggerFactory
042: .getLogger(CsvParserImpl.class);
043:
044: private Pipeline pipeline;
045:
046: public CsvParserImpl() {
047: resetThePipeline();
048: }
049:
050: private void resetThePipeline() {
051: logger.debug("resetThePipeline() - start");
052:
053: pipeline = new Pipeline();
054: getPipeline().putFront(SeparatorHandler.ENDPIECE());
055: getPipeline().putFront(EscapeHandler.ACCEPT());
056: getPipeline().putFront(IsAlnumHandler.QUOTE());
057: getPipeline().putFront(QuoteHandler.QUOTE());
058: getPipeline().putFront(EscapeHandler.ESCAPE());
059: getPipeline().putFront(WhitespacesHandler.IGNORE());
060: getPipeline().putFront(TransparentHandler.IGNORE());
061: }
062:
063: public List parse(String csv) throws PipelineException,
064: IllegalInputCharacterException {
065: logger.debug("parse(csv=" + csv + ") - start");
066:
067: getPipeline().resetProducts();
068: CharacterIterator iterator = new StringCharacterIterator(csv);
069: for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator
070: .next()) {
071: getPipeline().handle(c);
072: }
073: getPipeline().noMoreInput();
074: getPipeline().thePieceIsDone();
075: return getPipeline().getProducts();
076: }
077:
078: public List parse(File file) throws IOException, CsvParserException {
079: logger.debug("parse(file=" + file + ") - start");
080:
081: BufferedReader reader = new BufferedReader(
082: new InputStreamReader(new FileInputStream(file)));
083: return parse(reader, file.getAbsolutePath().toString());
084: }
085:
086: public List parse(URL url) throws IOException, CsvParserException {
087: logger.debug("parse(url=" + url + ") - start");
088:
089: BufferedReader reader = new BufferedReader(
090: new InputStreamReader(url.openStream()));
091: return parse(reader, url.toString());
092: }
093:
094: public List parse(Reader reader, String source) throws IOException,
095: CsvParserException {
096: logger.debug("parse(reader=" + reader + ", source=" + source
097: + ") - start");
098:
099: LineNumberReader lineNumberReader = new LineNumberReader(reader);
100: List rows = new ArrayList();
101: List columnsInFirstLine = parseFirstLine(lineNumberReader,
102: source, rows);
103: parseTheData(columnsInFirstLine, lineNumberReader, rows);
104: return rows;
105: }
106:
107: private List parseFirstLine(LineNumberReader lineNumberReader,
108: File file, List rows) throws IOException,
109: CsvParserException {
110: logger.debug("parseFirstLine(lineNumberReader="
111: + lineNumberReader + ", file=" + file + ", rows="
112: + rows + ") - start");
113:
114: return parseFirstLine(lineNumberReader, file.getAbsolutePath()
115: .toString(), rows);
116: }
117:
118: /** parse the first line of data from the given source */
119: private List parseFirstLine(LineNumberReader lineNumberReader,
120: String source, List rows) throws IOException,
121: CsvParserException {
122: logger.debug("parseFirstLine(lineNumberReader="
123: + lineNumberReader + ", source=" + source + ", rows="
124: + rows + ") - start");
125:
126: String firstLine = lineNumberReader.readLine();
127: if (firstLine == null)
128: throw new CsvParserException("The first line of " + source
129: + " is null");
130:
131: final List columnsInFirstLine = parse(firstLine);
132: rows.add(columnsInFirstLine);
133: return columnsInFirstLine;
134: }
135:
136: private void parseTheData(final List columnsInFirstLine,
137: LineNumberReader lineNumberReader, List rows)
138: throws IOException, CsvParserException {
139: logger.debug("parseTheData(columnsInFirstLine="
140: + columnsInFirstLine + ", lineNumberReader="
141: + lineNumberReader + ", rows=" + rows + ") - start");
142:
143: int nColumns = columnsInFirstLine.size();
144: List columns;
145: while ((columns = collectExpectedNumberOfColumns(nColumns,
146: lineNumberReader)) != null) {
147: rows.add(columns);
148: }
149: }
150:
151: private List collectExpectedNumberOfColumns(
152: int expectedNumberOfColumns,
153: LineNumberReader lineNumberReader) throws IOException,
154: CsvParserException {
155: logger
156: .debug("collectExpectedNumberOfColumns(expectedNumberOfColumns="
157: + expectedNumberOfColumns
158: + ", lineNumberReader="
159: + lineNumberReader
160: + ") - start");
161:
162: List columns = null;
163: int columnsCollectedSoFar = 0;
164: StringBuffer buffer = new StringBuffer();
165: String anotherLine = lineNumberReader.readLine();
166: if (anotherLine == null)
167: return null;
168: boolean shouldProceed = false;
169: while (columnsCollectedSoFar < expectedNumberOfColumns) {
170: try {
171: buffer.append(anotherLine);
172: columns = parse(buffer.toString());
173: columnsCollectedSoFar = columns.size();
174: } catch (IllegalStateException e) {
175: logger.error("collectExpectedNumberOfColumns()", e);
176:
177: resetThePipeline();
178: anotherLine = lineNumberReader.readLine();
179: if (anotherLine == null)
180: break;
181: buffer.append("\n");
182: shouldProceed = true;
183: }
184: if (!shouldProceed)
185: break;
186: }
187: if (columnsCollectedSoFar != expectedNumberOfColumns) {
188: String message = new StringBuffer("Expected ").append(
189: expectedNumberOfColumns)
190: .append(" columns on line ").append(
191: lineNumberReader.getLineNumber()).append(
192: ", got ").append(columnsCollectedSoFar)
193: .append(". Offending line: ").append(buffer)
194: .toString();
195: throw new CsvParserException(message);
196: }
197: return columns;
198: }
199:
200: Pipeline getPipeline() {
201: logger.debug("getPipeline() - start");
202:
203: return pipeline;
204: }
205:
206: void setPipeline(Pipeline pipeline) {
207: logger.debug("setPipeline(pipeline=" + pipeline + ") - start");
208:
209: this.pipeline = pipeline;
210: }
211: }
|