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 }