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 }