View Javadoc
1   package org.csveed.row;
2   
3   import java.io.IOException;
4   import java.io.Reader;
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import org.csveed.api.Header;
9   import org.csveed.api.Row;
10  import org.csveed.report.CsvException;
11  import org.csveed.report.RowError;
12  import org.csveed.token.ParseException;
13  import org.csveed.token.ParseStateMachine;
14  
15  /**
16  * Builds up a List of cells (String) per read row. Note that this class is stateful, so it
17  * can support a per-row parse approach as well.
18  * @author Robert Bor
19  */
20  public class RowReaderImpl implements RowReader {
21  
22      private ParseStateMachineteMachine">ParseStateMachine stateMachine = new ParseStateMachine();
23  
24      private RowInstructionsImpl rowInstructions;
25  
26      private int maxNumberOfColumns = -1;
27  
28      private HeaderImpl header;
29  
30      private Reader reader;
31  
32      public RowReaderImpl(Reader reader) {
33          this(reader, new RowInstructionsImpl());
34      }
35  
36      public RowReaderImpl(Reader reader, RowInstructions instructionsInterface) {
37          this.reader = reader;
38          this.rowInstructions = (RowInstructionsImpl) instructionsInterface;
39          stateMachine.setSymbolMapping(rowInstructions.getSymbolMapping());
40      }
41  
42      @Override
43      public List<Row> readRows() {
44          List<Row> allRows = new ArrayList<>();
45          while (!isFinished()) {
46              Row row = readRow();
47              if (row != null && row.size() > 0) {
48                  allRows.add(row);
49              }
50          }
51          return allRows;
52      }
53  
54      @Override
55      public Row readRow() {
56          getHeader();
57          Line unmappedLine = readBareLine();
58          if (unmappedLine == null) {
59              return null;
60          }
61          checkNumberOfColumns(unmappedLine);
62          return new RowImpl(unmappedLine, getHeader());
63      }
64  
65      @Override
66      public int getCurrentLine() {
67          return this.stateMachine.getCurrentLine();
68      }
69  
70      @Override
71      public Header getHeader() {
72          return header == null && rowInstructions.isUseHeader() ? readHeader() : header;
73      }
74  
75      public int getMaxNumberOfColumns() {
76          return this.maxNumberOfColumns;
77      }
78  
79      @Override
80      public Header readHeader() {
81          if (header != null) {
82              return header;
83          }
84          Line unmappedLine = readBareLine();
85          if (unmappedLine == null) {
86              return null;
87          }
88          return header = new HeaderImpl(unmappedLine);
89      }
90  
91      private void checkNumberOfColumns(Line unmappedLine) {
92          if (maxNumberOfColumns == -1) {
93              maxNumberOfColumns = header == null ? unmappedLine.size() : header.size();
94          }
95          if (unmappedLine.size() != maxNumberOfColumns) {
96              throw new CsvException(new RowError(
97                      "The expected number of columns is " + maxNumberOfColumns + ", whereas it was " + unmappedLine.size(),
98                      unmappedLine.reportOnEndOfLine(), getCurrentLine()
99                      ));
100         }
101     }
102 
103     @Override
104     public boolean isFinished() {
105         return stateMachine.isFinished();
106     }
107 
108     protected void logSettings() {
109         rowInstructions.logSettings();
110         this.stateMachine.getSymbolMapping().logSettings();
111     }
112 
113     protected Line readBareLine() {
114         logSettings();
115 
116         LineWithInfo line = null;
117         while (line == null && !stateMachine.isFinished()) {
118             line = new LineWithInfo();
119             while (!stateMachine.isFinished()) {
120                 final String token;
121                 final int symbol;
122                 try {
123                     symbol = reader.read();
124                 } catch (IOException err) {
125                     throw new RuntimeException(err);
126                 }
127                 try {
128                     token = stateMachine.offerSymbol(symbol);
129                 } catch (ParseException e) {
130                     throw new CsvException(new RowError(e.getMessage(), line.reportOnEndOfLine(), getCurrentLine()));
131                 }
132                 if (stateMachine.isTrash()) {
133                     continue;
134                 }
135                 if (stateMachine.isTokenStart()) {
136                     line.markStartOfColumn();
137                 }
138                 if (token != null) {
139                     line.addCell(token);
140                 }
141                 line.addCharacter(symbol);
142                 if (stateMachine.isLineFinished()) {
143                     break;
144                 }
145             }
146             line = stateMachine.ignoreLine() && rowInstructions.isSkipEmptyLines() ? null : line;
147         }
148         return line;
149     }
150 
151     @Override
152     public RowInstructions getRowInstructions() {
153         return this.rowInstructions;
154     }
155 
156 }