mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-25 17:07:26 -04:00
Refactor
This commit is contained in:
@@ -4,7 +4,10 @@ import io.xpipe.core.store.FileStore;
|
||||
import io.xpipe.core.store.StreamDataStore;
|
||||
import lombok.Value;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.*;
|
||||
@@ -15,8 +18,12 @@ import java.util.Map;
|
||||
|
||||
public abstract class Charsetter {
|
||||
|
||||
private static final int MAX_BYTES = 8192;
|
||||
public static Charsetter INSTANCE;
|
||||
private static CharsetterUniverse universe;
|
||||
|
||||
protected Charsetter() {}
|
||||
|
||||
protected static void checkInit() {
|
||||
if (universe == null) {
|
||||
throw new IllegalStateException("Charsetter not initialized");
|
||||
@@ -27,30 +34,25 @@ public abstract class Charsetter {
|
||||
universe = CharsetterUniverse.create(ctx);
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Result {
|
||||
StreamCharset charset;
|
||||
NewLine newLine;
|
||||
}
|
||||
|
||||
protected Charsetter() {
|
||||
}
|
||||
|
||||
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;
|
||||
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 BufferedReader reader(StreamDataStore store, StreamCharset charset) throws Exception {
|
||||
@@ -73,16 +75,15 @@ public abstract class Charsetter {
|
||||
return new BufferedReader(new InputStreamReader(stream, charset.getCharset()));
|
||||
}
|
||||
|
||||
public abstract Result read(FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con) throws Exception;
|
||||
|
||||
private static final int MAX_BYTES = 8192;
|
||||
public abstract Result read(
|
||||
FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con)
|
||||
throws Exception;
|
||||
|
||||
public Result detect(StreamDataStore store) throws Exception {
|
||||
Result result = new Result(null, null);
|
||||
|
||||
if (store.canOpen()) {
|
||||
|
||||
|
||||
try (InputStream inputStream = store.openBufferedInput()) {
|
||||
StreamCharset detected = null;
|
||||
for (var charset : StreamCharset.COMMON) {
|
||||
@@ -135,25 +136,10 @@ public abstract class Charsetter {
|
||||
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;
|
||||
return count.entrySet().stream()
|
||||
.min(Comparator.comparingInt(Map.Entry::getValue))
|
||||
.orElseThrow()
|
||||
.getKey();
|
||||
}
|
||||
|
||||
public Charset inferCharset(byte[] content) {
|
||||
@@ -179,4 +165,21 @@ public abstract class Charsetter {
|
||||
|
||||
return StandardCharsets.UTF_8;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Value
|
||||
public static class Result {
|
||||
StreamCharset charset;
|
||||
NewLine newLine;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,15 +11,13 @@ import java.util.Locale;
|
||||
@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;
|
||||
|
||||
public static CharsetterContext empty() {
|
||||
return new CharsetterContext(
|
||||
Charset.defaultCharset().name(), Locale.getDefault(), Locale.getDefault(), List.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,24 +5,11 @@ 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;
|
||||
|
||||
@@ -31,6 +18,20 @@ public enum NewLine {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public String getNewLine() {
|
||||
return newLine;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,42 @@ import java.util.stream.Stream;
|
||||
@Value
|
||||
public class StreamCharset {
|
||||
|
||||
public static final StreamCharset UTF8 = new StreamCharset(StandardCharsets.UTF_8, null);
|
||||
public static final StreamCharset UTF8_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_8, new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
|
||||
public static final StreamCharset UTF16 = new StreamCharset(StandardCharsets.UTF_16, null);
|
||||
public static final StreamCharset UTF16_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_16, new byte[] {(byte) 0xFE, (byte) 0xFF});
|
||||
public static final StreamCharset UTF16_LE = new StreamCharset(StandardCharsets.UTF_16LE, null);
|
||||
public static final StreamCharset UTF16_LE_BOM =
|
||||
new StreamCharset(StandardCharsets.UTF_16LE, new byte[] {(byte) 0xFF, (byte) 0xFE});
|
||||
public static final StreamCharset UTF32 = new StreamCharset(Charset.forName("utf-32"), null);
|
||||
public static final StreamCharset UTF32_BOM =
|
||||
new StreamCharset(Charset.forName("utf-32"), new byte[] {0x00, 0x00, (byte) 0xFE, (byte) 0xFF});
|
||||
public static final List<StreamCharset> COMMON = List.of(
|
||||
UTF8,
|
||||
UTF8_BOM,
|
||||
UTF16,
|
||||
UTF16_BOM,
|
||||
UTF16_LE,
|
||||
UTF16_LE_BOM,
|
||||
UTF32,
|
||||
UTF32_BOM,
|
||||
new StreamCharset(StandardCharsets.US_ASCII, null),
|
||||
new StreamCharset(StandardCharsets.ISO_8859_1, null),
|
||||
new StreamCharset(Charset.forName("Windows-1251"), null),
|
||||
new StreamCharset(Charset.forName("Windows-1252"), null));
|
||||
public static final List<StreamCharset> RARE = Charset.availableCharsets().values().stream()
|
||||
.filter(charset -> COMMON.stream().noneMatch(c -> c.getCharset().equals(charset)))
|
||||
.map(charset -> new StreamCharset(charset, null))
|
||||
.toList();
|
||||
Charset charset;
|
||||
byte[] byteOrderMark;
|
||||
|
||||
public static StreamCharset get(Charset charset, boolean byteOrderMark) {
|
||||
return Stream.concat(COMMON.stream(), RARE.stream())
|
||||
.filter(streamCharset -> streamCharset.getCharset()
|
||||
.equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
|
||||
.filter(streamCharset ->
|
||||
streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
@@ -24,66 +56,15 @@ public class StreamCharset {
|
||||
@JsonCreator
|
||||
public static StreamCharset get(String s) {
|
||||
var byteOrderMark = s.endsWith("-bom");
|
||||
var charset = Charset.forName(s.substring(
|
||||
0, s.length() - (byteOrderMark ?
|
||||
4 :
|
||||
0)));
|
||||
var charset = Charset.forName(s.substring(0, s.length() - (byteOrderMark ? 4 : 0)));
|
||||
return StreamCharset.get(charset, byteOrderMark);
|
||||
}
|
||||
|
||||
Charset charset;
|
||||
byte[] byteOrderMark;
|
||||
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
return getCharset()
|
||||
.name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ?
|
||||
"-bom" :
|
||||
"");
|
||||
return getCharset().name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ? "-bom" : "");
|
||||
}
|
||||
|
||||
public static final StreamCharset UTF8 = new StreamCharset(StandardCharsets.UTF_8, null);
|
||||
public static final StreamCharset UTF8_BOM = new StreamCharset(StandardCharsets.UTF_8, new byte[]{
|
||||
(byte) 0xEF,
|
||||
(byte) 0xBB,
|
||||
(byte) 0xBF
|
||||
});
|
||||
|
||||
public static final StreamCharset UTF16 = new StreamCharset(StandardCharsets.UTF_16, null);
|
||||
public static final StreamCharset UTF16_BOM = new StreamCharset(StandardCharsets.UTF_16, new byte[]{
|
||||
(byte) 0xFE,
|
||||
(byte) 0xFF
|
||||
});
|
||||
|
||||
public static final StreamCharset UTF16_LE = new StreamCharset(StandardCharsets.UTF_16LE, null);
|
||||
public static final StreamCharset UTF16_LE_BOM = new StreamCharset(StandardCharsets.UTF_16LE, new byte[]{
|
||||
(byte) 0xFF,
|
||||
(byte) 0xFE
|
||||
});
|
||||
|
||||
public static final StreamCharset UTF32 = new StreamCharset(Charset.forName("utf-32"), null);
|
||||
public static final StreamCharset UTF32_BOM = new StreamCharset(Charset.forName("utf-32"), new byte[]{
|
||||
0x00,
|
||||
0x00,
|
||||
(byte) 0xFE,
|
||||
(byte) 0xFF
|
||||
});
|
||||
|
||||
public static final List<StreamCharset> COMMON = List.of(
|
||||
UTF8, UTF8_BOM, UTF16, UTF16_BOM, UTF16_LE, UTF16_LE_BOM, UTF32, UTF32_BOM, new StreamCharset(StandardCharsets.US_ASCII, null),
|
||||
new StreamCharset(StandardCharsets.ISO_8859_1, null),
|
||||
new StreamCharset(Charset.forName("Windows-1251"), null), new StreamCharset(Charset.forName("Windows-1252"), null)
|
||||
);
|
||||
|
||||
public static final List<StreamCharset> RARE = Charset.availableCharsets()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(charset -> COMMON.stream()
|
||||
.noneMatch(c -> c.getCharset()
|
||||
.equals(charset)))
|
||||
.map(charset -> new StreamCharset(charset, null))
|
||||
.toList();
|
||||
|
||||
public boolean hasByteOrderMark() {
|
||||
return byteOrderMark != null;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.xpipe.core.data.generic;
|
||||
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.ValueNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -16,8 +16,8 @@ public class GenericArrayReader implements GenericAbstractReader {
|
||||
private int currentIndex = 0;
|
||||
private GenericAbstractReader currentReader;
|
||||
private DataStructureNode created;
|
||||
public GenericArrayReader() {
|
||||
}
|
||||
|
||||
public GenericArrayReader() {}
|
||||
|
||||
public static GenericArrayReader newReader(int length) {
|
||||
var ar = new GenericArrayReader();
|
||||
|
||||
@@ -4,22 +4,15 @@ import java.util.Map;
|
||||
|
||||
public interface GenericDataStreamCallback {
|
||||
|
||||
default void onName(String name) {
|
||||
}
|
||||
default void onName(String name) {}
|
||||
|
||||
default void onArrayStart(int length) {
|
||||
}
|
||||
default void onArrayStart(int length) {}
|
||||
|
||||
default void onArrayEnd(Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onArrayEnd(Map<Integer, String> metaAttributes) {}
|
||||
|
||||
default void onTupleStart(int length) {
|
||||
}
|
||||
default void onTupleStart(int length) {}
|
||||
|
||||
default void onTupleEnd(Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onTupleEnd(Map<Integer, String> metaAttributes) {}
|
||||
|
||||
|
||||
default void onValue(byte[] value, Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onValue(byte[] value, Map<Integer, String> metaAttributes) {}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ public class GenericDataStructureNodeReader implements GenericDataStreamCallback
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
node = ValueNode.of(value).tag(metaAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ public class GenericTupleReader implements GenericAbstractReader {
|
||||
private int currentIndex = 0;
|
||||
private GenericAbstractReader currentReader;
|
||||
private DataStructureNode created;
|
||||
public GenericTupleReader() {
|
||||
}
|
||||
|
||||
public GenericTupleReader() {}
|
||||
|
||||
public static GenericTupleReader newReader(int length) {
|
||||
var tr = new GenericTupleReader();
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
public abstract class ArrayNode extends DataStructureNode {
|
||||
|
||||
protected ArrayNode() {}
|
||||
|
||||
public static ArrayNode empty() {
|
||||
return of(List.of());
|
||||
}
|
||||
@@ -20,9 +22,6 @@ public abstract class ArrayNode extends DataStructureNode {
|
||||
return new SimpleArrayNode(nodes);
|
||||
}
|
||||
|
||||
protected ArrayNode() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@@ -32,7 +31,8 @@ public abstract class ArrayNode extends DataStructureNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
var toReturn = getNodes().equals(that.getNodes()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
var toReturn =
|
||||
getNodes().equals(that.getNodes()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
|
||||
// Useful for debugging
|
||||
if (toReturn == false) {
|
||||
@@ -64,6 +64,7 @@ public abstract class ArrayNode extends DataStructureNode {
|
||||
|
||||
@Override
|
||||
public final ArrayType determineDataType() {
|
||||
return ArrayType.ofSharedType(getNodes().stream().map(DataStructureNode::determineDataType).toList());
|
||||
return ArrayType.ofSharedType(
|
||||
getNodes().stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String getMetaAttribute(Integer key) {
|
||||
if (metaAttributes == null) {
|
||||
return null;
|
||||
@@ -104,9 +103,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
throw unsupported("get nodes");
|
||||
}
|
||||
|
||||
public record KeyValue(String key, DataStructureNode value) {
|
||||
}
|
||||
|
||||
protected abstract String getName();
|
||||
|
||||
protected UnsupportedOperationException unsupported(String s) {
|
||||
@@ -125,12 +121,15 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
}
|
||||
|
||||
public String metaToString() {
|
||||
return "(" + (metaAttributes != null ?
|
||||
metaAttributes.entrySet()
|
||||
.stream()
|
||||
.map(e -> e.getValue() != null ? e.getKey() + ":" + e.getValue() : e.getKey().toString())
|
||||
.collect(Collectors.joining("|")) :
|
||||
"") + ")";
|
||||
return "("
|
||||
+ (metaAttributes != null
|
||||
? metaAttributes.entrySet().stream()
|
||||
.map(e -> e.getValue() != null
|
||||
? e.getKey() + ":" + e.getValue()
|
||||
: e.getKey().toString())
|
||||
.collect(Collectors.joining("|"))
|
||||
: "")
|
||||
+ ")";
|
||||
}
|
||||
|
||||
public abstract String toString(int indent);
|
||||
@@ -146,11 +145,11 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
public boolean isValue() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public DataStructureNode set(int index, DataStructureNode node) {
|
||||
throw unsupported("set at index");
|
||||
}
|
||||
|
||||
|
||||
public final ValueNode asValue() {
|
||||
if (!isValue()) {
|
||||
throw new UnsupportedOperationException(getName() + " is not a value node");
|
||||
@@ -235,4 +234,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
|
||||
public Iterator<DataStructureNode> iterator() {
|
||||
throw unsupported("iterator creation");
|
||||
}
|
||||
|
||||
public record KeyValue(String key, DataStructureNode value) {}
|
||||
}
|
||||
|
||||
@@ -152,9 +152,7 @@ public class DataStructureNodePointer {
|
||||
|
||||
@Override
|
||||
public DataStructureNode tryMatch(DataStructureNode n) {
|
||||
var res = n.stream()
|
||||
.filter(selector)
|
||||
.findAny();
|
||||
var res = n.stream().filter(selector).findAny();
|
||||
return res.orElse(null);
|
||||
}
|
||||
|
||||
@@ -184,7 +182,6 @@ public class DataStructureNodePointer {
|
||||
return new Builder(new ArrayList<>(path));
|
||||
}
|
||||
|
||||
|
||||
public Builder name(String name) {
|
||||
path.add(new NameElement(name));
|
||||
return this;
|
||||
@@ -219,7 +216,8 @@ public class DataStructureNodePointer {
|
||||
});
|
||||
}
|
||||
|
||||
public Builder pointerEvaluation(DataStructureNodePointer pointer, Function<DataStructureNode, String> converter) {
|
||||
public Builder pointerEvaluation(
|
||||
DataStructureNodePointer pointer, Function<DataStructureNode, String> converter) {
|
||||
path.add(new FunctionElement((current) -> {
|
||||
var res = pointer.get(current);
|
||||
if (res != null) {
|
||||
|
||||
@@ -84,7 +84,9 @@ public class LinkedTupleNode extends TupleNode {
|
||||
|
||||
@Override
|
||||
public DataType determineDataType() {
|
||||
return TupleType.of(getKeyNames(), getNodes().stream().map(DataStructureNode::determineDataType).toList());
|
||||
return TupleType.of(
|
||||
getKeyNames(),
|
||||
getNodes().stream().map(DataStructureNode::determineDataType).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,7 +144,6 @@ public class LinkedTupleNode extends TupleNode {
|
||||
return "LinkedTupleNode(" + size() + ")";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return tupleNodes.stream().mapToInt(TupleNode::size).sum();
|
||||
@@ -174,6 +175,7 @@ public class LinkedTupleNode extends TupleNode {
|
||||
return this;
|
||||
}
|
||||
|
||||
return new LinkedTupleNode(tupleNodes.stream().map(n -> n.isMutable() ? n : n.mutable()).toList());
|
||||
return new LinkedTupleNode(
|
||||
tupleNodes.stream().map(n -> n.isMutable() ? n : n.mutable()).toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@AllArgsConstructor
|
||||
|
||||
|
||||
public class SimpleArrayNode extends ArrayNode {
|
||||
|
||||
List<DataStructureNode> nodes;
|
||||
@@ -79,6 +77,4 @@ public class SimpleArrayNode extends ArrayNode {
|
||||
nodes.remove(index);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,11 @@ public class SimpleValueNode extends ValueNode {
|
||||
|
||||
@Override
|
||||
public String toString(int indent) {
|
||||
var string = getRawData().length == 0 && !hasMetaAttribute(IS_TEXT) ? "<null>" : new String(getRawData(), StandardCharsets.UTF_8);
|
||||
return (hasMetaAttribute(IS_TEXT) ? "\"" : "") + string + (hasMetaAttribute(IS_TEXT) ? "\"" : "") + " " + metaToString();
|
||||
var string = getRawData().length == 0 && !hasMetaAttribute(IS_TEXT)
|
||||
? "<null>"
|
||||
: new String(getRawData(), StandardCharsets.UTF_8);
|
||||
return (hasMetaAttribute(IS_TEXT) ? "\"" : "") + string + (hasMetaAttribute(IS_TEXT) ? "\"" : "") + " "
|
||||
+ metaToString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public abstract class TupleNode extends DataStructureNode {
|
||||
|
||||
public static Builder builder() {
|
||||
@@ -46,13 +45,15 @@ public abstract class TupleNode extends DataStructureNode {
|
||||
public String toString(int indent) {
|
||||
var is = " ".repeat(indent);
|
||||
var start = "{\n";
|
||||
var kvs = getKeyValuePairs().stream().map(kv -> {
|
||||
if (kv.key() == null) {
|
||||
return is + " " + kv.value().toString(indent + 1) + "\n";
|
||||
} else {
|
||||
return is + " " + kv.key() + "=" + kv.value().toString(indent + 1) + "\n";
|
||||
}
|
||||
}).collect(Collectors.joining());
|
||||
var kvs = getKeyValuePairs().stream()
|
||||
.map(kv -> {
|
||||
if (kv.key() == null) {
|
||||
return is + " " + kv.value().toString(indent + 1) + "\n";
|
||||
} else {
|
||||
return is + " " + kv.key() + "=" + kv.value().toString(indent + 1) + "\n";
|
||||
}
|
||||
})
|
||||
.collect(Collectors.joining());
|
||||
var end = is + "}";
|
||||
return start + kvs + end;
|
||||
}
|
||||
@@ -65,8 +66,9 @@ public abstract class TupleNode extends DataStructureNode {
|
||||
if (!(o instanceof TupleNode that)) {
|
||||
return false;
|
||||
}
|
||||
var toReturn = getKeyNames().equals(that.getKeyNames()) && getNodes().equals(that.getNodes()) &&
|
||||
Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
var toReturn = getKeyNames().equals(that.getKeyNames())
|
||||
&& getNodes().equals(that.getNodes())
|
||||
&& Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
|
||||
// Useful for debugging
|
||||
if (toReturn == false) {
|
||||
@@ -98,11 +100,11 @@ public abstract class TupleNode extends DataStructureNode {
|
||||
|
||||
public TupleNode build() {
|
||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
|
||||
return hasKeys ? TupleNode.of(
|
||||
entries.stream().map(KeyValue::key).toList(),
|
||||
entries.stream().map(KeyValue::value).toList()
|
||||
) :
|
||||
TupleNode.of(entries.stream().map(KeyValue::value).toList());
|
||||
return hasKeys
|
||||
? TupleNode.of(
|
||||
entries.stream().map(KeyValue::key).toList(),
|
||||
entries.stream().map(KeyValue::value).toList())
|
||||
: TupleNode.of(entries.stream().map(KeyValue::value).toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,32 +11,7 @@ import java.util.Objects;
|
||||
|
||||
public abstract class ValueNode extends DataStructureNode {
|
||||
|
||||
|
||||
protected ValueNode() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof ValueNode that)) {
|
||||
return false;
|
||||
}
|
||||
var toReturn = Arrays.equals(getRawData(), that.getRawData()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
|
||||
// Useful for debugging
|
||||
if (toReturn == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(getRawData()) + Objects.hash(getMetaAttributes());
|
||||
}
|
||||
protected ValueNode() {}
|
||||
|
||||
public static ValueNode nullValue() {
|
||||
return new SimpleValueNode(new byte[0]).tag(IS_NULL).asValue();
|
||||
@@ -79,6 +54,7 @@ public abstract class ValueNode extends DataStructureNode {
|
||||
created.tag(IS_FLOATING_POINT);
|
||||
return created;
|
||||
}
|
||||
|
||||
public static ValueNode ofBoolean(Boolean bool) {
|
||||
var created = of(bool);
|
||||
created.tag(IS_BOOLEAN);
|
||||
@@ -93,6 +69,30 @@ public abstract class ValueNode extends DataStructureNode {
|
||||
return of(o.toString().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof ValueNode that)) {
|
||||
return false;
|
||||
}
|
||||
var toReturn = Arrays.equals(getRawData(), that.getRawData())
|
||||
&& Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||
|
||||
// Useful for debugging
|
||||
if (toReturn == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(getRawData()) + Objects.hash(getMetaAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int asInt() {
|
||||
return Integer.parseInt(asString());
|
||||
@@ -114,5 +114,4 @@ public abstract class ValueNode extends DataStructureNode {
|
||||
}
|
||||
|
||||
public abstract byte[] getRawData();
|
||||
|
||||
}
|
||||
|
||||
@@ -2,15 +2,11 @@ package io.xpipe.core.data.type;
|
||||
|
||||
public interface DataTypeVisitor {
|
||||
|
||||
default void onValue(ValueType type) {
|
||||
}
|
||||
default void onValue(ValueType type) {}
|
||||
|
||||
default void onTuple(TupleType type) {
|
||||
}
|
||||
default void onTuple(TupleType type) {}
|
||||
|
||||
default void onArray(ArrayType type) {
|
||||
}
|
||||
default void onArray(ArrayType type) {}
|
||||
|
||||
default void onWildcard(WildcardType type) {
|
||||
}
|
||||
default void onWildcard(WildcardType type) {}
|
||||
}
|
||||
|
||||
@@ -41,9 +41,7 @@ public class DataTypeVisitors {
|
||||
* Creates a visitor that allows for visiting possible recursive columns of table.
|
||||
*/
|
||||
public static DataTypeVisitor table(
|
||||
Consumer<String> newTuple,
|
||||
Runnable endTuple,
|
||||
BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
Consumer<String> newTuple, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) {
|
||||
return new DataTypeVisitor() {
|
||||
private final Stack<TupleType> tuples = new Stack<>();
|
||||
private final Stack<Integer> keyIndices = new Stack<>();
|
||||
|
||||
@@ -17,6 +17,8 @@ import java.util.Optional;
|
||||
@Value
|
||||
public class WildcardType extends DataType {
|
||||
|
||||
private WildcardType() {}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
@@ -24,8 +26,6 @@ public class WildcardType extends DataType {
|
||||
return new WildcardType();
|
||||
}
|
||||
|
||||
private WildcardType() {}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "wildcard";
|
||||
|
||||
@@ -7,27 +7,19 @@ import java.util.Map;
|
||||
|
||||
public interface TypedDataStreamCallback {
|
||||
|
||||
default void onValue(byte[] data, Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onValue(byte[] data, Map<Integer, String> metaAttributes) {}
|
||||
|
||||
default void onGenericNode(DataStructureNode node) {
|
||||
}
|
||||
default void onGenericNode(DataStructureNode node) {}
|
||||
|
||||
default void onTupleBegin(TupleType type) {
|
||||
}
|
||||
default void onTupleBegin(TupleType type) {}
|
||||
|
||||
default void onTupleEnd(Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onTupleEnd(Map<Integer, String> metaAttributes) {}
|
||||
|
||||
default void onArrayBegin(int size) {
|
||||
}
|
||||
default void onArrayBegin(int size) {}
|
||||
|
||||
default void onArrayEnd(Map<Integer, String> metaAttributes) {
|
||||
}
|
||||
default void onArrayEnd(Map<Integer, String> metaAttributes) {}
|
||||
|
||||
default void onNodeBegin() {
|
||||
}
|
||||
default void onNodeBegin() {}
|
||||
|
||||
default void onNodeEnd() {
|
||||
}
|
||||
default void onNodeEnd() {}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.xpipe.core.data.typed;
|
||||
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.generic.GenericDataStreamParser;
|
||||
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeIO;
|
||||
import io.xpipe.core.data.type.ArrayType;
|
||||
import io.xpipe.core.data.type.DataType;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
@@ -21,7 +21,7 @@ public class TypedDataStreamParser {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
private boolean hasNext(InputStream in) throws IOException {
|
||||
private boolean hasNext(InputStream in) throws IOException {
|
||||
var b = in.read();
|
||||
if (b == -1) {
|
||||
return false;
|
||||
@@ -34,7 +34,8 @@ public class TypedDataStreamParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer) throws IOException {
|
||||
public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer)
|
||||
throws IOException {
|
||||
while (hasNext(in)) {
|
||||
cb.onNodeBegin();
|
||||
parse(in, cb, dataType);
|
||||
|
||||
@@ -12,20 +12,13 @@ import java.util.Stack;
|
||||
|
||||
public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||
|
||||
public static TypedDataStructureNodeReader of(DataType type) {
|
||||
return new TypedDataStructureNodeReader(type);
|
||||
}
|
||||
|
||||
private DataStructureNode readNode;
|
||||
|
||||
private final Stack<List<DataStructureNode>> children;
|
||||
private final Stack<DataStructureNode> nodes;
|
||||
private int arrayDepth;
|
||||
|
||||
private final List<DataType> flattened;
|
||||
private DataStructureNode readNode;
|
||||
private int arrayDepth;
|
||||
private DataType expectedType;
|
||||
private int currentExpectedTypeIndex;
|
||||
|
||||
private TypedDataStructureNodeReader(DataType type) {
|
||||
flattened = new ArrayList<>();
|
||||
type.visit(DataTypeVisitors.flatten(flattened::add));
|
||||
@@ -34,6 +27,10 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||
expectedType = flattened.get(0);
|
||||
}
|
||||
|
||||
public static TypedDataStructureNodeReader of(DataType type) {
|
||||
return new TypedDataStructureNodeReader(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNodeBegin() {
|
||||
if (nodes.size() != 0 || children.size() != 0) {
|
||||
@@ -134,7 +131,8 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
|
||||
private void moveExpectedType(boolean force) {
|
||||
if (!isInArray() || force) {
|
||||
currentExpectedTypeIndex++;
|
||||
expectedType = currentExpectedTypeIndex == flattened.size() ? null : flattened.get(currentExpectedTypeIndex);
|
||||
expectedType =
|
||||
currentExpectedTypeIndex == flattened.size() ? null : flattened.get(currentExpectedTypeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ public class BaseQueryElement extends DialogElement {
|
||||
protected String value;
|
||||
|
||||
@JsonCreator
|
||||
public BaseQueryElement(String description, boolean newLine, boolean required, boolean secret, boolean quiet, String value) {
|
||||
public BaseQueryElement(
|
||||
String description, boolean newLine, boolean required, boolean secret, boolean quiet, String value) {
|
||||
this.description = description;
|
||||
this.newLine = newLine;
|
||||
this.required = required;
|
||||
|
||||
@@ -18,6 +18,18 @@ public class ChoiceElement extends DialogElement {
|
||||
|
||||
private int selected;
|
||||
|
||||
@JsonCreator
|
||||
public ChoiceElement(String description, List<Choice> elements, boolean required, int selected) {
|
||||
if (elements.stream().allMatch(Choice::isDisabled)) {
|
||||
throw new IllegalArgumentException("All choices are disabled");
|
||||
}
|
||||
|
||||
this.description = description;
|
||||
this.elements = elements;
|
||||
this.required = required;
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresExplicitUserInput() {
|
||||
return required && selected == -1;
|
||||
@@ -42,7 +54,8 @@ public class ChoiceElement extends DialogElement {
|
||||
}
|
||||
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
if (elements.get(i).getCharacter() != null && elements.get(i).getCharacter().equals(c)) {
|
||||
if (elements.get(i).getCharacter() != null
|
||||
&& elements.get(i).getCharacter().equals(c)) {
|
||||
selected = i;
|
||||
return true;
|
||||
}
|
||||
@@ -59,18 +72,6 @@ public class ChoiceElement extends DialogElement {
|
||||
return false;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public ChoiceElement(String description, List<Choice> elements, boolean required, int selected) {
|
||||
if (elements.stream().allMatch(Choice::isDisabled)) {
|
||||
throw new IllegalArgumentException("All choices are disabled");
|
||||
}
|
||||
|
||||
this.description = description;
|
||||
this.elements = elements;
|
||||
this.required = required;
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public List<Choice> getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package io.xpipe.core.dialog;
|
||||
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -24,6 +26,10 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public abstract class Dialog {
|
||||
|
||||
private final List<Consumer<?>> completion = new ArrayList<>();
|
||||
protected Object eval;
|
||||
private Supplier<?> evaluation;
|
||||
|
||||
/**
|
||||
* Creates an empty dialogue. This dialogue completes immediately and does not handle any questions or answers.
|
||||
*/
|
||||
@@ -43,33 +49,6 @@ public abstract class Dialog {
|
||||
};
|
||||
}
|
||||
|
||||
public static class Choice extends Dialog {
|
||||
|
||||
private final ChoiceElement element;
|
||||
|
||||
private Choice(String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, int selected) {
|
||||
this.element = new ChoiceElement(description, elements, required, selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DialogElement next(String answer) throws Exception {
|
||||
if (element.apply(answer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private int getSelected() {
|
||||
return element.getSelected();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a choice dialogue.
|
||||
*
|
||||
@@ -78,7 +57,8 @@ public abstract class Dialog {
|
||||
* @param required signals whether a choice is required or can be left empty
|
||||
* @param selected the selected element index
|
||||
*/
|
||||
public static Dialog.Choice choice(String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, int selected) {
|
||||
public static Dialog.Choice choice(
|
||||
String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, int selected) {
|
||||
Dialog.Choice c = new Dialog.Choice(description, elements, required, selected);
|
||||
c.evaluateTo(c::getSelected);
|
||||
return c;
|
||||
@@ -94,8 +74,11 @@ public abstract class Dialog {
|
||||
* @param vals the range of possible elements
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Dialog.Choice choice(String description, Function<T, String> toString, boolean required, T def, T... vals) {
|
||||
var elements = Arrays.stream(vals).map(v -> new io.xpipe.core.dialog.Choice(null, toString.apply(v))).toList();
|
||||
public static <T> Dialog.Choice choice(
|
||||
String description, Function<T, String> toString, boolean required, T def, T... vals) {
|
||||
var elements = Arrays.stream(vals)
|
||||
.map(v -> new io.xpipe.core.dialog.Choice(null, toString.apply(v)))
|
||||
.toList();
|
||||
var index = Arrays.asList(vals).indexOf(def);
|
||||
if (def != null && index == -1) {
|
||||
throw new IllegalArgumentException("Default value " + def.toString() + " is not in possible values");
|
||||
@@ -111,38 +94,6 @@ public abstract class Dialog {
|
||||
return c;
|
||||
}
|
||||
|
||||
public static class Query extends Dialog {
|
||||
|
||||
private final QueryElement element;
|
||||
|
||||
private <T> Query(String description, boolean newLine, boolean required, boolean quiet, T value, QueryConverter<T> converter, boolean hidden) {
|
||||
this.element = new QueryElement(description, newLine, required, quiet, value, converter, hidden);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DialogElement next(String answer) throws Exception {
|
||||
if (element.requiresExplicitUserInput() && (answer == null || answer.trim()
|
||||
.length() == 0)) {
|
||||
return element;
|
||||
}
|
||||
|
||||
if (element.apply(answer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private <T> T getConvertedValue() {
|
||||
return element.getConvertedValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple query dialogue.
|
||||
*
|
||||
@@ -155,7 +106,13 @@ public abstract class Dialog {
|
||||
* @param value the default value
|
||||
* @param converter the converter
|
||||
*/
|
||||
public static <T> Dialog.Query query(String description, boolean newLine, boolean required, boolean quiet, T value, QueryConverter<T> converter) {
|
||||
public static <T> Dialog.Query query(
|
||||
String description,
|
||||
boolean newLine,
|
||||
boolean required,
|
||||
boolean quiet,
|
||||
T value,
|
||||
QueryConverter<T> converter) {
|
||||
var q = new <T>Dialog.Query(description, newLine, required, quiet, value, converter, false);
|
||||
q.evaluateTo(q::getConvertedValue);
|
||||
return q;
|
||||
@@ -201,8 +158,7 @@ public abstract class Dialog {
|
||||
DialogElement currentElement = ds[current].receive(answer);
|
||||
if (currentElement == null) {
|
||||
DialogElement next = null;
|
||||
while (current < ds.length - 1 && (next = ds[++current].start()) == null) {
|
||||
}
|
||||
while (current < ds.length - 1 && (next = ds[++current].start()) == null) {}
|
||||
;
|
||||
return next;
|
||||
}
|
||||
@@ -218,7 +174,6 @@ public abstract class Dialog {
|
||||
public static <T> Dialog repeatIf(Dialog d, Predicate<T> shouldRepeat) {
|
||||
return new Dialog() {
|
||||
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
eval = null;
|
||||
@@ -272,11 +227,6 @@ public abstract class Dialog {
|
||||
return of(new BusyElement());
|
||||
}
|
||||
|
||||
public static interface FailableSupplier<T> {
|
||||
|
||||
T get() throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dialogue that will only evaluate when needed.
|
||||
* This allows a dialogue to incorporate completion information about a previous dialogue.
|
||||
@@ -305,7 +255,6 @@ public abstract class Dialog {
|
||||
private static Dialog of(DialogElement e) {
|
||||
return new Dialog() {
|
||||
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
eval = null;
|
||||
@@ -323,7 +272,6 @@ public abstract class Dialog {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a dialogue that will not be executed if the condition is true.
|
||||
*/
|
||||
@@ -393,7 +341,12 @@ public abstract class Dialog {
|
||||
* @param selected the index of the element that is selected by default
|
||||
* @param c the dialogue index mapping function
|
||||
*/
|
||||
public static Dialog fork(String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, int selected, Function<Integer, Dialog> c) {
|
||||
public static Dialog fork(
|
||||
String description,
|
||||
List<io.xpipe.core.dialog.Choice> elements,
|
||||
boolean required,
|
||||
int selected,
|
||||
Function<Integer, Dialog> c) {
|
||||
var choice = new ChoiceElement(description, elements, required, selected);
|
||||
return new Dialog() {
|
||||
|
||||
@@ -427,13 +380,9 @@ public abstract class Dialog {
|
||||
};
|
||||
}
|
||||
|
||||
protected Object eval;
|
||||
private Supplier<?> evaluation;
|
||||
private final List<Consumer<?>> completion = new ArrayList<>();
|
||||
|
||||
/* TODO: Implement automatic completion mechanism for start as well
|
||||
* In case start returns null, the completion is not automatically done.
|
||||
* */
|
||||
* In case start returns null, the completion is not automatically done.
|
||||
* */
|
||||
public abstract DialogElement start() throws Exception;
|
||||
|
||||
public Dialog evaluateTo(Dialog d) {
|
||||
@@ -493,4 +442,75 @@ public abstract class Dialog {
|
||||
}
|
||||
|
||||
protected abstract DialogElement next(String answer) throws Exception;
|
||||
|
||||
public static interface FailableSupplier<T> {
|
||||
|
||||
T get() throws Exception;
|
||||
}
|
||||
|
||||
public static class Choice extends Dialog {
|
||||
|
||||
private final ChoiceElement element;
|
||||
|
||||
private Choice(String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, int selected) {
|
||||
this.element = new ChoiceElement(description, elements, required, selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DialogElement next(String answer) throws Exception {
|
||||
if (element.apply(answer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private int getSelected() {
|
||||
return element.getSelected();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Query extends Dialog {
|
||||
|
||||
private final QueryElement element;
|
||||
|
||||
private <T> Query(
|
||||
String description,
|
||||
boolean newLine,
|
||||
boolean required,
|
||||
boolean quiet,
|
||||
T value,
|
||||
QueryConverter<T> converter,
|
||||
boolean hidden) {
|
||||
this.element = new QueryElement(description, newLine, required, quiet, value, converter, hidden);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DialogElement start() throws Exception {
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DialogElement next(String answer) throws Exception {
|
||||
if (element.requiresExplicitUserInput()
|
||||
&& (answer == null || answer.trim().length() == 0)) {
|
||||
return element;
|
||||
}
|
||||
|
||||
if (element.apply(answer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private <T> T getConvertedValue() {
|
||||
return element.getConvertedValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ package io.xpipe.core.dialog;
|
||||
*/
|
||||
public class DialogCancelException extends Exception {
|
||||
|
||||
public DialogCancelException() {
|
||||
}
|
||||
public DialogCancelException() {}
|
||||
|
||||
public DialogCancelException(String message) {
|
||||
super(message);
|
||||
@@ -20,7 +19,8 @@ public class DialogCancelException extends Exception {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DialogCancelException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
public DialogCancelException(
|
||||
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ public abstract class QueryConverter<T> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static final QueryConverter<StreamCharset> CHARSET = new QueryConverter<StreamCharset>() {
|
||||
@Override
|
||||
protected StreamCharset fromString(String s) {
|
||||
@@ -60,26 +59,27 @@ public abstract class QueryConverter<T> {
|
||||
}
|
||||
};
|
||||
|
||||
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER = new QueryConverter<Map.Entry<String, String>>() {
|
||||
@Override
|
||||
protected Map.Entry<String, String> fromString(String s) {
|
||||
if (!s.contains(":")) {
|
||||
throw new IllegalArgumentException("Missing colon");
|
||||
}
|
||||
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER =
|
||||
new QueryConverter<Map.Entry<String, String>>() {
|
||||
@Override
|
||||
protected Map.Entry<String, String> fromString(String s) {
|
||||
if (!s.contains(":")) {
|
||||
throw new IllegalArgumentException("Missing colon");
|
||||
}
|
||||
|
||||
var split = s.split(":");
|
||||
if (split.length != 2) {
|
||||
throw new IllegalArgumentException("Too many colons");
|
||||
}
|
||||
var split = s.split(":");
|
||||
if (split.length != 2) {
|
||||
throw new IllegalArgumentException("Too many colons");
|
||||
}
|
||||
|
||||
return new AbstractMap.SimpleEntry<>(split[0].trim(), split[1].trim());
|
||||
}
|
||||
return new AbstractMap.SimpleEntry<>(split[0].trim(), split[1].trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toString(Map.Entry<String, String> value) {
|
||||
return value.getKey() + ": " + value.getValue();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
protected String toString(Map.Entry<String, String> value) {
|
||||
return value.getKey() + ": " + value.getValue();
|
||||
}
|
||||
};
|
||||
|
||||
public static final QueryConverter<URI> URI = new QueryConverter<URI>() {
|
||||
@Override
|
||||
@@ -141,9 +141,7 @@ public abstract class QueryConverter<T> {
|
||||
|
||||
@Override
|
||||
protected String toString(Boolean value) {
|
||||
return value ?
|
||||
"yes" :
|
||||
"no";
|
||||
return value ? "yes" : "no";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,14 @@ public class QueryElement extends BaseQueryElement {
|
||||
|
||||
private final QueryConverter<?> converter;
|
||||
|
||||
public <T> QueryElement(String description, boolean newLine, boolean required, boolean quiet, T value, QueryConverter<T> converter, boolean hidden) {
|
||||
public <T> QueryElement(
|
||||
String description,
|
||||
boolean newLine,
|
||||
boolean required,
|
||||
boolean quiet,
|
||||
T value,
|
||||
QueryConverter<T> converter,
|
||||
boolean hidden) {
|
||||
super(description, newLine, required, hidden, quiet, value != null ? converter.toString(value) : null);
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@@ -50,5 +50,3 @@ public abstract class BatchTableWriteConnection implements TableWriteConnection
|
||||
|
||||
protected abstract DataStructureNodeAcceptor<ArrayNode> writeBatchLinesAcceptor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ public class BinarySource extends RawDataSource<StreamDataStore> {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected RawReadConnection newReadConnection() {
|
||||
return new RawReadConnection() {
|
||||
|
||||
@@ -48,8 +48,7 @@ public class LimitTableReadConnection implements TableReadConnection {
|
||||
}
|
||||
count++;
|
||||
|
||||
var returned = lineAcceptor
|
||||
.accept(node);
|
||||
var returned = lineAcceptor.accept(node);
|
||||
localCounter.getAndIncrement();
|
||||
|
||||
return returned;
|
||||
|
||||
@@ -9,14 +9,12 @@ import io.xpipe.core.source.TableWriteConnection;
|
||||
|
||||
public class PreservingTableWriteConnection extends PreservingWriteConnection implements TableWriteConnection {
|
||||
|
||||
public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection,
|
||||
boolean append
|
||||
) {
|
||||
public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) {
|
||||
super(DataSourceType.TABLE, source, append, connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor() {
|
||||
return ((TableWriteConnection)connection).writeLinesAcceptor();
|
||||
return ((TableWriteConnection) connection).writeLinesAcceptor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ import io.xpipe.core.source.TextWriteConnection;
|
||||
|
||||
public class PreservingTextWriteConnection extends PreservingWriteConnection implements TextWriteConnection {
|
||||
|
||||
public PreservingTextWriteConnection(
|
||||
DataSource<?> source, DataSourceConnection connection,
|
||||
boolean append
|
||||
) {
|
||||
public PreservingTextWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) {
|
||||
super(DataSourceType.TEXT, source, append, connection);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@ import java.nio.file.Files;
|
||||
|
||||
public class PreservingWriteConnection implements DataSourceConnection {
|
||||
|
||||
protected final DataSourceConnection connection;
|
||||
private final DataSourceType type;
|
||||
private final DataSource<?> source;
|
||||
private final boolean append ;
|
||||
protected final DataSourceConnection connection;
|
||||
private final boolean append;
|
||||
|
||||
public PreservingWriteConnection(DataSourceType type, DataSource<?> source, boolean append, DataSourceConnection connection) {
|
||||
public PreservingWriteConnection(
|
||||
DataSourceType type, DataSource<?> source, boolean append, DataSourceConnection connection) {
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
this.append = append;
|
||||
@@ -26,13 +27,13 @@ public class PreservingWriteConnection implements DataSourceConnection {
|
||||
var nativeStore = FileStore.local(temp);
|
||||
var nativeSource = DataSource.createInternalDataSource(type, nativeStore);
|
||||
if (source.getStore().canOpen()) {
|
||||
try (var in = source.openReadConnection(); var out = nativeSource.openWriteConnection()) {
|
||||
try (var in = source.openReadConnection();
|
||||
var out = nativeSource.openWriteConnection()) {
|
||||
in.forward(out);
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
connection.init();
|
||||
if (source.getStore().canOpen()) {
|
||||
|
||||
@@ -45,5 +46,4 @@ public class PreservingWriteConnection implements DataSourceConnection {
|
||||
public void close() throws Exception {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ public class TextReadConnection extends StreamReadConnection implements io.xpipe
|
||||
return bufferedReader.lines();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
bufferedReader.close();
|
||||
|
||||
@@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized;
|
||||
@JsonTypeName("text")
|
||||
@SuperBuilder
|
||||
@Jacksonized
|
||||
public final class TextSource extends TextDataSource<StreamDataStore> implements Charsettable {
|
||||
public final class TextSource extends TextDataSource<StreamDataStore> implements Charsettable {
|
||||
|
||||
private final StreamCharset charset;
|
||||
private final NewLine newLine;
|
||||
|
||||
@@ -13,6 +13,6 @@ public class XpbsWriteConnection extends StreamWriteConnection implements Struct
|
||||
|
||||
@Override
|
||||
public void write(DataStructureNode node) throws Exception {
|
||||
GenericDataStreamWriter.writeStructure(outputStream,node);
|
||||
GenericDataStreamWriter.writeStructure(outputStream, node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,15 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class XpbtReadConnection implements TableReadConnection {
|
||||
|
||||
private final StreamDataStore store;
|
||||
private TupleType dataType;
|
||||
private InputStream inputStream;
|
||||
private TypedDataStreamParser parser;
|
||||
private boolean empty;
|
||||
protected XpbtReadConnection(StreamDataStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
this.inputStream = store.openBufferedInput();
|
||||
@@ -36,8 +45,8 @@ public class XpbtReadConnection implements TableReadConnection {
|
||||
this.inputStream.skip(headerLength + 1);
|
||||
List<String> names = JacksonMapper.newMapper()
|
||||
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
|
||||
.readerFor(new TypeReference<List<String>>() {
|
||||
}).readValue(header);
|
||||
.readerFor(new TypeReference<List<String>>() {})
|
||||
.readValue(header);
|
||||
TupleType dataType = TupleType.tableType(names);
|
||||
this.dataType = dataType;
|
||||
this.parser = new TypedDataStreamParser(dataType);
|
||||
@@ -48,16 +57,6 @@ public class XpbtReadConnection implements TableReadConnection {
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
private TupleType dataType;
|
||||
private final StreamDataStore store;
|
||||
private InputStream inputStream;
|
||||
private TypedDataStreamParser parser;
|
||||
private boolean empty;
|
||||
|
||||
protected XpbtReadConnection(StreamDataStore store) {
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleType getDataType() {
|
||||
return dataType;
|
||||
|
||||
@@ -13,8 +13,6 @@ import lombok.extern.jackson.Jacksonized;
|
||||
@Jacksonized
|
||||
public class XpbtSource extends TableDataSource<StreamDataStore> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected TableWriteConnection newWriteConnection() {
|
||||
return new XpbtWriteConnection(store);
|
||||
|
||||
@@ -58,7 +58,8 @@ public class XpbtWriteConnection implements TableWriteConnection {
|
||||
try (JsonGenerator g = f.createGenerator(writer)
|
||||
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||
.setPrettyPrinter(new DefaultPrettyPrinter())) {
|
||||
JacksonMapper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||
JacksonMapper.newMapper()
|
||||
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||
.writeValue(g, tupleNode.getKeyNames());
|
||||
writer.append("\n");
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ public interface CollectionReadConnection extends DataSourceReadConnection {
|
||||
try (var tCon = (CollectionWriteConnection) con) {
|
||||
tCon.init();
|
||||
listEntries().forEach(s -> {
|
||||
// try (var subCon = open(s)) {
|
||||
// ((CollectionWriteConnection) con).write(s, subCon);
|
||||
// }
|
||||
// try (var subCon = open(s)) {
|
||||
// ((CollectionWriteConnection) con).write(s, subCon);
|
||||
// }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,22 +22,23 @@ import java.util.Optional;
|
||||
* This instance is only valid in combination with its associated data store instance.
|
||||
*/
|
||||
@SuperBuilder
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
property = "type"
|
||||
)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public abstract class DataSource<DS extends DataStore> extends JacksonizedValue {
|
||||
|
||||
protected DS store;
|
||||
|
||||
public static DataSource<?> createInternalDataSource(DataSourceType t, DataStore store) {
|
||||
try {
|
||||
return switch (t) {
|
||||
case TABLE -> XpbtSource.builder().store(store.asNeeded()).build();
|
||||
case TABLE -> XpbtSource.builder().store(store.asNeeded()).build();
|
||||
case STRUCTURE -> null;
|
||||
case TEXT -> TextSource.builder().store(store.asNeeded()).newLine(NewLine.LF).charset(
|
||||
StreamCharset.UTF8).build();
|
||||
case TEXT -> TextSource.builder()
|
||||
.store(store.asNeeded())
|
||||
.newLine(NewLine.LF)
|
||||
.charset(StreamCharset.UTF8)
|
||||
.build();
|
||||
case RAW -> null;
|
||||
//TODO
|
||||
// TODO
|
||||
case COLLECTION -> null;
|
||||
};
|
||||
} catch (Exception ex) {
|
||||
@@ -45,9 +46,6 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
|
||||
}
|
||||
}
|
||||
|
||||
protected DS store;
|
||||
|
||||
|
||||
public void test() throws Exception {
|
||||
store.validate();
|
||||
}
|
||||
@@ -68,7 +66,6 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
|
||||
return WriteMode.values();
|
||||
}
|
||||
|
||||
|
||||
public DataFlow getFlow() {
|
||||
if (store == null) {
|
||||
return null;
|
||||
|
||||
@@ -49,7 +49,8 @@ public class DataSourceId {
|
||||
throw new IllegalArgumentException("Trimmed collection name is empty");
|
||||
}
|
||||
if (collectionName != null && collectionName.contains("" + SEPARATOR)) {
|
||||
throw new IllegalArgumentException("Separator character " + SEPARATOR + " is not allowed in the collection name");
|
||||
throw new IllegalArgumentException(
|
||||
"Separator character " + SEPARATOR + " is not allowed in the collection name");
|
||||
}
|
||||
|
||||
if (entryName == null) {
|
||||
@@ -59,7 +60,8 @@ public class DataSourceId {
|
||||
throw new IllegalArgumentException("Trimmed entry name is empty");
|
||||
}
|
||||
if (entryName.contains("" + SEPARATOR)) {
|
||||
throw new IllegalArgumentException("Separator character " + SEPARATOR + " is not allowed in the entry name");
|
||||
throw new IllegalArgumentException(
|
||||
"Separator character " + SEPARATOR + " is not allowed in the entry name");
|
||||
}
|
||||
|
||||
return new DataSourceId(collectionName, entryName);
|
||||
|
||||
@@ -23,6 +23,61 @@ public abstract class DataSourceInfo {
|
||||
|
||||
public abstract DataSourceType getType();
|
||||
|
||||
/**
|
||||
* Casts this instance to a table info.
|
||||
*/
|
||||
public Table asTable() {
|
||||
if (!getType().equals(DataSourceType.TABLE)) {
|
||||
throw new IllegalStateException("Not a table");
|
||||
}
|
||||
|
||||
return (Table) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a structure info.
|
||||
*/
|
||||
public Structure asStructure() {
|
||||
if (!getType().equals(DataSourceType.STRUCTURE)) {
|
||||
throw new IllegalStateException("Not a structure");
|
||||
}
|
||||
|
||||
return (Structure) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a text info.
|
||||
*/
|
||||
public Text asText() {
|
||||
if (!getType().equals(DataSourceType.TEXT)) {
|
||||
throw new IllegalStateException("Not a text");
|
||||
}
|
||||
|
||||
return (Text) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a raw info.
|
||||
*/
|
||||
public Raw asRaw() {
|
||||
if (!getType().equals(DataSourceType.RAW)) {
|
||||
throw new IllegalStateException("Not raw");
|
||||
}
|
||||
|
||||
return (Raw) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a collection info.
|
||||
*/
|
||||
public Collection asCollection() {
|
||||
if (!getType().equals(DataSourceType.COLLECTION)) {
|
||||
throw new IllegalStateException("Not a collection");
|
||||
}
|
||||
|
||||
return (Collection) this;
|
||||
}
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Value
|
||||
@JsonTypeName("table")
|
||||
@@ -101,7 +156,6 @@ public abstract class DataSourceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Value
|
||||
@JsonTypeName("raw")
|
||||
@@ -118,59 +172,4 @@ public abstract class DataSourceInfo {
|
||||
return DataSourceType.RAW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a table info.
|
||||
*/
|
||||
public Table asTable() {
|
||||
if (!getType().equals(DataSourceType.TABLE)) {
|
||||
throw new IllegalStateException("Not a table");
|
||||
}
|
||||
|
||||
return (Table) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a structure info.
|
||||
*/
|
||||
public Structure asStructure() {
|
||||
if (!getType().equals(DataSourceType.STRUCTURE)) {
|
||||
throw new IllegalStateException("Not a structure");
|
||||
}
|
||||
|
||||
return (Structure) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a text info.
|
||||
*/
|
||||
public Text asText() {
|
||||
if (!getType().equals(DataSourceType.TEXT)) {
|
||||
throw new IllegalStateException("Not a text");
|
||||
}
|
||||
|
||||
return (Text) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a raw info.
|
||||
*/
|
||||
public Raw asRaw() {
|
||||
if (!getType().equals(DataSourceType.RAW)) {
|
||||
throw new IllegalStateException("Not raw");
|
||||
}
|
||||
|
||||
return (Raw) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts this instance to a collection info.
|
||||
*/
|
||||
public Collection asCollection() {
|
||||
if (!getType().equals(DataSourceType.COLLECTION)) {
|
||||
throw new IllegalStateException("Not a collection");
|
||||
}
|
||||
|
||||
return (Collection) this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,14 +65,10 @@ public interface DataSourceReference {
|
||||
return new Name(s.trim());
|
||||
}
|
||||
|
||||
enum Type {
|
||||
ID,
|
||||
NAME,
|
||||
LATEST
|
||||
}
|
||||
|
||||
Type getType();
|
||||
|
||||
DataSourceId getId();
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
@@ -82,6 +78,12 @@ public interface DataSourceReference {
|
||||
|
||||
String toString();
|
||||
|
||||
enum Type {
|
||||
ID,
|
||||
NAME,
|
||||
LATEST
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper class for {@link DataSourceId} instances.
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* This distinction is necessary as the general workflow differs for each type.
|
||||
*/
|
||||
public enum DataSourceType {
|
||||
|
||||
@JsonProperty("table")
|
||||
TABLE,
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import java.io.OutputStream;
|
||||
|
||||
public interface RawReadConnection extends DataSourceReadConnection {
|
||||
|
||||
byte[] readBytes(int max) throws Exception;
|
||||
|
||||
int BUFFER_SIZE = 8192;
|
||||
|
||||
byte[] readBytes(int max) throws Exception;
|
||||
|
||||
default void forwardBytes(OutputStream out, int maxBytes) throws Exception {
|
||||
if (maxBytes == 0) {
|
||||
return;
|
||||
|
||||
@@ -9,10 +9,10 @@ import java.io.Reader;
|
||||
|
||||
public abstract class StreamReadConnection implements DataSourceReadConnection {
|
||||
|
||||
protected final StreamDataStore store;
|
||||
private final StreamCharset charset;
|
||||
protected InputStream inputStream;
|
||||
protected Reader reader;
|
||||
private final StreamCharset charset;
|
||||
protected final StreamDataStore store;
|
||||
|
||||
public StreamReadConnection(StreamDataStore store, StreamCharset charset) {
|
||||
this.store = store;
|
||||
|
||||
@@ -9,8 +9,8 @@ import java.io.OutputStreamWriter;
|
||||
public class StreamWriteConnection implements DataSourceConnection {
|
||||
|
||||
protected final StreamDataStore store;
|
||||
protected OutputStream outputStream;
|
||||
private final StreamCharset charset;
|
||||
protected OutputStream outputStream;
|
||||
protected OutputStreamWriter writer;
|
||||
|
||||
public StreamWriteConnection(StreamDataStore store, StreamCharset charset) {
|
||||
@@ -27,8 +27,7 @@ public class StreamWriteConnection implements DataSourceConnection {
|
||||
outputStream = store.openOutput();
|
||||
if (charset != null) {
|
||||
if (charset.hasByteOrderMark()) {
|
||||
outputStream
|
||||
.write(charset.getByteOrderMark());
|
||||
outputStream.write(charset.getByteOrderMark());
|
||||
}
|
||||
writer = new OutputStreamWriter(outputStream, charset.getCharset());
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package io.xpipe.core.source;
|
||||
|
||||
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.data.typed.TypedDataStreamWriter;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.xpipe.core.source;
|
||||
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.ArrayNode;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,6 @@ public abstract class TextDataSource<DS extends DataStore> extends DataSource<DS
|
||||
return con;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final TextWriteConnection openPrependingWriteConnection() throws Exception {
|
||||
var con = newPrependingWriteConnection();
|
||||
@@ -64,13 +63,9 @@ public abstract class TextDataSource<DS extends DataStore> extends DataSource<DS
|
||||
return new PreservingTextWriteConnection(this, newWriteConnection(), true);
|
||||
}
|
||||
|
||||
|
||||
protected TextWriteConnection newPrependingWriteConnection() {
|
||||
return new PreservingTextWriteConnection(this, newWriteConnection(), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected abstract TextReadConnection newReadConnection();
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ public interface TextReadConnection extends DataSourceReadConnection {
|
||||
|
||||
default void forward(DataSourceConnection con) throws Exception {
|
||||
var tCon = (TextWriteConnection) con;
|
||||
for (var it = lines().iterator(); it.hasNext(); ) {
|
||||
tCon.writeLine(it.next());
|
||||
}
|
||||
for (var it = lines().iterator(); it.hasNext(); ) {
|
||||
tCon.writeLine(it.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,6 @@ public enum WriteMode {
|
||||
@JsonProperty("prepend")
|
||||
PREPEND(DataSource::openPrependingWriteConnection);
|
||||
|
||||
public static interface FailableFunction<T, R, E extends Throwable> {
|
||||
R apply(T input) throws E;
|
||||
|
||||
}
|
||||
|
||||
private final FailableFunction<DataSource<?>, DataSourceConnection, Exception> connectionOpener;
|
||||
|
||||
WriteMode(FailableFunction<DataSource<?>, DataSourceConnection, Exception> connectionOpener) {
|
||||
@@ -24,4 +19,8 @@ public enum WriteMode {
|
||||
public DataSourceConnection open(DataSource<?> source) throws Exception {
|
||||
return connectionOpener.apply(source);
|
||||
}
|
||||
|
||||
public static interface FailableFunction<T, R, E extends Throwable> {
|
||||
R apply(T input) throws E;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ public abstract class CollectionEntryDataStore implements FilenameStore, StreamD
|
||||
private final String name;
|
||||
private final DataStore collectionStore;
|
||||
|
||||
|
||||
public CollectionEntryDataStore(boolean directory, String name, DataStore collectionStore) {
|
||||
this.directory = directory;
|
||||
this.name = name;
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.xpipe.core.store;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public enum DataFlow {
|
||||
|
||||
@JsonProperty("input")
|
||||
INPUT,
|
||||
@JsonProperty("output")
|
||||
|
||||
@@ -28,7 +28,6 @@ public interface DataStore {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether this data store can only be accessed by the current running application.
|
||||
* One example are standard in and standard out stores.
|
||||
@@ -56,17 +55,14 @@ public interface DataStore {
|
||||
*
|
||||
* @throws Exception if any part of the validation went wrong
|
||||
*/
|
||||
default void validate() throws Exception {
|
||||
}
|
||||
default void validate() throws Exception {}
|
||||
|
||||
default void checkComplete() throws Exception {
|
||||
}
|
||||
default void checkComplete() throws Exception {}
|
||||
|
||||
default boolean delete() throws Exception {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Casts this instance to the required type without checking whether a cast is possible.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,6 @@ public class DataStoreFormatter {
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
public static String specialFormatHostName(String input) {
|
||||
if (input.contains(":")) {
|
||||
input = input.split(":")[0];
|
||||
|
||||
@@ -19,6 +19,14 @@ import java.nio.file.Path;
|
||||
@Getter
|
||||
public class FileStore extends JacksonizedValue implements FilenameStore, StreamDataStore {
|
||||
|
||||
MachineFileStore machine;
|
||||
String file;
|
||||
|
||||
public FileStore(MachineFileStore machine, String file) {
|
||||
this.machine = machine;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public static FileStore local(Path p) {
|
||||
return new FileStore(new LocalStore(), p.toString());
|
||||
}
|
||||
@@ -30,14 +38,6 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream
|
||||
return new FileStore(new LocalStore(), p);
|
||||
}
|
||||
|
||||
MachineFileStore machine;
|
||||
String file;
|
||||
|
||||
public FileStore(MachineFileStore machine, String file) {
|
||||
this.machine = machine;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Exception {
|
||||
if (machine == null) {
|
||||
@@ -46,7 +46,6 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream
|
||||
if (file == null) {
|
||||
throw new IllegalStateException("File is missing");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,5 +71,4 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream
|
||||
}
|
||||
return split[split.length - 1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ public interface FilenameStore extends DataStore {
|
||||
return Optional.of(i != -1 ? n.substring(0, i) : n);
|
||||
}
|
||||
|
||||
|
||||
default String getFileExtension() {
|
||||
default String getFileExtension() {
|
||||
var split = getFileName().split("[\\\\.]");
|
||||
if (split.length == 0) {
|
||||
return "";
|
||||
|
||||
@@ -20,7 +20,6 @@ public class InMemoryStore extends JacksonizedValue implements StreamDataStore {
|
||||
|
||||
private byte[] value;
|
||||
|
||||
|
||||
@JsonCreator
|
||||
public InMemoryStore(byte[] value) {
|
||||
this.value = value;
|
||||
@@ -38,7 +37,7 @@ public class InMemoryStore extends JacksonizedValue implements StreamDataStore {
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput() throws Exception {
|
||||
return new ByteArrayOutputStream(){
|
||||
return new ByteArrayOutputStream() {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
|
||||
@@ -39,5 +39,4 @@ public class LocalDirectoryDataStore implements DataStore {
|
||||
public Path getPath() {
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,51 @@ public class LocalStore extends JacksonizedValue implements MachineFileStore, St
|
||||
return true;
|
||||
}
|
||||
|
||||
class LocalProcessControl extends ProcessControl {
|
||||
@Override
|
||||
public boolean exists(String file) {
|
||||
return Files.exists(Path.of(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mkdirs(String file) throws Exception {
|
||||
Files.createDirectories(Path.of(file).getParent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewLine getNewLine() {
|
||||
return ShellTypes.getDefault().getNewLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInput(String file) throws Exception {
|
||||
var p = Path.of(file);
|
||||
return Files.newInputStream(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput(String file) throws Exception {
|
||||
mkdirs(file);
|
||||
var p = Path.of(file);
|
||||
return Files.newOutputStream(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl prepareCommand(List<SecretValue> input, List<String> cmd, Integer timeout) {
|
||||
return new LocalProcessControl(input, cmd, getEffectiveTimeOut(timeout));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl preparePrivilegedCommand(List<SecretValue> input, List<String> cmd, Integer timeOut)
|
||||
throws Exception {
|
||||
return new LocalProcessControl(input, cmd, getEffectiveTimeOut(timeOut));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellType determineType() throws Exception {
|
||||
return ShellTypes.getDefault();
|
||||
}
|
||||
|
||||
class LocalProcessControl extends ProcessControl {
|
||||
|
||||
private final List<SecretValue> input;
|
||||
private final Integer timeout;
|
||||
@@ -38,7 +82,8 @@ public class LocalStore extends JacksonizedValue implements MachineFileStore, St
|
||||
}
|
||||
|
||||
private InputStream createInputStream() {
|
||||
var string = input.stream().map(secret -> secret.getSecretValue()).collect(Collectors.joining("\n")) + "\r\n";
|
||||
var string =
|
||||
input.stream().map(secret -> secret.getSecretValue()).collect(Collectors.joining("\n")) + "\r\n";
|
||||
return new ByteArrayInputStream(string.getBytes(StandardCharsets.US_ASCII));
|
||||
}
|
||||
|
||||
@@ -51,7 +96,7 @@ public class LocalStore extends JacksonizedValue implements MachineFileStore, St
|
||||
charset = type.determineCharset(LocalStore.this);
|
||||
|
||||
var t = new Thread(() -> {
|
||||
try (var inputStream = createInputStream()){
|
||||
try (var inputStream = createInputStream()) {
|
||||
process.getOutputStream().flush();
|
||||
inputStream.transferTo(process.getOutputStream());
|
||||
process.getOutputStream().close();
|
||||
@@ -77,12 +122,12 @@ public class LocalStore extends JacksonizedValue implements MachineFileStore, St
|
||||
return process.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getStdin() {
|
||||
return process.getOutputStream();
|
||||
}
|
||||
@Override
|
||||
public OutputStream getStdin() {
|
||||
return process.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public InputStream getStderr() {
|
||||
return process.getErrorStream();
|
||||
}
|
||||
@@ -96,48 +141,4 @@ public class LocalStore extends JacksonizedValue implements MachineFileStore, St
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String file) {
|
||||
return Files.exists(Path.of(file));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mkdirs(String file) throws Exception {
|
||||
Files.createDirectories(Path.of(file).getParent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewLine getNewLine() {
|
||||
return ShellTypes.getDefault().getNewLine();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InputStream openInput(String file) throws Exception {
|
||||
var p = Path.of(file);
|
||||
return Files.newInputStream(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput(String file) throws Exception {
|
||||
mkdirs(file);
|
||||
var p = Path.of(file);
|
||||
return Files.newOutputStream(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl prepareCommand(List<SecretValue> input, List<String> cmd, Integer timeout) {
|
||||
return new LocalProcessControl(input, cmd, getEffectiveTimeOut(timeout));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl preparePrivilegedCommand(List<SecretValue> input, List<String> cmd, Integer timeOut) throws Exception {
|
||||
return new LocalProcessControl(input, cmd, getEffectiveTimeOut(timeOut));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellType determineType() throws Exception {
|
||||
return ShellTypes.getDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public abstract class ProcessControl {
|
||||
public abstract int waitFor() throws Exception;
|
||||
|
||||
public abstract InputStream getStdout();
|
||||
|
||||
public abstract OutputStream getStdin();
|
||||
|
||||
public abstract InputStream getStderr();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.xpipe.core.store;
|
||||
|
||||
public class ProcessOutputException extends Exception{
|
||||
public class ProcessOutputException extends Exception {
|
||||
public ProcessOutputException() {
|
||||
super();
|
||||
}
|
||||
@@ -17,7 +17,8 @@ public class ProcessOutputException extends Exception{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected ProcessOutputException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
protected ProcessOutputException(
|
||||
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ public interface ShellStore extends DataStore {
|
||||
if (ec == 0 && !(read.get().isEmpty() && !readError.get().isEmpty())) {
|
||||
return read.get().trim();
|
||||
} else {
|
||||
throw new ProcessOutputException("Command returned with " + ec + ": " + readError.get().trim());
|
||||
throw new ProcessOutputException(
|
||||
"Command returned with " + ec + ": " + readError.get().trim());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,17 @@ import java.util.List;
|
||||
|
||||
public class ShellTypes {
|
||||
|
||||
public static final StandardShellStore.ShellType POWERSHELL = new PowerShell();
|
||||
public static final StandardShellStore.ShellType CMD = new Cmd();
|
||||
public static final StandardShellStore.ShellType SH = new Sh();
|
||||
|
||||
public static StandardShellStore.ShellType determine(ShellStore store) throws Exception {
|
||||
var o = store.executeAndCheckOut(List.of(), List.of("echo", "$0"), null).strip();
|
||||
if (!o.equals("$0")) {
|
||||
return SH;
|
||||
} else {
|
||||
o = store.executeAndCheckOut(List.of(), List.of("(dir 2>&1 *`|echo CMD);&<# rem #>echo PowerShell"), null).trim();
|
||||
o = store.executeAndCheckOut(List.of(), List.of("(dir 2>&1 *`|echo CMD);&<# rem #>echo PowerShell"), null)
|
||||
.trim();
|
||||
if (o.equals("PowerShell")) {
|
||||
return POWERSHELL;
|
||||
} else {
|
||||
@@ -36,13 +41,6 @@ public class ShellTypes {
|
||||
}
|
||||
}
|
||||
|
||||
public static final StandardShellStore.ShellType POWERSHELL = new PowerShell();
|
||||
|
||||
|
||||
public static final StandardShellStore.ShellType CMD = new Cmd();
|
||||
|
||||
public static final StandardShellStore.ShellType SH = new Sh();
|
||||
|
||||
public static StandardShellStore.ShellType getDefault() {
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
return CMD;
|
||||
@@ -51,16 +49,12 @@ public class ShellTypes {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static StandardShellStore.ShellType[] getWindowsShells() {
|
||||
return new StandardShellStore.ShellType[]{
|
||||
CMD,
|
||||
POWERSHELL
|
||||
};
|
||||
return new StandardShellStore.ShellType[] {CMD, POWERSHELL};
|
||||
}
|
||||
|
||||
public static StandardShellStore.ShellType[] getLinuxShells() {
|
||||
return new StandardShellStore.ShellType[]{SH};
|
||||
return new StandardShellStore.ShellType[] {SH};
|
||||
}
|
||||
|
||||
@JsonTypeName("cmd")
|
||||
@@ -85,7 +79,8 @@ public class ShellTypes {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl prepareElevatedCommand(ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
public ProcessControl prepareElevatedCommand(
|
||||
ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
var l = List.of("net", "session", ";", "if", "%errorLevel%", "!=", "0");
|
||||
return st.prepareCommand(List.of(), l, timeout);
|
||||
}
|
||||
@@ -188,7 +183,8 @@ public class ShellTypes {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessControl prepareElevatedCommand(ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
public ProcessControl prepareElevatedCommand(
|
||||
ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
var l = new ArrayList<>(cmd);
|
||||
l.add(0, "sudo");
|
||||
l.add(1, "-S");
|
||||
|
||||
@@ -15,12 +15,55 @@ public interface StandardShellStore extends MachineFileStore, ShellStore {
|
||||
return false;
|
||||
}
|
||||
|
||||
public default NewLine getNewLine() throws Exception {
|
||||
return determineType().getNewLine();
|
||||
}
|
||||
|
||||
public abstract ShellType determineType() throws Exception;
|
||||
|
||||
public default String querySystemName() throws Exception {
|
||||
var result = executeAndCheckOut(List.of(), determineType().getOperatingSystemNameCommand(), getTimeout());
|
||||
return result.strip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public default InputStream openInput(String file) throws Exception {
|
||||
var type = determineType();
|
||||
var cmd = type.createFileReadCommand(file);
|
||||
var p = prepareCommand(List.of(), cmd, null);
|
||||
p.start();
|
||||
return p.getStdout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public default OutputStream openOutput(String file) throws Exception {
|
||||
return null;
|
||||
// var type = determineType();
|
||||
// var cmd = type.createFileWriteCommand(file);
|
||||
// var p = prepare(cmd).redirectErrorStream(true);
|
||||
// var proc = p.start();
|
||||
// return proc.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public default boolean exists(String file) throws Exception {
|
||||
var type = determineType();
|
||||
var cmd = type.createFileExistsCommand(file);
|
||||
var p = prepareCommand(List.of(), cmd, null);
|
||||
p.start();
|
||||
return p.waitFor() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public default void mkdirs(String file) throws Exception {}
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public static interface ShellType {
|
||||
|
||||
List<String> switchTo(List<String> cmd);
|
||||
|
||||
default ProcessControl prepareElevatedCommand(ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
default ProcessControl prepareElevatedCommand(
|
||||
ShellStore st, List<SecretValue> in, List<String> cmd, Integer timeout, String pw) throws Exception {
|
||||
return st.prepareCommand(in, cmd, timeout);
|
||||
}
|
||||
|
||||
@@ -40,50 +83,4 @@ public interface StandardShellStore extends MachineFileStore, ShellStore {
|
||||
|
||||
List<String> getOperatingSystemNameCommand();
|
||||
}
|
||||
|
||||
|
||||
public default NewLine getNewLine() throws Exception {
|
||||
return determineType().getNewLine();
|
||||
}
|
||||
|
||||
public abstract ShellType determineType() throws Exception;
|
||||
|
||||
public default String querySystemName() throws Exception {
|
||||
var result = executeAndCheckOut(List.of(), determineType().getOperatingSystemNameCommand(), getTimeout());
|
||||
return result.strip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public default InputStream openInput(String file) throws Exception {
|
||||
var type = determineType();
|
||||
var cmd = type.createFileReadCommand(file);
|
||||
var p = prepareCommand(List.of(), cmd, null);
|
||||
p.start();
|
||||
return p.getStdout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public default OutputStream openOutput(String file) throws Exception {
|
||||
return null;
|
||||
// var type = determineType();
|
||||
// var cmd = type.createFileWriteCommand(file);
|
||||
// var p = prepare(cmd).redirectErrorStream(true);
|
||||
// var proc = p.start();
|
||||
// return proc.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public default boolean exists(String file) throws Exception {
|
||||
var type = determineType();
|
||||
var cmd = type.createFileExistsCommand(file);
|
||||
var p = prepareCommand(List.of(), cmd, null);
|
||||
p.start();
|
||||
return p.waitFor() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public default void mkdirs(String file) throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,7 @@ public class StdinDataStore extends JacksonizedValue implements StreamDataStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
public void close() throws IOException {}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
|
||||
@@ -48,8 +48,7 @@ public class StdoutDataStore extends JacksonizedValue implements StreamDataStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
public void close() throws IOException {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.io.OutputStream;
|
||||
*/
|
||||
public interface StreamDataStore extends DataStore {
|
||||
|
||||
|
||||
/**
|
||||
* Opens an input stream that can be used to read its data.
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,6 @@ import lombok.extern.jackson.Jacksonized;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
@JsonTypeName("url")
|
||||
@SuperBuilder
|
||||
@Jacksonized
|
||||
|
||||
@@ -38,7 +38,6 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
context.registerSubtypes(
|
||||
new NamedType(TextSource.class),
|
||||
new NamedType(XpbtSource.class),
|
||||
|
||||
new NamedType(FileStore.class),
|
||||
new NamedType(StdinDataStore.class),
|
||||
new NamedType(StdoutDataStore.class),
|
||||
@@ -47,27 +46,22 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
new NamedType(InMemoryStore.class),
|
||||
new NamedType(LocalStore.class),
|
||||
new NamedType(NamedStore.class),
|
||||
|
||||
new NamedType(ValueType.class),
|
||||
new NamedType(TupleType.class),
|
||||
new NamedType(ArrayType.class),
|
||||
new NamedType(WildcardType.class),
|
||||
|
||||
new NamedType(ShellTypes.Cmd.class),
|
||||
new NamedType(ShellTypes.PowerShell.class),
|
||||
new NamedType(ShellTypes.Sh.class),
|
||||
|
||||
new NamedType(DataSourceInfo.Table.class),
|
||||
new NamedType(DataSourceInfo.Structure.class),
|
||||
new NamedType(DataSourceInfo.Text.class),
|
||||
new NamedType(DataSourceInfo.Collection.class),
|
||||
new NamedType(DataSourceInfo.Raw.class),
|
||||
|
||||
new NamedType(BaseQueryElement.class),
|
||||
new NamedType(ChoiceElement.class),
|
||||
new NamedType(BusyElement.class),
|
||||
new NamedType(HeaderElement.class)
|
||||
);
|
||||
new NamedType(HeaderElement.class));
|
||||
|
||||
addSerializer(Charset.class, new CharsetSerializer());
|
||||
addDeserializer(Charset.class, new CharsetDeserializer());
|
||||
@@ -98,12 +92,6 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
}
|
||||
}
|
||||
|
||||
public class NullSerializer extends JsonSerializer<Object> {
|
||||
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
|
||||
jgen.writeNull();
|
||||
}
|
||||
}
|
||||
|
||||
public static class NullDeserializer extends JsonDeserializer<DataSource> {
|
||||
|
||||
@Override
|
||||
@@ -112,7 +100,6 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class DataSourceReferenceSerializer extends JsonSerializer<DataSourceReference> {
|
||||
|
||||
@Override
|
||||
@@ -133,8 +120,7 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
public static class CharsetSerializer extends JsonSerializer<Charset> {
|
||||
|
||||
@Override
|
||||
public void serialize(Charset value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
public void serialize(Charset value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(value.name());
|
||||
}
|
||||
}
|
||||
@@ -150,8 +136,7 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
public static class LocalPathSerializer extends JsonSerializer<Path> {
|
||||
|
||||
@Override
|
||||
public void serialize(Path value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
public void serialize(Path value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(value.toString());
|
||||
}
|
||||
}
|
||||
@@ -167,8 +152,7 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
public static class SecretSerializer extends JsonSerializer<SecretValue> {
|
||||
|
||||
@Override
|
||||
public void serialize(SecretValue value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
public void serialize(SecretValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(value.getEncryptedValue());
|
||||
}
|
||||
}
|
||||
@@ -184,11 +168,17 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
@JsonSerialize(as = Throwable.class)
|
||||
public abstract static class ThrowableTypeMixIn {
|
||||
|
||||
@JsonIdentityInfo(generator= ObjectIdGenerators.StringIdGenerator.class, property="$id")
|
||||
@JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class, property = "$id")
|
||||
private Throwable cause;
|
||||
}
|
||||
|
||||
@JsonSerialize(as = DataSourceReference.class)
|
||||
public abstract static class DataSourceReferenceTypeMixIn {
|
||||
public abstract static class DataSourceReferenceTypeMixIn {}
|
||||
|
||||
public class NullSerializer extends JsonSerializer<Object> {
|
||||
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException, JsonProcessingException {
|
||||
jgen.writeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import java.util.function.Consumer;
|
||||
public class JacksonMapper {
|
||||
|
||||
private static final ObjectMapper BASE = new ObjectMapper();
|
||||
private static ObjectMapper INSTANCE = new ObjectMapper();
|
||||
private static final ObjectMapper DEFAULT;
|
||||
private static ObjectMapper INSTANCE = new ObjectMapper();
|
||||
private static boolean init = false;
|
||||
|
||||
static {
|
||||
@@ -24,12 +24,14 @@ public class JacksonMapper {
|
||||
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
|
||||
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
|
||||
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
|
||||
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
|
||||
objectMapper.setVisibility(objectMapper
|
||||
.getSerializationConfig()
|
||||
.getDefaultVisibilityChecker()
|
||||
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
|
||||
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
|
||||
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
|
||||
|
||||
var modules = findModules(ModuleLayer.boot());
|
||||
objectMapper.registerModules(modules);
|
||||
@@ -54,8 +56,8 @@ public class JacksonMapper {
|
||||
|
||||
private static List<Module> findModules(ModuleLayer layer) {
|
||||
ArrayList<Module> modules = new ArrayList<Module>();
|
||||
ServiceLoader<Module> loader = layer != null ?
|
||||
ServiceLoader.load(layer, Module.class) : ServiceLoader.load(Module.class);
|
||||
ServiceLoader<Module> loader =
|
||||
layer != null ? ServiceLoader.load(layer, Module.class) : ServiceLoader.load(Module.class);
|
||||
for (Module module : loader) {
|
||||
modules.add(module);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ import lombok.experimental.SuperBuilder;
|
||||
@SuperBuilder
|
||||
public class JacksonizedValue {
|
||||
|
||||
public JacksonizedValue() {
|
||||
}
|
||||
public JacksonizedValue() {}
|
||||
|
||||
@SneakyThrows
|
||||
public final String toString() {
|
||||
@@ -34,5 +33,4 @@ public class JacksonizedValue {
|
||||
var tree = JacksonMapper.newMapper().valueToTree(this);
|
||||
return tree.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import java.util.Base64;
|
||||
@EqualsAndHashCode
|
||||
public class SecretValue {
|
||||
|
||||
String value;
|
||||
|
||||
public static SecretValue createForSecretValue(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
@@ -22,8 +24,6 @@ public class SecretValue {
|
||||
return new SecretValue(Base64.getEncoder().encodeToString(s.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
String value;
|
||||
|
||||
public String getDisplay() {
|
||||
return "*".repeat(value.length());
|
||||
}
|
||||
|
||||
@@ -20,5 +20,7 @@ open module io.xpipe.core {
|
||||
requires static lombok;
|
||||
|
||||
uses com.fasterxml.jackson.databind.Module;
|
||||
provides com.fasterxml.jackson.databind.Module with CoreJacksonModule;
|
||||
}
|
||||
|
||||
provides com.fasterxml.jackson.databind.Module with
|
||||
CoreJacksonModule;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user