Files
perfdb/pdb-ui/src/main/java/org/lucares/pdbui/CsvReaderSettings.java

373 lines
12 KiB
Java

package org.lucares.pdbui;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.lucares.pdbui.domain.TagMatcher;
import org.lucares.utils.Preconditions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public final class CsvReaderSettings {
public static final String ISO_8601 = "ISO-8601";
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static String stripPrefixDefault(final String value) {
if (value.startsWith("Default")) {
return value.replaceFirst("Default", "");
}
return value;
}
public enum PostProcessors {
LOWER_CASE(String::toLowerCase), STRIP(String::trim),
STRIP_PREFIX_DEFAULT(CsvReaderSettings::stripPrefixDefault);
private final Function<String, String> function;
PostProcessors(final Function<String, String> function) {
this.function = function;
}
public Function<String, String> getFunction() {
return function;
}
public static Function<String, String> toFunction(final EnumSet<PostProcessors> postProcessors) {
if (postProcessors == null || postProcessors.isEmpty()) {
return Function.identity();
}
final Iterator<PostProcessors> it = postProcessors.iterator();
Function<String, String> result = it.next().getFunction();
while (it.hasNext()) {
final Function<String, String> next = it.next().getFunction();
result = result.andThen(next);
}
return result;
}
}
public static final class ColumnDefinitions {
Map<String, ColumnDefinition> columns = new HashMap<>();
public Map<String, ColumnDefinition> getColumns() {
return columns;
}
public void setColumns(final Map<String, ColumnDefinition> columnDefinitions) {
this.columns = columnDefinitions;
}
public void ignoreColumn(final String csvColumnHeader) {
columns.putIfAbsent(csvColumnHeader, new ColumnDefinition());
columns.get(csvColumnHeader).setIgnore(true);
}
public void rename(final String csvColumnHeader, final String renameTo) {
columns.putIfAbsent(csvColumnHeader, new ColumnDefinition());
columns.get(csvColumnHeader).setRenameTo(renameTo);
}
public void postProcess(final String csvColumnHeader, final EnumSet<PostProcessors> postProcessors) {
columns.putIfAbsent(csvColumnHeader, new ColumnDefinition());
columns.get(csvColumnHeader).setPostProcessors(postProcessors);
}
public boolean isIgnoredColumn(final String csvColumnHeader) {
return columns.getOrDefault(csvColumnHeader, new ColumnDefinition()).isIgnore();
}
public String getRenameTo(final String csvColumnHeader) {
return columns.getOrDefault(csvColumnHeader, new ColumnDefinition()).getRenameTo();
}
public EnumSet<PostProcessors> getPostProcessors(final String csvColumnHeader) {
return columns.getOrDefault(csvColumnHeader, new ColumnDefinition()).getPostProcessors();
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
for (final String col : columns.keySet()) {
result.append(col);
result.append(":");
result.append(columns.get(col));
result.append("\n");
}
return result.toString();
}
}
public static final class ColumnDefinition {
private boolean ignore;
private String renameTo;
private EnumSet<PostProcessors> postProcessors = EnumSet.noneOf(PostProcessors.class);
public ColumnDefinition() {
super();
}
public boolean isIgnore() {
return ignore;
}
public void setIgnore(final boolean ignore) {
this.ignore = ignore;
}
public String getRenameTo() {
return renameTo;
}
public void setRenameTo(final String renameTo) {
this.renameTo = renameTo;
}
public EnumSet<PostProcessors> getPostProcessors() {
return postProcessors != null ? postProcessors : EnumSet.noneOf(PostProcessors.class);
}
public void setPostProcessors(final EnumSet<PostProcessors> postProcessors) {
this.postProcessors = postProcessors;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
if (ignore) {
builder.append(" ignore=");
builder.append(ignore);
}
if (renameTo != null) {
builder.append(" renameTo=");
builder.append(renameTo);
}
if (postProcessors != null && !postProcessors.isEmpty()) {
builder.append(" postProcess=");
builder.append(postProcessors);
}
return builder.toString();
}
}
private String separator;
private Character quoteCharacter = null;
private ColumnDefinitions columnDefinitions = new ColumnDefinitions();
private Map<String, String> additionalTags = new HashMap<String, String>();
private String timeColumn;
private String valueColumn;
private String comment = "#";
private String dateTimePattern = ISO_8601;
private final List<TagMatcher> firstLineMatcher = new ArrayList<>();
public CsvReaderSettings() {
this("@timestamp", "duration", ",", new ColumnDefinitions());
}
private CsvReaderSettings(final String timeColumn, final String valueColumn, final String separator,
final ColumnDefinitions columnDefinitions) {
this.timeColumn = timeColumn;
this.valueColumn = valueColumn;
this.separator = separator;
this.columnDefinitions = columnDefinitions;
}
public static CsvReaderSettings create(final String timeColumn, final String valueColumn, final String separator,
final ColumnDefinitions columnDefinitions) {
Preconditions.checkTrue(separator.getBytes(StandardCharsets.UTF_8).length == 1,
"Only separators that fulfill separator == (byte)separator are supported. "
+ "This restriction is because the parsing algorithm skips the overhead of "
+ "translating bytes to characters.");
return new CsvReaderSettings(timeColumn, valueColumn, separator, columnDefinitions);
}
public String getTimeColumn() {
return timeColumn;
}
public void setTimeColumn(final String timeColumn) {
this.timeColumn = timeColumn;
}
public String getValueColumn() {
return valueColumn;
}
public void setValueColumn(final String valueColumn) {
this.valueColumn = valueColumn;
}
public String getSeparator() {
return separator;
}
public void setSeparator(final String separator) {
this.separator = separator;
}
public byte separatorByte() {
final byte[] bytes = separator.getBytes(StandardCharsets.UTF_8);
Preconditions.checkEqual(bytes.length, 1,
"separator must be a character that is represented as a single byte in UTF-8");
return bytes[0];
}
public String getComment() {
return comment;
}
public void setComment(final String comment) {
this.comment = comment;
}
public byte commentByte() {
final byte[] bytes = comment.getBytes(StandardCharsets.UTF_8);
Preconditions.checkEqual(bytes.length, 1,
"comment must be a character that is represented as a single byte in UTF-8");
return bytes[0];
}
public void putAdditionalTag(final String field, final String value) {
additionalTags.put(field, value);
}
public void putAdditionalTag(final Map<String, String> additionalTags) {
this.additionalTags.putAll(additionalTags);
}
public Map<String, String> getAdditionalTags() {
return Map.copyOf(additionalTags);
}
public void setAdditionalTags(final Map<String, String> additionalTags) {
this.additionalTags = additionalTags;
}
public ColumnDefinitions getColumnDefinitions() {
return columnDefinitions;
}
public void setColumnDefinitions(final ColumnDefinitions columnDefinitions) {
this.columnDefinitions = columnDefinitions;
}
public List<TagMatcher> getFirstLineMatcher() {
return firstLineMatcher;
}
public void setFirstLineMatcher(final Collection<TagMatcher> firstLineMatchers) {
this.firstLineMatcher.clear();
this.firstLineMatcher.addAll(firstLineMatchers);
}
public void addFirstLineMatcher(final TagMatcher tagMatcher) {
this.firstLineMatcher.add(tagMatcher);
}
/**
* The quote character. If null then no quoting is allowed.
*
* @param quoteCharacter
*/
public void setQuoteCharacter(final Character quoteCharacter) {
this.quoteCharacter = quoteCharacter;
}
/**
* The quote character. If null then no quoting is allowed.
*
* @return the quote character
*/
public Character getQuoteCharacter() {
return quoteCharacter;
}
public String getDateTimePattern() {
return dateTimePattern;
}
public void setDateTimePattern(final String dateTimePattern) {
this.dateTimePattern = dateTimePattern;
}
public CsvReaderSettings copy() {
try {
final String json = OBJECT_MAPPER.writeValueAsString(this);
return OBJECT_MAPPER.readValue(json, CsvReaderSettings.class);
} catch (final JsonProcessingException e) {
throw new IllegalStateException(e);
}
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
if (separator != null) {
builder.append("\nseparator=");
builder.append(separator);
builder.append(", ");
}
if (quoteCharacter != null) {
builder.append("\nquoteCharacter=");
builder.append(quoteCharacter);
} else {
builder.append("\nno quotes");
}
if (columnDefinitions != null) {
builder.append("\ncolumnDefinitions=");
builder.append(columnDefinitions);
builder.append(", ");
}
if (additionalTags != null) {
builder.append("\nadditionalTags=");
builder.append(additionalTags);
builder.append(", ");
}
if (timeColumn != null) {
builder.append("\ntimeColumn=");
builder.append(timeColumn);
builder.append(", ");
}
if (valueColumn != null) {
builder.append("\nvalueColumn=");
builder.append(valueColumn);
builder.append(", ");
}
if (firstLineMatcher != null) {
builder.append("\nfirstLineMatcher=");
builder.append(firstLineMatcher);
builder.append(", ");
}
if (comment != null) {
builder.append("\ncomment=");
builder.append(comment);
}
return builder.toString();
}
}