mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 23:20:23 +00:00
Refactor
This commit is contained in:
parent
27843ae0fd
commit
55da767dab
186 changed files with 1541 additions and 1606 deletions
|
@ -27,10 +27,6 @@ import java.nio.file.Path;
|
|||
*/
|
||||
public interface DataSource {
|
||||
|
||||
void forwardTo(DataSource target);
|
||||
|
||||
void appendTo(DataSource target);
|
||||
|
||||
/**
|
||||
* NOT YET IMPLEMENTED!
|
||||
*
|
||||
|
@ -126,7 +122,6 @@ public interface DataSource {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for {@link #create(DataSourceId, String, InputStream)} that creates an anonymous data source.
|
||||
*/
|
||||
|
@ -168,6 +163,10 @@ public interface DataSource {
|
|||
return DataSourceImpl.create(id, type, in);
|
||||
}
|
||||
|
||||
void forwardTo(DataSource target);
|
||||
|
||||
void appendTo(DataSource target);
|
||||
|
||||
public io.xpipe.core.source.DataSource<?> getInternalSource();
|
||||
|
||||
/**
|
||||
|
@ -180,7 +179,6 @@ public interface DataSource {
|
|||
*/
|
||||
DataSourceType getType();
|
||||
|
||||
|
||||
DataSourceConfig getConfig();
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,9 @@ public class DataStores {
|
|||
public static void addNamedStore(DataStore store, String name) {
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = StoreAddExchange.Request.builder()
|
||||
.storeInput(store).name(name).build();
|
||||
.storeInput(store)
|
||||
.name(name)
|
||||
.build();
|
||||
StoreAddExchange.Response res = con.performSimpleExchange(req);
|
||||
|
||||
new QuietDialogHandler(res.getConfig(), con, Map.of()).handle();
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.util.Optional;
|
|||
|
||||
public final class XPipeConnection extends BeaconConnection {
|
||||
|
||||
private XPipeConnection() {}
|
||||
|
||||
public static XPipeConnection open() {
|
||||
var con = new XPipeConnection();
|
||||
con.constructSocket();
|
||||
|
@ -23,7 +25,9 @@ public final class XPipeConnection extends BeaconConnection {
|
|||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder().dialogKey(reference.getDialogId()).build());
|
||||
DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder()
|
||||
.dialogKey(reference.getDialogId())
|
||||
.build());
|
||||
element = response.getElement();
|
||||
if (response.getElement() == null) {
|
||||
break;
|
||||
|
@ -58,40 +62,6 @@ public final class XPipeConnection extends BeaconConnection {
|
|||
}
|
||||
}
|
||||
|
||||
private XPipeConnection() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void constructSocket() {
|
||||
if (!BeaconServer.isRunning()) {
|
||||
try {
|
||||
start();
|
||||
} catch (Exception ex) {
|
||||
throw new BeaconException("Unable to start xpipe daemon", ex);
|
||||
}
|
||||
|
||||
var r = waitForStartup(null);
|
||||
if (r.isEmpty()) {
|
||||
throw new BeaconException("Wait for xpipe daemon timed out");
|
||||
} else {
|
||||
beaconClient = r.get();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
beaconClient = new BeaconClient();
|
||||
} catch (Exception ex) {
|
||||
throw new BeaconException("Unable to connect to running xpipe daemon", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void start() throws Exception {
|
||||
if (BeaconServer.tryStart() == null) {
|
||||
throw new UnsupportedOperationException("Unable to determine xpipe daemon launch command");
|
||||
};
|
||||
}
|
||||
|
||||
public static Optional<BeaconClient> waitForStartup(Process process) {
|
||||
for (int i = 0; i < 160; i++) {
|
||||
if (process != null && !process.isAlive()) {
|
||||
|
@ -125,6 +95,38 @@ public final class XPipeConnection extends BeaconConnection {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void constructSocket() {
|
||||
if (!BeaconServer.isRunning()) {
|
||||
try {
|
||||
start();
|
||||
} catch (Exception ex) {
|
||||
throw new BeaconException("Unable to start xpipe daemon", ex);
|
||||
}
|
||||
|
||||
var r = waitForStartup(null);
|
||||
if (r.isEmpty()) {
|
||||
throw new BeaconException("Wait for xpipe daemon timed out");
|
||||
} else {
|
||||
beaconClient = r.get();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
beaconClient = new BeaconClient();
|
||||
} catch (Exception ex) {
|
||||
throw new BeaconException("Unable to connect to running xpipe daemon", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void start() throws Exception {
|
||||
if (BeaconServer.tryStart() == null) {
|
||||
throw new UnsupportedOperationException("Unable to determine xpipe daemon launch command");
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface Handler {
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@ package io.xpipe.api.impl;
|
|||
|
||||
import io.xpipe.api.DataRaw;
|
||||
import io.xpipe.api.DataSourceConfig;
|
||||
import io.xpipe.core.source.*;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceInfo;
|
||||
import io.xpipe.core.source.DataSourceType;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
|
@ -10,7 +12,11 @@ public class DataRawImpl extends DataSourceImpl implements DataRaw {
|
|||
|
||||
private final DataSourceInfo.Raw info;
|
||||
|
||||
public DataRawImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Raw info, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
public DataRawImpl(
|
||||
DataSourceId sourceId,
|
||||
DataSourceConfig sourceConfig,
|
||||
DataSourceInfo.Raw info,
|
||||
io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
super(sourceId, sourceConfig, internalSource);
|
||||
this.info = info;
|
||||
}
|
||||
|
|
|
@ -13,28 +13,15 @@ import java.io.InputStream;
|
|||
|
||||
public abstract class DataSourceImpl implements DataSource {
|
||||
|
||||
@Override
|
||||
public void forwardTo(DataSource target) {
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = ForwardExchange.Request.builder()
|
||||
.source(DataSourceReference.id(sourceId))
|
||||
.target(DataSourceReference.id(target.getId()))
|
||||
.build();
|
||||
ForwardExchange.Response res = con.performSimpleExchange(req);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(DataSource target) {
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = ForwardExchange.Request.builder()
|
||||
.source(DataSourceReference.id(sourceId))
|
||||
.target(DataSourceReference.id(target.getId()))
|
||||
.append(true)
|
||||
.build();
|
||||
ForwardExchange.Response res = con.performSimpleExchange(req);
|
||||
});
|
||||
private final DataSourceId sourceId;
|
||||
private final DataSourceConfig config;
|
||||
private final io.xpipe.core.source.DataSource<?> internalSource;
|
||||
|
||||
public DataSourceImpl(
|
||||
DataSourceId sourceId, DataSourceConfig config, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
this.sourceId = sourceId;
|
||||
this.config = config;
|
||||
this.internalSource = internalSource;
|
||||
}
|
||||
|
||||
public static DataSource get(DataSourceReference ds) {
|
||||
|
@ -59,17 +46,17 @@ public abstract class DataSourceImpl implements DataSource {
|
|||
var info = res.getInfo().asRaw();
|
||||
yield new DataRawImpl(res.getId(), config, info, res.getInternalSource());
|
||||
}
|
||||
case COLLECTION -> throw new UnsupportedOperationException("Unimplemented case: " + res.getInfo().getType());
|
||||
default -> throw new IllegalArgumentException("Unexpected value: " + res.getInfo().getType());
|
||||
case COLLECTION -> throw new UnsupportedOperationException(
|
||||
"Unimplemented case: " + res.getInfo().getType());
|
||||
default -> throw new IllegalArgumentException(
|
||||
"Unexpected value: " + res.getInfo().getType());
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static DataSource create(DataSourceId id, io.xpipe.core.source.DataSource<?> source) {
|
||||
var startReq = AddSourceExchange.Request.builder()
|
||||
.source(source)
|
||||
.target(id)
|
||||
.build();
|
||||
var startReq =
|
||||
AddSourceExchange.Request.builder().source(source).target(id).build();
|
||||
var returnedId = XPipeConnection.execute(con -> {
|
||||
AddSourceExchange.Response r = con.performSimpleExchange(startReq);
|
||||
return r.getId();
|
||||
|
@ -108,9 +95,7 @@ public abstract class DataSourceImpl implements DataSource {
|
|||
var configInstance = startRes.getConfig();
|
||||
XPipeConnection.finishDialog(configInstance);
|
||||
|
||||
var ref = id != null ?
|
||||
DataSourceReference.id(id) :
|
||||
DataSourceReference.latest();
|
||||
var ref = id != null ? DataSourceReference.id(id) : DataSourceReference.latest();
|
||||
return get(ref);
|
||||
}
|
||||
|
||||
|
@ -137,20 +122,31 @@ public abstract class DataSourceImpl implements DataSource {
|
|||
var configInstance = startRes.getConfig();
|
||||
XPipeConnection.finishDialog(configInstance);
|
||||
|
||||
var ref = id != null ?
|
||||
DataSourceReference.id(id) :
|
||||
DataSourceReference.latest();
|
||||
var ref = id != null ? DataSourceReference.id(id) : DataSourceReference.latest();
|
||||
return get(ref);
|
||||
}
|
||||
|
||||
private final DataSourceId sourceId;
|
||||
private final DataSourceConfig config;
|
||||
private final io.xpipe.core.source.DataSource<?> internalSource;
|
||||
@Override
|
||||
public void forwardTo(DataSource target) {
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = ForwardExchange.Request.builder()
|
||||
.source(DataSourceReference.id(sourceId))
|
||||
.target(DataSourceReference.id(target.getId()))
|
||||
.build();
|
||||
ForwardExchange.Response res = con.performSimpleExchange(req);
|
||||
});
|
||||
}
|
||||
|
||||
public DataSourceImpl(DataSourceId sourceId, DataSourceConfig config, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
this.sourceId = sourceId;
|
||||
this.config = config;
|
||||
this.internalSource = internalSource;
|
||||
@Override
|
||||
public void appendTo(DataSource target) {
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = ForwardExchange.Request.builder()
|
||||
.source(DataSourceReference.id(sourceId))
|
||||
.target(DataSourceReference.id(target.getId()))
|
||||
.append(true)
|
||||
.build();
|
||||
ForwardExchange.Response res = con.performSimpleExchange(req);
|
||||
});
|
||||
}
|
||||
|
||||
public io.xpipe.core.source.DataSource<?> getInternalSource() {
|
||||
|
|
|
@ -3,13 +3,19 @@ package io.xpipe.api.impl;
|
|||
import io.xpipe.api.DataSourceConfig;
|
||||
import io.xpipe.api.DataStructure;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.source.*;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceInfo;
|
||||
import io.xpipe.core.source.DataSourceType;
|
||||
|
||||
public class DataStructureImpl extends DataSourceImpl implements DataStructure {
|
||||
|
||||
private final DataSourceInfo.Structure info;
|
||||
|
||||
public DataStructureImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Structure info, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
public DataStructureImpl(
|
||||
DataSourceId sourceId,
|
||||
DataSourceConfig sourceConfig,
|
||||
DataSourceInfo.Structure info,
|
||||
io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
super(sourceId, sourceConfig, internalSource);
|
||||
this.info = info;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,11 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
|
|||
connection.close();
|
||||
|
||||
var req = ReadExchange.Request.builder()
|
||||
.target(id).store(res.getStore()).provider("xpbt").configureAll(false).build();
|
||||
.target(id)
|
||||
.store(res.getStore())
|
||||
.provider("xpbt")
|
||||
.configureAll(false)
|
||||
.build();
|
||||
ReadExchange.Response response = XPipeConnection.execute(con -> {
|
||||
return con.performSimpleExchange(req);
|
||||
});
|
||||
|
@ -71,7 +75,9 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
|
|||
|
||||
@Override
|
||||
public synchronized void add(DataStructureNode row) {
|
||||
TupleNode toUse = type.matches(row) ? row.asTuple() : type.convert(row).orElseThrow().asTuple();
|
||||
TupleNode toUse = type.matches(row)
|
||||
? row.asTuple()
|
||||
: type.convert(row).orElseThrow().asTuple();
|
||||
connection.withOutputStream(out -> {
|
||||
writeDescriptor();
|
||||
TypedDataStreamWriter.writeStructure(out, toUse, writtenDescriptor);
|
||||
|
|
|
@ -27,7 +27,11 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
|
||||
private final DataSourceInfo.Table info;
|
||||
|
||||
DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, DataSourceInfo.Table info, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
DataTableImpl(
|
||||
DataSourceId id,
|
||||
DataSourceConfig sourceConfig,
|
||||
DataSourceInfo.Table info,
|
||||
io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
super(id, sourceConfig, internalSource);
|
||||
this.info = info;
|
||||
}
|
||||
|
@ -44,8 +48,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
|
||||
public Stream<TupleNode> stream() {
|
||||
var iterator = new TableIterator();
|
||||
return StreamSupport.stream(
|
||||
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false).onClose(iterator::finish);
|
||||
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
|
||||
.onClose(iterator::finish);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,7 +67,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
List<DataStructureNode> nodes = new ArrayList<>();
|
||||
XPipeConnection.execute(con -> {
|
||||
var req = QueryTableDataExchange.Request.builder()
|
||||
.ref(DataSourceReference.id(getId())).maxRows(maxRows).build();
|
||||
.ref(DataSourceReference.id(getId()))
|
||||
.maxRows(maxRows)
|
||||
.build();
|
||||
con.performInputExchange(req, (QueryTableDataExchange.Response res, InputStream in) -> {
|
||||
var r = new TypedDataStreamParser(info.getDataType());
|
||||
r.parseStructures(in, TypedDataStructureNodeReader.of(info.getDataType()), nodes::add);
|
||||
|
@ -72,6 +78,12 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
return ArrayNode.of(nodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<TupleNode> iterator() {
|
||||
return new TableIterator();
|
||||
}
|
||||
;
|
||||
|
||||
private class TableIterator implements Iterator<TupleNode> {
|
||||
|
||||
private final BeaconConnection connection;
|
||||
|
@ -85,7 +97,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
|
||||
connection = XPipeConnection.open();
|
||||
var req = QueryTableDataExchange.Request.builder()
|
||||
.ref(DataSourceReference.id(getId())).maxRows(Integer.MAX_VALUE).build();
|
||||
.ref(DataSourceReference.id(getId()))
|
||||
.maxRows(Integer.MAX_VALUE)
|
||||
.build();
|
||||
connection.sendRequest(req);
|
||||
connection.receiveResponse();
|
||||
connection.receiveBody();
|
||||
|
@ -116,10 +130,5 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public Iterator<TupleNode> iterator() {
|
||||
return new TableIterator();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,11 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
|
|||
|
||||
private final DataSourceInfo.Text info;
|
||||
|
||||
public DataTextImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Text info, io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
public DataTextImpl(
|
||||
DataSourceId sourceId,
|
||||
DataSourceConfig sourceConfig,
|
||||
DataSourceInfo.Text info,
|
||||
io.xpipe.core.source.DataSource<?> internalSource) {
|
||||
super(sourceId, sourceConfig, internalSource);
|
||||
this.info = info;
|
||||
}
|
||||
|
@ -70,7 +74,9 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
|
|||
{
|
||||
connection = XPipeConnection.open();
|
||||
var req = QueryTextDataExchange.Request.builder()
|
||||
.ref(DataSourceReference.id(getId())).maxLines(-1).build();
|
||||
.ref(DataSourceReference.id(getId()))
|
||||
.maxLines(-1)
|
||||
.build();
|
||||
connection.sendRequest(req);
|
||||
connection.receiveResponse();
|
||||
reader = new BufferedReader(new InputStreamReader(connection.receiveBody(), StandardCharsets.UTF_8));
|
||||
|
@ -98,8 +104,7 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
|
|||
}
|
||||
};
|
||||
|
||||
return StreamSupport
|
||||
.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
|
||||
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
|
||||
.onClose(iterator::close);
|
||||
}
|
||||
|
||||
|
@ -123,6 +128,4 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
|
|||
});
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ import java.util.UUID;
|
|||
public class QuietDialogHandler {
|
||||
|
||||
private final UUID dialogKey;
|
||||
private DialogElement element;
|
||||
private final BeaconConnection connection;
|
||||
private final Map<String, String> overrides;
|
||||
private DialogElement element;
|
||||
|
||||
public QuietDialogHandler(DialogReference ref, BeaconConnection connection, Map<String, String> overrides) {
|
||||
this.dialogKey = ref.getDialogId();
|
||||
|
@ -36,10 +36,13 @@ public class QuietDialogHandler {
|
|||
response = handleQuery(q);
|
||||
}
|
||||
|
||||
DialogExchange.Response res = connection.performSimpleExchange(
|
||||
DialogExchange.Request.builder().dialogKey(dialogKey).value(response).build());
|
||||
DialogExchange.Response res = connection.performSimpleExchange(DialogExchange.Request.builder()
|
||||
.dialogKey(dialogKey)
|
||||
.value(response)
|
||||
.build());
|
||||
if (res.getElement() != null && element.equals(res.getElement())) {
|
||||
throw new ClientException("Invalid value for key " + res.getElement().toDisplayString());
|
||||
throw new ClientException(
|
||||
"Invalid value for key " + res.getElement().toDisplayString());
|
||||
}
|
||||
|
||||
element = res.getElement();
|
||||
|
|
|
@ -6,8 +6,7 @@ import java.util.stream.Collectors;
|
|||
public class TypeDescriptor {
|
||||
|
||||
public static String create(List<String> names) {
|
||||
return "[" + names.stream()
|
||||
.map(n -> n != null ? "\"" + n + "\"" : null)
|
||||
.collect(Collectors.joining(",")) + "]\n";
|
||||
return "[" + names.stream().map(n -> n != null ? "\"" + n + "\"" : null).collect(Collectors.joining(","))
|
||||
+ "]\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,11 @@ public class DataTableAccumulatorTest extends ApiTest {
|
|||
|
||||
@Test
|
||||
public void test() {
|
||||
var type = TupleType.of(
|
||||
List.of("col1", "col2"),
|
||||
List.of(ValueType.of(), ValueType.of()));
|
||||
var type = TupleType.of(List.of("col1", "col2"), List.of(ValueType.of(), ValueType.of()));
|
||||
var acc = DataTableAccumulator.create(type);
|
||||
|
||||
var val = type.convert(
|
||||
TupleNode.of(List.of(ValueNode.of("val1"), ValueNode.of("val2")))).orElseThrow();
|
||||
var val = type.convert(TupleNode.of(List.of(ValueNode.of("val1"), ValueNode.of("val2"))))
|
||||
.orElseThrow();
|
||||
acc.add(val);
|
||||
var table = acc.finish(":test");
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ public class DataTableTest extends ApiTest {
|
|||
|
||||
@BeforeAll
|
||||
public static void setupStorage() throws Exception {
|
||||
DataSource.create(DataSourceId.fromString(":usernames"), "csv", DataTableTest.class.getResource("username.csv"));
|
||||
DataSource.create(
|
||||
DataSourceId.fromString(":usernames"), "csv", DataTableTest.class.getResource("username.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -23,32 +23,6 @@ import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR;
|
|||
|
||||
public class BeaconClient implements AutoCloseable {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableBiConsumer<T, U, E extends Throwable> {
|
||||
|
||||
void accept(T var1, U var2) throws E;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableConsumer<T, E extends Throwable> {
|
||||
|
||||
void accept(T var1) throws E;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableRunnable<E extends Throwable> {
|
||||
|
||||
void run() throws E;
|
||||
}
|
||||
|
||||
public static Optional<BeaconClient> tryConnect() {
|
||||
try {
|
||||
return Optional.of(new BeaconClient());
|
||||
} catch (IOException ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private final Closeable closeable;
|
||||
private final InputStream in;
|
||||
private final OutputStream out;
|
||||
|
@ -66,6 +40,14 @@ public class BeaconClient implements AutoCloseable {
|
|||
this.out = out;
|
||||
}
|
||||
|
||||
public static Optional<BeaconClient> tryConnect() {
|
||||
try {
|
||||
return Optional.of(new BeaconClient());
|
||||
} catch (IOException ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws ConnectorException {
|
||||
try {
|
||||
closeable.close();
|
||||
|
@ -109,7 +91,8 @@ public class BeaconClient implements AutoCloseable {
|
|||
msg.set("xPipeMessage", json);
|
||||
|
||||
if (BeaconConfig.printMessages()) {
|
||||
System.out.println("Sending request to server of type " + req.getClass().getName());
|
||||
System.out.println(
|
||||
"Sending request to server of type " + req.getClass().getName());
|
||||
}
|
||||
|
||||
var writer = new StringWriter();
|
||||
|
@ -226,4 +209,22 @@ public class BeaconClient implements AutoCloseable {
|
|||
public OutputStream getRawOutputStream() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableBiConsumer<T, U, E extends Throwable> {
|
||||
|
||||
void accept(T var1, U var2) throws E;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableConsumer<T, E extends Throwable> {
|
||||
|
||||
void accept(T var1) throws E;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableRunnable<E extends Throwable> {
|
||||
|
||||
void run() throws E;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,14 @@ import java.nio.charset.StandardCharsets;
|
|||
public class BeaconConfig {
|
||||
|
||||
public static final byte[] BODY_SEPARATOR = "\n\n".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||
public static final int DEFAULT_PORT = System.getProperty("os.name").startsWith("Windows") ? 21721 : 21722;
|
||||
private static final String PRINT_MESSAGES_PROPERTY = "io.xpipe.beacon.printMessages";
|
||||
private static final String LAUNCH_DAEMON_IN_DEBUG_PROP = "io.xpipe.beacon.launchDebugDaemon";
|
||||
private static final String ATTACH_DEBUGGER_PROP = "io.xpipe.beacon.attachDebuggerToDaemon";
|
||||
private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.printDaemonOutput";
|
||||
private static final String EXEC_PROCESS_PROP = "io.xpipe.beacon.customDaemonCommand";
|
||||
private static final String DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs";
|
||||
|
||||
public static boolean printMessages() {
|
||||
if (System.getProperty(PRINT_MESSAGES_PROPERTY) != null) {
|
||||
|
@ -18,8 +24,6 @@ public class BeaconConfig {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static final String LAUNCH_DAEMON_IN_DEBUG_PROP = "io.xpipe.beacon.launchDebugDaemon";
|
||||
|
||||
public static boolean launchDaemonInDebugMode() {
|
||||
if (System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP));
|
||||
|
@ -27,8 +31,6 @@ public class BeaconConfig {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static final String ATTACH_DEBUGGER_PROP = "io.xpipe.beacon.attachDebuggerToDaemon";
|
||||
|
||||
public static boolean attachDebuggerToDaemon() {
|
||||
if (System.getProperty(ATTACH_DEBUGGER_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(ATTACH_DEBUGGER_PROP));
|
||||
|
@ -36,10 +38,6 @@ public class BeaconConfig {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.printDaemonOutput";
|
||||
|
||||
public static boolean printDaemonOutput() {
|
||||
if (System.getProperty(EXEC_DEBUG_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(EXEC_DEBUG_PROP));
|
||||
|
@ -47,11 +45,6 @@ public class BeaconConfig {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||
public static final int DEFAULT_PORT = System.getProperty("os.name").startsWith("Windows") ? 21721 : 21722;
|
||||
|
||||
public static int getUsedPort() {
|
||||
if (System.getProperty(BEACON_PORT_PROP) != null) {
|
||||
return Integer.parseInt(System.getProperty(BEACON_PORT_PROP));
|
||||
|
@ -60,10 +53,6 @@ public class BeaconConfig {
|
|||
return DEFAULT_PORT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static final String EXEC_PROCESS_PROP = "io.xpipe.beacon.customDaemonCommand";
|
||||
|
||||
public static String getCustomDaemonCommand() {
|
||||
if (System.getProperty(EXEC_PROCESS_PROP) != null) {
|
||||
return System.getProperty(EXEC_PROCESS_PROP);
|
||||
|
@ -72,8 +61,6 @@ public class BeaconConfig {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static final String DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs";
|
||||
|
||||
public static String getDaemonArguments() {
|
||||
if (System.getProperty(DAEMON_ARGUMENTS_PROP) != null) {
|
||||
return System.getProperty(DAEMON_ARGUMENTS_PROP);
|
||||
|
@ -82,5 +69,3 @@ public class BeaconConfig {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.io.OutputStream;
|
|||
|
||||
public abstract class BeaconConnection implements AutoCloseable {
|
||||
|
||||
|
||||
protected BeaconClient beaconClient;
|
||||
|
||||
private InputStream bodyInput;
|
||||
|
@ -74,9 +73,7 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
}
|
||||
|
||||
public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputExchange(
|
||||
REQ req,
|
||||
BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer
|
||||
) {
|
||||
REQ req, BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer) {
|
||||
checkClosed();
|
||||
|
||||
performInputOutputExchange(req, null, responseConsumer);
|
||||
|
@ -85,8 +82,7 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputOutputExchange(
|
||||
REQ req,
|
||||
BeaconClient.FailableConsumer<OutputStream, IOException> reqWriter,
|
||||
BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer
|
||||
) {
|
||||
BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer) {
|
||||
checkClosed();
|
||||
|
||||
try {
|
||||
|
@ -105,9 +101,7 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
public <REQ extends RequestMessage> void sendRequest(
|
||||
REQ req
|
||||
) {
|
||||
public <REQ extends RequestMessage> void sendRequest(REQ req) {
|
||||
checkClosed();
|
||||
|
||||
try {
|
||||
|
@ -150,9 +144,7 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
}
|
||||
|
||||
public <REQ extends RequestMessage, RES extends ResponseMessage> RES performOutputExchange(
|
||||
REQ req,
|
||||
BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter
|
||||
) {
|
||||
REQ req, BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter) {
|
||||
checkClosed();
|
||||
|
||||
try {
|
||||
|
@ -166,9 +158,7 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
public <REQ extends RequestMessage, RES extends ResponseMessage> RES performSimpleExchange(
|
||||
REQ req
|
||||
) {
|
||||
public <REQ extends RequestMessage, RES extends ResponseMessage> RES performSimpleExchange(REQ req) {
|
||||
checkClosed();
|
||||
|
||||
try {
|
||||
|
@ -192,7 +182,6 @@ public abstract class BeaconConnection implements AutoCloseable {
|
|||
return new BeaconException("A beacon connection error occurred", s.getCause());
|
||||
}
|
||||
|
||||
|
||||
return new BeaconException("An unexpected error occurred", exception);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ package io.xpipe.beacon;
|
|||
*/
|
||||
public class BeaconException extends RuntimeException {
|
||||
|
||||
public BeaconException() {
|
||||
}
|
||||
public BeaconException() {}
|
||||
|
||||
public BeaconException(String message) {
|
||||
super(message);
|
||||
|
|
|
@ -34,9 +34,8 @@ public class BeaconServer {
|
|||
public static Process tryStartCustom() throws Exception {
|
||||
var custom = BeaconConfig.getCustomDaemonCommand();
|
||||
if (custom != null) {
|
||||
var command = custom + " " + (BeaconConfig.getDaemonArguments() != null ?
|
||||
BeaconConfig.getDaemonArguments() :
|
||||
"");
|
||||
var command =
|
||||
custom + " " + (BeaconConfig.getDaemonArguments() != null ? BeaconConfig.getDaemonArguments() : "");
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
printDaemonOutput(process, command);
|
||||
return process;
|
||||
|
@ -47,9 +46,8 @@ public class BeaconServer {
|
|||
public static Process tryStart() throws Exception {
|
||||
var daemonExecutable = getDaemonExecutable();
|
||||
if (daemonExecutable.isPresent()) {
|
||||
var command = "\"" + daemonExecutable.get() + "\" --external " + (BeaconConfig.getDaemonArguments() != null ?
|
||||
BeaconConfig.getDaemonArguments() :
|
||||
"");
|
||||
var command = "\"" + daemonExecutable.get() + "\" --external "
|
||||
+ (BeaconConfig.getDaemonArguments() != null ? BeaconConfig.getDaemonArguments() : "");
|
||||
// Tell daemon that we launched from an external tool
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
printDaemonOutput(process, command);
|
||||
|
@ -65,7 +63,9 @@ public class BeaconServer {
|
|||
System.out.println("Starting daemon: " + command);
|
||||
}
|
||||
|
||||
new Thread(null, () -> {
|
||||
new Thread(
|
||||
null,
|
||||
() -> {
|
||||
try {
|
||||
InputStreamReader isr = new InputStreamReader(proc.getInputStream());
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
|
@ -78,9 +78,13 @@ public class BeaconServer {
|
|||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}, "daemon sysout").start();
|
||||
},
|
||||
"daemon sysout")
|
||||
.start();
|
||||
|
||||
new Thread(null, () -> {
|
||||
new Thread(
|
||||
null,
|
||||
() -> {
|
||||
try {
|
||||
InputStreamReader isr = new InputStreamReader(proc.getErrorStream());
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
|
@ -93,7 +97,9 @@ public class BeaconServer {
|
|||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}, "daemon syserr").start();
|
||||
},
|
||||
"daemon syserr")
|
||||
.start();
|
||||
}
|
||||
|
||||
public static boolean tryStop(BeaconClient client) throws Exception {
|
||||
|
@ -111,7 +117,6 @@ public class BeaconServer {
|
|||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
|
||||
if (base == null) {
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
base = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe");
|
||||
|
|
|
@ -5,8 +5,7 @@ package io.xpipe.beacon;
|
|||
*/
|
||||
public class ClientException extends Exception {
|
||||
|
||||
public ClientException() {
|
||||
}
|
||||
public ClientException() {}
|
||||
|
||||
public ClientException(String message) {
|
||||
super(message);
|
||||
|
|
|
@ -5,8 +5,7 @@ package io.xpipe.beacon;
|
|||
*/
|
||||
public class ConnectorException extends Exception {
|
||||
|
||||
public ConnectorException() {
|
||||
}
|
||||
public ConnectorException() {}
|
||||
|
||||
public ConnectorException(String message) {
|
||||
super(message);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
public interface RequestMessage {
|
||||
|
||||
}
|
||||
public interface RequestMessage {}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
public interface ResponseMessage {
|
||||
|
||||
}
|
||||
public interface ResponseMessage {}
|
||||
|
|
|
@ -5,8 +5,7 @@ package io.xpipe.beacon;
|
|||
*/
|
||||
public class ServerException extends Exception {
|
||||
|
||||
public ServerException() {
|
||||
}
|
||||
public ServerException() {}
|
||||
|
||||
public ServerException(String message) {
|
||||
super(message);
|
||||
|
|
|
@ -21,7 +21,9 @@ public class AddSourceExchange implements MessageExchange {
|
|||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
DataSourceId target;
|
||||
@NonNull DataSource<?> source;
|
||||
|
||||
@NonNull
|
||||
DataSource<?> source;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
|
|
|
@ -31,6 +31,5 @@ public class ForwardExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ public class MessageExchanges {
|
|||
private static void loadAll() {
|
||||
if (ALL == null) {
|
||||
ALL = ServiceLoader.load(MessageExchange.class).stream()
|
||||
.map(ServiceLoader.Provider::get).collect(Collectors.toSet());
|
||||
.map(ServiceLoader.Provider::get)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,12 +27,16 @@ public class MessageExchanges {
|
|||
|
||||
public static <RQ extends RequestMessage> Optional<MessageExchange> byRequest(RQ req) {
|
||||
loadAll();
|
||||
return ALL.stream().filter(d -> d.getRequestClass().equals(req.getClass())).findAny();
|
||||
return ALL.stream()
|
||||
.filter(d -> d.getRequestClass().equals(req.getClass()))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
public static <RP extends ResponseMessage> Optional<MessageExchange> byResponse(RP rep) {
|
||||
loadAll();
|
||||
return ALL.stream().filter(d -> d.getResponseClass().equals(rep.getClass())).findAny();
|
||||
return ALL.stream()
|
||||
.filter(d -> d.getResponseClass().equals(rep.getClass()))
|
||||
.findAny();
|
||||
}
|
||||
|
||||
public static Set<MessageExchange> getAll() {
|
||||
|
|
|
@ -37,14 +37,18 @@ public class QueryDataSourceExchange implements MessageExchange {
|
|||
public static class Response implements ResponseMessage {
|
||||
@NonNull
|
||||
DataSourceId id;
|
||||
|
||||
boolean disabled;
|
||||
boolean hidden;
|
||||
|
||||
@NonNull
|
||||
DataSourceInfo info;
|
||||
|
||||
@NonNull
|
||||
String storeDisplay;
|
||||
|
||||
String provider;
|
||||
|
||||
@NonNull
|
||||
Map<String, String> config;
|
||||
|
||||
|
|
|
@ -32,6 +32,5 @@ public class ReadExecuteExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ public class StopExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -20,8 +20,7 @@ public class StoreStreamExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.api;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -29,6 +29,5 @@ public class QueryRawDataExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.api;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -32,6 +32,5 @@ public class QueryTableDataExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.api;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -30,6 +30,5 @@ public class QueryTextDataExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.dialog.DialogReference;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.dialog.DialogElement;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -34,6 +34,7 @@ public class DialogExchange implements MessageExchange {
|
|||
public static class Request implements RequestMessage {
|
||||
@NonNull
|
||||
UUID dialogKey;
|
||||
|
||||
String value;
|
||||
boolean cancel;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public class EditStoreExchange implements MessageExchange {
|
|||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
@NonNull DialogReference dialog;
|
||||
@NonNull
|
||||
DialogReference dialog;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@ public class InstanceExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.CollectionListEntry;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.CollectionListEntry;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
@ -20,9 +20,7 @@ public class ListCollectionsExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.EntryListEntry;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.EntryListEntry;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.StoreListEntry;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.StoreListEntry;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
@ -20,9 +20,7 @@ public class ListStoresExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
@ -26,7 +26,5 @@ public class ModeExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
@ -26,6 +26,5 @@ public class RemoveCollectionExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
@ -28,6 +28,5 @@ public class RemoveStoreExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
@ -21,6 +21,7 @@ public class RenameCollectionExchange implements MessageExchange {
|
|||
public static class Request implements RequestMessage {
|
||||
@NonNull
|
||||
String collectionName;
|
||||
|
||||
@NonNull
|
||||
String newName;
|
||||
}
|
||||
|
@ -28,6 +29,5 @@ public class RenameCollectionExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
|
@ -32,6 +32,7 @@ public class RenameEntryExchange implements MessageExchange {
|
|||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
@NonNull DataSourceId newId;
|
||||
@NonNull
|
||||
DataSourceId newId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
@ -21,6 +21,7 @@ public class RenameStoreExchange implements MessageExchange {
|
|||
public static class Request implements RequestMessage {
|
||||
@NonNull
|
||||
String storeName;
|
||||
|
||||
@NonNull
|
||||
String newName;
|
||||
}
|
||||
|
@ -28,6 +29,5 @@ public class RenameStoreExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -27,6 +27,5 @@ public class SelectExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.ProviderEntry;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.ProviderEntry;
|
||||
import io.xpipe.core.source.DataSourceType;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -23,13 +23,13 @@ public class SourceProviderListExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
@NonNull Map<DataSourceType, List<ProviderEntry>> entries;
|
||||
@NonNull
|
||||
Map<DataSourceType, List<ProviderEntry>> entries;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
@ -17,8 +17,7 @@ public class StatusExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.dialog.DialogReference;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import lombok.Builder;
|
||||
|
|
|
@ -21,13 +21,13 @@ public class StoreProviderListExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
@NonNull List<ProviderEntry> entries;
|
||||
@NonNull
|
||||
List<ProviderEntry> entries;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
@ -17,9 +17,7 @@ public class VersionExchange implements MessageExchange {
|
|||
@lombok.extern.jackson.Jacksonized
|
||||
@lombok.Builder
|
||||
@lombok.Value
|
||||
public static class Request implements RequestMessage {
|
||||
|
||||
}
|
||||
public static class Request implements RequestMessage {}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.RequestMessage;
|
||||
import io.xpipe.beacon.ResponseMessage;
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
|
@ -35,6 +35,5 @@ public class WriteExecuteExchange implements MessageExchange {
|
|||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
public static class Response implements ResponseMessage {}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,10 @@ public class WritePreparationExchange implements MessageExchange {
|
|||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
String type;
|
||||
|
||||
@NonNull
|
||||
DataStore output;
|
||||
|
||||
@NonNull
|
||||
DataSourceReference source;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import io.xpipe.beacon.exchange.*;
|
||||
import io.xpipe.beacon.exchange.api.*;
|
||||
import io.xpipe.beacon.exchange.api.QueryRawDataExchange;
|
||||
import io.xpipe.beacon.exchange.api.QueryTableDataExchange;
|
||||
import io.xpipe.beacon.exchange.api.QueryTextDataExchange;
|
||||
import io.xpipe.beacon.exchange.cli.*;
|
||||
|
||||
module io.xpipe.beacon {
|
||||
|
@ -21,6 +23,7 @@ module io.xpipe.beacon {
|
|||
requires static lombok;
|
||||
|
||||
uses MessageExchange;
|
||||
|
||||
provides io.xpipe.beacon.exchange.MessageExchange with
|
||||
ForwardExchange,
|
||||
InstanceExchange,
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FailableConsumer<T, E extends Throwable> {
|
||||
|
||||
void accept(T var1) throws E;
|
||||
}
|
||||
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 -> {
|
||||
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());
|
||||
})
|
||||
.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(
|
||||
return hasKeys
|
||||
? TupleNode.of(
|
||||
entries.stream().map(KeyValue::key).toList(),
|
||||
entries.stream().map(KeyValue::value).toList()
|
||||
) :
|
||||
TupleNode.of(entries.stream().map(KeyValue::value).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;
|
||||
|
@ -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,10 +380,6 @@ 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.
|
||||
* */
|
||||
|
@ -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,7 +59,8 @@ public abstract class QueryConverter<T> {
|
|||
}
|
||||
};
|
||||
|
||||
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER = new QueryConverter<Map.Entry<String, String>>() {
|
||||
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(":")) {
|
||||
|
@ -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,9 +9,7 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -22,20 +22,21 @@ 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 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
|
||||
case COLLECTION -> null;
|
||||
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue