1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.dbunit.dataset.csv;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.LineNumberReader;
30 import java.io.Reader;
31 import java.net.URL;
32 import java.text.CharacterIterator;
33 import java.text.StringCharacterIterator;
34 import java.util.ArrayList;
35 import java.util.List;
36
37 import org.dbunit.dataset.common.handlers.EscapeHandler;
38 import org.dbunit.dataset.common.handlers.IllegalInputCharacterException;
39 import org.dbunit.dataset.common.handlers.IsAlnumHandler;
40 import org.dbunit.dataset.common.handlers.Pipeline;
41 import org.dbunit.dataset.common.handlers.PipelineException;
42 import org.dbunit.dataset.common.handlers.QuoteHandler;
43 import org.dbunit.dataset.common.handlers.SeparatorHandler;
44 import org.dbunit.dataset.common.handlers.TransparentHandler;
45 import org.dbunit.dataset.common.handlers.WhitespacesHandler;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49
50
51
52
53
54
55 public class CsvParserImpl implements CsvParser {
56
57
58
59
60 private static final Logger logger = LoggerFactory.getLogger(CsvParserImpl.class);
61
62 private Pipeline pipeline;
63
64 public CsvParserImpl() {
65 resetThePipeline();
66 }
67
68 private void resetThePipeline() {
69 logger.debug("resetThePipeline() - start");
70
71 pipeline = new Pipeline();
72 getPipeline().putFront(SeparatorHandler.ENDPIECE());
73 getPipeline().putFront(EscapeHandler.ACCEPT());
74 getPipeline().putFront(IsAlnumHandler.QUOTE());
75 getPipeline().putFront(QuoteHandler.QUOTE());
76 getPipeline().putFront(EscapeHandler.ESCAPE());
77 getPipeline().putFront(WhitespacesHandler.IGNORE());
78 getPipeline().putFront(TransparentHandler.IGNORE());
79 }
80
81 public List parse(String csv) throws PipelineException, IllegalInputCharacterException {
82 logger.debug("parse(csv={}) - start", csv);
83
84 getPipeline().resetProducts();
85 CharacterIterator iterator = new StringCharacterIterator(csv);
86 for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
87 getPipeline().handle(c);
88 }
89 getPipeline().noMoreInput();
90 getPipeline().thePieceIsDone();
91 return getPipeline().getProducts();
92 }
93
94 public List parse(File file) throws IOException, CsvParserException {
95 logger.debug("parse(file={}) - start", file);
96
97 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
98 try {
99 return parse(reader, file.getAbsolutePath().toString());
100 }
101 finally {
102 reader.close();
103 }
104 }
105
106 public List parse(URL url) throws IOException, CsvParserException {
107 logger.debug("parse(url={}) - start", url);
108
109 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
110 try {
111 return parse(reader, url.toString());
112 }
113 finally {
114 reader.close();
115 }
116 }
117
118 public List parse(Reader reader, String source) throws IOException, CsvParserException {
119 logger.debug("parse(reader={}, source={}) - start", reader, source);
120
121 LineNumberReader lineNumberReader = new LineNumberReader(reader);
122 List rows = new ArrayList();
123 List columnsInFirstLine = parseFirstLine(lineNumberReader, source, rows);
124 parseTheData(columnsInFirstLine, lineNumberReader, rows);
125 return rows;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139 private List parseFirstLine(LineNumberReader lineNumberReader, String source, List rows) throws IOException, CsvParserException {
140 if(logger.isDebugEnabled())
141 logger.debug("parseFirstLine(lineNumberReader={}, source={}, rows={}) - start",
142 new Object[]{lineNumberReader,source,rows});
143
144 String firstLine = lineNumberReader.readLine();
145 if (firstLine == null)
146 throw new CsvParserException("The first line of " + source + " is null");
147
148 final List columnsInFirstLine = parse(firstLine);
149 rows.add(columnsInFirstLine);
150 return columnsInFirstLine;
151 }
152
153 private void parseTheData(final List columnsInFirstLine, LineNumberReader lineNumberReader, List rows) throws IOException, CsvParserException {
154 logger.debug("parseTheData(columnsInFirstLine={}, lineNumberReader={}, rows={}) - start",
155 new Object[] {columnsInFirstLine, lineNumberReader, rows} );
156
157 int nColumns = columnsInFirstLine.size();
158 List columns;
159 while ((columns = collectExpectedNumberOfColumns(nColumns, lineNumberReader)) != null) {
160 rows.add(columns);
161 }
162 }
163
164 private List collectExpectedNumberOfColumns(int expectedNumberOfColumns, LineNumberReader lineNumberReader) throws IOException, CsvParserException {
165 if(logger.isDebugEnabled())
166 logger.debug("collectExpectedNumberOfColumns(expectedNumberOfColumns={}, lineNumberReader={}) - start",
167 String.valueOf(expectedNumberOfColumns), lineNumberReader);
168
169 List columns = null;
170 int columnsCollectedSoFar = 0;
171 final StringBuilder buffer = new StringBuilder();
172 String anotherLine = lineNumberReader.readLine();
173 if(anotherLine == null)
174 return null;
175 boolean shouldProceed = false;
176 while (columnsCollectedSoFar < expectedNumberOfColumns) {
177 try {
178 buffer.append(anotherLine);
179 columns = parse(buffer.toString());
180 columnsCollectedSoFar = columns.size();
181 } catch (IllegalStateException e) {
182 resetThePipeline();
183 anotherLine = lineNumberReader.readLine();
184 if(anotherLine == null)
185 break;
186 buffer.append("\n");
187 shouldProceed = true;
188 }
189 if (!shouldProceed)
190 break;
191 }
192 if (columnsCollectedSoFar != expectedNumberOfColumns) {
193 String message = new StringBuilder("Expected ").append(expectedNumberOfColumns)
194 .append(" columns on line ").append(lineNumberReader.getLineNumber())
195 .append(", got ").append(columnsCollectedSoFar).append(". Offending line: ").append(buffer).toString();
196 throw new CsvParserException(message);
197 }
198 return columns;
199 }
200
201 Pipeline getPipeline() {
202 logger.debug("getPipeline() - start");
203
204 return pipeline;
205 }
206
207 void setPipeline(Pipeline pipeline) {
208 logger.debug("setPipeline(pipeline={}) - start", pipeline);
209
210 this.pipeline = pipeline;
211 }
212 }