This commit is contained in:
Christopher Schnick 2022-10-15 16:06:02 +02:00
parent 27843ae0fd
commit 55da767dab
186 changed files with 1541 additions and 1606 deletions

View file

@ -27,10 +27,6 @@ import java.nio.file.Path;
*/ */
public interface DataSource { public interface DataSource {
void forwardTo(DataSource target);
void appendTo(DataSource target);
/** /**
* NOT YET IMPLEMENTED! * NOT YET IMPLEMENTED!
* *
@ -126,7 +122,6 @@ public interface DataSource {
} }
} }
/** /**
* Wrapper for {@link #create(DataSourceId, String, InputStream)} that creates an anonymous data source. * 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); return DataSourceImpl.create(id, type, in);
} }
void forwardTo(DataSource target);
void appendTo(DataSource target);
public io.xpipe.core.source.DataSource<?> getInternalSource(); public io.xpipe.core.source.DataSource<?> getInternalSource();
/** /**
@ -180,7 +179,6 @@ public interface DataSource {
*/ */
DataSourceType getType(); DataSourceType getType();
DataSourceConfig getConfig(); DataSourceConfig getConfig();
/** /**

View file

@ -12,7 +12,9 @@ public class DataStores {
public static void addNamedStore(DataStore store, String name) { public static void addNamedStore(DataStore store, String name) {
XPipeConnection.execute(con -> { XPipeConnection.execute(con -> {
var req = StoreAddExchange.Request.builder() var req = StoreAddExchange.Request.builder()
.storeInput(store).name(name).build(); .storeInput(store)
.name(name)
.build();
StoreAddExchange.Response res = con.performSimpleExchange(req); StoreAddExchange.Response res = con.performSimpleExchange(req);
new QuietDialogHandler(res.getConfig(), con, Map.of()).handle(); new QuietDialogHandler(res.getConfig(), con, Map.of()).handle();

View file

@ -8,6 +8,8 @@ import java.util.Optional;
public final class XPipeConnection extends BeaconConnection { public final class XPipeConnection extends BeaconConnection {
private XPipeConnection() {}
public static XPipeConnection open() { public static XPipeConnection open() {
var con = new XPipeConnection(); var con = new XPipeConnection();
con.constructSocket(); con.constructSocket();
@ -23,7 +25,9 @@ public final class XPipeConnection extends BeaconConnection {
throw new IllegalStateException(); 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(); element = response.getElement();
if (response.getElement() == null) { if (response.getElement() == null) {
break; 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) { public static Optional<BeaconClient> waitForStartup(Process process) {
for (int i = 0; i < 160; i++) { for (int i = 0; i < 160; i++) {
if (process != null && !process.isAlive()) { 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 @FunctionalInterface
public static interface Handler { public static interface Handler {

View file

@ -2,7 +2,9 @@ package io.xpipe.api.impl;
import io.xpipe.api.DataRaw; import io.xpipe.api.DataRaw;
import io.xpipe.api.DataSourceConfig; 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; import java.io.InputStream;
@ -10,7 +12,11 @@ public class DataRawImpl extends DataSourceImpl implements DataRaw {
private final DataSourceInfo.Raw info; 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); super(sourceId, sourceConfig, internalSource);
this.info = info; this.info = info;
} }

View file

@ -13,28 +13,15 @@ import java.io.InputStream;
public abstract class DataSourceImpl implements DataSource { public abstract class DataSourceImpl implements DataSource {
@Override private final DataSourceId sourceId;
public void forwardTo(DataSource target) { private final DataSourceConfig config;
XPipeConnection.execute(con -> { private final io.xpipe.core.source.DataSource<?> internalSource;
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);
});
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) { public static DataSource get(DataSourceReference ds) {
@ -59,17 +46,17 @@ public abstract class DataSourceImpl implements DataSource {
var info = res.getInfo().asRaw(); var info = res.getInfo().asRaw();
yield new DataRawImpl(res.getId(), config, info, res.getInternalSource()); yield new DataRawImpl(res.getId(), config, info, res.getInternalSource());
} }
case COLLECTION -> throw new UnsupportedOperationException("Unimplemented case: " + res.getInfo().getType()); case COLLECTION -> throw new UnsupportedOperationException(
default -> throw new IllegalArgumentException("Unexpected value: " + res.getInfo().getType()); "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) { public static DataSource create(DataSourceId id, io.xpipe.core.source.DataSource<?> source) {
var startReq = AddSourceExchange.Request.builder() var startReq =
.source(source) AddSourceExchange.Request.builder().source(source).target(id).build();
.target(id)
.build();
var returnedId = XPipeConnection.execute(con -> { var returnedId = XPipeConnection.execute(con -> {
AddSourceExchange.Response r = con.performSimpleExchange(startReq); AddSourceExchange.Response r = con.performSimpleExchange(startReq);
return r.getId(); return r.getId();
@ -108,9 +95,7 @@ public abstract class DataSourceImpl implements DataSource {
var configInstance = startRes.getConfig(); var configInstance = startRes.getConfig();
XPipeConnection.finishDialog(configInstance); XPipeConnection.finishDialog(configInstance);
var ref = id != null ? var ref = id != null ? DataSourceReference.id(id) : DataSourceReference.latest();
DataSourceReference.id(id) :
DataSourceReference.latest();
return get(ref); return get(ref);
} }
@ -137,20 +122,31 @@ public abstract class DataSourceImpl implements DataSource {
var configInstance = startRes.getConfig(); var configInstance = startRes.getConfig();
XPipeConnection.finishDialog(configInstance); XPipeConnection.finishDialog(configInstance);
var ref = id != null ? var ref = id != null ? DataSourceReference.id(id) : DataSourceReference.latest();
DataSourceReference.id(id) :
DataSourceReference.latest();
return get(ref); return get(ref);
} }
private final DataSourceId sourceId; @Override
private final DataSourceConfig config; public void forwardTo(DataSource target) {
private final io.xpipe.core.source.DataSource<?> internalSource; 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) { @Override
this.sourceId = sourceId; public void appendTo(DataSource target) {
this.config = config; XPipeConnection.execute(con -> {
this.internalSource = internalSource; 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() { public io.xpipe.core.source.DataSource<?> getInternalSource() {

View file

@ -3,13 +3,19 @@ package io.xpipe.api.impl;
import io.xpipe.api.DataSourceConfig; import io.xpipe.api.DataSourceConfig;
import io.xpipe.api.DataStructure; import io.xpipe.api.DataStructure;
import io.xpipe.core.data.node.DataStructureNode; 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 { public class DataStructureImpl extends DataSourceImpl implements DataStructure {
private final DataSourceInfo.Structure info; 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); super(sourceId, sourceConfig, internalSource);
this.info = info; this.info = info;
} }

View file

@ -47,7 +47,11 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
connection.close(); connection.close();
var req = ReadExchange.Request.builder() 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 -> { ReadExchange.Response response = XPipeConnection.execute(con -> {
return con.performSimpleExchange(req); return con.performSimpleExchange(req);
}); });
@ -71,7 +75,9 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
@Override @Override
public synchronized void add(DataStructureNode row) { 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 -> { connection.withOutputStream(out -> {
writeDescriptor(); writeDescriptor();
TypedDataStreamWriter.writeStructure(out, toUse, writtenDescriptor); TypedDataStreamWriter.writeStructure(out, toUse, writtenDescriptor);

View file

@ -27,7 +27,11 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
private final DataSourceInfo.Table info; 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); super(id, sourceConfig, internalSource);
this.info = info; this.info = info;
} }
@ -44,8 +48,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
public Stream<TupleNode> stream() { public Stream<TupleNode> stream() {
var iterator = new TableIterator(); var iterator = new TableIterator();
return StreamSupport.stream( return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false).onClose(iterator::finish); .onClose(iterator::finish);
} }
@Override @Override
@ -63,15 +67,23 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
List<DataStructureNode> nodes = new ArrayList<>(); List<DataStructureNode> nodes = new ArrayList<>();
XPipeConnection.execute(con -> { XPipeConnection.execute(con -> {
var req = QueryTableDataExchange.Request.builder() 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) -> { con.performInputExchange(req, (QueryTableDataExchange.Response res, InputStream in) -> {
var r = new TypedDataStreamParser(info.getDataType()); var r = new TypedDataStreamParser(info.getDataType());
r.parseStructures(in, TypedDataStructureNodeReader.of(info.getDataType()), nodes::add); r.parseStructures(in, TypedDataStructureNodeReader.of(info.getDataType()), nodes::add);
}); });
}); });
return ArrayNode.of(nodes); return ArrayNode.of(nodes);
} }
@Override
public Iterator<TupleNode> iterator() {
return new TableIterator();
}
;
private class TableIterator implements Iterator<TupleNode> { private class TableIterator implements Iterator<TupleNode> {
private final BeaconConnection connection; private final BeaconConnection connection;
@ -85,7 +97,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
connection = XPipeConnection.open(); connection = XPipeConnection.open();
var req = QueryTableDataExchange.Request.builder() 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.sendRequest(req);
connection.receiveResponse(); connection.receiveResponse();
connection.receiveBody(); connection.receiveBody();
@ -116,10 +130,5 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
return node; return node;
} }
};
@Override
public Iterator<TupleNode> iterator() {
return new TableIterator();
} }
} }

View file

@ -27,7 +27,11 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
private final DataSourceInfo.Text info; 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); super(sourceId, sourceConfig, internalSource);
this.info = info; this.info = info;
} }
@ -70,7 +74,9 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
{ {
connection = XPipeConnection.open(); connection = XPipeConnection.open();
var req = QueryTextDataExchange.Request.builder() var req = QueryTextDataExchange.Request.builder()
.ref(DataSourceReference.id(getId())).maxLines(-1).build(); .ref(DataSourceReference.id(getId()))
.maxLines(-1)
.build();
connection.sendRequest(req); connection.sendRequest(req);
connection.receiveResponse(); connection.receiveResponse();
reader = new BufferedReader(new InputStreamReader(connection.receiveBody(), StandardCharsets.UTF_8)); reader = new BufferedReader(new InputStreamReader(connection.receiveBody(), StandardCharsets.UTF_8));
@ -98,8 +104,7 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
} }
}; };
return StreamSupport return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
.onClose(iterator::close); .onClose(iterator::close);
} }
@ -123,6 +128,4 @@ public class DataTextImpl extends DataSourceImpl implements DataText {
}); });
return builder.toString(); return builder.toString();
} }
} }

View file

@ -14,9 +14,9 @@ import java.util.UUID;
public class QuietDialogHandler { public class QuietDialogHandler {
private final UUID dialogKey; private final UUID dialogKey;
private DialogElement element;
private final BeaconConnection connection; private final BeaconConnection connection;
private final Map<String, String> overrides; private final Map<String, String> overrides;
private DialogElement element;
public QuietDialogHandler(DialogReference ref, BeaconConnection connection, Map<String, String> overrides) { public QuietDialogHandler(DialogReference ref, BeaconConnection connection, Map<String, String> overrides) {
this.dialogKey = ref.getDialogId(); this.dialogKey = ref.getDialogId();
@ -36,10 +36,13 @@ public class QuietDialogHandler {
response = handleQuery(q); response = handleQuery(q);
} }
DialogExchange.Response res = connection.performSimpleExchange( DialogExchange.Response res = connection.performSimpleExchange(DialogExchange.Request.builder()
DialogExchange.Request.builder().dialogKey(dialogKey).value(response).build()); .dialogKey(dialogKey)
.value(response)
.build());
if (res.getElement() != null && element.equals(res.getElement())) { 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(); element = res.getElement();

View file

@ -6,8 +6,7 @@ import java.util.stream.Collectors;
public class TypeDescriptor { public class TypeDescriptor {
public static String create(List<String> names) { public static String create(List<String> names) {
return "[" + names.stream() return "[" + names.stream().map(n -> n != null ? "\"" + n + "\"" : null).collect(Collectors.joining(","))
.map(n -> n != null ? "\"" + n + "\"" : null) + "]\n";
.collect(Collectors.joining(",")) + "]\n";
} }
} }

View file

@ -15,13 +15,11 @@ public class DataTableAccumulatorTest extends ApiTest {
@Test @Test
public void test() { public void test() {
var type = TupleType.of( var type = TupleType.of(List.of("col1", "col2"), List.of(ValueType.of(), ValueType.of()));
List.of("col1", "col2"),
List.of(ValueType.of(), ValueType.of()));
var acc = DataTableAccumulator.create(type); var acc = DataTableAccumulator.create(type);
var val = type.convert( var val = type.convert(TupleNode.of(List.of(ValueNode.of("val1"), ValueNode.of("val2"))))
TupleNode.of(List.of(ValueNode.of("val1"), ValueNode.of("val2")))).orElseThrow(); .orElseThrow();
acc.add(val); acc.add(val);
var table = acc.finish(":test"); var table = acc.finish(":test");

View file

@ -9,7 +9,8 @@ public class DataTableTest extends ApiTest {
@BeforeAll @BeforeAll
public static void setupStorage() throws Exception { 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 @Test

View file

@ -23,32 +23,6 @@ import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR;
public class BeaconClient implements AutoCloseable { 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 Closeable closeable;
private final InputStream in; private final InputStream in;
private final OutputStream out; private final OutputStream out;
@ -66,6 +40,14 @@ public class BeaconClient implements AutoCloseable {
this.out = out; 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 { public void close() throws ConnectorException {
try { try {
closeable.close(); closeable.close();
@ -104,12 +86,13 @@ public class BeaconClient implements AutoCloseable {
json.set("messageType", new TextNode(prov.get().getId())); json.set("messageType", new TextNode(prov.get().getId()));
json.set("messagePhase", new TextNode("request")); json.set("messagePhase", new TextNode("request"));
//json.set("id", new TextNode(UUID.randomUUID().toString())); // json.set("id", new TextNode(UUID.randomUUID().toString()));
var msg = JsonNodeFactory.instance.objectNode(); var msg = JsonNodeFactory.instance.objectNode();
msg.set("xPipeMessage", json); msg.set("xPipeMessage", json);
if (BeaconConfig.printMessages()) { 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(); var writer = new StringWriter();
@ -198,13 +181,13 @@ public class BeaconClient implements AutoCloseable {
var type = content.required("messageType").textValue(); var type = content.required("messageType").textValue();
var phase = content.required("messagePhase").textValue(); var phase = content.required("messagePhase").textValue();
//var requestId = UUID.fromString(content.required("id").textValue()); // var requestId = UUID.fromString(content.required("id").textValue());
if (!phase.equals("response")) { if (!phase.equals("response")) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
content.remove("messageType"); content.remove("messageType");
content.remove("messagePhase"); content.remove("messagePhase");
//content.remove("id"); // content.remove("id");
var prov = MessageExchanges.byId(type); var prov = MessageExchanges.byId(type);
if (prov.isEmpty()) { if (prov.isEmpty()) {
@ -226,4 +209,22 @@ public class BeaconClient implements AutoCloseable {
public OutputStream getRawOutputStream() { public OutputStream getRawOutputStream() {
return out; 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;
}
} }

View file

@ -8,8 +8,14 @@ import java.nio.charset.StandardCharsets;
public class BeaconConfig { public class BeaconConfig {
public static final byte[] BODY_SEPARATOR = "\n\n".getBytes(StandardCharsets.UTF_8); 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 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() { public static boolean printMessages() {
if (System.getProperty(PRINT_MESSAGES_PROPERTY) != null) { if (System.getProperty(PRINT_MESSAGES_PROPERTY) != null) {
@ -18,8 +24,6 @@ public class BeaconConfig {
return false; return false;
} }
private static final String LAUNCH_DAEMON_IN_DEBUG_PROP = "io.xpipe.beacon.launchDebugDaemon";
public static boolean launchDaemonInDebugMode() { public static boolean launchDaemonInDebugMode() {
if (System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP) != null) { if (System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP) != null) {
return Boolean.parseBoolean(System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP)); return Boolean.parseBoolean(System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP));
@ -27,8 +31,6 @@ public class BeaconConfig {
return false; return false;
} }
private static final String ATTACH_DEBUGGER_PROP = "io.xpipe.beacon.attachDebuggerToDaemon";
public static boolean attachDebuggerToDaemon() { public static boolean attachDebuggerToDaemon() {
if (System.getProperty(ATTACH_DEBUGGER_PROP) != null) { if (System.getProperty(ATTACH_DEBUGGER_PROP) != null) {
return Boolean.parseBoolean(System.getProperty(ATTACH_DEBUGGER_PROP)); return Boolean.parseBoolean(System.getProperty(ATTACH_DEBUGGER_PROP));
@ -36,10 +38,6 @@ public class BeaconConfig {
return false; return false;
} }
private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.printDaemonOutput";
public static boolean printDaemonOutput() { public static boolean printDaemonOutput() {
if (System.getProperty(EXEC_DEBUG_PROP) != null) { if (System.getProperty(EXEC_DEBUG_PROP) != null) {
return Boolean.parseBoolean(System.getProperty(EXEC_DEBUG_PROP)); return Boolean.parseBoolean(System.getProperty(EXEC_DEBUG_PROP));
@ -47,11 +45,6 @@ public class BeaconConfig {
return false; 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() { public static int getUsedPort() {
if (System.getProperty(BEACON_PORT_PROP) != null) { if (System.getProperty(BEACON_PORT_PROP) != null) {
return Integer.parseInt(System.getProperty(BEACON_PORT_PROP)); return Integer.parseInt(System.getProperty(BEACON_PORT_PROP));
@ -60,10 +53,6 @@ public class BeaconConfig {
return DEFAULT_PORT; return DEFAULT_PORT;
} }
private static final String EXEC_PROCESS_PROP = "io.xpipe.beacon.customDaemonCommand";
public static String getCustomDaemonCommand() { public static String getCustomDaemonCommand() {
if (System.getProperty(EXEC_PROCESS_PROP) != null) { if (System.getProperty(EXEC_PROCESS_PROP) != null) {
return System.getProperty(EXEC_PROCESS_PROP); return System.getProperty(EXEC_PROCESS_PROP);
@ -72,8 +61,6 @@ public class BeaconConfig {
return null; return null;
} }
private static final String DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs";
public static String getDaemonArguments() { public static String getDaemonArguments() {
if (System.getProperty(DAEMON_ARGUMENTS_PROP) != null) { if (System.getProperty(DAEMON_ARGUMENTS_PROP) != null) {
return System.getProperty(DAEMON_ARGUMENTS_PROP); return System.getProperty(DAEMON_ARGUMENTS_PROP);
@ -82,5 +69,3 @@ public class BeaconConfig {
return null; return null;
} }
} }

View file

@ -6,7 +6,6 @@ import java.io.OutputStream;
public abstract class BeaconConnection implements AutoCloseable { public abstract class BeaconConnection implements AutoCloseable {
protected BeaconClient beaconClient; protected BeaconClient beaconClient;
private InputStream bodyInput; private InputStream bodyInput;
@ -74,9 +73,7 @@ public abstract class BeaconConnection implements AutoCloseable {
} }
public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputExchange( public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputExchange(
REQ req, REQ req, BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer) {
BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer
) {
checkClosed(); checkClosed();
performInputOutputExchange(req, null, responseConsumer); performInputOutputExchange(req, null, responseConsumer);
@ -85,8 +82,7 @@ public abstract class BeaconConnection implements AutoCloseable {
public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputOutputExchange( public <REQ extends RequestMessage, RES extends ResponseMessage> void performInputOutputExchange(
REQ req, REQ req,
BeaconClient.FailableConsumer<OutputStream, IOException> reqWriter, BeaconClient.FailableConsumer<OutputStream, IOException> reqWriter,
BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer) {
) {
checkClosed(); checkClosed();
try { try {
@ -105,9 +101,7 @@ public abstract class BeaconConnection implements AutoCloseable {
} }
} }
public <REQ extends RequestMessage> void sendRequest( public <REQ extends RequestMessage> void sendRequest(REQ req) {
REQ req
) {
checkClosed(); checkClosed();
try { try {
@ -150,9 +144,7 @@ public abstract class BeaconConnection implements AutoCloseable {
} }
public <REQ extends RequestMessage, RES extends ResponseMessage> RES performOutputExchange( public <REQ extends RequestMessage, RES extends ResponseMessage> RES performOutputExchange(
REQ req, REQ req, BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter) {
BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter
) {
checkClosed(); checkClosed();
try { try {
@ -166,9 +158,7 @@ public abstract class BeaconConnection implements AutoCloseable {
} }
} }
public <REQ extends RequestMessage, RES extends ResponseMessage> RES performSimpleExchange( public <REQ extends RequestMessage, RES extends ResponseMessage> RES performSimpleExchange(REQ req) {
REQ req
) {
checkClosed(); checkClosed();
try { try {
@ -192,7 +182,6 @@ public abstract class BeaconConnection implements AutoCloseable {
return new BeaconException("A beacon connection error occurred", s.getCause()); return new BeaconException("A beacon connection error occurred", s.getCause());
} }
return new BeaconException("An unexpected error occurred", exception); return new BeaconException("An unexpected error occurred", exception);
} }
} }

View file

@ -5,8 +5,7 @@ package io.xpipe.beacon;
*/ */
public class BeaconException extends RuntimeException { public class BeaconException extends RuntimeException {
public BeaconException() { public BeaconException() {}
}
public BeaconException(String message) { public BeaconException(String message) {
super(message); super(message);

View file

@ -34,9 +34,8 @@ public class BeaconServer {
public static Process tryStartCustom() throws Exception { public static Process tryStartCustom() throws Exception {
var custom = BeaconConfig.getCustomDaemonCommand(); var custom = BeaconConfig.getCustomDaemonCommand();
if (custom != null) { if (custom != null) {
var command = custom + " " + (BeaconConfig.getDaemonArguments() != null ? var command =
BeaconConfig.getDaemonArguments() : custom + " " + (BeaconConfig.getDaemonArguments() != null ? BeaconConfig.getDaemonArguments() : "");
"");
Process process = Runtime.getRuntime().exec(command); Process process = Runtime.getRuntime().exec(command);
printDaemonOutput(process, command); printDaemonOutput(process, command);
return process; return process;
@ -47,9 +46,8 @@ public class BeaconServer {
public static Process tryStart() throws Exception { public static Process tryStart() throws Exception {
var daemonExecutable = getDaemonExecutable(); var daemonExecutable = getDaemonExecutable();
if (daemonExecutable.isPresent()) { if (daemonExecutable.isPresent()) {
var command = "\"" + daemonExecutable.get() + "\" --external " + (BeaconConfig.getDaemonArguments() != null ? var command = "\"" + daemonExecutable.get() + "\" --external "
BeaconConfig.getDaemonArguments() : + (BeaconConfig.getDaemonArguments() != null ? BeaconConfig.getDaemonArguments() : "");
"");
// Tell daemon that we launched from an external tool // Tell daemon that we launched from an external tool
Process process = Runtime.getRuntime().exec(command); Process process = Runtime.getRuntime().exec(command);
printDaemonOutput(process, command); printDaemonOutput(process, command);
@ -65,35 +63,43 @@ public class BeaconServer {
System.out.println("Starting daemon: " + command); System.out.println("Starting daemon: " + command);
} }
new Thread(null, () -> { new Thread(
try { null,
InputStreamReader isr = new InputStreamReader(proc.getInputStream()); () -> {
BufferedReader br = new BufferedReader(isr); try {
String line; InputStreamReader isr = new InputStreamReader(proc.getInputStream());
while ((line = br.readLine()) != null) { BufferedReader br = new BufferedReader(isr);
if (print) { String line;
System.out.println("[xpiped] " + line); while ((line = br.readLine()) != null) {
} if (print) {
} System.out.println("[xpiped] " + line);
} catch (Exception ioe) { }
ioe.printStackTrace(); }
} } catch (Exception ioe) {
}, "daemon sysout").start(); ioe.printStackTrace();
}
},
"daemon sysout")
.start();
new Thread(null, () -> { new Thread(
try { null,
InputStreamReader isr = new InputStreamReader(proc.getErrorStream()); () -> {
BufferedReader br = new BufferedReader(isr); try {
String line; InputStreamReader isr = new InputStreamReader(proc.getErrorStream());
while ((line = br.readLine()) != null) { BufferedReader br = new BufferedReader(isr);
if (print) { String line;
System.err.println("[xpiped] " + line); while ((line = br.readLine()) != null) {
} if (print) {
} System.err.println("[xpiped] " + line);
} catch (Exception ioe) { }
ioe.printStackTrace(); }
} } catch (Exception ioe) {
}, "daemon syserr").start(); ioe.printStackTrace();
}
},
"daemon syserr")
.start();
} }
public static boolean tryStop(BeaconClient client) throws Exception { public static boolean tryStop(BeaconClient client) throws Exception {
@ -111,7 +117,6 @@ public class BeaconServer {
} catch (Exception ex) { } catch (Exception ex) {
} }
if (base == null) { if (base == null) {
if (System.getProperty("os.name").startsWith("Windows")) { if (System.getProperty("os.name").startsWith("Windows")) {
base = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe"); base = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe");

View file

@ -5,8 +5,7 @@ package io.xpipe.beacon;
*/ */
public class ClientException extends Exception { public class ClientException extends Exception {
public ClientException() { public ClientException() {}
}
public ClientException(String message) { public ClientException(String message) {
super(message); super(message);

View file

@ -5,8 +5,7 @@ package io.xpipe.beacon;
*/ */
public class ConnectorException extends Exception { public class ConnectorException extends Exception {
public ConnectorException() { public ConnectorException() {}
}
public ConnectorException(String message) { public ConnectorException(String message) {
super(message); super(message);

View file

@ -1,5 +1,3 @@
package io.xpipe.beacon; package io.xpipe.beacon;
public interface RequestMessage { public interface RequestMessage {}
}

View file

@ -1,5 +1,3 @@
package io.xpipe.beacon; package io.xpipe.beacon;
public interface ResponseMessage { public interface ResponseMessage {}
}

View file

@ -5,8 +5,7 @@ package io.xpipe.beacon;
*/ */
public class ServerException extends Exception { public class ServerException extends Exception {
public ServerException() { public ServerException() {}
}
public ServerException(String message) { public ServerException(String message) {
super(message); super(message);

View file

@ -21,7 +21,9 @@ public class AddSourceExchange implements MessageExchange {
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
DataSourceId target; DataSourceId target;
@NonNull DataSource<?> source;
@NonNull
DataSource<?> source;
} }
@Jacksonized @Jacksonized

View file

@ -31,6 +31,5 @@ public class ForwardExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -15,7 +15,8 @@ public class MessageExchanges {
private static void loadAll() { private static void loadAll() {
if (ALL == null) { if (ALL == null) {
ALL = ServiceLoader.load(MessageExchange.class).stream() 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) { public static <RQ extends RequestMessage> Optional<MessageExchange> byRequest(RQ req) {
loadAll(); 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) { public static <RP extends ResponseMessage> Optional<MessageExchange> byResponse(RP rep) {
loadAll(); 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() { public static Set<MessageExchange> getAll() {

View file

@ -37,14 +37,18 @@ public class QueryDataSourceExchange implements MessageExchange {
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@NonNull @NonNull
DataSourceId id; DataSourceId id;
boolean disabled; boolean disabled;
boolean hidden; boolean hidden;
@NonNull @NonNull
DataSourceInfo info; DataSourceInfo info;
@NonNull @NonNull
String storeDisplay; String storeDisplay;
String provider; String provider;
@NonNull @NonNull
Map<String, String> config; Map<String, String> config;

View file

@ -32,6 +32,5 @@ public class ReadExecuteExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -19,8 +19,7 @@ public class StopExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -20,8 +20,7 @@ public class StoreStreamExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.api; package io.xpipe.beacon.exchange.api;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -29,6 +29,5 @@ public class QueryRawDataExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.api; package io.xpipe.beacon.exchange.api;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -32,6 +32,5 @@ public class QueryTableDataExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.api; package io.xpipe.beacon.exchange.api;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -30,6 +30,5 @@ public class QueryTextDataExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.dialog.DialogReference; import io.xpipe.core.dialog.DialogReference;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.dialog.DialogElement; import io.xpipe.core.dialog.DialogElement;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -34,6 +34,7 @@ public class DialogExchange implements MessageExchange {
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
@NonNull @NonNull
UUID dialogKey; UUID dialogKey;
String value; String value;
boolean cancel; boolean cancel;
} }

View file

@ -28,6 +28,7 @@ public class EditStoreExchange implements MessageExchange {
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@NonNull DialogReference dialog; @NonNull
DialogReference dialog;
} }
} }

View file

@ -19,9 +19,7 @@ public class InstanceExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,9 +1,9 @@
package io.xpipe.beacon.exchange.cli; 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.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.exchange.data.CollectionListEntry;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
@ -20,9 +20,7 @@ public class ListCollectionsExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,9 +1,9 @@
package io.xpipe.beacon.exchange.cli; 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.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.exchange.data.EntryListEntry;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;

View file

@ -1,9 +1,9 @@
package io.xpipe.beacon.exchange.cli; 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.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.exchange.data.StoreListEntry;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
@ -20,9 +20,7 @@ public class ListStoresExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -26,7 +26,5 @@ public class ModeExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -26,6 +26,5 @@ public class RemoveCollectionExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -28,6 +28,5 @@ public class RemoveStoreExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -21,6 +21,7 @@ public class RenameCollectionExchange implements MessageExchange {
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
@NonNull @NonNull
String collectionName; String collectionName;
@NonNull @NonNull
String newName; String newName;
} }
@ -28,6 +29,5 @@ public class RenameCollectionExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
@ -32,6 +32,7 @@ public class RenameEntryExchange implements MessageExchange {
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@NonNull DataSourceId newId; @NonNull
DataSourceId newId;
} }
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
import lombok.Value; import lombok.Value;
@ -21,6 +21,7 @@ public class RenameStoreExchange implements MessageExchange {
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
@NonNull @NonNull
String storeName; String storeName;
@NonNull @NonNull
String newName; String newName;
} }
@ -28,6 +29,5 @@ public class RenameStoreExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -27,6 +27,5 @@ public class SelectExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -1,9 +1,9 @@
package io.xpipe.beacon.exchange.cli; 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.RequestMessage;
import io.xpipe.beacon.ResponseMessage; 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 io.xpipe.core.source.DataSourceType;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -23,13 +23,13 @@ public class SourceProviderListExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@NonNull Map<DataSourceType, List<ProviderEntry>> entries; @NonNull
Map<DataSourceType, List<ProviderEntry>> entries;
} }
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
@ -17,8 +17,7 @@ public class StatusExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.dialog.DialogReference; import io.xpipe.core.dialog.DialogReference;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import lombok.Builder; import lombok.Builder;

View file

@ -21,13 +21,13 @@ public class StoreProviderListExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@NonNull List<ProviderEntry> entries; @NonNull
List<ProviderEntry> entries;
} }
} }

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
@ -17,9 +17,7 @@ public class VersionExchange implements MessageExchange {
@lombok.extern.jackson.Jacksonized @lombok.extern.jackson.Jacksonized
@lombok.Builder @lombok.Builder
@lombok.Value @lombok.Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {}
}
@Jacksonized @Jacksonized
@Builder @Builder

View file

@ -1,8 +1,8 @@
package io.xpipe.beacon.exchange.cli; package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull; import lombok.NonNull;
@ -35,6 +35,5 @@ public class WriteExecuteExchange implements MessageExchange {
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {}
}
} }

View file

@ -26,8 +26,10 @@ public class WritePreparationExchange implements MessageExchange {
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
String type; String type;
@NonNull @NonNull
DataStore output; DataStore output;
@NonNull @NonNull
DataSourceReference source; DataSourceReference source;
} }

View file

@ -1,5 +1,7 @@
import io.xpipe.beacon.exchange.*; 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.*; import io.xpipe.beacon.exchange.cli.*;
module io.xpipe.beacon { module io.xpipe.beacon {
@ -21,6 +23,7 @@ module io.xpipe.beacon {
requires static lombok; requires static lombok;
uses MessageExchange; uses MessageExchange;
provides io.xpipe.beacon.exchange.MessageExchange with provides io.xpipe.beacon.exchange.MessageExchange with
ForwardExchange, ForwardExchange,
InstanceExchange, InstanceExchange,

View file

@ -13,7 +13,7 @@ compileJava {
options.compilerArgs << '-parameters' options.compilerArgs << '-parameters'
} }
dependencies{ dependencies {
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.13.0" api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.13.0"
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: "2.13.0" implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: "2.13.0"
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.13.0" implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.13.0"

View file

@ -4,7 +4,10 @@ import io.xpipe.core.store.FileStore;
import io.xpipe.core.store.StreamDataStore; import io.xpipe.core.store.StreamDataStore;
import lombok.Value; 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.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.charset.*; import java.nio.charset.*;
@ -15,8 +18,12 @@ import java.util.Map;
public abstract class Charsetter { public abstract class Charsetter {
private static final int MAX_BYTES = 8192;
public static Charsetter INSTANCE;
private static CharsetterUniverse universe; private static CharsetterUniverse universe;
protected Charsetter() {}
protected static void checkInit() { protected static void checkInit() {
if (universe == null) { if (universe == null) {
throw new IllegalStateException("Charsetter not initialized"); throw new IllegalStateException("Charsetter not initialized");
@ -27,30 +34,25 @@ public abstract class Charsetter {
universe = CharsetterUniverse.create(ctx); universe = CharsetterUniverse.create(ctx);
} }
@Value
public static class Result {
StreamCharset charset;
NewLine newLine;
}
protected Charsetter() {
}
public static Charsetter INSTANCE;
public static Charsetter get() { public static Charsetter get() {
return INSTANCE; return INSTANCE;
} }
@FunctionalInterface private static int count(byte[] outerArray, byte[] smallerArray) {
public interface FailableSupplier<R, E extends Throwable> { int count = 0;
R get() throws E; for (int i = 0; i < outerArray.length - smallerArray.length + 1; ++i) {
} boolean found = true;
for (int j = 0; j < smallerArray.length; ++j) {
@FunctionalInterface if (outerArray[i + j] != smallerArray[j]) {
public interface FailableConsumer<T, E extends Throwable> { found = false;
break;
void accept(T var1) throws E; }
}
if (found) {
count++;
}
}
return count;
} }
public BufferedReader reader(StreamDataStore store, StreamCharset charset) throws Exception { 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())); return new BufferedReader(new InputStreamReader(stream, charset.getCharset()));
} }
public abstract Result read(FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con) throws Exception; public abstract Result read(
FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con)
private static final int MAX_BYTES = 8192; throws Exception;
public Result detect(StreamDataStore store) throws Exception { public Result detect(StreamDataStore store) throws Exception {
Result result = new Result(null, null); Result result = new Result(null, null);
if (store.canOpen()) { if (store.canOpen()) {
try (InputStream inputStream = store.openBufferedInput()) { try (InputStream inputStream = store.openBufferedInput()) {
StreamCharset detected = null; StreamCharset detected = null;
for (var charset : StreamCharset.COMMON) { for (var charset : StreamCharset.COMMON) {
@ -135,25 +136,10 @@ public abstract class Charsetter {
return null; return null;
} }
return count.entrySet().stream().min(Comparator.comparingInt(Map.Entry::getValue)) return count.entrySet().stream()
.orElseThrow().getKey(); .min(Comparator.comparingInt(Map.Entry::getValue))
} .orElseThrow()
.getKey();
private static int count(byte[] outerArray, byte[] smallerArray) {
int count = 0;
for (int i = 0; i < outerArray.length - smallerArray.length + 1; ++i) {
boolean found = true;
for (int j = 0; j < smallerArray.length; ++j) {
if (outerArray[i + j] != smallerArray[j]) {
found = false;
break;
}
}
if (found) {
count++;
}
}
return count;
} }
public Charset inferCharset(byte[] content) { public Charset inferCharset(byte[] content) {
@ -179,4 +165,21 @@ public abstract class Charsetter {
return StandardCharsets.UTF_8; 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;
}
} }

View file

@ -11,15 +11,13 @@ import java.util.Locale;
@AllArgsConstructor @AllArgsConstructor
public class CharsetterContext { public class CharsetterContext {
public static CharsetterContext empty() {
return new CharsetterContext(Charset.defaultCharset().name(), Locale.getDefault(), Locale.getDefault(), List.of());
}
String systemCharsetName; String systemCharsetName;
Locale systemLocale; Locale systemLocale;
Locale appLocale; Locale appLocale;
List<String> observedCharsets; List<String> observedCharsets;
public static CharsetterContext empty() {
return new CharsetterContext(
Charset.defaultCharset().name(), Locale.getDefault(), Locale.getDefault(), List.of());
}
} }

View file

@ -5,24 +5,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays; import java.util.Arrays;
public enum NewLine { public enum NewLine {
@JsonProperty("lf") @JsonProperty("lf")
LF("\n", "lf"), LF("\n", "lf"),
@JsonProperty("crlf") @JsonProperty("crlf")
CRLF("\r\n", "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 newLine;
private final String id; private final String id;
@ -31,6 +18,20 @@ public enum NewLine {
this.id = id; 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() { public String getNewLine() {
return newLine; return newLine;
} }

View file

@ -13,10 +13,42 @@ import java.util.stream.Stream;
@Value @Value
public class StreamCharset { 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) { public static StreamCharset get(Charset charset, boolean byteOrderMark) {
return Stream.concat(COMMON.stream(), RARE.stream()) return Stream.concat(COMMON.stream(), RARE.stream())
.filter(streamCharset -> streamCharset.getCharset() .filter(streamCharset ->
.equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark) streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
.findFirst() .findFirst()
.orElseThrow(); .orElseThrow();
} }
@ -24,66 +56,15 @@ public class StreamCharset {
@JsonCreator @JsonCreator
public static StreamCharset get(String s) { public static StreamCharset get(String s) {
var byteOrderMark = s.endsWith("-bom"); var byteOrderMark = s.endsWith("-bom");
var charset = Charset.forName(s.substring( var charset = Charset.forName(s.substring(0, s.length() - (byteOrderMark ? 4 : 0)));
0, s.length() - (byteOrderMark ?
4 :
0)));
return StreamCharset.get(charset, byteOrderMark); return StreamCharset.get(charset, byteOrderMark);
} }
Charset charset;
byte[] byteOrderMark;
@JsonValue @JsonValue
public String toString() { public String toString() {
return getCharset() return getCharset().name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ? "-bom" : "");
.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() { public boolean hasByteOrderMark() {
return byteOrderMark != null; return byteOrderMark != null;
} }

View file

@ -1,7 +1,7 @@
package io.xpipe.core.data.generic; 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.ArrayNode;
import io.xpipe.core.data.node.DataStructureNode;
import io.xpipe.core.data.node.ValueNode; import io.xpipe.core.data.node.ValueNode;
import java.util.ArrayList; import java.util.ArrayList;
@ -16,8 +16,8 @@ public class GenericArrayReader implements GenericAbstractReader {
private int currentIndex = 0; private int currentIndex = 0;
private GenericAbstractReader currentReader; private GenericAbstractReader currentReader;
private DataStructureNode created; private DataStructureNode created;
public GenericArrayReader() {
} public GenericArrayReader() {}
public static GenericArrayReader newReader(int length) { public static GenericArrayReader newReader(int length) {
var ar = new GenericArrayReader(); var ar = new GenericArrayReader();

View file

@ -4,22 +4,15 @@ import java.util.Map;
public interface GenericDataStreamCallback { 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) {
}
} }

View file

@ -86,7 +86,6 @@ public class GenericDataStructureNodeReader implements GenericDataStreamCallback
return; return;
} }
node = ValueNode.of(value).tag(metaAttributes); node = ValueNode.of(value).tag(metaAttributes);
} }
} }

View file

@ -18,8 +18,8 @@ public class GenericTupleReader implements GenericAbstractReader {
private int currentIndex = 0; private int currentIndex = 0;
private GenericAbstractReader currentReader; private GenericAbstractReader currentReader;
private DataStructureNode created; private DataStructureNode created;
public GenericTupleReader() {
} public GenericTupleReader() {}
public static GenericTupleReader newReader(int length) { public static GenericTupleReader newReader(int length) {
var tr = new GenericTupleReader(); var tr = new GenericTupleReader();

View file

@ -8,6 +8,8 @@ import java.util.stream.Collectors;
public abstract class ArrayNode extends DataStructureNode { public abstract class ArrayNode extends DataStructureNode {
protected ArrayNode() {}
public static ArrayNode empty() { public static ArrayNode empty() {
return of(List.of()); return of(List.of());
} }
@ -20,9 +22,6 @@ public abstract class ArrayNode extends DataStructureNode {
return new SimpleArrayNode(nodes); return new SimpleArrayNode(nodes);
} }
protected ArrayNode() {
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -32,7 +31,8 @@ public abstract class ArrayNode extends DataStructureNode {
return false; 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 // Useful for debugging
if (toReturn == false) { if (toReturn == false) {
@ -64,6 +64,7 @@ public abstract class ArrayNode extends DataStructureNode {
@Override @Override
public final ArrayType determineDataType() { public final ArrayType determineDataType() {
return ArrayType.ofSharedType(getNodes().stream().map(DataStructureNode::determineDataType).toList()); return ArrayType.ofSharedType(
getNodes().stream().map(DataStructureNode::determineDataType).toList());
} }
} }

View file

@ -67,7 +67,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
return this; return this;
} }
public String getMetaAttribute(Integer key) { public String getMetaAttribute(Integer key) {
if (metaAttributes == null) { if (metaAttributes == null) {
return null; return null;
@ -104,9 +103,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
throw unsupported("get nodes"); throw unsupported("get nodes");
} }
public record KeyValue(String key, DataStructureNode value) {
}
protected abstract String getName(); protected abstract String getName();
protected UnsupportedOperationException unsupported(String s) { protected UnsupportedOperationException unsupported(String s) {
@ -125,12 +121,15 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
} }
public String metaToString() { public String metaToString() {
return "(" + (metaAttributes != null ? return "("
metaAttributes.entrySet() + (metaAttributes != null
.stream() ? metaAttributes.entrySet().stream()
.map(e -> e.getValue() != null ? e.getKey() + ":" + e.getValue() : e.getKey().toString()) .map(e -> e.getValue() != null
.collect(Collectors.joining("|")) : ? e.getKey() + ":" + e.getValue()
"") + ")"; : e.getKey().toString())
.collect(Collectors.joining("|"))
: "")
+ ")";
} }
public abstract String toString(int indent); public abstract String toString(int indent);
@ -146,11 +145,11 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
public boolean isValue() { public boolean isValue() {
return false; return false;
} }
public DataStructureNode set(int index, DataStructureNode node) { public DataStructureNode set(int index, DataStructureNode node) {
throw unsupported("set at index"); throw unsupported("set at index");
} }
public final ValueNode asValue() { public final ValueNode asValue() {
if (!isValue()) { if (!isValue()) {
throw new UnsupportedOperationException(getName() + " is not a value node"); throw new UnsupportedOperationException(getName() + " is not a value node");
@ -235,4 +234,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
public Iterator<DataStructureNode> iterator() { public Iterator<DataStructureNode> iterator() {
throw unsupported("iterator creation"); throw unsupported("iterator creation");
} }
public record KeyValue(String key, DataStructureNode value) {}
} }

View file

@ -152,9 +152,7 @@ public class DataStructureNodePointer {
@Override @Override
public DataStructureNode tryMatch(DataStructureNode n) { public DataStructureNode tryMatch(DataStructureNode n) {
var res = n.stream() var res = n.stream().filter(selector).findAny();
.filter(selector)
.findAny();
return res.orElse(null); return res.orElse(null);
} }
@ -184,7 +182,6 @@ public class DataStructureNodePointer {
return new Builder(new ArrayList<>(path)); return new Builder(new ArrayList<>(path));
} }
public Builder name(String name) { public Builder name(String name) {
path.add(new NameElement(name)); path.add(new NameElement(name));
return this; 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) -> { path.add(new FunctionElement((current) -> {
var res = pointer.get(current); var res = pointer.get(current);
if (res != null) { if (res != null) {

View file

@ -84,7 +84,9 @@ public class LinkedTupleNode extends TupleNode {
@Override @Override
public DataType determineDataType() { public DataType determineDataType() {
return TupleType.of(getKeyNames(), getNodes().stream().map(DataStructureNode::determineDataType).toList()); return TupleType.of(
getKeyNames(),
getNodes().stream().map(DataStructureNode::determineDataType).toList());
} }
@Override @Override
@ -142,7 +144,6 @@ public class LinkedTupleNode extends TupleNode {
return "LinkedTupleNode(" + size() + ")"; return "LinkedTupleNode(" + size() + ")";
} }
@Override @Override
public int size() { public int size() {
return tupleNodes.stream().mapToInt(TupleNode::size).sum(); return tupleNodes.stream().mapToInt(TupleNode::size).sum();
@ -174,6 +175,7 @@ public class LinkedTupleNode extends TupleNode {
return this; 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());
} }
} }

View file

@ -10,8 +10,6 @@ import java.util.function.Consumer;
import java.util.stream.Stream; import java.util.stream.Stream;
@AllArgsConstructor @AllArgsConstructor
public class SimpleArrayNode extends ArrayNode { public class SimpleArrayNode extends ArrayNode {
List<DataStructureNode> nodes; List<DataStructureNode> nodes;
@ -79,6 +77,4 @@ public class SimpleArrayNode extends ArrayNode {
nodes.remove(index); nodes.remove(index);
return this; return this;
} }
} }

View file

@ -23,8 +23,11 @@ public class SimpleValueNode extends ValueNode {
@Override @Override
public String toString(int indent) { public String toString(int indent) {
var string = getRawData().length == 0 && !hasMetaAttribute(IS_TEXT) ? "<null>" : new String(getRawData(), StandardCharsets.UTF_8); var string = getRawData().length == 0 && !hasMetaAttribute(IS_TEXT)
return (hasMetaAttribute(IS_TEXT) ? "\"" : "") + string + (hasMetaAttribute(IS_TEXT) ? "\"" : "") + " " + metaToString(); ? "<null>"
: new String(getRawData(), StandardCharsets.UTF_8);
return (hasMetaAttribute(IS_TEXT) ? "\"" : "") + string + (hasMetaAttribute(IS_TEXT) ? "\"" : "") + " "
+ metaToString();
} }
@Override @Override

View file

@ -5,7 +5,6 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public abstract class TupleNode extends DataStructureNode { public abstract class TupleNode extends DataStructureNode {
public static Builder builder() { public static Builder builder() {
@ -46,13 +45,15 @@ public abstract class TupleNode extends DataStructureNode {
public String toString(int indent) { public String toString(int indent) {
var is = " ".repeat(indent); var is = " ".repeat(indent);
var start = "{\n"; var start = "{\n";
var kvs = getKeyValuePairs().stream().map(kv -> { var kvs = getKeyValuePairs().stream()
if (kv.key() == null) { .map(kv -> {
return is + " " + kv.value().toString(indent + 1) + "\n"; if (kv.key() == null) {
} else { return is + " " + kv.value().toString(indent + 1) + "\n";
return is + " " + kv.key() + "=" + 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 + "}"; var end = is + "}";
return start + kvs + end; return start + kvs + end;
} }
@ -65,8 +66,9 @@ public abstract class TupleNode extends DataStructureNode {
if (!(o instanceof TupleNode that)) { if (!(o instanceof TupleNode that)) {
return false; return false;
} }
var toReturn = getKeyNames().equals(that.getKeyNames()) && getNodes().equals(that.getNodes()) && var toReturn = getKeyNames().equals(that.getKeyNames())
Objects.equals(getMetaAttributes(), that.getMetaAttributes()); && getNodes().equals(that.getNodes())
&& Objects.equals(getMetaAttributes(), that.getMetaAttributes());
// Useful for debugging // Useful for debugging
if (toReturn == false) { if (toReturn == false) {
@ -98,11 +100,11 @@ public abstract class TupleNode extends DataStructureNode {
public TupleNode build() { public TupleNode build() {
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null); boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
return hasKeys ? TupleNode.of( return hasKeys
entries.stream().map(KeyValue::key).toList(), ? TupleNode.of(
entries.stream().map(KeyValue::value).toList() entries.stream().map(KeyValue::key).toList(),
) : entries.stream().map(KeyValue::value).toList())
TupleNode.of(entries.stream().map(KeyValue::value).toList()); : TupleNode.of(entries.stream().map(KeyValue::value).toList());
} }
} }
} }

View file

@ -11,32 +11,7 @@ import java.util.Objects;
public abstract class ValueNode extends DataStructureNode { public abstract class ValueNode extends DataStructureNode {
protected ValueNode() {}
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());
}
public static ValueNode nullValue() { public static ValueNode nullValue() {
return new SimpleValueNode(new byte[0]).tag(IS_NULL).asValue(); 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); created.tag(IS_FLOATING_POINT);
return created; return created;
} }
public static ValueNode ofBoolean(Boolean bool) { public static ValueNode ofBoolean(Boolean bool) {
var created = of(bool); var created = of(bool);
created.tag(IS_BOOLEAN); created.tag(IS_BOOLEAN);
@ -93,6 +69,30 @@ public abstract class ValueNode extends DataStructureNode {
return of(o.toString().getBytes(StandardCharsets.UTF_8)); 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 @Override
public final int asInt() { public final int asInt() {
return Integer.parseInt(asString()); return Integer.parseInt(asString());
@ -114,5 +114,4 @@ public abstract class ValueNode extends DataStructureNode {
} }
public abstract byte[] getRawData(); public abstract byte[] getRawData();
} }

View file

@ -2,15 +2,11 @@ package io.xpipe.core.data.type;
public interface DataTypeVisitor { 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) {}
}
} }

View file

@ -41,9 +41,7 @@ public class DataTypeVisitors {
* Creates a visitor that allows for visiting possible recursive columns of table. * Creates a visitor that allows for visiting possible recursive columns of table.
*/ */
public static DataTypeVisitor table( public static DataTypeVisitor table(
Consumer<String> newTuple, Consumer<String> newTuple, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) {
Runnable endTuple,
BiConsumer<String, DataStructureNodePointer> newValue) {
return new DataTypeVisitor() { return new DataTypeVisitor() {
private final Stack<TupleType> tuples = new Stack<>(); private final Stack<TupleType> tuples = new Stack<>();
private final Stack<Integer> keyIndices = new Stack<>(); private final Stack<Integer> keyIndices = new Stack<>();

View file

@ -17,6 +17,8 @@ import java.util.Optional;
@Value @Value
public class WildcardType extends DataType { public class WildcardType extends DataType {
private WildcardType() {}
/** /**
* Creates a new instance. * Creates a new instance.
*/ */
@ -24,8 +26,6 @@ public class WildcardType extends DataType {
return new WildcardType(); return new WildcardType();
} }
private WildcardType() {}
@Override @Override
public String getName() { public String getName() {
return "wildcard"; return "wildcard";

View file

@ -7,27 +7,19 @@ import java.util.Map;
public interface TypedDataStreamCallback { 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() {}
}
} }

View file

@ -1,9 +1,9 @@
package io.xpipe.core.data.typed; 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.GenericDataStreamParser;
import io.xpipe.core.data.generic.GenericDataStructureNodeReader; 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.ArrayType;
import io.xpipe.core.data.type.DataType; import io.xpipe.core.data.type.DataType;
import io.xpipe.core.data.type.TupleType; import io.xpipe.core.data.type.TupleType;
@ -21,7 +21,7 @@ public class TypedDataStreamParser {
this.dataType = dataType; this.dataType = dataType;
} }
private boolean hasNext(InputStream in) throws IOException { private boolean hasNext(InputStream in) throws IOException {
var b = in.read(); var b = in.read();
if (b == -1) { if (b == -1) {
return false; return false;
@ -34,7 +34,8 @@ public class TypedDataStreamParser {
return true; 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)) { while (hasNext(in)) {
cb.onNodeBegin(); cb.onNodeBegin();
parse(in, cb, dataType); parse(in, cb, dataType);

View file

@ -12,20 +12,13 @@ import java.util.Stack;
public class TypedDataStructureNodeReader implements TypedAbstractReader { 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<List<DataStructureNode>> children;
private final Stack<DataStructureNode> nodes; private final Stack<DataStructureNode> nodes;
private int arrayDepth;
private final List<DataType> flattened; private final List<DataType> flattened;
private DataStructureNode readNode;
private int arrayDepth;
private DataType expectedType; private DataType expectedType;
private int currentExpectedTypeIndex; private int currentExpectedTypeIndex;
private TypedDataStructureNodeReader(DataType type) { private TypedDataStructureNodeReader(DataType type) {
flattened = new ArrayList<>(); flattened = new ArrayList<>();
type.visit(DataTypeVisitors.flatten(flattened::add)); type.visit(DataTypeVisitors.flatten(flattened::add));
@ -34,6 +27,10 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
expectedType = flattened.get(0); expectedType = flattened.get(0);
} }
public static TypedDataStructureNodeReader of(DataType type) {
return new TypedDataStructureNodeReader(type);
}
@Override @Override
public void onNodeBegin() { public void onNodeBegin() {
if (nodes.size() != 0 || children.size() != 0) { if (nodes.size() != 0 || children.size() != 0) {
@ -134,7 +131,8 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
private void moveExpectedType(boolean force) { private void moveExpectedType(boolean force) {
if (!isInArray() || force) { if (!isInArray() || force) {
currentExpectedTypeIndex++; currentExpectedTypeIndex++;
expectedType = currentExpectedTypeIndex == flattened.size() ? null : flattened.get(currentExpectedTypeIndex); expectedType =
currentExpectedTypeIndex == flattened.size() ? null : flattened.get(currentExpectedTypeIndex);
} }
} }

View file

@ -20,7 +20,8 @@ public class BaseQueryElement extends DialogElement {
protected String value; protected String value;
@JsonCreator @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.description = description;
this.newLine = newLine; this.newLine = newLine;
this.required = required; this.required = required;

View file

@ -18,6 +18,18 @@ public class ChoiceElement extends DialogElement {
private int selected; 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 @Override
public boolean requiresExplicitUserInput() { public boolean requiresExplicitUserInput() {
return required && selected == -1; return required && selected == -1;
@ -42,7 +54,8 @@ public class ChoiceElement extends DialogElement {
} }
for (int i = 0; i < elements.size(); i++) { 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; selected = i;
return true; return true;
} }
@ -59,18 +72,6 @@ public class ChoiceElement extends DialogElement {
return false; 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() { public List<Choice> getElements() {
return elements; return elements;
} }

View file

@ -2,7 +2,9 @@ package io.xpipe.core.dialog;
import io.xpipe.core.util.SecretValue; 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.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -24,6 +26,10 @@ import java.util.function.Supplier;
*/ */
public abstract class Dialog { 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. * 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. * 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 required signals whether a choice is required or can be left empty
* @param selected the selected element index * @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); Dialog.Choice c = new Dialog.Choice(description, elements, required, selected);
c.evaluateTo(c::getSelected); c.evaluateTo(c::getSelected);
return c; return c;
@ -94,8 +74,11 @@ public abstract class Dialog {
* @param vals the range of possible elements * @param vals the range of possible elements
*/ */
@SafeVarargs @SafeVarargs
public static <T> Dialog.Choice choice(String description, Function<T, String> toString, boolean required, T def, T... vals) { public static <T> Dialog.Choice choice(
var elements = Arrays.stream(vals).map(v -> new io.xpipe.core.dialog.Choice(null, toString.apply(v))).toList(); 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); var index = Arrays.asList(vals).indexOf(def);
if (def != null && index == -1) { if (def != null && index == -1) {
throw new IllegalArgumentException("Default value " + def.toString() + " is not in possible values"); throw new IllegalArgumentException("Default value " + def.toString() + " is not in possible values");
@ -111,38 +94,6 @@ public abstract class Dialog {
return c; 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. * Creates a simple query dialogue.
* *
@ -155,7 +106,13 @@ public abstract class Dialog {
* @param value the default value * @param value the default value
* @param converter the converter * @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); var q = new <T>Dialog.Query(description, newLine, required, quiet, value, converter, false);
q.evaluateTo(q::getConvertedValue); q.evaluateTo(q::getConvertedValue);
return q; return q;
@ -201,8 +158,7 @@ public abstract class Dialog {
DialogElement currentElement = ds[current].receive(answer); DialogElement currentElement = ds[current].receive(answer);
if (currentElement == null) { if (currentElement == null) {
DialogElement next = 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; return next;
} }
@ -218,7 +174,6 @@ public abstract class Dialog {
public static <T> Dialog repeatIf(Dialog d, Predicate<T> shouldRepeat) { public static <T> Dialog repeatIf(Dialog d, Predicate<T> shouldRepeat) {
return new Dialog() { return new Dialog() {
@Override @Override
public DialogElement start() throws Exception { public DialogElement start() throws Exception {
eval = null; eval = null;
@ -272,11 +227,6 @@ public abstract class Dialog {
return of(new BusyElement()); return of(new BusyElement());
} }
public static interface FailableSupplier<T> {
T get() throws Exception;
}
/** /**
* Creates a dialogue that will only evaluate when needed. * Creates a dialogue that will only evaluate when needed.
* This allows a dialogue to incorporate completion information about a previous dialogue. * 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) { private static Dialog of(DialogElement e) {
return new Dialog() { return new Dialog() {
@Override @Override
public DialogElement start() throws Exception { public DialogElement start() throws Exception {
eval = null; eval = null;
@ -323,7 +272,6 @@ public abstract class Dialog {
}; };
} }
/** /**
* Creates a dialogue that will not be executed if the condition is true. * 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 selected the index of the element that is selected by default
* @param c the dialogue index mapping function * @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); var choice = new ChoiceElement(description, elements, required, selected);
return new Dialog() { return new Dialog() {
@ -427,13 +380,9 @@ public abstract class Dialog {
}; };
} }
protected Object eval;
private Supplier<?> evaluation;
private final List<Consumer<?>> completion = new ArrayList<>();
/* TODO: Implement automatic completion mechanism for start as well /* TODO: Implement automatic completion mechanism for start as well
* In case start returns null, the completion is not automatically done. * In case start returns null, the completion is not automatically done.
* */ * */
public abstract DialogElement start() throws Exception; public abstract DialogElement start() throws Exception;
public Dialog evaluateTo(Dialog d) { public Dialog evaluateTo(Dialog d) {
@ -493,4 +442,75 @@ public abstract class Dialog {
} }
protected abstract DialogElement next(String answer) throws Exception; 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();
}
}
} }

View file

@ -5,8 +5,7 @@ package io.xpipe.core.dialog;
*/ */
public class DialogCancelException extends Exception { public class DialogCancelException extends Exception {
public DialogCancelException() { public DialogCancelException() {}
}
public DialogCancelException(String message) { public DialogCancelException(String message) {
super(message); super(message);
@ -20,7 +19,8 @@ public class DialogCancelException extends Exception {
super(cause); 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); super(message, cause, enableSuppression, writableStackTrace);
} }
} }

View file

@ -23,7 +23,6 @@ public abstract class QueryConverter<T> {
} }
}; };
public static final QueryConverter<StreamCharset> CHARSET = new QueryConverter<StreamCharset>() { public static final QueryConverter<StreamCharset> CHARSET = new QueryConverter<StreamCharset>() {
@Override @Override
protected StreamCharset fromString(String s) { protected StreamCharset fromString(String s) {
@ -60,26 +59,27 @@ public abstract class QueryConverter<T> {
} }
}; };
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER = new QueryConverter<Map.Entry<String, String>>() { public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER =
@Override new QueryConverter<Map.Entry<String, String>>() {
protected Map.Entry<String, String> fromString(String s) { @Override
if (!s.contains(":")) { protected Map.Entry<String, String> fromString(String s) {
throw new IllegalArgumentException("Missing colon"); if (!s.contains(":")) {
} throw new IllegalArgumentException("Missing colon");
}
var split = s.split(":"); var split = s.split(":");
if (split.length != 2) { if (split.length != 2) {
throw new IllegalArgumentException("Too many colons"); throw new IllegalArgumentException("Too many colons");
} }
return new AbstractMap.SimpleEntry<>(split[0].trim(), split[1].trim()); return new AbstractMap.SimpleEntry<>(split[0].trim(), split[1].trim());
} }
@Override @Override
protected String toString(Map.Entry<String, String> value) { protected String toString(Map.Entry<String, String> value) {
return value.getKey() + ": " + value.getValue(); return value.getKey() + ": " + value.getValue();
} }
}; };
public static final QueryConverter<URI> URI = new QueryConverter<URI>() { public static final QueryConverter<URI> URI = new QueryConverter<URI>() {
@Override @Override
@ -141,9 +141,7 @@ public abstract class QueryConverter<T> {
@Override @Override
protected String toString(Boolean value) { protected String toString(Boolean value) {
return value ? return value ? "yes" : "no";
"yes" :
"no";
} }
}; };

View file

@ -7,7 +7,14 @@ public class QueryElement extends BaseQueryElement {
private final QueryConverter<?> converter; 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); super(description, newLine, required, hidden, quiet, value != null ? converter.toString(value) : null);
this.converter = converter; this.converter = converter;
} }

View file

@ -50,5 +50,3 @@ public abstract class BatchTableWriteConnection implements TableWriteConnection
protected abstract DataStructureNodeAcceptor<ArrayNode> writeBatchLinesAcceptor(); protected abstract DataStructureNodeAcceptor<ArrayNode> writeBatchLinesAcceptor();
} }

View file

@ -37,7 +37,6 @@ public class BinarySource extends RawDataSource<StreamDataStore> {
}; };
} }
@Override @Override
protected RawReadConnection newReadConnection() { protected RawReadConnection newReadConnection() {
return new RawReadConnection() { return new RawReadConnection() {

View file

@ -48,8 +48,7 @@ public class LimitTableReadConnection implements TableReadConnection {
} }
count++; count++;
var returned = lineAcceptor var returned = lineAcceptor.accept(node);
.accept(node);
localCounter.getAndIncrement(); localCounter.getAndIncrement();
return returned; return returned;

View file

@ -9,14 +9,12 @@ import io.xpipe.core.source.TableWriteConnection;
public class PreservingTableWriteConnection extends PreservingWriteConnection implements TableWriteConnection { public class PreservingTableWriteConnection extends PreservingWriteConnection implements TableWriteConnection {
public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection, public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) {
boolean append
) {
super(DataSourceType.TABLE, source, append, connection); super(DataSourceType.TABLE, source, append, connection);
} }
@Override @Override
public DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor() { public DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor() {
return ((TableWriteConnection)connection).writeLinesAcceptor(); return ((TableWriteConnection) connection).writeLinesAcceptor();
} }
} }

View file

@ -7,10 +7,7 @@ import io.xpipe.core.source.TextWriteConnection;
public class PreservingTextWriteConnection extends PreservingWriteConnection implements TextWriteConnection { public class PreservingTextWriteConnection extends PreservingWriteConnection implements TextWriteConnection {
public PreservingTextWriteConnection( public PreservingTextWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) {
DataSource<?> source, DataSourceConnection connection,
boolean append
) {
super(DataSourceType.TEXT, source, append, connection); super(DataSourceType.TEXT, source, append, connection);
} }

View file

@ -9,12 +9,13 @@ import java.nio.file.Files;
public class PreservingWriteConnection implements DataSourceConnection { public class PreservingWriteConnection implements DataSourceConnection {
protected final DataSourceConnection connection;
private final DataSourceType type; private final DataSourceType type;
private final DataSource<?> source; private final DataSource<?> source;
private final boolean append ; 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.type = type;
this.source = source; this.source = source;
this.append = append; this.append = append;
@ -26,13 +27,13 @@ public class PreservingWriteConnection implements DataSourceConnection {
var nativeStore = FileStore.local(temp); var nativeStore = FileStore.local(temp);
var nativeSource = DataSource.createInternalDataSource(type, nativeStore); var nativeSource = DataSource.createInternalDataSource(type, nativeStore);
if (source.getStore().canOpen()) { 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); in.forward(out);
} }
; ;
} }
connection.init(); connection.init();
if (source.getStore().canOpen()) { if (source.getStore().canOpen()) {
@ -45,5 +46,4 @@ public class PreservingWriteConnection implements DataSourceConnection {
public void close() throws Exception { public void close() throws Exception {
connection.close(); connection.close();
} }
} }

View file

@ -24,7 +24,6 @@ public class TextReadConnection extends StreamReadConnection implements io.xpipe
return bufferedReader.lines(); return bufferedReader.lines();
} }
@Override @Override
public void close() throws Exception { public void close() throws Exception {
bufferedReader.close(); bufferedReader.close();

View file

@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized;
@JsonTypeName("text") @JsonTypeName("text")
@SuperBuilder @SuperBuilder
@Jacksonized @Jacksonized
public final class TextSource extends TextDataSource<StreamDataStore> implements Charsettable { public final class TextSource extends TextDataSource<StreamDataStore> implements Charsettable {
private final StreamCharset charset; private final StreamCharset charset;
private final NewLine newLine; private final NewLine newLine;

View file

@ -13,6 +13,6 @@ public class XpbsWriteConnection extends StreamWriteConnection implements Struct
@Override @Override
public void write(DataStructureNode node) throws Exception { public void write(DataStructureNode node) throws Exception {
GenericDataStreamWriter.writeStructure(outputStream,node); GenericDataStreamWriter.writeStructure(outputStream, node);
} }
} }

View file

@ -21,6 +21,15 @@ import java.util.concurrent.atomic.AtomicReference;
public class XpbtReadConnection implements TableReadConnection { 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 @Override
public void init() throws Exception { public void init() throws Exception {
this.inputStream = store.openBufferedInput(); this.inputStream = store.openBufferedInput();
@ -36,8 +45,8 @@ public class XpbtReadConnection implements TableReadConnection {
this.inputStream.skip(headerLength + 1); this.inputStream.skip(headerLength + 1);
List<String> names = JacksonMapper.newMapper() List<String> names = JacksonMapper.newMapper()
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE) .disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
.readerFor(new TypeReference<List<String>>() { .readerFor(new TypeReference<List<String>>() {})
}).readValue(header); .readValue(header);
TupleType dataType = TupleType.tableType(names); TupleType dataType = TupleType.tableType(names);
this.dataType = dataType; this.dataType = dataType;
this.parser = new TypedDataStreamParser(dataType); this.parser = new TypedDataStreamParser(dataType);
@ -48,16 +57,6 @@ public class XpbtReadConnection implements TableReadConnection {
inputStream.close(); 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 @Override
public TupleType getDataType() { public TupleType getDataType() {
return dataType; return dataType;

View file

@ -13,8 +13,6 @@ import lombok.extern.jackson.Jacksonized;
@Jacksonized @Jacksonized
public class XpbtSource extends TableDataSource<StreamDataStore> { public class XpbtSource extends TableDataSource<StreamDataStore> {
@Override @Override
protected TableWriteConnection newWriteConnection() { protected TableWriteConnection newWriteConnection() {
return new XpbtWriteConnection(store); return new XpbtWriteConnection(store);

View file

@ -58,7 +58,8 @@ public class XpbtWriteConnection implements TableWriteConnection {
try (JsonGenerator g = f.createGenerator(writer) try (JsonGenerator g = f.createGenerator(writer)
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET) .disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
.setPrettyPrinter(new DefaultPrettyPrinter())) { .setPrettyPrinter(new DefaultPrettyPrinter())) {
JacksonMapper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET) JacksonMapper.newMapper()
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
.writeValue(g, tupleNode.getKeyNames()); .writeValue(g, tupleNode.getKeyNames());
writer.append("\n"); writer.append("\n");
} }

View file

@ -14,9 +14,9 @@ public interface CollectionReadConnection extends DataSourceReadConnection {
try (var tCon = (CollectionWriteConnection) con) { try (var tCon = (CollectionWriteConnection) con) {
tCon.init(); tCon.init();
listEntries().forEach(s -> { listEntries().forEach(s -> {
// try (var subCon = open(s)) { // try (var subCon = open(s)) {
// ((CollectionWriteConnection) con).write(s, subCon); // ((CollectionWriteConnection) con).write(s, subCon);
// } // }
}); });
} }
} }

View file

@ -22,22 +22,23 @@ import java.util.Optional;
* This instance is only valid in combination with its associated data store instance. * This instance is only valid in combination with its associated data store instance.
*/ */
@SuperBuilder @SuperBuilder
@JsonTypeInfo( @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public abstract class DataSource<DS extends DataStore> extends JacksonizedValue { public abstract class DataSource<DS extends DataStore> extends JacksonizedValue {
protected DS store;
public static DataSource<?> createInternalDataSource(DataSourceType t, DataStore store) { public static DataSource<?> createInternalDataSource(DataSourceType t, DataStore store) {
try { try {
return switch (t) { return switch (t) {
case TABLE -> XpbtSource.builder().store(store.asNeeded()).build(); case TABLE -> XpbtSource.builder().store(store.asNeeded()).build();
case STRUCTURE -> null; case STRUCTURE -> null;
case TEXT -> TextSource.builder().store(store.asNeeded()).newLine(NewLine.LF).charset( case TEXT -> TextSource.builder()
StreamCharset.UTF8).build(); .store(store.asNeeded())
.newLine(NewLine.LF)
.charset(StreamCharset.UTF8)
.build();
case RAW -> null; case RAW -> null;
//TODO // TODO
case COLLECTION -> null; case COLLECTION -> null;
}; };
} catch (Exception ex) { } catch (Exception ex) {
@ -45,9 +46,6 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
} }
} }
protected DS store;
public void test() throws Exception { public void test() throws Exception {
store.validate(); store.validate();
} }
@ -68,7 +66,6 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
return WriteMode.values(); return WriteMode.values();
} }
public DataFlow getFlow() { public DataFlow getFlow() {
if (store == null) { if (store == null) {
return null; return null;

View file

@ -49,7 +49,8 @@ public class DataSourceId {
throw new IllegalArgumentException("Trimmed collection name is empty"); throw new IllegalArgumentException("Trimmed collection name is empty");
} }
if (collectionName != null && collectionName.contains("" + SEPARATOR)) { 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) { if (entryName == null) {
@ -59,7 +60,8 @@ public class DataSourceId {
throw new IllegalArgumentException("Trimmed entry name is empty"); throw new IllegalArgumentException("Trimmed entry name is empty");
} }
if (entryName.contains("" + SEPARATOR)) { 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); return new DataSourceId(collectionName, entryName);

Some files were not shown because too many files have changed in this diff Show more