package org.openlca.io.refdata; import org.apache.commons.io.ByteOrderMark; import org.apache.commons.io.input.BOMInputStream; import org.openlca.core.database.IDatabase; import org.openlca.core.database.NativeSql; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.io.CsvListReader; import org.supercsv.prefs.CsvPreference; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; abstract class AbstractImport { protected Logger log = LoggerFactory.getLogger(getClass()); protected Seq seq; protected IDatabase database; private List<List<Object>> nextBatch = new ArrayList<>(); public void run(File file, Seq seq, IDatabase database) throws Exception { this.seq = seq; this.database = database; CsvPreference pref = new CsvPreference.Builder('"', ';', "\n").build(); try (FileInputStream fis = new FileInputStream(file); // exclude the byte order mark, if there is any BOMInputStream bom = new BOMInputStream(fis, false, ByteOrderMark.UTF_8); InputStreamReader reader = new InputStreamReader(bom, "utf-8"); BufferedReader buffer = new BufferedReader(reader); CsvListReader csvReader = new CsvListReader(buffer, pref)) { importFile(csvReader, database); } } private void importFile(CsvListReader csvReader, IDatabase database) throws Exception { CellProcessor[] processors = getCellProcessors(); List<Object> values; while ((values = next(processors, csvReader)) != null) { if (isValid(values)) nextBatch.add(values); if (nextBatch.size() > 2000) execBatch(database); } execBatch(database); } protected abstract boolean isValid(List<Object> values); private List<Object> next(CellProcessor[] processors, CsvListReader csvReader) { try { return csvReader.read(processors); } catch (Exception e) { log.error("failed to read line " + csvReader.getLineNumber(), e); return null; } } private void execBatch(IDatabase database) { if (nextBatch.isEmpty()) return; try { NativeSql.on(database).batchInsert(getStatement(), nextBatch.size(), new BatchHandler()); } catch (Exception e) { log.error("failed to execute batch insert", e); } nextBatch.clear(); } protected abstract String getStatement(); protected abstract CellProcessor[] getCellProcessors(); protected abstract void setValues(PreparedStatement statement, List<Object> values) throws Exception; private class BatchHandler implements NativeSql.BatchInsertHandler { @Override public boolean addBatch(int i, PreparedStatement stmt) throws SQLException { try { setValues(stmt, nextBatch.get(i)); return true; } catch (Exception e) { log.error("failed to set values", e); return false; } } } }