View Javadoc
1   /*
2    * Copyright 2013 Olivier Godineau
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at http://www.apache.org/licenses/LICENSE-2.0
7    * 
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11   * License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package olg.csv.bean;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import olg.csv.base.IReader;
22  import olg.csv.base.IWriter;
23  import olg.csv.base.csv.CSVReader;
24  import olg.csv.base.csv.CSVSettings;
25  import olg.csv.base.csv.CSVWriter;
26  import olg.csv.base.ods.ODSReader;
27  import olg.csv.base.ods.ODSSettings;
28  import olg.csv.base.ods.ODSWriter;
29  import olg.csv.bean.annotations.processor.AnnotationProcessorException;
30  import olg.csv.bean.annotations.processor.RowBeanProcessor;
31  import olg.csv.bean.parser.ParseException;
32  
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  /**
37   * Main class to manage bean writing/reading based on Annotations setted on bean class.
38   * 
39   * @author Olivier Godineau
40   * 
41   * @param <T>
42   *            the bean to manage.
43   */
44  public final class RowBean<T> {
45  	/**
46  	 * class logger.
47  	 */
48  	private static final Logger LOGGER = LoggerFactory.getLogger(RowBean.class);
49  	/**
50  	 * The class this RowBean instance deals with.
51  	 */
52  	private Class<T> clazz;
53  
54  	/**
55  	 * the processor to load RowProcessor/BeanProcessor/file reader settings/file writer settings.
56  	 */
57  	private RowBeanProcessor<T> rowBeanProcessor;
58  
59  	/**
60  	 * Constructor.
61  	 * 
62  	 * @param clazz
63  	 *            the class RowBean instance supports and deals with.
64  	 */
65  	public RowBean(Class<T> clazz) {
66  		super();
67  		if (clazz == null) {
68  			throw new IllegalArgumentException("RowBean constructor class argument must not be null");
69  		}
70  		this.clazz = clazz;
71  		this.rowBeanProcessor = new RowBeanProcessor<T>(this.clazz);
72  	}
73  
74  	/**
75  	 * Returns a ODS or CSV reader with settings read from RowBean Annotation setted on T class. throws
76  	 * IllegalArgumentException if file is null or or it's not possible to define a reader.
77  	 * 
78  	 * @param in
79  	 *            the file. Must be an ODS or CSV file. ODS files must have .ods or.ODS extension. CSV files must have
80  	 *            .csv,.CSV,.txt, .TXT, .dat or.DAT.
81  	 * @return the reader corresponding to the extension of the file.
82  	 * @throws IOException
83  	 *             if an error occurs during the file opening.
84  	 * @throws AnnotationProcessorException
85  	 *             an error occurs on settings annotation reading at the rowBean annotation setted on the T class.
86  	 * 
87  	 */
88  	public IReader getReader(File in) throws IOException, AnnotationProcessorException {
89  		if (in == null) {
90  			throw new IllegalArgumentException("RowBean.getReader file argument must not be null");
91  		}
92  
93  		if (!in.exists()) {
94  			throw new IllegalArgumentException(String.format("RowBean.getReader file argument [%s] doesn't exist",
95  					in.getAbsolutePath()));
96  		}
97  		// Cas CSV
98  		if (isCSVFile(in)) {
99  			return new CSVReader(in, this.rowBeanProcessor.getReadingCSVSettings());
100 		}
101 		// Cas ODS
102 		if (isODSFile(in)) {
103 			return new ODSReader(in, this.rowBeanProcessor.getReadingODSSettings());
104 		}
105 		throw new IllegalArgumentException(
106 				"RowBean.getReader has not identified the file in argument as an ODS or CSV file."
107 						+ " Use instead the constructor of the class of your choice : ODSReader or CSVReader.");
108 
109 	}
110 
111 	/**
112 	 * Returns a ODS or CSV writer with settings read from RowBean Annotation setted on T class. Throws
113 	 * IllegalArgumentException if file is null or or it's not possible to define a writer.
114 	 * 
115 	 * @param out
116 	 *            the file. Must be an ODS or CSV file. ODS files must have .ods or.ODS extension. CSV files must have
117 	 *            .csv,.CSV,.txt, .TXT, .dat or.DAT.
118 	 * @return the writer the row writer corresponding to the extension of the file.
119 	 * @throws AnnotationProcessorException
120 	 *             error occurs on writing settings RowBean annotation
121 	 * @throws IOException
122 	 *             errors occurs on file opening
123 	 */
124 	public IWriter getWriter(File out) throws AnnotationProcessorException, IOException {
125 		if (out == null) {
126 			throw new IllegalArgumentException("RowBean.getWriter file argument must not be null");
127 		}
128 		if (isCSVFile(out)) {
129 			return new CSVWriter(out, this.rowBeanProcessor.getWritingCSVSettings());
130 		}
131 		if (isODSFile(out)) {
132 			return new ODSWriter(out, this.rowBeanProcessor.getWritingODSSettings());
133 		}
134 		throw new IllegalArgumentException(
135 				"RowBean.getWriter has not identified the file in argument as an ODS or CSV file."
136 						+ "  Use instead the constructor of the class ODSWriter or CSVWriter");
137 
138 	}
139 	/**
140 	 * Extracts a list from a CSV file opened with some CSV settings. Use Annotations on T class to define how to read
141 	 * bean and how set the file reader.
142 	 * 
143 	 * @param in
144 	 *            the CSV file.
145 	 * @param csvSettings
146 	 *            the settings the file will be opened with.
147 	 * @return the list of T extracted from the file.
148 	 * @throws AnnotationProcessorException
149 	 *             if an error occurs during the annotation reading on T class.
150 	 * @throws IOException
151 	 *             if an error occurs during the file opening.
152 	 */
153 	public List<T> fromFile(File in, CSVSettings csvSettings) throws AnnotationProcessorException, IOException {
154 		return fromReader(new CSVReader(in, csvSettings), in);
155 	}
156 
157 	/**
158 	 * Extracts a list from an ODS file opened with some ODS settings. Use Annotations on T class to define how to read
159 	 * beans and how to set the file reader.
160 	 * 
161 	 * @param in
162 	 *            the ODS file.
163 	 * @param odsSettings
164 	 *            the settings the file will be opened with.
165 	 * @return the list of T extracted from the file.
166 	 * @throws AnnotationProcessorException
167 	 *             if error occurs during the annotation reading on T class.
168 	 * @throws IOException
169 	 *             if an error occurs during the file opening.
170 	 */
171 	public List<T> fromFile(File in, ODSSettings odsSettings) throws AnnotationProcessorException, IOException {
172 		return fromReader(new ODSReader(in, odsSettings), in);
173 	}
174 	/**
175 	 * Extracts a list from a file. Use Annotations on T class to define how to read bean and how set the file reader.
176 	 * Throws IllegalArgumentException if file is null or or it's not possible to define a reader.
177 	 * 
178 	 * @param in
179 	 *            the file. Must be an ODS or CSV file. ODS files must have .ods or.ODS extension. CSV files must have
180 	 *            .csv,.CSV,.txt, .TXT, .dat or.DAT. Use the reading settings read from RowBean Annotation setted on T
181 	 *            class.
182 	 * @return the list of T extracted from the file.
183 	 * @throws AnnotationProcessorException
184 	 *             if error occurs during the annotation reading on T class.
185 	 * @throws IOException
186 	 *             if an error occurs during the file opening.
187 	 */
188 	public List<T> fromFile(File in) throws AnnotationProcessorException, IOException {
189 
190 		return fromReader(getReader(in), in);
191 	}
192 
193 	/**
194 	 * Copy in a new file a list of T. Use the RowBean annotation setted on T class. Throws IllegalArgumentException if
195 	 * file is null or or it's not possible to define a writer.
196 	 * 
197 	 * @param beans
198 	 *            the list.
199 	 * @param out
200 	 *            the file. Must be an ODS or CSV file. ODS files must have .ods or.ODS extension. CSV files must have
201 	 *            .csv,.CSV,.txt, .TXT, .dat or.DAT. Use writing settings read from RowBean Annotation setted on T
202 	 *            class.
203 	 * @throws AnnotationProcessorException
204 	 *             if error occurs during the annotation reading on T class.
205 	 * @throws IOException
206 	 *             if the file exists but is a directory rather than a regular file, does not exist but cannot be
207 	 *             created, or cannot be opened for any other reason
208 	 */
209 	public void toFile(List<T> beans, File out) throws AnnotationProcessorException, IOException {
210 
211 		toWriter(beans, getWriter(out), out);
212 	}
213 
214 	/**
215 	 * Copy in a CSV file a list of T. Use the RowBean annotation setted on T class.
216 	 * 
217 	 * @param beans
218 	 *            the beans to copy.
219 	 * @param out
220 	 *            the file.
221 	 * @param csvSettings
222 	 *            the settings the file is written with.
223 	 * @throws AnnotationProcessorException
224 	 *             if error occurs during the annotation reading on T class.
225 	 * @throws IOException
226 	 *             if the file exists but is a directory rather than a regular file, does not exist but cannot be
227 	 *             created, or cannot be opened for any other reason
228 	 */
229 	public void toFile(List<T> beans, File out, CSVSettings csvSettings) throws AnnotationProcessorException,
230 			IOException {
231 		toWriter(beans, new CSVWriter(out, csvSettings), out);
232 	}
233 
234 	/**
235 	 * Copy in an ODS file a list of T. Use the RowBean annotation setted on T class.
236 	 * 
237 	 * @param beans
238 	 *            the T beans to copy.
239 	 * @param out
240 	 *            the file
241 	 * @param odsSettings
242 	 *            the settings the file is written with.
243 	 * @throws AnnotationProcessorException
244 	 *             if error occurs during the annotation reading on T class.
245 	 * @throws IOException
246 	 *             if the file exists but is a directory rather than a regular file, does not exist but cannot be
247 	 *             created, or cannot be opened for any other reason
248 	 */
249 	public void toFile(List<T> beans, File out, ODSSettings odsSettings) throws AnnotationProcessorException,
250 			IOException {
251 		toWriter(beans, new ODSWriter(out, odsSettings), out);
252 	}
253 
254 	/**
255 	 * check if a file extension matchs text file extension(.csv,.txt,.dat).
256 	 * 
257 	 * @param file
258 	 *            the file to check
259 	 * @return true if the file has a text file extension.
260 	 */
261 	private static boolean isCSVFile(File file) {
262 		return file.getName().matches(".+\\.(:?csv|CSV|TXT|txt|dat|DAT)$");
263 
264 	}
265 	/**
266 	 * check if a file extension matchs ODS file extension.
267 	 * 
268 	 * @param file
269 	 *            the file to check
270 	 * @return true if has ODS extension
271 	 */
272 	private static boolean isODSFile(File file) {
273 		return file.getName().matches(".+\\.(:?ods|ODS)$");
274 
275 	}
276 	/**
277 	 * Provides the row processor built from the annoted T class.
278 	 * 
279 	 * @return the row processor.
280 	 * @throws AnnotationProcessorException
281 	 *             if an error occurs during processor building.
282 	 */
283 	private IRowProcessor<T> getRowProcessor() throws AnnotationProcessorException {
284 		return this.rowBeanProcessor.getRowProcessor();
285 	}
286 
287 	/**
288 	 * Provides the Bean processor built from the annoted T class.
289 	 * 
290 	 * @return the bean processor.
291 	 * @throws AnnotationProcessorException
292 	 *             if error occurs during annotation processing.
293 	 */
294 	private IBeanProcessor<T> getBeanProcessor() throws AnnotationProcessorException {
295 		return this.rowBeanProcessor.getBeanProcessor();
296 	}
297 
298 	/**
299 	 * Extracts a list from a reader.
300 	 * 
301 	 * @param fileReader
302 	 *            the reader
303 	 * @param in
304 	 *            the file
305 	 * @return the list of T extracted from the file.
306 	 * @throws AnnotationProcessorException
307 	 *             if error occurs during the annotation reading on T class.
308 	 */
309 	private List<T> fromReader(IReader fileReader, File in) throws AnnotationProcessorException {
310 		List<T> list = new ArrayList<T>();
311 		BeanReader<T> reader = null;
312 		int count = 0;
313 		try {
314 			reader = new BeanReader<T>(getBeanProcessor(), fileReader);
315 			while (reader.hasNext()) {
316 				try {
317 					count++;
318 					list.add(reader.next());
319 				} catch (ParseException ex) {
320 					LOGGER.warn(String.format("Error at record[%s] on Reading file[%s] ", count, in.getAbsolutePath()),
321 							ex);
322 				}
323 			}
324 		} finally {
325 			if (reader != null) {
326 				reader.close();
327 			}
328 		}
329 		return list;
330 	}
331 
332 	/**
333 	 * Copy a list of T on a writer.
334 	 * 
335 	 * @param beans
336 	 *            the beans to copy.
337 	 * @param fileWriter
338 	 *            the writer
339 	 * @param out
340 	 *            the opened file.
341 	 * @throws AnnotationProcessorException
342 	 *             if error occurs during the annotation reading on T class.
343 	 */
344 	private void toWriter(List<T> beans, IWriter fileWriter, File out) throws AnnotationProcessorException {
345 
346 		if (beans == null) {
347 			throw new IllegalArgumentException();
348 		}
349 
350 		BeanWriter<T> writer = null;
351 		try {
352 			writer = new BeanWriter<T>(getRowProcessor(), fileWriter);
353 
354 			for (T bean : beans) {
355 				try {
356 					writer.write(bean);
357 				} catch (PropertyException ex) {
358 					LOGGER.warn(String.format("Error on writing bean[%s] in file[%s] ", bean, out.getAbsolutePath()),
359 							ex);
360 				}
361 			}
362 		} finally {
363 			if (writer != null) {
364 				writer.close();
365 			}
366 		}
367 	}
368 
369 }