1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.jameleon.data;
21
22 import net.sf.jameleon.util.JameleonDefaultValues;
23
24 import java.io.BufferedReader;
25 import java.io.InputStreamReader;
26 import java.io.IOException;
27 import java.io.FileInputStream;
28 import java.io.File;
29 import java.io.UnsupportedEncodingException;
30
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35
36 /***
37 * Am implementation of @{link DataDriver} for CSV Files.
38 * This implementation can accept different delimiters. The
39 * default delimiter is ','.
40 */
41 public class CsvDataDriver implements DataDriver{
42 protected File csvFile;
43 protected BufferedReader in;
44 protected final static char DEFAULT_DELIMETER = ',';
45 protected char delimiter = DEFAULT_DELIMETER;
46 protected String encoding = JameleonDefaultValues.FILE_CHARSET;
47 protected List keys;
48 protected String line;
49
50 /***
51 * Default construtor. After calling this constructor,
52 * setFile() will need to be set.
53 */
54 public CsvDataDriver(){
55 csvFile = null;
56 in = null;
57 keys = new ArrayList();
58 }
59
60 /***
61 * Sets the file to be read in to <code>csvFile</code>
62 * @param csvFile - the file to be used for parsing
63 */
64 public CsvDataDriver(File csvFile){
65 this();
66 this.csvFile = csvFile;
67 }
68
69 /***
70 * Sets the file and the delimiter of the file to be read in
71 * @param csvFile - the file to be used for parsing
72 * @param delimiter - the field delimiter of the csv file.
73 */
74 public CsvDataDriver(File csvFile, char delimiter){
75 this(csvFile);
76 this.delimiter = delimiter;
77 }
78
79 /***
80 * Closes the handle to the data source
81 */
82 public void close() {
83 keys.clear();
84 if (in != null) {
85 try{
86 in.close();
87 }catch(IOException ioe){}
88 }
89 }
90
91 /***
92 * Opens the handle to the data source
93 * @throws IOException when the data source can not be found.
94 */
95 public void open() throws IOException {
96 if (csvFile != null) {
97 try{
98 in = new BufferedReader(new InputStreamReader(new FileInputStream(csvFile), encoding));
99 }catch(UnsupportedEncodingException uee){
100 throw new IOException(encoding + " is an unsupported encoding type");
101 }
102 }else{
103 throw new IOException("No file set to open");
104 }
105 }
106
107 /***
108 * Gets the encoding of the csv file. Defaults to UTF-8
109 * @return the encoding of the csv file
110 */
111 public String getEncoding(){
112 return encoding;
113 }
114
115 /***
116 * Sets the encoding of the csv file.
117 * @param encoding - the encoding of the csv file
118 */
119 public void setEncoding(String encoding){
120 this.encoding = encoding;
121 }
122
123 /***
124 * Gets the CSV file used as a datasource.
125 * @return the CSV file used as a datasource.
126 */
127 public File getFile(){
128 return csvFile;
129 }
130
131 /***
132 * Sets the CSV file used as a datasource.
133 * @param csvFile - the CSV file used as a datasource.
134 */
135 public void setFile(File csvFile){
136 this.csvFile = csvFile;
137 }
138
139 /***
140 * Gets the next row from the data source
141 * @return a key-value HashMap representing the data row or null if
142 * no data row is available
143 * @throws IllegalStateException if there are more values than keys
144 */
145 public Map getNextRow() {
146 Map vars = null;
147 try{
148 if (line == null) {
149 readLine();
150 }
151 if (line != null) {
152 vars = new HashMap();
153 List values = parseLine(line, false);
154 if (values.size() > keys.size()) {
155 throw new IllegalStateException(csvFile.getPath() + " has more values than keys!");
156 }
157 String tmp = null;
158 for (int index = 0; index < values.size(); index++) {
159 tmp = (String)values.get(index);
160 if (tmp == null || tmp.length() == 0) {
161 tmp = null;
162 }
163 vars.put(keys.get(index),tmp);
164 }
165 }
166 }finally{
167 line = null;
168 }
169 return vars;
170 }
171
172 /***
173 * Gets the field delimiter for the csv file
174 * @return the field delimiter for the csv file
175 */
176 public char getDelimiter(){
177 return delimiter;
178 }
179
180 /***
181 * Sets the field delimiter for the csv file
182 * @param delimiter - the field delimiter for the csv file
183 */
184 public void setDelimiter(char delimiter){
185 this.delimiter = delimiter;
186 }
187
188 /***
189 * Sets the key columns from the csv file
190 */
191 protected void setKeys(){
192 if (keys.size() == 0) {
193 getNextUcommentedLine();
194 if (line != null) {
195 keys = parseLine(line, true);
196 line = null;
197 }
198 }
199 }
200
201 /***
202 * Tells whether the data source has another row
203 * @return true if the data source still has more rows
204 */
205 public boolean hasMoreRows() {
206 boolean moreRows = false;
207 if (line == null) {
208 readLine();
209 }
210 if (line != null) {
211 moreRows = true;
212 }
213 return moreRows;
214 }
215
216 protected List parseLine(String line, boolean keysLine){
217
218 List list = new ArrayList();
219 if (isLineCommented(line)) { return list; }
220
221 String[] values = line.split( "//"+String.valueOf(delimiter), -1 );
222 for (int i = 0; i < values.length; i++) {
223 String value = values[i];
224 String trimmedValue = value.trim();
225 if ( trimmedValue.startsWith("\"") && trimmedValue.endsWith("\"") ) {
226 list.add( trimmedValue.subSequence(1, trimmedValue.length()-1) );
227 } else {
228 if (keysLine) {
229 list.add(trimmedValue);
230 } else {
231 list.add(value);
232 }
233 }
234 }
235
236 return list;
237 }
238
239 protected boolean isLineCommented(String line){
240 boolean commented = false;
241 if (line != null && line.startsWith("#")) {
242 commented = true;
243 }
244 return commented;
245 }
246
247 protected void readLine(){
248 line = null;
249 setKeys();
250 getNextUcommentedLine();
251 }
252
253 protected void getNextUcommentedLine(){
254 try{
255 String tempLine = null;
256 while (in != null &&
257 in.ready() &&
258 line == null &&
259 (tempLine = new String(in.readLine().getBytes(encoding),encoding)) != null) {
260 if (!isLineCommented(tempLine)) {
261 line = tempLine;
262 }
263 }
264 }catch(IOException ioe){
265 ioe.printStackTrace();
266 }
267 }
268
269 }