Large refactor

This commit is contained in:
Christopher Schnick
2022-06-18 00:29:41 +02:00
parent 9440037f03
commit 3cc527dfa3
76 changed files with 359 additions and 387 deletions

View File

@@ -0,0 +1,8 @@
package io.xpipe.core.charsetter;
import java.nio.charset.Charset;
public interface Charsettable {
Charset getCharset();
}

View File

@@ -0,0 +1,108 @@
package io.xpipe.core.charsetter;
import lombok.Value;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.*;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
public abstract class Charsetter {
private static CharsetterUniverse universe;
protected static void checkInit() {
if (universe == null) {
throw new IllegalStateException("Charsetter not initialized");
}
}
public static void init(CharsetterContext ctx) {
universe = CharsetterUniverse.create(ctx);
}
@Value
public static class Result {
Charset charset;
NewLine newLine;
}
public static Charsetter INSTANCE;
public static Charsetter get() {
return INSTANCE;
}
@FunctionalInterface
public interface FailableSupplier<R, E extends Throwable> {
R get() throws E;
}
@FunctionalInterface
public interface FailableConsumer<T, E extends Throwable> {
void accept(T var1) throws E;
}
public abstract Result read(FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con) throws Exception;
public NewLine inferNewLine(byte[] content) {
Map<NewLine, Integer> count = new HashMap<>();
for (var nl : NewLine.values()) {
var nlBytes = nl.getNewLine().getBytes(StandardCharsets.UTF_8);
count.put(nl, count(content, nlBytes));
}
if (count.values().stream().allMatch(v -> v == 0)) {
return null;
}
return count.entrySet().stream().min(Comparator.comparingInt(Map.Entry::getValue))
.orElseThrow().getKey();
}
private static int count(byte[] outerArray, byte[] smallerArray) {
int count = 0;
for(int i = 0; i < outerArray.length - smallerArray.length+1; ++i) {
boolean found = true;
for(int j = 0; j < smallerArray.length; ++j) {
if (outerArray[i+j] != smallerArray[j]) {
found = false;
break;
}
}
if (found) {
count++;
}
}
return count;
}
public Charset inferCharset(byte[] content) {
checkInit();
for (Charset c : universe.getCharsets()) {
CharsetDecoder decoder = c.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
ByteBuffer byteBuf = ByteBuffer.wrap(content);
CharBuffer charBuf = CharBuffer.allocate(byteBuf.capacity() * 2);
CoderResult coderResult = decoder.decode(byteBuf, charBuf, false);
if (coderResult != null) {
if (coderResult.isError()) {
continue;
}
}
return c;
}
return StandardCharsets.UTF_8;
}
}

View File

@@ -0,0 +1,25 @@
package io.xpipe.core.charsetter;
import lombok.AllArgsConstructor;
import lombok.Value;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
@Value
@AllArgsConstructor
public class CharsetterContext {
public static CharsetterContext empty() {
return new CharsetterContext(Charset.defaultCharset().name(), Locale.getDefault(), Locale.getDefault(), List.of());
}
String systemCharsetName;
Locale systemLocale;
Locale appLocale;
List<String> observedCharsets;
}

View File

@@ -0,0 +1,32 @@
package io.xpipe.core.charsetter;
import lombok.AllArgsConstructor;
import lombok.Value;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Value
@AllArgsConstructor
public class CharsetterUniverse {
List<Charset> charsets;
public static CharsetterUniverse create(CharsetterContext ctx) {
List<Charset> cs = new ArrayList<>();
cs.add(StandardCharsets.UTF_8);
var system = Charset.forName(ctx.getSystemCharsetName());
cs.add(system);
// TODO: Locales
var observed = ctx.getObservedCharsets().stream().map(Charset::forName).toList();
cs.addAll(observed);
return new CharsetterUniverse(cs);
}
}

View File

@@ -0,0 +1,41 @@
package io.xpipe.core.charsetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
public enum NewLine {
@JsonProperty("lf")
LF("\n", "lf"),
@JsonProperty("crlf")
CRLF("\r\n", "crlf");
public static NewLine platform() {
return Arrays.stream(values())
.filter(n -> n.getNewLine().equals(System.getProperty("line.separator")))
.findFirst().orElseThrow();
}
public static NewLine id(String id) {
return Arrays.stream(values())
.filter(n -> n.getId().equalsIgnoreCase(id))
.findFirst().orElseThrow();
}
private final String newLine;
private final String id;
NewLine(String newLine, String id) {
this.newLine = newLine;
this.id = id;
}
public String getNewLine() {
return newLine;
}
public String getId() {
return id;
}
}

View File

@@ -79,7 +79,13 @@ public class GenericDataStreamParser {
}
private static void parseValue(InputStream in, GenericDataStreamCallback cb) throws IOException {
var textual = in.read() != 0;
var type = in.read();
if (type == DataStructureNodeIO.VALUE_TYPE_NULL) {
cb.onValue(null, false);
return;
}
var textual = type == DataStructureNodeIO.VALUE_TYPE_TEXT;
var size = in.read();
var data = in.readNBytes(size);
cb.onValue(data, textual);

View File

@@ -51,10 +51,15 @@ public class GenericDataStreamWriter {
}
}
private static void writeValue(OutputStream out, ValueNode value) throws IOException {
private static void writeValue(OutputStream out, ValueNode n) throws IOException {
out.write(DataStructureNodeIO.GENERIC_VALUE_ID);
out.write(value.isTextual() ? 1 : 0);
out.write(value.getRawData().length);
out.write(value.getRawData());
if (n.isNull()) {
out.write(DataStructureNodeIO.VALUE_TYPE_NULL);
return;
}
out.write(n.isTextual() ? DataStructureNodeIO.VALUE_TYPE_TEXT : DataStructureNodeIO.VALUE_TYPE_BARE);
out.write(n.getRawData().length);
out.write(n.getRawData());
}
}

View File

@@ -12,4 +12,8 @@ public class DataStructureNodeIO {
public static final int TYPED_TUPLE_ID = 6;
public static final int TYPED_ARRAY_ID = 7;
public static final int TYPED_VALUE_ID = 8;
public static final int VALUE_TYPE_BARE = 0;
public static final int VALUE_TYPE_TEXT = 1;
public static final int VALUE_TYPE_NULL = 2;
}

View File

@@ -21,9 +21,18 @@ public class MutableValueNode extends ValueNode {
@Override
public String toString(int indent) {
if (isNull()) {
return "null (M)";
}
return (textual ? "\"" : "") + new String(data) + (textual ? "\"" : "") + " (M)";
}
@Override
public boolean isNull() {
return data == null;
}
@Override
public boolean isTextual() {
return textual;

View File

@@ -129,7 +129,13 @@ public class TypedDataStreamParser {
}
private void parseValue(InputStream in, TypedDataStreamCallback cb) throws IOException {
var textual = in.read() != 0;
var type = in.read();
if (type == DataStructureNodeIO.VALUE_TYPE_NULL) {
cb.onValue(null, false);
return;
}
var textual = type == DataStructureNodeIO.VALUE_TYPE_TEXT;
var size = in.read();
var data = in.readNBytes(size);
cb.onValue(data, textual);

View File

@@ -32,7 +32,12 @@ public class TypedDataStreamWriter {
private static void writeValue(OutputStream out, ValueNode n) throws IOException {
out.write(DataStructureNodeIO.TYPED_VALUE_ID);
out.write(n.isTextual() ? 1 : 0);
if (n.isNull()) {
out.write(DataStructureNodeIO.VALUE_TYPE_NULL);
return;
}
out.write(n.isTextual() ? DataStructureNodeIO.VALUE_TYPE_TEXT : DataStructureNodeIO.VALUE_TYPE_BARE);
out.write(n.getRawData().length);
out.write(n.getRawData());
}

View File

@@ -1,26 +0,0 @@
package io.xpipe.core.dialog;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Value;
@Value
@AllArgsConstructor
public class ConfigParameter {
String key;
@JsonCreator
public ConfigParameter(String key) {
this.key = key;
this.converter = null;
}
@JsonIgnore
QueryConverter<?> converter;
@SuppressWarnings("unchecked")
public <T> QueryConverter<T> getConverter() {
return (QueryConverter<T>) converter;
}
}

View File

@@ -1,54 +0,0 @@
package io.xpipe.core.dialog;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.AllArgsConstructor;
import lombok.Value;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Value
@AllArgsConstructor(onConstructor_={@JsonCreator})
public class ConfigParameterSetInstance {
/**
* The available configuration parameters.
*/
List<ConfigParameter> configParameters;
/**
* The current configuration options that are set.
*/
Map<String, String> currentValues;
public ConfigParameterSetInstance(Map<ConfigParameter, Object> map) {
configParameters = map.keySet().stream().toList();
currentValues = map.entrySet().stream().collect(Collectors.toMap(
e -> e.getKey().getKey(),
e -> e.getKey().getConverter().convertToString(e.getValue())));
}
public <X, T extends Function<X,?>> ConfigParameterSetInstance(Map<ConfigParameter, T> map, Object v) {
configParameters = map.keySet().stream().toList();
currentValues = map.entrySet().stream().collect(Collectors.toMap(
e -> e.getKey().getKey(),
e -> e.getKey().getConverter().convertToString(apply(e.getValue(), v))));
}
@SuppressWarnings("unchecked")
private static <X, T extends Function<X,?>, V> Object apply(T func, Object v) {
return func.apply((X) v);
}
public void update(ConfigParameter p, String val) {
currentValues.put(p.getKey(), val);
}
public Map<ConfigParameter, Object> evaluate() {
return configParameters.stream().collect(Collectors.toMap(
p -> p,
p -> p.getConverter().convertFromString(currentValues.get(p.getKey()))));
}
}

View File

@@ -1,47 +0,0 @@
package io.xpipe.core.source;
import com.fasterxml.jackson.annotation.JsonCreator;
import io.xpipe.core.dialog.ConfigParameter;
import io.xpipe.core.dialog.ConfigParameterSetInstance;
import lombok.AllArgsConstructor;
import lombok.Value;
import java.util.Map;
import java.util.function.Function;
/**
* Represents the current configuration of a data source.
* This configuration can either be in progress or complete.
*/
@Value
@AllArgsConstructor(onConstructor_={@JsonCreator})
public class DataSourceConfigInstance {
public static DataSourceConfigInstance xpbt() {
return new DataSourceConfigInstance("xpbt", new ConfigParameterSetInstance(Map.of()));
}
/**
* The data source provider id.
*/
String provider;
/**
* The available configuration parameters.
*/
ConfigParameterSetInstance configInstance;
public DataSourceConfigInstance(String provider, Map<ConfigParameter, Object> map) {
this.provider = provider;
this.configInstance = new ConfigParameterSetInstance(map);
}
public <X, T extends Function<X,?>> DataSourceConfigInstance(String provider, Map<ConfigParameter, T> map, Object val) {
this.provider = provider;
this.configInstance = new ConfigParameterSetInstance(map, val);
}
public Map<ConfigParameter, Object> evaluate() {
return configInstance.evaluate();
}
}

View File

@@ -9,7 +9,6 @@ module io.xpipe.core {
exports io.xpipe.core.data.node;
exports io.xpipe.core.data.typed;
exports io.xpipe.core.dialog;
exports io.xpipe.core.connection;
opens io.xpipe.core.store;
opens io.xpipe.core.source;
@@ -19,6 +18,7 @@ module io.xpipe.core {
opens io.xpipe.core.data.node;
opens io.xpipe.core.data.typed;
opens io.xpipe.core.dialog;
exports io.xpipe.core.charsetter;
requires com.fasterxml.jackson.core;
requires com.fasterxml.jackson.databind;