373 lines
12 KiB
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();
|
|
}
|
|
|
|
}
|