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

View file

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

View file

@ -8,6 +8,8 @@ import java.util.Optional;
public final class XPipeConnection extends BeaconConnection {
private XPipeConnection() {}
public static XPipeConnection open() {
var con = new XPipeConnection();
con.constructSocket();
@ -23,7 +25,9 @@ public final class XPipeConnection extends BeaconConnection {
throw new IllegalStateException();
}
DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder().dialogKey(reference.getDialogId()).build());
DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder()
.dialogKey(reference.getDialogId())
.build());
element = response.getElement();
if (response.getElement() == null) {
break;
@ -58,40 +62,6 @@ public final class XPipeConnection extends BeaconConnection {
}
}
private XPipeConnection() {
}
@Override
protected void constructSocket() {
if (!BeaconServer.isRunning()) {
try {
start();
} catch (Exception ex) {
throw new BeaconException("Unable to start xpipe daemon", ex);
}
var r = waitForStartup(null);
if (r.isEmpty()) {
throw new BeaconException("Wait for xpipe daemon timed out");
} else {
beaconClient = r.get();
return;
}
}
try {
beaconClient = new BeaconClient();
} catch (Exception ex) {
throw new BeaconException("Unable to connect to running xpipe daemon", ex);
}
}
private void start() throws Exception {
if (BeaconServer.tryStart() == null) {
throw new UnsupportedOperationException("Unable to determine xpipe daemon launch command");
};
}
public static Optional<BeaconClient> waitForStartup(Process process) {
for (int i = 0; i < 160; i++) {
if (process != null && !process.isAlive()) {
@ -125,6 +95,38 @@ public final class XPipeConnection extends BeaconConnection {
}
}
@Override
protected void constructSocket() {
if (!BeaconServer.isRunning()) {
try {
start();
} catch (Exception ex) {
throw new BeaconException("Unable to start xpipe daemon", ex);
}
var r = waitForStartup(null);
if (r.isEmpty()) {
throw new BeaconException("Wait for xpipe daemon timed out");
} else {
beaconClient = r.get();
return;
}
}
try {
beaconClient = new BeaconClient();
} catch (Exception ex) {
throw new BeaconException("Unable to connect to running xpipe daemon", ex);
}
}
private void start() throws Exception {
if (BeaconServer.tryStart() == null) {
throw new UnsupportedOperationException("Unable to determine xpipe daemon launch command");
}
;
}
@FunctionalInterface
public static interface Handler {

View file

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

View file

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

View file

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

View file

@ -47,7 +47,11 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
connection.close();
var req = ReadExchange.Request.builder()
.target(id).store(res.getStore()).provider("xpbt").configureAll(false).build();
.target(id)
.store(res.getStore())
.provider("xpbt")
.configureAll(false)
.build();
ReadExchange.Response response = XPipeConnection.execute(con -> {
return con.performSimpleExchange(req);
});
@ -71,7 +75,9 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
@Override
public synchronized void add(DataStructureNode row) {
TupleNode toUse = type.matches(row) ? row.asTuple() : type.convert(row).orElseThrow().asTuple();
TupleNode toUse = type.matches(row)
? row.asTuple()
: type.convert(row).orElseThrow().asTuple();
connection.withOutputStream(out -> {
writeDescriptor();
TypedDataStreamWriter.writeStructure(out, toUse, writtenDescriptor);

View file

@ -27,7 +27,11 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
private final DataSourceInfo.Table info;
DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, DataSourceInfo.Table info, io.xpipe.core.source.DataSource<?> internalSource) {
DataTableImpl(
DataSourceId id,
DataSourceConfig sourceConfig,
DataSourceInfo.Table info,
io.xpipe.core.source.DataSource<?> internalSource) {
super(id, sourceConfig, internalSource);
this.info = info;
}
@ -44,8 +48,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
public Stream<TupleNode> stream() {
var iterator = new TableIterator();
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false).onClose(iterator::finish);
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
.onClose(iterator::finish);
}
@Override
@ -63,7 +67,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
List<DataStructureNode> nodes = new ArrayList<>();
XPipeConnection.execute(con -> {
var req = QueryTableDataExchange.Request.builder()
.ref(DataSourceReference.id(getId())).maxRows(maxRows).build();
.ref(DataSourceReference.id(getId()))
.maxRows(maxRows)
.build();
con.performInputExchange(req, (QueryTableDataExchange.Response res, InputStream in) -> {
var r = new TypedDataStreamParser(info.getDataType());
r.parseStructures(in, TypedDataStructureNodeReader.of(info.getDataType()), nodes::add);
@ -72,6 +78,12 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
return ArrayNode.of(nodes);
}
@Override
public Iterator<TupleNode> iterator() {
return new TableIterator();
}
;
private class TableIterator implements Iterator<TupleNode> {
private final BeaconConnection connection;
@ -85,7 +97,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
connection = XPipeConnection.open();
var req = QueryTableDataExchange.Request.builder()
.ref(DataSourceReference.id(getId())).maxRows(Integer.MAX_VALUE).build();
.ref(DataSourceReference.id(getId()))
.maxRows(Integer.MAX_VALUE)
.build();
connection.sendRequest(req);
connection.receiveResponse();
connection.receiveBody();
@ -116,10 +130,5 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
return node;
}
};
@Override
public Iterator<TupleNode> iterator() {
return new TableIterator();
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,8 @@ public class DataTableTest extends ApiTest {
@BeforeAll
public static void setupStorage() throws Exception {
DataSource.create(DataSourceId.fromString(":usernames"), "csv", DataTableTest.class.getResource("username.csv"));
DataSource.create(
DataSourceId.fromString(":usernames"), "csv", DataTableTest.class.getResource("username.csv"));
}
@Test

View file

@ -23,32 +23,6 @@ import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR;
public class BeaconClient implements AutoCloseable {
@FunctionalInterface
public interface FailableBiConsumer<T, U, E extends Throwable> {
void accept(T var1, U var2) throws E;
}
@FunctionalInterface
public interface FailableConsumer<T, E extends Throwable> {
void accept(T var1) throws E;
}
@FunctionalInterface
public interface FailableRunnable<E extends Throwable> {
void run() throws E;
}
public static Optional<BeaconClient> tryConnect() {
try {
return Optional.of(new BeaconClient());
} catch (IOException ex) {
return Optional.empty();
}
}
private final Closeable closeable;
private final InputStream in;
private final OutputStream out;
@ -66,6 +40,14 @@ public class BeaconClient implements AutoCloseable {
this.out = out;
}
public static Optional<BeaconClient> tryConnect() {
try {
return Optional.of(new BeaconClient());
} catch (IOException ex) {
return Optional.empty();
}
}
public void close() throws ConnectorException {
try {
closeable.close();
@ -109,7 +91,8 @@ public class BeaconClient implements AutoCloseable {
msg.set("xPipeMessage", json);
if (BeaconConfig.printMessages()) {
System.out.println("Sending request to server of type " + req.getClass().getName());
System.out.println(
"Sending request to server of type " + req.getClass().getName());
}
var writer = new StringWriter();
@ -226,4 +209,22 @@ public class BeaconClient implements AutoCloseable {
public OutputStream getRawOutputStream() {
return out;
}
@FunctionalInterface
public interface FailableBiConsumer<T, U, E extends Throwable> {
void accept(T var1, U var2) throws E;
}
@FunctionalInterface
public interface FailableConsumer<T, E extends Throwable> {
void accept(T var1) throws E;
}
@FunctionalInterface
public interface FailableRunnable<E extends Throwable> {
void run() throws E;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,3 @@
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 ServerException() {
}
public ServerException() {}
public ServerException(String message) {
super(message);

View file

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

View file

@ -31,6 +31,5 @@ public class ForwardExchange implements MessageExchange {
@Jacksonized
@Builder
@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() {
if (ALL == null) {
ALL = ServiceLoader.load(MessageExchange.class).stream()
.map(ServiceLoader.Provider::get).collect(Collectors.toSet());
.map(ServiceLoader.Provider::get)
.collect(Collectors.toSet());
}
}
@ -26,12 +27,16 @@ public class MessageExchanges {
public static <RQ extends RequestMessage> Optional<MessageExchange> byRequest(RQ req) {
loadAll();
return ALL.stream().filter(d -> d.getRequestClass().equals(req.getClass())).findAny();
return ALL.stream()
.filter(d -> d.getRequestClass().equals(req.getClass()))
.findAny();
}
public static <RP extends ResponseMessage> Optional<MessageExchange> byResponse(RP rep) {
loadAll();
return ALL.stream().filter(d -> d.getResponseClass().equals(rep.getClass())).findAny();
return ALL.stream()
.filter(d -> d.getResponseClass().equals(rep.getClass()))
.findAny();
}
public static Set<MessageExchange> getAll() {

View file

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

View file

@ -32,6 +32,5 @@ public class ReadExecuteExchange implements MessageExchange {
@Jacksonized
@Builder
@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
@Builder
@Value
public static class Request implements RequestMessage {
}
public static class Request implements RequestMessage {}
@Jacksonized
@Builder

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,9 @@
package io.xpipe.beacon.exchange.cli;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.exchange.data.EntryListEntry;
import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage;
import io.xpipe.beacon.exchange.MessageExchange;
import io.xpipe.beacon.exchange.data.EntryListEntry;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,7 @@
import io.xpipe.beacon.exchange.*;
import io.xpipe.beacon.exchange.api.*;
import io.xpipe.beacon.exchange.api.QueryRawDataExchange;
import io.xpipe.beacon.exchange.api.QueryTableDataExchange;
import io.xpipe.beacon.exchange.api.QueryTextDataExchange;
import io.xpipe.beacon.exchange.cli.*;
module io.xpipe.beacon {
@ -21,6 +23,7 @@ module io.xpipe.beacon {
requires static lombok;
uses MessageExchange;
provides io.xpipe.beacon.exchange.MessageExchange with
ForwardExchange,
InstanceExchange,

View file

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

View file

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

View file

@ -5,24 +5,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
public enum NewLine {
@JsonProperty("lf")
LF("\n", "lf"),
@JsonProperty("crlf")
CRLF("\r\n", "crlf");
public static NewLine platform() {
return Arrays.stream(values())
.filter(n -> n.getNewLine().equals(System.getProperty("line.separator")))
.findFirst().orElseThrow();
}
public static NewLine id(String id) {
return Arrays.stream(values())
.filter(n -> n.getId().equalsIgnoreCase(id))
.findFirst().orElseThrow();
}
private final String newLine;
private final String id;
@ -31,6 +18,20 @@ public enum NewLine {
this.id = id;
}
public static NewLine platform() {
return Arrays.stream(values())
.filter(n -> n.getNewLine().equals(System.getProperty("line.separator")))
.findFirst()
.orElseThrow();
}
public static NewLine id(String id) {
return Arrays.stream(values())
.filter(n -> n.getId().equalsIgnoreCase(id))
.findFirst()
.orElseThrow();
}
public String getNewLine() {
return newLine;
}

View file

@ -13,10 +13,42 @@ import java.util.stream.Stream;
@Value
public class StreamCharset {
public static final StreamCharset UTF8 = new StreamCharset(StandardCharsets.UTF_8, null);
public static final StreamCharset UTF8_BOM =
new StreamCharset(StandardCharsets.UTF_8, new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
public static final StreamCharset UTF16 = new StreamCharset(StandardCharsets.UTF_16, null);
public static final StreamCharset UTF16_BOM =
new StreamCharset(StandardCharsets.UTF_16, new byte[] {(byte) 0xFE, (byte) 0xFF});
public static final StreamCharset UTF16_LE = new StreamCharset(StandardCharsets.UTF_16LE, null);
public static final StreamCharset UTF16_LE_BOM =
new StreamCharset(StandardCharsets.UTF_16LE, new byte[] {(byte) 0xFF, (byte) 0xFE});
public static final StreamCharset UTF32 = new StreamCharset(Charset.forName("utf-32"), null);
public static final StreamCharset UTF32_BOM =
new StreamCharset(Charset.forName("utf-32"), new byte[] {0x00, 0x00, (byte) 0xFE, (byte) 0xFF});
public static final List<StreamCharset> COMMON = List.of(
UTF8,
UTF8_BOM,
UTF16,
UTF16_BOM,
UTF16_LE,
UTF16_LE_BOM,
UTF32,
UTF32_BOM,
new StreamCharset(StandardCharsets.US_ASCII, null),
new StreamCharset(StandardCharsets.ISO_8859_1, null),
new StreamCharset(Charset.forName("Windows-1251"), null),
new StreamCharset(Charset.forName("Windows-1252"), null));
public static final List<StreamCharset> RARE = Charset.availableCharsets().values().stream()
.filter(charset -> COMMON.stream().noneMatch(c -> c.getCharset().equals(charset)))
.map(charset -> new StreamCharset(charset, null))
.toList();
Charset charset;
byte[] byteOrderMark;
public static StreamCharset get(Charset charset, boolean byteOrderMark) {
return Stream.concat(COMMON.stream(), RARE.stream())
.filter(streamCharset -> streamCharset.getCharset()
.equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
.filter(streamCharset ->
streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
.findFirst()
.orElseThrow();
}
@ -24,66 +56,15 @@ public class StreamCharset {
@JsonCreator
public static StreamCharset get(String s) {
var byteOrderMark = s.endsWith("-bom");
var charset = Charset.forName(s.substring(
0, s.length() - (byteOrderMark ?
4 :
0)));
var charset = Charset.forName(s.substring(0, s.length() - (byteOrderMark ? 4 : 0)));
return StreamCharset.get(charset, byteOrderMark);
}
Charset charset;
byte[] byteOrderMark;
@JsonValue
public String toString() {
return getCharset()
.name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ?
"-bom" :
"");
return getCharset().name().toLowerCase(Locale.ROOT) + (hasByteOrderMark() ? "-bom" : "");
}
public static final StreamCharset UTF8 = new StreamCharset(StandardCharsets.UTF_8, null);
public static final StreamCharset UTF8_BOM = new StreamCharset(StandardCharsets.UTF_8, new byte[]{
(byte) 0xEF,
(byte) 0xBB,
(byte) 0xBF
});
public static final StreamCharset UTF16 = new StreamCharset(StandardCharsets.UTF_16, null);
public static final StreamCharset UTF16_BOM = new StreamCharset(StandardCharsets.UTF_16, new byte[]{
(byte) 0xFE,
(byte) 0xFF
});
public static final StreamCharset UTF16_LE = new StreamCharset(StandardCharsets.UTF_16LE, null);
public static final StreamCharset UTF16_LE_BOM = new StreamCharset(StandardCharsets.UTF_16LE, new byte[]{
(byte) 0xFF,
(byte) 0xFE
});
public static final StreamCharset UTF32 = new StreamCharset(Charset.forName("utf-32"), null);
public static final StreamCharset UTF32_BOM = new StreamCharset(Charset.forName("utf-32"), new byte[]{
0x00,
0x00,
(byte) 0xFE,
(byte) 0xFF
});
public static final List<StreamCharset> COMMON = List.of(
UTF8, UTF8_BOM, UTF16, UTF16_BOM, UTF16_LE, UTF16_LE_BOM, UTF32, UTF32_BOM, new StreamCharset(StandardCharsets.US_ASCII, null),
new StreamCharset(StandardCharsets.ISO_8859_1, null),
new StreamCharset(Charset.forName("Windows-1251"), null), new StreamCharset(Charset.forName("Windows-1252"), null)
);
public static final List<StreamCharset> RARE = Charset.availableCharsets()
.values()
.stream()
.filter(charset -> COMMON.stream()
.noneMatch(c -> c.getCharset()
.equals(charset)))
.map(charset -> new StreamCharset(charset, null))
.toList();
public boolean hasByteOrderMark() {
return byteOrderMark != null;
}

View file

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

View file

@ -4,22 +4,15 @@ import java.util.Map;
public interface GenericDataStreamCallback {
default void onName(String name) {
}
default void onName(String name) {}
default void onArrayStart(int length) {
}
default void onArrayStart(int length) {}
default void onArrayEnd(Map<Integer, String> metaAttributes) {
}
default void onArrayEnd(Map<Integer, String> metaAttributes) {}
default void onTupleStart(int length) {
}
default void onTupleStart(int length) {}
default void onTupleEnd(Map<Integer, String> metaAttributes) {
}
default void onTupleEnd(Map<Integer, String> metaAttributes) {}
default void onValue(byte[] value, Map<Integer, String> metaAttributes) {
}
default void onValue(byte[] value, Map<Integer, String> metaAttributes) {}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,32 +11,7 @@ import java.util.Objects;
public abstract class ValueNode extends DataStructureNode {
protected ValueNode() {
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ValueNode that)) {
return false;
}
var toReturn = Arrays.equals(getRawData(), that.getRawData()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
// Useful for debugging
if (toReturn == false) {
return false;
}
return toReturn;
}
@Override
public int hashCode() {
return Arrays.hashCode(getRawData()) + Objects.hash(getMetaAttributes());
}
protected ValueNode() {}
public static ValueNode nullValue() {
return new SimpleValueNode(new byte[0]).tag(IS_NULL).asValue();
@ -79,6 +54,7 @@ public abstract class ValueNode extends DataStructureNode {
created.tag(IS_FLOATING_POINT);
return created;
}
public static ValueNode ofBoolean(Boolean bool) {
var created = of(bool);
created.tag(IS_BOOLEAN);
@ -93,6 +69,30 @@ public abstract class ValueNode extends DataStructureNode {
return of(o.toString().getBytes(StandardCharsets.UTF_8));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ValueNode that)) {
return false;
}
var toReturn = Arrays.equals(getRawData(), that.getRawData())
&& Objects.equals(getMetaAttributes(), that.getMetaAttributes());
// Useful for debugging
if (toReturn == false) {
return false;
}
return toReturn;
}
@Override
public int hashCode() {
return Arrays.hashCode(getRawData()) + Objects.hash(getMetaAttributes());
}
@Override
public final int asInt() {
return Integer.parseInt(asString());
@ -114,5 +114,4 @@ public abstract class ValueNode extends DataStructureNode {
}
public abstract byte[] getRawData();
}

View file

@ -2,15 +2,11 @@ package io.xpipe.core.data.type;
public interface DataTypeVisitor {
default void onValue(ValueType type) {
}
default void onValue(ValueType type) {}
default void onTuple(TupleType type) {
}
default void onTuple(TupleType type) {}
default void onArray(ArrayType type) {
}
default void onArray(ArrayType type) {}
default void onWildcard(WildcardType type) {
}
default void onWildcard(WildcardType type) {}
}

View file

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

View file

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

View file

@ -7,27 +7,19 @@ import java.util.Map;
public interface TypedDataStreamCallback {
default void onValue(byte[] data, Map<Integer, String> metaAttributes) {
}
default void onValue(byte[] data, Map<Integer, String> metaAttributes) {}
default void onGenericNode(DataStructureNode node) {
}
default void onGenericNode(DataStructureNode node) {}
default void onTupleBegin(TupleType type) {
}
default void onTupleBegin(TupleType type) {}
default void onTupleEnd(Map<Integer, String> metaAttributes) {
}
default void onTupleEnd(Map<Integer, String> metaAttributes) {}
default void onArrayBegin(int size) {
}
default void onArrayBegin(int size) {}
default void onArrayEnd(Map<Integer, String> metaAttributes) {
}
default void onArrayEnd(Map<Integer, String> metaAttributes) {}
default void onNodeBegin() {
}
default void onNodeBegin() {}
default void onNodeEnd() {
}
default void onNodeEnd() {}
}

View file

@ -1,9 +1,9 @@
package io.xpipe.core.data.typed;
import io.xpipe.core.data.node.DataStructureNode;
import io.xpipe.core.data.node.DataStructureNodeIO;
import io.xpipe.core.data.generic.GenericDataStreamParser;
import io.xpipe.core.data.generic.GenericDataStructureNodeReader;
import io.xpipe.core.data.node.DataStructureNode;
import io.xpipe.core.data.node.DataStructureNodeIO;
import io.xpipe.core.data.type.ArrayType;
import io.xpipe.core.data.type.DataType;
import io.xpipe.core.data.type.TupleType;
@ -34,7 +34,8 @@ public class TypedDataStreamParser {
return true;
}
public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer) throws IOException {
public void parseStructures(InputStream in, TypedAbstractReader cb, Consumer<DataStructureNode> consumer)
throws IOException {
while (hasNext(in)) {
cb.onNodeBegin();
parse(in, cb, dataType);

View file

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

View file

@ -20,7 +20,8 @@ public class BaseQueryElement extends DialogElement {
protected String value;
@JsonCreator
public BaseQueryElement(String description, boolean newLine, boolean required, boolean secret, boolean quiet, String value) {
public BaseQueryElement(
String description, boolean newLine, boolean required, boolean secret, boolean quiet, String value) {
this.description = description;
this.newLine = newLine;
this.required = required;

View file

@ -18,6 +18,18 @@ public class ChoiceElement extends DialogElement {
private int selected;
@JsonCreator
public ChoiceElement(String description, List<Choice> elements, boolean required, int selected) {
if (elements.stream().allMatch(Choice::isDisabled)) {
throw new IllegalArgumentException("All choices are disabled");
}
this.description = description;
this.elements = elements;
this.required = required;
this.selected = selected;
}
@Override
public boolean requiresExplicitUserInput() {
return required && selected == -1;
@ -42,7 +54,8 @@ public class ChoiceElement extends DialogElement {
}
for (int i = 0; i < elements.size(); i++) {
if (elements.get(i).getCharacter() != null && elements.get(i).getCharacter().equals(c)) {
if (elements.get(i).getCharacter() != null
&& elements.get(i).getCharacter().equals(c)) {
selected = i;
return true;
}
@ -59,18 +72,6 @@ public class ChoiceElement extends DialogElement {
return false;
}
@JsonCreator
public ChoiceElement(String description, List<Choice> elements, boolean required, int selected) {
if (elements.stream().allMatch(Choice::isDisabled)) {
throw new IllegalArgumentException("All choices are disabled");
}
this.description = description;
this.elements = elements;
this.required = required;
this.selected = selected;
}
public List<Choice> getElements() {
return elements;
}

View file

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

View file

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

View file

@ -23,7 +23,6 @@ public abstract class QueryConverter<T> {
}
};
public static final QueryConverter<StreamCharset> CHARSET = new QueryConverter<StreamCharset>() {
@Override
protected StreamCharset fromString(String s) {
@ -60,7 +59,8 @@ public abstract class QueryConverter<T> {
}
};
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER = new QueryConverter<Map.Entry<String, String>>() {
public static final QueryConverter<Map.Entry<String, String>> HTTP_HEADER =
new QueryConverter<Map.Entry<String, String>>() {
@Override
protected Map.Entry<String, String> fromString(String s) {
if (!s.contains(":")) {
@ -141,9 +141,7 @@ public abstract class QueryConverter<T> {
@Override
protected String toString(Boolean value) {
return value ?
"yes" :
"no";
return value ? "yes" : "no";
}
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -49,7 +49,8 @@ public class DataSourceId {
throw new IllegalArgumentException("Trimmed collection name is empty");
}
if (collectionName != null && collectionName.contains("" + SEPARATOR)) {
throw new IllegalArgumentException("Separator character " + SEPARATOR + " is not allowed in the collection name");
throw new IllegalArgumentException(
"Separator character " + SEPARATOR + " is not allowed in the collection name");
}
if (entryName == null) {
@ -59,7 +60,8 @@ public class DataSourceId {
throw new IllegalArgumentException("Trimmed entry name is empty");
}
if (entryName.contains("" + SEPARATOR)) {
throw new IllegalArgumentException("Separator character " + SEPARATOR + " is not allowed in the entry name");
throw new IllegalArgumentException(
"Separator character " + SEPARATOR + " is not allowed in the entry name");
}
return new DataSourceId(collectionName, entryName);

View file

@ -23,6 +23,61 @@ public abstract class DataSourceInfo {
public abstract DataSourceType getType();
/**
* Casts this instance to a table info.
*/
public Table asTable() {
if (!getType().equals(DataSourceType.TABLE)) {
throw new IllegalStateException("Not a table");
}
return (Table) this;
}
/**
* Casts this instance to a structure info.
*/
public Structure asStructure() {
if (!getType().equals(DataSourceType.STRUCTURE)) {
throw new IllegalStateException("Not a structure");
}
return (Structure) this;
}
/**
* Casts this instance to a text info.
*/
public Text asText() {
if (!getType().equals(DataSourceType.TEXT)) {
throw new IllegalStateException("Not a text");
}
return (Text) this;
}
/**
* Casts this instance to a raw info.
*/
public Raw asRaw() {
if (!getType().equals(DataSourceType.RAW)) {
throw new IllegalStateException("Not raw");
}
return (Raw) this;
}
/**
* Casts this instance to a collection info.
*/
public Collection asCollection() {
if (!getType().equals(DataSourceType.COLLECTION)) {
throw new IllegalStateException("Not a collection");
}
return (Collection) this;
}
@EqualsAndHashCode(callSuper = false)
@Value
@JsonTypeName("table")
@ -101,7 +156,6 @@ public abstract class DataSourceInfo {
}
}
@EqualsAndHashCode(callSuper = false)
@Value
@JsonTypeName("raw")
@ -118,59 +172,4 @@ public abstract class DataSourceInfo {
return DataSourceType.RAW;
}
}
/**
* Casts this instance to a table info.
*/
public Table asTable() {
if (!getType().equals(DataSourceType.TABLE)) {
throw new IllegalStateException("Not a table");
}
return (Table) this;
}
/**
* Casts this instance to a structure info.
*/
public Structure asStructure() {
if (!getType().equals(DataSourceType.STRUCTURE)) {
throw new IllegalStateException("Not a structure");
}
return (Structure) this;
}
/**
* Casts this instance to a text info.
*/
public Text asText() {
if (!getType().equals(DataSourceType.TEXT)) {
throw new IllegalStateException("Not a text");
}
return (Text) this;
}
/**
* Casts this instance to a raw info.
*/
public Raw asRaw() {
if (!getType().equals(DataSourceType.RAW)) {
throw new IllegalStateException("Not raw");
}
return (Raw) this;
}
/**
* Casts this instance to a collection info.
*/
public Collection asCollection() {
if (!getType().equals(DataSourceType.COLLECTION)) {
throw new IllegalStateException("Not a collection");
}
return (Collection) this;
}
}

View file

@ -65,14 +65,10 @@ public interface DataSourceReference {
return new Name(s.trim());
}
enum Type {
ID,
NAME,
LATEST
}
Type getType();
DataSourceId getId();
String getName();
/**
@ -82,6 +78,12 @@ public interface DataSourceReference {
String toString();
enum Type {
ID,
NAME,
LATEST
}
/**
* A wrapper class for {@link DataSourceId} instances.
*/

View file

@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* This distinction is necessary as the general workflow differs for each type.
*/
public enum DataSourceType {
@JsonProperty("table")
TABLE,

View file

@ -4,10 +4,10 @@ import java.io.OutputStream;
public interface RawReadConnection extends DataSourceReadConnection {
byte[] readBytes(int max) throws Exception;
int BUFFER_SIZE = 8192;
byte[] readBytes(int max) throws Exception;
default void forwardBytes(OutputStream out, int maxBytes) throws Exception {
if (maxBytes == 0) {
return;

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