View Javadoc
1   /*
2    * Copyright 2007 Kasper B. Graversen
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.supercsv.io;
17  
18  import java.io.IOException;
19  import java.io.Reader;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.supercsv.cellprocessor.ift.CellProcessor;
24  import org.supercsv.exception.SuperCsvConstraintViolationException;
25  import org.supercsv.exception.SuperCsvException;
26  import org.supercsv.prefs.CsvPreference;
27  import org.supercsv.util.Util;
28  
29  /**
30   * Defines the standard behaviour of a CSV reader.
31   * 
32   * @author Kasper B. Graversen
33   * @author James Bassett
34   */
35  public abstract class AbstractCsvReader implements ICsvReader {
36  	
37  	private final ITokenizer tokenizer;
38  	
39  	private final CsvPreference preferences;
40  	
41  	// the current tokenized columns
42  	private final List<String> columns = new ArrayList<String>();
43  	
44  	// the number of CSV records read
45  	private int rowNumber = 0;
46  	
47  	/**
48  	 * Constructs a new <tt>AbstractCsvReader</tt>, using the default {@link Tokenizer}.
49  	 * 
50  	 * @param reader
51  	 *            the reader
52  	 * @param preferences
53  	 *            the CSV preferences
54  	 * @throws NullPointerException
55  	 *             if reader or preferences are null
56  	 */
57  	public AbstractCsvReader(final Reader reader, final CsvPreference preferences) {
58  		if( reader == null ) {
59  			throw new NullPointerException("reader should not be null");
60  		} else if( preferences == null ) {
61  			throw new NullPointerException("preferences should not be null");
62  		}
63  		
64  		this.preferences = preferences;
65  		this.tokenizer = new Tokenizer(reader, preferences);
66  	}
67  	
68  	/**
69  	 * Constructs a new <tt>AbstractCsvReader</tt>, using a custom {@link Tokenizer} (which should have already been set
70  	 * up with the Reader, CsvPreference, and CsvContext). This constructor should only be used if the default Tokenizer
71  	 * doesn't provide the required functionality.
72  	 * 
73  	 * @param tokenizer
74  	 *            the tokenizer
75  	 * @param preferences
76  	 *            the CSV preferences
77  	 * @throws NullPointerException
78  	 *             if tokenizer or preferences are null
79  	 */
80  	public AbstractCsvReader(final ITokenizer tokenizer, final CsvPreference preferences) {
81  		if( tokenizer == null ) {
82  			throw new NullPointerException("tokenizer should not be null");
83  		} else if( preferences == null ) {
84  			throw new NullPointerException("preferences should not be null");
85  		}
86  		
87  		this.preferences = preferences;
88  		this.tokenizer = tokenizer;
89  	}
90  	
91  	/**
92  	 * Closes the Tokenizer and its associated Reader.
93  	 */
94  	public void close() throws IOException {
95  		tokenizer.close();
96  	}
97  	
98  	/**
99  	 * {@inheritDoc}
100 	 */
101 	public String get(final int n) {
102 		return columns.get(n - 1); // column numbers start at 1
103 	}
104 	
105 	/**
106 	 * {@inheritDoc}
107 	 */
108 	public String[] getHeader(final boolean firstLineCheck) throws IOException {
109 		
110 		if( firstLineCheck && tokenizer.getLineNumber() != 0 ) {
111 			throw new SuperCsvException(String.format(
112 				"CSV header must be fetched as the first read operation, but %d lines have already been read",
113 				tokenizer.getLineNumber()));
114 		}
115 		
116 		if( readRow() ) {
117 			return columns.toArray(new String[columns.size()]);
118 		}
119 		
120 		return null;
121 	}
122 	
123 	/**
124 	 * {@inheritDoc}
125 	 */
126 	public int getLineNumber() {
127 		return tokenizer.getLineNumber();
128 	}
129 	
130 	/**
131 	 * {@inheritDoc}
132 	 */
133 	public String getUntokenizedRow() {
134 		return tokenizer.getUntokenizedRow();
135 	}
136 	
137 	/**
138 	 * {@inheritDoc}
139 	 */
140 	public int getRowNumber() {
141 		return rowNumber;
142 	}
143 	
144 	/**
145 	 * {@inheritDoc}
146 	 */
147 	public int length() {
148 		return columns.size();
149 	}
150 	
151 	/**
152 	 * Gets the tokenized columns.
153 	 * 
154 	 * @return the tokenized columns
155 	 */
156 	protected List<String> getColumns() {
157 		return columns;
158 	}
159 	
160 	/**
161 	 * Gets the preferences.
162 	 * 
163 	 * @return the preferences
164 	 */
165 	protected CsvPreference getPreferences() {
166 		return preferences;
167 	}
168 	
169 	/**
170 	 * Calls the tokenizer to read a CSV row. The columns can then be retrieved using {@link #getColumns()}.
171 	 * 
172 	 * @return true if something was read, and false if EOF
173 	 * @throws IOException
174 	 *             when an IOException occurs
175 	 * @throws SuperCsvException
176 	 *             on errors in parsing the input
177 	 */
178 	protected boolean readRow() throws IOException {
179 		if( tokenizer.readColumns(columns) ) {
180 			rowNumber++;
181 			return true;
182 		}
183 		return false;
184 	}
185 	
186 	/**
187 	 * Executes the supplied cell processors on the last row of CSV that was read and populates the supplied List of
188 	 * processed columns.
189 	 * 
190 	 * @param processedColumns
191 	 *            the List to populate with processed columns
192 	 * @param processors
193 	 *            the cell processors
194 	 * @return the updated List
195 	 * @throws NullPointerException
196 	 *             if processedColumns or processors is null
197 	 * @throws SuperCsvConstraintViolationException
198 	 *             if a CellProcessor constraint failed
199 	 * @throws SuperCsvException
200 	 *             if the wrong number of processors are supplied, or CellProcessor execution failed
201 	 */
202 	protected List<Object> executeProcessors(final List<Object> processedColumns, final CellProcessor[] processors) {
203 		Util.executeCellProcessors(processedColumns, getColumns(), processors, getLineNumber(), getRowNumber());
204 		return processedColumns;
205 	}
206 	
207 }