/* * Copyright (c) 2017 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.magma.datasource.csv; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import javax.validation.constraints.NotNull; import org.obiba.magma.ValueTable; import org.obiba.magma.ValueTableWriter; import org.obiba.magma.datasource.csv.support.Quote; import org.obiba.magma.datasource.csv.support.Separator; import org.obiba.magma.support.AbstractDatasource; import org.obiba.magma.support.DatasourceParsingException; import au.com.bytecode.opencsv.CSVParser; import au.com.bytecode.opencsv.CSVReader; import au.com.bytecode.opencsv.CSVWriter; public class CsvDatasource extends AbstractDatasource { public static final String TYPE = "csv"; public static final String VARIABLES_FILE = "variables.csv"; public static final String DATA_FILE = "data.csv"; public static final String DEFAULT_CHARACTER_SET = "UTF-8"; public static final char DEL_CHAR = (char) 127; private final Map<String, CsvValueTable> valueTables = new HashMap<>(); private String[] defaultVariablesHeader = "name#valueType#entityType#mimeType#unit#occurrenceGroup#repeatable#script" .split("#"); private Separator separator = Separator.COMMA; private Quote quote = Quote.DOUBLE; private String characterSet = DEFAULT_CHARACTER_SET; private int firstRow = 1; private boolean multilines; public CsvDatasource(String name) { super(name, TYPE); } public CsvDatasource(String name, File bundle) { super(name, TYPE); if(bundle.isDirectory()) { File[] directories = bundle.listFiles(new FileFilter() { @Override public boolean accept(File pathName) { return pathName.isDirectory(); } }); for(File dir : directories) { addValueTable(dir); } } else { addValueTable(bundle.getName().substring(0, bundle.getName().lastIndexOf('.')), null, bundle); } } @Override protected Set<String> getValueTableNames() { return valueTables.keySet(); } @Override protected ValueTable initialiseValueTable(String tableName) { return valueTables.get(tableName); } @Override public Set<ValueTable> getValueTables() { return Collections.unmodifiableSet(new HashSet<ValueTable>(valueTables.values())); } public CsvDatasource addValueTable(File tableDirectory) { addValueTable(tableDirectory.getName(), new File(tableDirectory, VARIABLES_FILE), new File(tableDirectory, DATA_FILE)); return this; } public CsvDatasource addValueTable(String tableName, @Nullable File variablesFile, @Nullable File dataFile) { valueTables .put(tableName, new CsvValueTable(this, tableName, variablesFile, dataFile, CsvValueTable.DEFAULT_ENTITY_TYPE)); return this; } public CsvDatasource addValueTable(String tableName, File dataFile, String entityType) { valueTables.put(tableName, new CsvValueTable(this, tableName, dataFile, entityType)); return this; } public CsvDatasource addValueTable(ValueTable refTable, File dataFile) { valueTables.put(refTable.getName(), new CsvValueTable(this, refTable, dataFile)); return this; } @NotNull @Override public ValueTableWriter createWriter(@NotNull String tableName, @NotNull String entityType) { if(!hasValueTable(tableName)) { throw new DatasourceParsingException( "Cannot create writer. A table with the name " + tableName + " does not exist.", "CsvCannotCreateWriter", tableName); } return new CsvValueTableWriter((CsvValueTable) getValueTable(tableName)); } public void setVariablesHeader(String tableName, String... header) { if(valueTables.containsKey(tableName)) { valueTables.get(tableName).setVariablesHeader(header); } else { throw new DatasourceParsingException( "Cannot set variables header. A table with the name " + tableName + " does not exist.", "CsvCannotSetVariableHeader", tableName); } } /** * Returns the variables.csv header that will be used if one was not explicitly provided for that table. This only * applies to new variables.csv files that are being written for the first time. Otherwise the existing header will be * used. */ public String[] getDefaultVariablesHeader() { return Arrays.copyOf(defaultVariablesHeader, defaultVariablesHeader.length); } /** * Set a variables.csv header that will be used by all tables that do not have a header explicitly set. This only * applies to new variables.csv files that are being written for the first time. Otherwise the existing header will be * used. */ public void setDefaultVariablesHeader(String... defaultVariablesHeader) { this.defaultVariablesHeader = Arrays.copyOf(defaultVariablesHeader, defaultVariablesHeader.length); } @Nullable CSVWriter getCsvWriter(@Nullable File file) { return file == null ? null : getCsvWriter(getWriter(file)); } CSVWriter getCsvWriter(Writer writer) { return new CSVWriter(writer, separator.getCharacter(), quote.getCharacter()); } Writer getWriter(File file) { try { return new OutputStreamWriter(new FileOutputStream(file, true), getCharacterSet()); } catch(IOException e) { throw new DatasourceParsingException("Can not get csv writer.", e, "CsvCannotObtainWriter"); } } @Nullable CSVReader getCsvReader(@Nullable File file) { return file == null ? null : getCsvReader(getReader(file)); } CSVReader getCsvReader(Reader reader) { // we don't want escape processing try DEL as a rare character until we can turn it off return new CSVReader(reader, separator.getCharacter(), quote.getCharacter(), DEL_CHAR, getFirstRow() - 1); } CSVParser getCsvParser() { // we don't want escape processing try DEL as a rare character until we can turn it off return new CSVParser(separator.getCharacter(), quote.getCharacter(), DEL_CHAR); } Reader getReader(File file) { try { return new InputStreamReader(new FileInputStream(file), getCharacterSet()); } catch(IOException e) { throw new DatasourceParsingException("Can not get csv reader.", e, "CsvCannotObtainReader"); } } public Separator getSeparator() { return separator; } public void setSeparator(Separator separator) { this.separator = separator; } public Quote getQuote() { return quote; } public void setQuote(Quote quote) { this.quote = quote; } public void setCharacterSet(String characterSet) { this.characterSet = characterSet; } public String getCharacterSet() { return characterSet; } public void setFirstRow(int firstRow) { this.firstRow = firstRow; } public int getFirstRow() { return firstRow; } public void setMultilines(boolean multilines) { this.multilines = multilines; } public boolean isMultilines() { return multilines; } }