001package io.konik.csv.mapper; 002 003import io.konik.csv.converter.RowToInvoiceConverter; 004import io.konik.csv.model.Row; 005import io.konik.zugferd.Invoice; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008import org.supercsv.cellprocessor.ift.CellProcessor; 009import org.supercsv.io.dozer.CsvDozerBeanReader; 010 011import java.io.File; 012import java.io.IOException; 013import java.util.LinkedList; 014import java.util.List; 015import java.util.concurrent.atomic.AtomicInteger; 016 017/** 018 * Reader class used for reading CSV files and returning a {@link List} of {@see Invoice}s. 019 * 020 * This is high-level component that should be used to import invoices from CSV files. 021 */ 022public class CsvInvoicesReader { 023 024 private static final Logger log = LoggerFactory.getLogger(CsvInvoicesReader.class); 025 026 private final ColumnsConfigurer columnsConfigurer; 027 028 public CsvInvoicesReader() { 029 this(new CsvMapperHeaderColumnsConfigurer()); 030 } 031 032 public CsvInvoicesReader(ColumnsConfigurer columnsConfigurer) { 033 this.columnsConfigurer = columnsConfigurer; 034 } 035 036 /** 037 * Loads invoices from given CSV file. 038 * @param csvFile 039 * @return 040 */ 041 public Result read(File csvFile) { 042 CsvMapperBuilder mapperBuilder = CsvMapperBuilder.withHeadersFromCsvFile(csvFile, columnsConfigurer); 043 CellProcessor[] processors = mapperBuilder.getCellProcessors(); 044 CsvDozerBeanReader reader = mapperBuilder.getBeanReader(csvFile, Row.class); 045 046 List<ConvertedRow> convertedRows = new LinkedList<ConvertedRow>(); 047 List<RowError> rowErrors = new LinkedList<RowError>(); 048 Row currentRow = null; 049 final AtomicInteger rowNumber = new AtomicInteger(1); 050 051 try { 052 do { 053 try { 054 currentRow = reader.read(Row.class, processors); 055 if (currentRow != null) { 056 Invoice invoice = RowToInvoiceConverter.convert(currentRow); 057 convertedRows.add(new ConvertedRow(rowNumber.getAndIncrement(), currentRow, invoice)); 058 } 059 } catch (Exception e) { 060 log.warn("Exception caught during reading a row"); 061 rowErrors.add(new RowError(rowNumber.getAndIncrement(), currentRow, e.getMessage(), e)); 062 } 063 } while (currentRow != null); 064 065 return new Result(convertedRows, rowErrors); 066 067 } catch (Exception e) { 068 throw new RuntimeException(e); 069 070 } finally { 071 if (reader != null) { 072 try { 073 reader.close(); 074 } catch (IOException e) { 075 log.error(e.getMessage(), e); 076 } 077 } 078 } 079 } 080 081 static public class ConvertedRow { 082 private final int rowNumber; 083 private final Row row; 084 private final Invoice invoice; 085 086 public ConvertedRow(int rowNumber, Row row, Invoice invoice) { 087 this.rowNumber = rowNumber; 088 this.row = row; 089 this.invoice = invoice; 090 } 091 092 public int getRowNumber() { 093 return rowNumber; 094 } 095 096 public Row getRow() { 097 return row; 098 } 099 100 public Invoice getInvoice() { 101 return invoice; 102 } 103 } 104 105 static public class RowError { 106 private final int rowNumber; 107 private final Row row; 108 private final String errorMessage; 109 private final Exception exception; 110 111 public RowError(int rowNumber, Row row, String errorMessage, Exception exception) { 112 this.rowNumber = rowNumber; 113 this.row = row; 114 this.errorMessage = errorMessage; 115 this.exception = exception; 116 } 117 118 public int getRowNumber() { 119 return rowNumber; 120 } 121 122 public Row getRow() { 123 return row; 124 } 125 126 public String getErrorMessage() { 127 return errorMessage; 128 } 129 130 public Exception getException() { 131 return exception; 132 } 133 } 134 135 static public class Result { 136 private final List<ConvertedRow> convertedRows; 137 private final List<RowError> rowErrors; 138 139 public Result(List<ConvertedRow> convertedRows, List<RowError> rowErrors) { 140 this.convertedRows = convertedRows; 141 this.rowErrors = rowErrors; 142 } 143 144 public List<ConvertedRow> getConvertedRows() { 145 return convertedRows; 146 } 147 148 public List<RowError> getRowErrors() { 149 return rowErrors; 150 } 151 } 152}