package com.anjlab.csv2db; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.script.ScriptEngine; import javax.script.ScriptException; public abstract class AbstractRecordHandler implements RecordHandler { private Set<String> transientColumns; private List<String> orderedTableColumnNames; private List<String> columnNamesWithInsertValues; private List<String> columnNamesWithUpdateValues; protected Configuration config; protected final ScriptEngine scriptEngine; protected Connection connection; protected boolean batchExecutionDisabled; protected final Router router; protected final int threadId; protected final int threadCount; public AbstractRecordHandler( Configuration config, ScriptEngine scriptEngine, Connection connection, Router router, int threadId, int threadCount) { this.config = config; this.scriptEngine = scriptEngine; this.connection = connection; this.transientColumns = new HashSet<String>(); if (config.getTransientColumns() != null) { this.transientColumns.addAll(config.getTransientColumns()); } this.router = router; this.threadId = threadId; this.threadCount = threadCount; } protected void closeQuietly(PreparedStatement statement) { try { statement.close(); } catch (SQLException e) { // Ignore } } protected void closeQuietly(ResultSet resultSet) { try { resultSet.close(); } catch (SQLException e) { // Ignore } } protected void closeQuietly(Connection connection) { try { connection.close(); } catch (SQLException e) { // Ignore } } protected List<String> getOrderedTableColumnNames() { if (orderedTableColumnNames != null) { return orderedTableColumnNames; } List<Integer> csvColumnIndices = new ArrayList<Integer>(); csvColumnIndices.addAll(config.getColumnMappings().keySet()); Collections.sort(csvColumnIndices); List<String> columnNames = new ArrayList<String>(); for (int csvColumnIndex : csvColumnIndices) { String columnName = config.getColumnMappings().get(csvColumnIndex); if (!isTransientColumn(columnName)) { columnNames.add(columnName); } } if (config.getSyntheticColumns() != null) { List<String> copy = new ArrayList<>(); copy.addAll(config.getSyntheticColumns()); Collections.sort(copy); for (String columnName : copy) { // There shouldn't be any transient columns between synthetic ones, // but we'll check this anyway for consistency if (!isTransientColumn(columnName)) { columnNames.add(columnName); } } } return orderedTableColumnNames = columnNames; } protected boolean isTransientColumn(String columnName) { return transientColumns.contains(columnName); } protected List<String> getColumnNamesWithInsertValues() { if (columnNamesWithInsertValues != null) { return columnNamesWithInsertValues; } if (config.getInsertValues() == null) { return columnNamesWithInsertValues = Collections.emptyList(); } List<String> columnNames = new ArrayList<String>(); columnNames.addAll(config.getInsertValues().keySet()); Collections.sort(columnNames); return columnNamesWithInsertValues = columnNames; } protected List<String> getColumnNamesWithUpdateValues() { if (columnNamesWithUpdateValues != null) { return columnNamesWithUpdateValues; } if (config.getUpdateValues() == null) { return columnNamesWithUpdateValues = Collections.emptyList(); } List<String> columnNames = new ArrayList<String>(); columnNames.addAll(config.getUpdateValues().keySet()); Collections.sort(columnNames); return columnNamesWithUpdateValues = columnNames; } protected Object transform(String targetTableColumnName, Map<String, Object> nameValues) throws ConfigurationException, ScriptException { if (config.getTransform() != null) { ValueDefinition transformer = config.getTransform().get(targetTableColumnName); if (transformer != null) { if (transformer.producesSQL()) { throw new ConfigurationException( "Transform definition for column '" + targetTableColumnName + "' produces SQL which is not supported. " + "SQL expressions only supported for 'insertValues' and 'updateValues'."); } try { return transformer.eval(targetTableColumnName, nameValues, scriptEngine); } catch (RuntimeException | ScriptException e) { System.err.println("Error running transformation for column '" + targetTableColumnName + "'"); throw e; } } } return nameValues.get(targetTableColumnName); } protected Object eval(ValueDefinition definition, String targetTableColumnName, Map<String, Object> nameValues) throws ScriptException { try { return definition.eval(targetTableColumnName, nameValues, scriptEngine); } catch (RuntimeException | ScriptException e) { System.err.println("Error evaluating value for column '" + targetTableColumnName + "'"); throw e; } } @Override public void close() { closeQuietly(connection); } protected static void printNameValues(Map<String, Object> nameValues) { List<String> names = new ArrayList<>(); names.addAll(nameValues.keySet()); Collections.sort(names); for (String name : names) { printNameValue(name, nameValues.get(name)); } } protected static void printNameValue(String name, Object value) { Import.logVerbose(name + "=" + (value == null ? "null" : "'" + value + "', class=" + value.getClass().getName())); } protected void enableBatchExecution() throws SQLException { batchExecutionDisabled = false; } protected void disableBatchExecution() { batchExecutionDisabled = true; } }