This commit is contained in:
Christopher Schnick 2022-12-30 12:54:40 +01:00
parent 8b5f2bf44e
commit 990bea4f59
117 changed files with 724 additions and 493 deletions

View file

@ -15,10 +15,10 @@ import java.nio.file.Path;
/** /**
* Represents a reference to a data source that is managed by X-Pipe. * Represents a reference to a data source that is managed by X-Pipe.
* * <p>
* The actual data is only queried when required and is not cached. * The actual data is only queried when required and is not cached.
* Therefore, the queried data is always up-to-date at the point of calling a method that queries the data. * Therefore, the queried data is always up-to-date at the point of calling a method that queries the data.
* * <p>
* As soon a data source reference is created, the data source is locked * As soon a data source reference is created, the data source is locked
* within X-Pipe to prevent concurrent modification and the problems that can arise from it. * within X-Pipe to prevent concurrent modification and the problems that can arise from it.
* By default, the lock is held until the calling program terminates and prevents * By default, the lock is held until the calling program terminates and prevents
@ -29,14 +29,14 @@ public interface DataSource {
/** /**
* NOT YET IMPLEMENTED! * NOT YET IMPLEMENTED!
* * <p>
* Creates a new supplier data source that will be interpreted as the generated data source. * Creates a new supplier data source that will be interpreted as the generated data source.
* In case this program should be a data source generator, this method has to be called at * In case this program should be a data source generator, this method has to be called at
* least once to register that it actually generates a data source. * least once to register that it actually generates a data source.
* * <p>
* All content that is written to this data source until the generator program terminates is * All content that is written to this data source until the generator program terminates is
* will be available later on when the data source is used as a supplier later on. * will be available later on when the data source is used as a supplier later on.
* * <p>
* In case this method is called multiple times, the same data source is returned. * In case this method is called multiple times, the same data source is returned.
* *
* @return the generator data source * @return the generator data source
@ -132,9 +132,9 @@ public interface DataSource {
/** /**
* Creates a new data source from an input stream. * Creates a new data source from an input stream.
* *
* @param id the data source id * @param id the data source id
* @param type the data source type * @param type the data source type
* @param in the input stream to read * @param in the input stream to read
* @return a {@link DataSource} instances that can be used to access the underlying data * @return a {@link DataSource} instances that can be used to access the underlying data
*/ */
public static DataSource create(DataSourceId id, String type, InputStream in) { public static DataSource create(DataSourceId id, String type, InputStream in) {
@ -153,10 +153,11 @@ public interface DataSource {
/** /**
* Creates a new data source from an input stream. * Creates a new data source from an input stream.
*1 * 1
* @param id the data source id *
* @param id the data source id
* @param type the data source type * @param type the data source type
* @param in the data store to add * @param in the data store to add
* @return a {@link DataSource} instances that can be used to access the underlying data * @return a {@link DataSource} instances that can be used to access the underlying data
*/ */
public static DataSource create(DataSourceId id, String type, DataStore in) { public static DataSource create(DataSourceId id, String type, DataStore in) {

View file

@ -1,8 +1,8 @@
package io.xpipe.api; package io.xpipe.api;
import io.xpipe.api.connector.XPipeApiConnection; import io.xpipe.api.connector.XPipeApiConnection;
import io.xpipe.beacon.util.QuietDialogHandler;
import io.xpipe.beacon.exchange.cli.StoreAddExchange; import io.xpipe.beacon.exchange.cli.StoreAddExchange;
import io.xpipe.beacon.util.QuietDialogHandler;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import java.util.Map; import java.util.Map;

View file

@ -8,7 +8,7 @@ import io.xpipe.core.source.DataSourceId;
/** /**
* An accumulator for table data. * An accumulator for table data.
* * <p>
* This class can be used to construct new table data sources by * This class can be used to construct new table data sources by
* accumulating the rows using {@link #add(DataStructureNode)} or {@link #acceptor()} and then calling * accumulating the rows using {@link #add(DataStructureNode)} or {@link #acceptor()} and then calling
* {@link #finish(DataSourceId)} to complete the construction process and create a new data source. * {@link #finish(DataSourceId)} to complete the construction process and create a new data source.

View file

@ -12,7 +12,8 @@ import java.util.Optional;
public final class XPipeApiConnection extends BeaconConnection { public final class XPipeApiConnection extends BeaconConnection {
private XPipeApiConnection() {} private XPipeApiConnection() {
}
public static XPipeApiConnection open() { public static XPipeApiConnection open() {
var con = new XPipeApiConnection(); var con = new XPipeApiConnection();
@ -30,8 +31,8 @@ public final class XPipeApiConnection extends BeaconConnection {
} }
DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder() DialogExchange.Response response = con.performSimpleExchange(DialogExchange.Request.builder()
.dialogKey(reference.getDialogId()) .dialogKey(reference.getDialogId())
.build()); .build());
element = response.getElement(); element = response.getElement();
if (response.getElement() == null) { if (response.getElement() == null) {
break; break;
@ -78,9 +79,9 @@ public final class XPipeApiConnection extends BeaconConnection {
} }
var s = BeaconClient.tryConnect(BeaconClient.ApiClientInformation.builder() var s = BeaconClient.tryConnect(BeaconClient.ApiClientInformation.builder()
.version("?") .version("?")
.language("Java") .language("Java")
.build()); .build());
if (s.isPresent()) { if (s.isPresent()) {
return s; return s;
} }
@ -122,9 +123,9 @@ public final class XPipeApiConnection extends BeaconConnection {
try { try {
beaconClient = BeaconClient.connect(BeaconClient.ApiClientInformation.builder() beaconClient = BeaconClient.connect(BeaconClient.ApiClientInformation.builder()
.version("?") .version("?")
.language("Java") .language("Java")
.build()); .build());
} catch (Exception ex) { } catch (Exception ex) {
throw new BeaconException("Unable to connect to running xpipe daemon", ex); throw new BeaconException("Unable to connect to running xpipe daemon", ex);
} }

View file

@ -12,7 +12,8 @@ public class DataRawImpl extends DataSourceImpl implements DataRaw {
public DataRawImpl( public DataRawImpl(
DataSourceId sourceId, DataSourceId sourceId,
DataSourceConfig sourceConfig, DataSourceConfig sourceConfig,
io.xpipe.core.source.DataSource<?> internalSource) { io.xpipe.core.source.DataSource<?> internalSource
) {
super(sourceId, sourceConfig, internalSource); super(sourceId, sourceConfig, internalSource);
} }

View file

@ -18,7 +18,8 @@ public abstract class DataSourceImpl implements DataSource {
private final io.xpipe.core.source.DataSource<?> internalSource; private final io.xpipe.core.source.DataSource<?> internalSource;
public DataSourceImpl( public DataSourceImpl(
DataSourceId sourceId, DataSourceConfig config, io.xpipe.core.source.DataSource<?> internalSource) { DataSourceId sourceId, DataSourceConfig config, io.xpipe.core.source.DataSource<?> internalSource
) {
this.sourceId = sourceId; this.sourceId = sourceId;
this.config = config; this.config = config;
this.internalSource = internalSource; this.internalSource = internalSource;

View file

@ -11,7 +11,8 @@ public class DataStructureImpl extends DataSourceImpl implements DataStructure {
DataStructureImpl( DataStructureImpl(
DataSourceId sourceId, DataSourceId sourceId,
DataSourceConfig sourceConfig, DataSourceConfig sourceConfig,
io.xpipe.core.source.DataSource<?> internalSource) { io.xpipe.core.source.DataSource<?> internalSource
) {
super(sourceId, sourceConfig, internalSource); super(sourceId, sourceConfig, internalSource);
} }

View file

@ -27,7 +27,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
DataTableImpl( DataTableImpl(
DataSourceId id, DataSourceId id,
DataSourceConfig sourceConfig, DataSourceConfig sourceConfig,
io.xpipe.core.source.DataSource<?> internalSource) { io.xpipe.core.source.DataSource<?> internalSource
) {
super(id, sourceConfig, internalSource); super(id, sourceConfig, internalSource);
} }
@ -73,6 +74,7 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
public Iterator<TupleNode> iterator() { public Iterator<TupleNode> iterator() {
return new TableIterator(); return new TableIterator();
} }
; ;
private class TableIterator implements Iterator<TupleNode> { private class TableIterator implements Iterator<TupleNode> {

View file

@ -24,10 +24,11 @@ import java.util.stream.StreamSupport;
public class DataTextImpl extends DataSourceImpl implements DataText { public class DataTextImpl extends DataSourceImpl implements DataText {
DataTextImpl( DataTextImpl(
DataSourceId sourceId, DataSourceId sourceId,
DataSourceConfig sourceConfig, DataSourceConfig sourceConfig,
io.xpipe.core.source.DataSource<?> internalSource) { io.xpipe.core.source.DataSource<?> internalSource
) {
super(sourceId, sourceConfig, internalSource); super(sourceId, sourceConfig, internalSource);
} }

View file

@ -5,11 +5,9 @@ import io.xpipe.core.data.node.TupleNode;
import io.xpipe.core.data.node.ValueNode; import io.xpipe.core.data.node.ValueNode;
import io.xpipe.core.data.type.TupleType; import io.xpipe.core.data.type.TupleType;
import io.xpipe.core.data.type.ValueType; import io.xpipe.core.data.type.ValueType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
import java.util.OptionalInt;
public class DataTableAccumulatorTest extends ApiTest { public class DataTableAccumulatorTest extends ApiTest {

View file

@ -33,78 +33,8 @@ import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR;
public class BeaconClient implements AutoCloseable { public class BeaconClient implements AutoCloseable {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public abstract static class ClientInformation {
public final CliClientInformation cli() {
return (CliClientInformation) this;
}
public abstract String toDisplayString();
}
@JsonTypeName("cli")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class CliClientInformation extends ClientInformation {
int consoleWidth;
@Override
public String toDisplayString() {
return "X-Pipe CLI";
}
}
@JsonTypeName("reachableCheck")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class ReachableCheckInformation extends ClientInformation {
@Override
public String toDisplayString() {
return "Reachable check";
}
}
@JsonTypeName("gateway")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class GatewayClientInformation extends ClientInformation {
String version;
@Override
public String toDisplayString() {
return "X-Pipe Gateway " + version;
}
}
@JsonTypeName("api")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class ApiClientInformation extends ClientInformation {
String version;
String language;
@Override
public String toDisplayString() {
return String.format("X-Pipe %s API v%s", language, version);
}
}
@Getter @Getter
private final Closeable base; private final Closeable base;
private final InputStream in; private final InputStream in;
private final OutputStream out; private final OutputStream out;
@ -130,15 +60,15 @@ public class BeaconClient implements AutoCloseable {
command.discardErr(); command.discardErr();
return new BeaconClient(command, command.getStdout(), command.getStdin()) { return new BeaconClient(command, command.getStdout(), command.getStdin()) {
// { // {
// new Thread(() -> { // new Thread(() -> {
// while (true) { // while (true) {
// if (!control.isRunning()) { // if (!control.isRunning()) {
// close(); // close();
// } // }
// } // }
// }) // })
// } // }
@Override @Override
public <T extends ResponseMessage> T receiveResponse() public <T extends ResponseMessage> T receiveResponse()
@ -365,4 +295,76 @@ public class BeaconClient implements AutoCloseable {
void run() throws E; void run() throws E;
} }
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public abstract static class ClientInformation {
public final CliClientInformation cli() {
return (CliClientInformation) this;
}
public abstract String toDisplayString();
}
@JsonTypeName("cli")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class CliClientInformation extends ClientInformation {
int consoleWidth;
@Override
public String toDisplayString() {
return "X-Pipe CLI";
}
}
@JsonTypeName("reachableCheck")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class ReachableCheckInformation extends ClientInformation {
@Override
public String toDisplayString() {
return "Reachable check";
}
}
@JsonTypeName("gateway")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class GatewayClientInformation extends ClientInformation {
String version;
@Override
public String toDisplayString() {
return "X-Pipe Gateway " + version;
}
}
@JsonTypeName("api")
@Value
@Builder
@Jacksonized
@EqualsAndHashCode(callSuper = false)
public static class ApiClientInformation extends ClientInformation {
String version;
String language;
@Override
public String toDisplayString() {
return String.format("X-Pipe %s API v%s", language, version);
}
}
} }

View file

@ -78,7 +78,8 @@ 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, BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer) { REQ req, BeaconClient.FailableBiConsumer<RES, InputStream, Exception> responseConsumer
) {
checkClosed(); checkClosed();
performInputOutputExchange(req, null, responseConsumer); performInputOutputExchange(req, null, responseConsumer);
@ -87,7 +88,8 @@ 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 {
@ -149,7 +151,8 @@ 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, BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter) { REQ req, BeaconClient.FailableConsumer<OutputStream, Exception> reqWriter
) {
checkClosed(); checkClosed();
try { try {

View file

@ -72,7 +72,7 @@ public class BeaconDaemonController {
throw new IOException("Wait for daemon start up timed out"); throw new IOException("Wait for daemon start up timed out");
} }
private static void waitForShutdown() { private static void waitForShutdown() {
for (int i = 0; i < 40; i++) { for (int i = 0; i < 40; i++) {
try { try {
Thread.sleep(500); Thread.sleep(500);

View file

@ -5,7 +5,8 @@ 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

@ -10,6 +10,7 @@ public class BeaconJacksonModule extends SimpleModule {
context.registerSubtypes( context.registerSubtypes(
new NamedType(BeaconClient.ApiClientInformation.class), new NamedType(BeaconClient.ApiClientInformation.class),
new NamedType(BeaconClient.CliClientInformation.class), new NamedType(BeaconClient.CliClientInformation.class),
new NamedType(BeaconClient.ReachableCheckInformation.class)); new NamedType(BeaconClient.ReachableCheckInformation.class)
);
} }
} }

View file

@ -81,8 +81,8 @@ public class BeaconProxyImpl extends ProxyProvider {
try { try {
client = BeaconClient.connectProxy(proxy); client = BeaconClient.connectProxy(proxy);
client.sendRequest(ProxyReadConnectionExchange.Request.builder() client.sendRequest(ProxyReadConnectionExchange.Request.builder()
.source(downstream) .source(downstream)
.build()); .build());
client.receiveResponse(); client.receiveResponse();
BeaconClient finalClient = client; BeaconClient finalClient = client;
var inputStream = new FilterInputStream(finalClient.receiveBody()) { var inputStream = new FilterInputStream(finalClient.receiveBody()) {
@ -96,22 +96,24 @@ public class BeaconProxyImpl extends ProxyProvider {
var inputSource = DataSource.createInternalDataSource(source.getType(), new InputStreamStore(inputStream)); var inputSource = DataSource.createInternalDataSource(source.getType(), new InputStreamStore(inputStream));
return (T) inputSource.openReadConnection(); return (T) inputSource.openReadConnection();
} catch (Exception ex) { } catch (Exception ex) {
if (client != null) client.close(); if (client != null) {
client.close();
}
throw ex; throw ex;
} }
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends DataSourceConnection> T createRemoteWriteConnection(DataSource<?> source, WriteMode mode, ShellStore proxy) throws Exception { public <T extends DataSourceConnection> T createRemoteWriteConnection(DataSource<?> source, WriteMode mode, ShellStore proxy) throws Exception {
var downstream = downstreamTransform(source, proxy); var downstream = downstreamTransform(source, proxy);
BeaconClient client = null; BeaconClient client = null;
try { try {
client = BeaconClient.connectProxy(proxy); client = BeaconClient.connectProxy(proxy);
client.sendRequest(ProxyWriteConnectionExchange.Request.builder() client.sendRequest(ProxyWriteConnectionExchange.Request.builder()
.source(downstream) .source(downstream)
.build()); .build());
BeaconClient finalClient = client; BeaconClient finalClient = client;
var outputStream = new FilterOutputStream(client.sendBody()) { var outputStream = new FilterOutputStream(client.sendBody()) {
@Override @Override
@ -125,7 +127,9 @@ public class BeaconProxyImpl extends ProxyProvider {
var outputSource = DataSource.createInternalDataSource(source.getType(), new OutputStreamStore(outputStream)); var outputSource = DataSource.createInternalDataSource(source.getType(), new OutputStreamStore(outputStream));
return (T) outputSource.openWriteConnection(mode); return (T) outputSource.openWriteConnection(mode);
} catch (Exception ex) { } catch (Exception ex) {
if (client != null) client.close(); if (client != null) {
client.close();
}
throw ex; throw ex;
} }
} }

View file

@ -30,9 +30,9 @@ public class BeaconServer {
if (custom != null) { if (custom != null) {
var command = ShellTypes.getPlatformDefault() var command = ShellTypes.getPlatformDefault()
.executeCommandListWithShell(custom .executeCommandListWithShell(custom
+ (BeaconConfig.getDaemonArguments() != null + (BeaconConfig.getDaemonArguments() != null
? " " + BeaconConfig.getDaemonArguments() ? " " + BeaconConfig.getDaemonArguments()
: "")); : ""));
Process process = Runtime.getRuntime().exec(command.toArray(String[]::new)); Process process = Runtime.getRuntime().exec(command.toArray(String[]::new));
printDaemonOutput(process, command); printDaemonOutput(process, command);
return process; return process;
@ -77,7 +77,8 @@ public class BeaconServer {
ioe.printStackTrace(); ioe.printStackTrace();
} }
}, },
"daemon sysout"); "daemon sysout"
);
out.setDaemon(true); out.setDaemon(true);
out.start(); out.start();
@ -97,7 +98,8 @@ public class BeaconServer {
ioe.printStackTrace(); ioe.printStackTrace();
} }
}, },
"daemon syserr"); "daemon syserr"
);
err.setDaemon(true); err.setDaemon(true);
err.start(); err.start();
} }

View file

@ -5,7 +5,8 @@ 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,7 +5,8 @@ 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,3 +1,4 @@
package io.xpipe.beacon; package io.xpipe.beacon;
public interface RequestMessage {} public interface RequestMessage {
}

View file

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

View file

@ -5,7 +5,8 @@ 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

@ -31,5 +31,6 @@ 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

@ -2,9 +2,9 @@ package io.xpipe.beacon.exchange;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.xpipe.core.util.ProxyFunction;
import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.RequestMessage;
import io.xpipe.beacon.ResponseMessage; import io.xpipe.beacon.ResponseMessage;
import io.xpipe.core.util.ProxyFunction;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
@ -21,8 +21,14 @@ public class ProxyFunctionExchange implements MessageExchange {
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
@JsonSerialize(using = ProxyFunction.Serializer.class, as = ProxyFunction.class) @JsonSerialize(
@JsonDeserialize(using = ProxyFunction.Deserializer.class, as = ProxyFunction.class) using = ProxyFunction.Serializer.class,
as = ProxyFunction.class
)
@JsonDeserialize(
using = ProxyFunction.Deserializer.class,
as = ProxyFunction.class
)
ProxyFunction function; ProxyFunction function;
} }
@ -31,8 +37,14 @@ public class ProxyFunctionExchange implements MessageExchange {
@Value @Value
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
@JsonSerialize(using = ProxyFunction.Serializer.class, as = ProxyFunction.class) @JsonSerialize(
@JsonDeserialize(using = ProxyFunction.Deserializer.class, as = ProxyFunction.class) using = ProxyFunction.Serializer.class,
as = ProxyFunction.class
)
@JsonDeserialize(
using = ProxyFunction.Deserializer.class,
as = ProxyFunction.class
)
ProxyFunction function; ProxyFunction function;
} }
} }

View file

@ -19,7 +19,8 @@ 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

@ -29,5 +29,6 @@ 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

@ -30,5 +30,6 @@ 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

@ -19,7 +19,8 @@ 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

@ -20,7 +20,8 @@ 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

@ -20,7 +20,8 @@ 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

@ -26,5 +26,6 @@ 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

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

View file

@ -26,5 +26,6 @@ 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

@ -26,5 +26,6 @@ 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

@ -29,5 +29,6 @@ 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

@ -29,5 +29,6 @@ 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

@ -27,5 +27,6 @@ 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

@ -23,7 +23,8 @@ 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

View file

@ -17,7 +17,8 @@ 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

@ -22,7 +22,8 @@ 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

View file

@ -17,7 +17,8 @@ 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

@ -13,15 +13,10 @@ import java.util.UUID;
public class QuietDialogHandler { public class QuietDialogHandler {
public static void handle(DialogReference ref, BeaconConnection connection) {
new QuietDialogHandler(ref, connection, Map.of()).handle();
}
private final UUID dialogKey; private final UUID dialogKey;
private final BeaconConnection connection; private final BeaconConnection connection;
private final Map<String, String> overrides; private final Map<String, String> overrides;
private DialogElement element; 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();
this.element = ref.getStart(); this.element = ref.getStart();
@ -29,6 +24,10 @@ public class QuietDialogHandler {
this.overrides = overrides; this.overrides = overrides;
} }
public static void handle(DialogReference ref, BeaconConnection connection) {
new QuietDialogHandler(ref, connection, Map.of()).handle();
}
public void handle() { public void handle() {
String response = null; String response = null;
@ -41,9 +40,9 @@ public class QuietDialogHandler {
} }
DialogExchange.Response res = connection.performSimpleExchange(DialogExchange.Request.builder() DialogExchange.Response res = connection.performSimpleExchange(DialogExchange.Request.builder()
.dialogKey(dialogKey) .dialogKey(dialogKey)
.value(response) .value(response)
.build()); .build());
if (res.getElement() != null && element.equals(res.getElement())) { if (res.getElement() != null && element.equals(res.getElement())) {
throw new BeaconException( throw new BeaconException(
"Invalid value for key " + res.getElement().toDisplayString()); "Invalid value for key " + res.getElement().toDisplayString());

View file

@ -23,7 +23,8 @@ public abstract class Charsetter {
public static Charsetter INSTANCE; public static Charsetter INSTANCE;
private static CharsetterUniverse universe; private static CharsetterUniverse universe;
protected Charsetter() {} protected Charsetter() {
}
protected static void checkInit() { protected static void checkInit() {
if (universe == null) { if (universe == null) {
@ -77,7 +78,8 @@ public abstract class Charsetter {
} }
public abstract Result read( public abstract Result read(
FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con) FailableSupplier<InputStream, Exception> in, FailableConsumer<InputStreamReader, Exception> con
)
throws Exception; throws Exception;
public Result detect(StreamDataStore store) throws Exception { public Result detect(StreamDataStore store) throws Exception {

View file

@ -20,8 +20,13 @@ public class StreamCharset {
public static final StreamCharset UTF8_BOM = new StreamCharset( public static final StreamCharset UTF8_BOM = new StreamCharset(
StandardCharsets.UTF_8, StandardCharsets.UTF_8,
new byte[] {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}, new byte[]{
Identifiers.get("utf", "8", "bom")); (byte) 0xEF,
(byte) 0xBB,
(byte) 0xBF
},
Identifiers.get("utf", "8", "bom")
);
// ====== // ======
// UTF-16 // UTF-16
@ -32,16 +37,24 @@ public class StreamCharset {
public static final StreamCharset UTF16_BE_BOM = new StreamCharset( public static final StreamCharset UTF16_BE_BOM = new StreamCharset(
StandardCharsets.UTF_16BE, StandardCharsets.UTF_16BE,
new byte[] {(byte) 0xFE, (byte) 0xFF}, new byte[]{
Identifiers.get("utf", "16", "be", "bom")); (byte) 0xFE,
(byte) 0xFF
},
Identifiers.get("utf", "16", "be", "bom")
);
public static final StreamCharset UTF16_LE = public static final StreamCharset UTF16_LE =
new StreamCharset(StandardCharsets.UTF_16LE, null, Identifiers.get("utf", "16", "le")); new StreamCharset(StandardCharsets.UTF_16LE, null, Identifiers.get("utf", "16", "le"));
public static final StreamCharset UTF16_LE_BOM = new StreamCharset( public static final StreamCharset UTF16_LE_BOM = new StreamCharset(
StandardCharsets.UTF_16LE, StandardCharsets.UTF_16LE,
new byte[] {(byte) 0xFF, (byte) 0xFE}, new byte[]{
Identifiers.get("utf", "16", "le", "bom")); (byte) 0xFF,
(byte) 0xFE
},
Identifiers.get("utf", "16", "le", "bom")
);
public static final StreamCharset UTF16 = public static final StreamCharset UTF16 =
new StreamCharset(StandardCharsets.UTF_16, null, Identifiers.get("utf", "16")); new StreamCharset(StandardCharsets.UTF_16, null, Identifiers.get("utf", "16"));
@ -51,30 +64,12 @@ public class StreamCharset {
ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN) ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)
? UTF16_BE_BOM.getByteOrderMark() ? UTF16_BE_BOM.getByteOrderMark()
: UTF16_LE_BOM.getByteOrderMark(), : UTF16_LE_BOM.getByteOrderMark(),
Identifiers.get("utf", "16", "bom")); Identifiers.get("utf", "16", "bom")
);
// ====== // ======
// UTF-32 // UTF-32
// ====== // ======
public static final StreamCharset UTF32_LE =
new StreamCharset(Charset.forName("utf-32le"), null, Identifiers.get("utf", "32", "le"));
public static final StreamCharset UTF32_LE_BOM = new StreamCharset(
Charset.forName("utf-32le"),
new byte[] {0x00, 0x00, (byte) 0xFE, (byte) 0xFF},
Identifiers.get("utf", "32", "le", "bom"));
public static final StreamCharset UTF32_BE =
new StreamCharset(Charset.forName("utf-32be"), null, Identifiers.get("utf", "32", "be"));
public static final StreamCharset UTF32_BE_BOM = new StreamCharset(
Charset.forName("utf-32be"),
new byte[] {
(byte) 0xFF, (byte) 0xFE, 0x00, 0x00,
},
Identifiers.get("utf", "32", "be", "bom"));
public static final List<StreamCharset> COMMON = List.of( public static final List<StreamCharset> COMMON = List.of(
UTF8, UTF8,
UTF8_BOM, UTF8_BOM,
@ -83,7 +78,8 @@ public class StreamCharset {
new StreamCharset( new StreamCharset(
StandardCharsets.US_ASCII, StandardCharsets.US_ASCII,
null, null,
Identifiers.join(Identifiers.get("ascii"), Identifiers.get("us", "ascii"))), Identifiers.join(Identifiers.get("ascii"), Identifiers.get("us", "ascii"))
),
new StreamCharset( new StreamCharset(
StandardCharsets.ISO_8859_1, StandardCharsets.ISO_8859_1,
null, null,
@ -91,16 +87,44 @@ public class StreamCharset {
Identifiers.get("iso", "8859"), Identifiers.get("iso", "8859"),
Identifiers.get("iso", "8859", "1"), Identifiers.get("iso", "8859", "1"),
Identifiers.get("8859"), Identifiers.get("8859"),
Identifiers.get("8859", "1"))), Identifiers.get("8859", "1")
)
),
new StreamCharset( new StreamCharset(
Charset.forName("Windows-1251"), Charset.forName("Windows-1251"),
null, null,
Identifiers.join(Identifiers.get("windows", "1251"), Identifiers.get("1251"))), Identifiers.join(Identifiers.get("windows", "1251"), Identifiers.get("1251"))
),
new StreamCharset( new StreamCharset(
Charset.forName("Windows-1252"), Charset.forName("Windows-1252"),
null, null,
Identifiers.join(Identifiers.get("windows", "1252"), Identifiers.get("1252")))); Identifiers.join(Identifiers.get("windows", "1252"), Identifiers.get("1252"))
)
);
public static final StreamCharset UTF32_LE =
new StreamCharset(Charset.forName("utf-32le"), null, Identifiers.get("utf", "32", "le"));
public static final StreamCharset UTF32_LE_BOM = new StreamCharset(
Charset.forName("utf-32le"),
new byte[]{
0x00,
0x00,
(byte) 0xFE,
(byte) 0xFF
},
Identifiers.get("utf", "32", "le", "bom")
);
public static final StreamCharset UTF32_BE =
new StreamCharset(Charset.forName("utf-32be"), null, Identifiers.get("utf", "32", "be"));
public static final StreamCharset UTF32_BE_BOM = new StreamCharset(
Charset.forName("utf-32be"),
new byte[]{
(byte) 0xFF,
(byte) 0xFE,
0x00,
0x00,
},
Identifiers.get("utf", "32", "be", "bom")
);
private static final List<StreamCharset> RARE_NAMED = private static final List<StreamCharset> RARE_NAMED =
List.of(UTF16_LE, UTF16_LE_BOM, UTF16_BE, UTF16_BE_BOM, UTF32_LE, UTF32_LE_BOM, UTF32_BE, UTF32_BE_BOM); List.of(UTF16_LE, UTF16_LE_BOM, UTF16_BE, UTF16_BE_BOM, UTF32_LE, UTF32_LE_BOM, UTF32_BE, UTF32_BE_BOM);
@ -113,23 +137,41 @@ public class StreamCharset {
&& !charset.displayName().startsWith("X-") && !charset.displayName().startsWith("X-")
&& !charset.displayName().endsWith("-BOM") && !charset.displayName().endsWith("-BOM")
&& COMMON.stream() && COMMON.stream()
.noneMatch(c -> c.getCharset().equals(charset)) .noneMatch(c -> c.getCharset().equals(charset))
&& RARE_NAMED.stream() && RARE_NAMED.stream()
.noneMatch(c -> c.getCharset().equals(charset))) .noneMatch(c -> c.getCharset().equals(charset)))
.map(charset -> new StreamCharset( .map(charset -> new StreamCharset(
charset, charset,
null, null,
Identifiers.get(charset.name().split("-"))))) Identifiers.get(charset.name().split("-"))
))
)
.toList(); .toList();
public static final List<StreamCharset> ALL = Stream.concat(COMMON.stream(), RARE.stream()).toList(); public static final List<StreamCharset> ALL = Stream.concat(COMMON.stream(), RARE.stream()).toList();
Charset charset; Charset charset;
byte[] byteOrderMark; byte[] byteOrderMark;
List<String> names; List<String> names;
public static StreamCharset get(Charset charset, boolean byteOrderMark) {
return ALL.stream()
.filter(streamCharset ->
streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
.findFirst()
.orElseThrow();
}
public static StreamCharset get(String s) {
var found = ALL.stream().filter(streamCharset -> streamCharset.getNames().contains(s.toLowerCase(Locale.ROOT))).findFirst();
if (found.isEmpty()) {
throw new IllegalArgumentException("Unknown charset name: " + s);
}
return found.get();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -148,23 +190,6 @@ public class StreamCharset {
return result; return result;
} }
public static StreamCharset get(Charset charset, boolean byteOrderMark) {
return ALL.stream()
.filter(streamCharset ->
streamCharset.getCharset().equals(charset) && streamCharset.hasByteOrderMark() == byteOrderMark)
.findFirst()
.orElseThrow();
}
public static StreamCharset get(String s) {
var found = ALL.stream().filter(streamCharset -> streamCharset.getNames().contains(s.toLowerCase(Locale.ROOT))).findFirst();
if (found.isEmpty()) {
throw new IllegalArgumentException("Unknown charset name: " + s);
}
return found.get();
}
public String toString() { public String toString() {
return getNames().get(0); return getNames().get(0);
} }

View file

@ -17,7 +17,8 @@ public class GenericArrayReader implements GenericAbstractReader {
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,15 +4,21 @@ 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

@ -19,7 +19,8 @@ public class GenericTupleReader implements GenericAbstractReader {
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,7 +8,8 @@ import java.util.stream.Collectors;
public abstract class ArrayNode extends DataStructureNode { public abstract class ArrayNode extends DataStructureNode {
protected ArrayNode() {} protected ArrayNode() {
}
public static ArrayNode empty() { public static ArrayNode empty() {
return of(List.of()); return of(List.of());

View file

@ -129,13 +129,13 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
public String metaToString() { public String metaToString() {
return "(" return "("
+ (metaAttributes != null + (metaAttributes != null
? metaAttributes.entrySet().stream() ? metaAttributes.entrySet().stream()
.sorted(Comparator.comparingInt(entry -> entry.getKey())) .sorted(Comparator.comparingInt(entry -> entry.getKey()))
.map(e -> e.getValue() != null .map(e -> e.getValue() != null
? e.getKey() + ":" + e.getValue() ? e.getKey() + ":" + e.getValue()
: e.getKey().toString()) : e.getKey().toString())
.collect(Collectors.joining("|")) .collect(Collectors.joining("|"))
: "") : "")
+ ")"; + ")";
} }
@ -242,5 +242,6 @@ public abstract class DataStructureNode implements Iterable<DataStructureNode> {
throw unsupported("iterator creation"); throw unsupported("iterator creation");
} }
public record KeyValue(String key, DataStructureNode value) {} public record KeyValue(String key, DataStructureNode value) {
}
} }

View file

@ -217,7 +217,8 @@ public class DataStructureNodePointer {
} }
public Builder pointerEvaluation( public Builder pointerEvaluation(
DataStructureNodePointer pointer, Function<DataStructureNode, String> converter) { 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

@ -86,7 +86,8 @@ public class LinkedTupleNode extends TupleNode {
public DataType determineDataType() { public DataType determineDataType() {
return TupleType.of( return TupleType.of(
getKeyNames(), getKeyNames(),
getNodes().stream().map(DataStructureNode::determineDataType).toList()); getNodes().stream().map(DataStructureNode::determineDataType).toList()
);
} }
@Override @Override

View file

@ -67,7 +67,9 @@ public class SimpleTupleNode extends TupleNode {
@Override @Override
public DataStructureNode clear() { public DataStructureNode clear() {
nodes.clear(); nodes.clear();
if (names != null) names.clear(); if (names != null) {
names.clear();
}
return this; return this;
} }

View file

@ -102,8 +102,9 @@ public abstract class TupleNode extends DataStructureNode {
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null); boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
return hasKeys return hasKeys
? TupleNode.of( ? TupleNode.of(
entries.stream().map(KeyValue::key).toList(), entries.stream().map(KeyValue::key).toList(),
entries.stream().map(KeyValue::value).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

@ -13,7 +13,8 @@ import java.util.Objects;
public abstract class ValueNode extends DataStructureNode { public abstract class ValueNode extends DataStructureNode {
protected ValueNode() {} protected ValueNode() {
}
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();

View file

@ -10,7 +10,10 @@ import java.util.Optional;
* To check whether a {@link DataStructureNode} instance conforms to the specified type, * To check whether a {@link DataStructureNode} instance conforms to the specified type,
* the method {@link #matches(DataStructureNode)} can be used. * the method {@link #matches(DataStructureNode)} can be used.
*/ */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public abstract class DataType { public abstract class DataType {
/** /**

View file

@ -2,11 +2,15 @@ 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,7 +41,8 @@ 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, Runnable endTuple, BiConsumer<String, DataStructureNodePointer> newValue) { Consumer<String> newTuple, 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,7 +17,8 @@ import java.util.Optional;
@Value @Value
public class WildcardType extends DataType { public class WildcardType extends DataType {
private WildcardType() {} private WildcardType() {
}
/** /**
* Creates a new instance. * Creates a new instance.

View file

@ -7,19 +7,27 @@ 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

@ -19,6 +19,7 @@ public class TypedDataStructureNodeReader implements TypedAbstractReader {
private int arrayDepth; 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));

View file

@ -21,7 +21,8 @@ public class BaseQueryElement extends DialogElement {
@JsonCreator @JsonCreator
public BaseQueryElement( public BaseQueryElement(
String description, boolean newLine, boolean required, boolean secret, boolean quiet, String value) { 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

@ -30,13 +30,6 @@ public abstract class Dialog {
protected Object eval; protected Object eval;
private Supplier<?> evaluation; private Supplier<?> evaluation;
/**
* Removes all completion listeners. Intended for internal use only.
*/
public void clearCompletion() {
completion.clear();
}
/** /**
* 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.
*/ */
@ -65,7 +58,8 @@ public abstract class Dialog {
* @param selected the selected element index * @param selected the selected element index
*/ */
public static Dialog.Choice choice( public static Dialog.Choice choice(
String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, boolean quiet, int selected) { String description, List<io.xpipe.core.dialog.Choice> elements, boolean required, boolean quiet, int selected
) {
Dialog.Choice c = new Dialog.Choice(description, elements, required, quiet, selected); Dialog.Choice c = new Dialog.Choice(description, elements, required, quiet, selected);
c.evaluateTo(c::getSelected); c.evaluateTo(c::getSelected);
return c; return c;
@ -83,7 +77,8 @@ public abstract class Dialog {
*/ */
@SafeVarargs @SafeVarargs
public static <T> Dialog.Choice choice( public static <T> Dialog.Choice choice(
String description, Function<T, String> toString, boolean required, boolean quiet, T def, T... vals) { String description, Function<T, String> toString, boolean required, boolean quiet, T def, T... vals
) {
var elements = Arrays.stream(vals) var elements = Arrays.stream(vals)
.map(v -> new io.xpipe.core.dialog.Choice(null, toString.apply(v))) .map(v -> new io.xpipe.core.dialog.Choice(null, toString.apply(v)))
.toList(); .toList();
@ -120,7 +115,8 @@ public abstract class Dialog {
boolean required, boolean required,
boolean quiet, boolean quiet,
T value, T value,
QueryConverter<T> converter) { 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;
@ -166,7 +162,8 @@ 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;
} }
@ -357,7 +354,8 @@ public abstract class Dialog {
List<io.xpipe.core.dialog.Choice> elements, List<io.xpipe.core.dialog.Choice> elements,
boolean required, boolean required,
int selected, int selected,
Function<Integer, Dialog> c) { Function<Integer, Dialog> c
) {
var choice = new ChoiceElement(description, elements, required, false, selected); var choice = new ChoiceElement(description, elements, required, false, selected);
return new Dialog() { return new Dialog() {
@ -391,6 +389,13 @@ public abstract class Dialog {
}; };
} }
/**
* Removes all completion listeners. Intended for internal use only.
*/
public void clearCompletion() {
completion.clear();
}
/* 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.
* */ * */
@ -497,7 +502,8 @@ public abstract class Dialog {
boolean quiet, boolean quiet,
T value, T value,
QueryConverter<T> converter, QueryConverter<T> converter,
boolean hidden) { boolean hidden
) {
this.element = new QueryElement(description, newLine, required, quiet, value, converter, hidden); this.element = new QueryElement(description, newLine, required, quiet, value, converter, hidden);
} }

View file

@ -5,7 +5,8 @@ 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 +21,8 @@ public class DialogCancelException extends Exception {
} }
public DialogCancelException( public DialogCancelException(
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace
) {
super(message, cause, enableSuppression, writableStackTrace); super(message, cause, enableSuppression, writableStackTrace);
} }
} }

View file

@ -8,7 +8,10 @@ import java.util.UUID;
@EqualsAndHashCode @EqualsAndHashCode
@ToString @ToString
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public abstract class DialogElement { public abstract class DialogElement {
protected String id; protected String id;

View file

@ -22,7 +22,7 @@ public class DialogMapper {
return map; return map;
} }
private void handle(DialogElement element) throws Exception { private void handle(DialogElement element) throws Exception {
String response = null; String response = null;
if (element instanceof ChoiceElement c) { if (element instanceof ChoiceElement c) {
response = handleChoice(c); response = handleChoice(c);
@ -45,8 +45,8 @@ public class DialogMapper {
} }
private String handleQuery(BaseQueryElement q) { private String handleQuery(BaseQueryElement q) {
map.put(q.getDescription(), q.getValue()); map.put(q.getDescription(), q.getValue());
return q.getValue(); return q.getValue();
} }
private String handleChoice(ChoiceElement c) { private String handleChoice(ChoiceElement c) {

View file

@ -14,7 +14,8 @@ public class QueryElement extends BaseQueryElement {
boolean quiet, boolean quiet,
T value, T value,
QueryConverter<T> converter, QueryConverter<T> converter,
boolean hidden) { 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

@ -44,13 +44,13 @@ public class BinarySource extends RawDataSource<StreamDataStore> {
protected RawReadConnection newReadConnection() { protected RawReadConnection newReadConnection() {
return new RawReadConnection() { return new RawReadConnection() {
private InputStream inputStream;
@Override @Override
public boolean canRead() throws Exception { public boolean canRead() throws Exception {
return getStore().canOpen(); return getStore().canOpen();
} }
private InputStream inputStream;
@Override @Override
public void init() throws Exception { public void init() throws Exception {
if (inputStream != null) { if (inputStream != null) {

View file

@ -43,7 +43,7 @@ public class FileNames {
return backslash ? toWindows(file) : toUnix(file); return backslash ? toWindows(file) : toUnix(file);
} }
private static List<String> split(String file) { private static List<String> split(String file) {
var split = file.split("[\\\\/]"); var split = file.split("[\\\\/]");
return Arrays.stream(split).filter(s -> !s.isEmpty()).toList(); return Arrays.stream(split).filter(s -> !s.isEmpty()).toList();
} }

View file

@ -32,7 +32,18 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream
this.file = file; this.file = file;
} }
public String getParent() { public static FileStore local(Path p) {
return new FileStore(new LocalStore(), p.toString());
}
/**
* Creates a file store for a file that is local to the callers machine.
*/
public static FileStore local(String p) {
return new FileStore(new LocalStore(), p);
}
public String getParent() {
var matcher = Pattern.compile("^(.+?)[^\\\\/]+$").matcher(file); var matcher = Pattern.compile("^(.+?)[^\\\\/]+$").matcher(file);
if (!matcher.matches()) { if (!matcher.matches()) {
throw new IllegalArgumentException("Unable to determine parent of " + file); throw new IllegalArgumentException("Unable to determine parent of " + file);
@ -45,17 +56,6 @@ public class FileStore extends JacksonizedValue implements FilenameStore, Stream
return fileSystem instanceof LocalStore; return fileSystem instanceof LocalStore;
} }
public static FileStore local(Path p) {
return new FileStore(new LocalStore(), p.toString());
}
/**
* Creates a file store for a file that is local to the callers machine.
*/
public static FileStore local(String p) {
return new FileStore(new LocalStore(), p);
}
@Override @Override
public void checkComplete() throws Exception { public void checkComplete() throws Exception {
if (fileSystem == null) { if (fileSystem == null) {

View file

@ -6,20 +6,20 @@ import java.util.ServiceLoader;
public abstract class LocalProcessControlProvider { public abstract class LocalProcessControlProvider {
private static LocalProcessControlProvider INSTANCE;
public static LocalProcessControlProvider get() { public static LocalProcessControlProvider get() {
return INSTANCE; return INSTANCE;
} }
private static LocalProcessControlProvider INSTANCE;
public static void init(ModuleLayer layer) { public static void init(ModuleLayer layer) {
INSTANCE = layer != null INSTANCE = layer != null
? ServiceLoader.load(layer, LocalProcessControlProvider.class) ? ServiceLoader.load(layer, LocalProcessControlProvider.class)
.findFirst() .findFirst()
.orElse(null) .orElse(null)
: ServiceLoader.load(LocalProcessControlProvider.class) : ServiceLoader.load(LocalProcessControlProvider.class)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
public static ShellProcessControl create() { public static ShellProcessControl create() {

View file

@ -45,6 +45,7 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac
var p = Path.of(file); var p = Path.of(file);
return Files.newOutputStream(p); return Files.newOutputStream(p);
} }
@Override @Override
public ShellProcessControl create() { public ShellProcessControl create() {
return LocalProcessControlProvider.create(); return LocalProcessControlProvider.create();

View file

@ -12,6 +12,7 @@ public class PreservingTableWriteConnection extends PreservingWriteConnection im
public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) { public PreservingTableWriteConnection(DataSource<?> source, DataSourceConnection connection, boolean append) {
super(DataSourceType.TABLE, source, append, connection); super(DataSourceType.TABLE, source, append, connection);
} }
@Override @Override
public Optional<TableMapping> createMapping(TupleType inputType) throws Exception { public Optional<TableMapping> createMapping(TupleType inputType) throws Exception {
return ((TableWriteConnection) connection).createMapping(inputType); return ((TableWriteConnection) connection).createMapping(inputType);

View file

@ -15,7 +15,8 @@ public class PreservingWriteConnection implements DataSourceConnection {
private final boolean append; private final boolean append;
public PreservingWriteConnection( public PreservingWriteConnection(
DataSourceType type, DataSource<?> source, boolean append, DataSourceConnection connection) { 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;
@ -28,7 +29,7 @@ public class PreservingWriteConnection implements DataSourceConnection {
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(); try (var in = source.openReadConnection();
var out = nativeSource.openWriteConnection(WriteMode.REPLACE)) { var out = nativeSource.openWriteConnection(WriteMode.REPLACE)) {
in.init(); in.init();
out.init(); out.init();
in.forward(out); in.forward(out);

View file

@ -7,7 +7,7 @@ import io.xpipe.core.source.TableWriteConnection;
import java.util.Optional; import java.util.Optional;
public interface SimpleTableWriteConnection<T extends TableDataSource<?>> extends TableWriteConnection { public interface SimpleTableWriteConnection<T extends TableDataSource<?>> extends TableWriteConnection {
public T getSource(); public T getSource();
@ -18,7 +18,7 @@ public interface SimpleTableWriteConnection<T extends TableDataSource<?>> exten
public default Optional<TableMapping> createMapping(TupleType inputType) throws Exception { public default Optional<TableMapping> createMapping(TupleType inputType) throws Exception {
var outputType = getType(); var outputType = getType();
if (outputType.isEmpty() || outputType.get().getSize() == 0){ if (outputType.isEmpty() || outputType.get().getSize() == 0) {
return Optional.of(TableMapping.createIdentity(inputType)); return Optional.of(TableMapping.createIdentity(inputType));
} }

View file

@ -21,14 +21,6 @@ import java.nio.channels.Pipe;
@Getter @Getter
public class SinkDrainStore extends JacksonizedValue implements KnownFormatStreamDataStore, StatefulDataStore { public class SinkDrainStore extends JacksonizedValue implements KnownFormatStreamDataStore, StatefulDataStore {
public static enum State {
NONE_CONNECTED,
PRODUCER_CONNECTED,
CONSUMER_CONNECTED,
OPEN,
CLOSED
}
private final StreamCharset charset; private final StreamCharset charset;
private final NewLine newLine; private final NewLine newLine;
@ -163,4 +155,12 @@ public class SinkDrainStore extends JacksonizedValue implements KnownFormatStrea
throw new IllegalStateException("Consumer is already connected"); throw new IllegalStateException("Consumer is already connected");
} }
} }
public static enum State {
NONE_CONNECTED,
PRODUCER_CONNECTED,
CONSUMER_CONNECTED,
OPEN,
CLOSED
}
} }

View file

@ -26,7 +26,8 @@ public class StdinDataStore extends JacksonizedValue implements StreamDataStore
// Prevent closing the standard in when the returned input stream is closed // Prevent closing the standard in when the returned input stream is closed
return new FilterInputStream(in) { return new FilterInputStream(in) {
@Override @Override
public void close() throws IOException {} public void close() throws IOException {
}
}; };
} }
} }

View file

@ -30,7 +30,8 @@ public class StdoutDataStore extends JacksonizedValue implements StreamDataStore
// Create an output stream that will write to standard out but will not close it // Create an output stream that will write to standard out but will not close it
return new FilterOutputStream(System.out) { return new FilterOutputStream(System.out) {
@Override @Override
public void close() throws IOException {} public void close() throws IOException {
}
}; };
} }
} }

View file

@ -24,6 +24,7 @@ public class XpbtReadConnection extends StreamReadConnection implements TableRea
private TupleType dataType; private TupleType dataType;
private TypedDataStreamParser parser; private TypedDataStreamParser parser;
private boolean empty; private boolean empty;
protected XpbtReadConnection(XpbtSource source) { protected XpbtReadConnection(XpbtSource source) {
super(source.getStore(), null); super(source.getStore(), null);
this.store = source.getStore(); this.store = source.getStore();
@ -46,7 +47,8 @@ public class XpbtReadConnection extends StreamReadConnection implements TableRea
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;

View file

@ -9,16 +9,6 @@ public interface OsType {
Linux LINUX = new Linux(); Linux LINUX = new Linux();
Mac MAC = new Mac(); Mac MAC = new Mac();
String getName();
String getTempDirectory(ShellProcessControl pc) throws Exception;
String normalizeFileName(String file);
Map<String, String> getProperties(ShellProcessControl pc) throws Exception;
String determineOperatingSystemName(ShellProcessControl pc) throws Exception;
public static OsType getLocal() { public static OsType getLocal() {
String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
if ((osName.contains("mac")) || (osName.contains("darwin"))) { if ((osName.contains("mac")) || (osName.contains("darwin"))) {
@ -32,6 +22,16 @@ public interface OsType {
} }
} }
String getName();
String getTempDirectory(ShellProcessControl pc) throws Exception;
String normalizeFileName(String file);
Map<String, String> getProperties(ShellProcessControl pc) throws Exception;
String determineOperatingSystemName(ShellProcessControl pc) throws Exception;
static class Windows implements OsType { static class Windows implements OsType {
@Override @Override
@ -52,7 +52,7 @@ public interface OsType {
@Override @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
try (CommandProcessControl c = try (CommandProcessControl c =
pc.subShell(ShellTypes.CMD).command("systeminfo").start()) { pc.subShell(ShellTypes.CMD).command("systeminfo").start()) {
var text = c.readOrThrow(); var text = c.readOrThrow();
return PropertiesFormatsParser.parse(text, ":"); return PropertiesFormatsParser.parse(text, ":");
} }
@ -144,7 +144,7 @@ public interface OsType {
@Override @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
try (CommandProcessControl c = try (CommandProcessControl c =
pc.subShell(ShellTypes.BASH).command("sw_vers").start()) { pc.subShell(ShellTypes.BASH).command("sw_vers").start()) {
var text = c.readOrThrow(); var text = c.readOrThrow();
return PropertiesFormatsParser.parse(text, ":"); return PropertiesFormatsParser.parse(text, ":");
} }

View file

@ -8,7 +8,7 @@ import java.nio.charset.Charset;
public interface ProcessControl extends Closeable, AutoCloseable { public interface ProcessControl extends Closeable, AutoCloseable {
String prepareTerminalOpen() throws Exception; String prepareTerminalOpen() throws Exception;
void closeStdin() throws IOException; void closeStdin() throws IOException;
@ -24,6 +24,7 @@ public interface ProcessControl extends Closeable, AutoCloseable {
@Override @Override
void close() throws IOException; void close() throws IOException;
void kill() throws Exception; void kill() throws Exception;
ProcessControl start() throws Exception; ProcessControl start() throws Exception;

View file

@ -18,7 +18,8 @@ public class ProcessOutputException extends Exception {
} }
protected ProcessOutputException( protected ProcessOutputException(
String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace
) {
super(message, cause, enableSuppression, writableStackTrace); super(message, cause, enableSuppression, writableStackTrace);
} }
} }

View file

@ -55,8 +55,8 @@ public interface ShellProcessControl extends ProcessControl {
default ShellProcessControl subShell(@NonNull ShellType type) { default ShellProcessControl subShell(@NonNull ShellType type) {
return subShell(p -> type.getNormalOpenCommand(), (shellProcessControl, s) -> { return subShell(p -> type.getNormalOpenCommand(), (shellProcessControl, s) -> {
return s == null ? type.getNormalOpenCommand() : type.executeCommandWithShell(s); return s == null ? type.getNormalOpenCommand() : type.executeCommandWithShell(s);
}) })
.elevation(getElevationPassword()); .elevation(getElevationPassword());
} }
@ -71,7 +71,8 @@ public interface ShellProcessControl extends ProcessControl {
ShellProcessControl subShell( ShellProcessControl subShell(
@NonNull Function<ShellProcessControl, String> command, @NonNull Function<ShellProcessControl, String> command,
BiFunction<ShellProcessControl, String, String> terminalCommand); BiFunction<ShellProcessControl, String, String> terminalCommand
);
void executeCommand(String command) throws Exception; void executeCommand(String command) throws Exception;
@ -81,7 +82,8 @@ public interface ShellProcessControl extends ProcessControl {
CommandProcessControl command(Function<ShellProcessControl, String> command); CommandProcessControl command(Function<ShellProcessControl, String> command);
CommandProcessControl command( CommandProcessControl command(
Function<ShellProcessControl, String> command, Function<ShellProcessControl, String> terminalCommand); Function<ShellProcessControl, String> command, Function<ShellProcessControl, String> terminalCommand
);
default CommandProcessControl command(String command) { default CommandProcessControl command(String command) {
return command(shellProcessControl -> command); return command(shellProcessControl -> command);

View file

@ -7,7 +7,10 @@ import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public interface ShellType { public interface ShellType {
String getScriptFileEnding(); String getScriptFileEnding();
@ -25,8 +28,8 @@ public interface ShellType {
default String flatten(List<String> command) { default String flatten(List<String> command) {
return command.stream() return command.stream()
.map(s -> s.contains(" ") .map(s -> s.contains(" ")
&& !(s.startsWith("\"") && s.endsWith("\"")) && !(s.startsWith("\"") && s.endsWith("\""))
&& !(s.startsWith("'") && s.endsWith("'")) && !(s.startsWith("'") && s.endsWith("'"))
? "\"" + s + "\"" ? "\"" + s + "\""
: s) : s)
.collect(Collectors.joining(" ")); .collect(Collectors.joining(" "));

View file

@ -32,7 +32,13 @@ public class ShellTypes {
} }
public static ShellType[] getAllShellTypes() { public static ShellType[] getAllShellTypes() {
return new ShellType[] {CMD, POWERSHELL, ZSH, BASH, SH}; return new ShellType[]{
CMD,
POWERSHELL,
ZSH,
BASH,
SH
};
} }
@JsonTypeName("cmd") @JsonTypeName("cmd")
@ -295,7 +301,8 @@ public class ShellTypes {
@Override @Override
public void elevate(ShellProcessControl control, String command, String displayCommand) throws Exception { public void elevate(ShellProcessControl control, String command, String displayCommand) throws Exception {
try (CommandProcessControl c = control.command( try (CommandProcessControl c = control.command(
"([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)") "([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security" +
".Principal.WindowsBuiltinRole]::Administrator)")
.start()) { .start()) {
if (c.startAndCheckExit()) { if (c.startAndCheckExit()) {
throw new IllegalStateException("The command \"" + displayCommand + "\" requires elevation."); throw new IllegalStateException("The command \"" + displayCommand + "\" requires elevation.");

View file

@ -23,7 +23,10 @@ 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(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(
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; protected DS store;
@ -39,7 +42,7 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
.charset(StreamCharset.UTF8) .charset(StreamCharset.UTF8)
.build(); .build();
case RAW -> null; case RAW -> null;
// TODO // TODO
case COLLECTION -> null; case COLLECTION -> null;
}; };
} catch (Exception ex) { } catch (Exception ex) {
@ -47,7 +50,7 @@ public abstract class DataSource<DS extends DataStore> extends JacksonizedValue
} }
} }
public boolean isComplete() { public boolean isComplete() {
try { try {
checkComplete(); checkComplete();
return true; return true;

View file

@ -9,7 +9,9 @@ public interface DataSourceConnection extends AutoCloseable {
* Initializes this connection. Required to be called * Initializes this connection. Required to be called
* exactly once prior to attempting to use this connection. * exactly once prior to attempting to use this connection.
*/ */
default void init() throws Exception {} default void init() throws Exception {
}
default void close() throws Exception {} default void close() throws Exception {
}
} }

View file

@ -11,7 +11,7 @@ import lombok.Getter;
* To allow for a simple usage of data source ids, the collection and entry names are trimmed and * To allow for a simple usage of data source ids, the collection and entry names are trimmed and
* converted to lower case names when creating them. * converted to lower case names when creating them.
* The two names are separated by a colon and are therefore not allowed to contain colons themselves. * The two names are separated by a colon and are therefore not allowed to contain colons themselves.
* * <p>
* A missing collection name indicates that the data source exists only temporarily. * A missing collection name indicates that the data source exists only temporarily.
* *
* @see #create(String, String) * @see #create(String, String)

View file

@ -10,7 +10,7 @@ import java.util.Objects;
* Represents a reference to an X-Pipe data source. * Represents a reference to an X-Pipe data source.
* Using {@link DataSourceReference} instances instead of {@link DataSourceId} * Using {@link DataSourceReference} instances instead of {@link DataSourceId}
* instances is mainly done for user convenience purposes. * instances is mainly done for user convenience purposes.
* * <p>
* While a {@link DataSourceId} represents a unique and canonical identifier for an X-Pipe data source, * While a {@link DataSourceId} represents a unique and canonical identifier for an X-Pipe data source,
* there also exist easier and shorter ways to address a data source. * there also exist easier and shorter ways to address a data source.
* This convenience comes at the price of ambiguity and instability for other types of references. * This convenience comes at the price of ambiguity and instability for other types of references.
@ -105,8 +105,12 @@ public interface DataSourceReference {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (o == null || getClass() != o.getClass()) return false; return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Id id = (Id) o; Id id = (Id) o;
return value.equals(id.value); return value.equals(id.value);
} }
@ -155,8 +159,12 @@ public interface DataSourceReference {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
if (o == null || getClass() != o.getClass()) return false; return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Name n = (Name) o; Name n = (Name) o;
return value.equals(n.value); return value.equals(n.value);
} }
@ -201,7 +209,9 @@ public interface DataSourceReference {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) {
return true;
}
return o != null && getClass() == o.getClass(); return o != null && getClass() == o.getClass();
} }

View file

@ -45,28 +45,6 @@ public abstract class TableDataSource<DS extends DataStore> extends DataSource<D
return newReadConnection(); return newReadConnection();
} }
@NoArgsConstructor
private static class CreateMappingFunction extends SimpleProxyFunction<TableMapping> {
private TableDataSource<?> source;
private TupleType type;
public CreateMappingFunction(TableDataSource<?> source, TupleType type) {
this.source = source;
this.type = type;
}
private TableMapping mapping;
@SneakyThrows
public void callLocal() {
try (TableWriteConnection w = source.openWriteConnection(WriteMode.REPLACE)) {
w.init();
mapping = w.createMapping(type).orElse(null);
}
}
}
public final Optional<TableMapping> createMapping(TupleType inputType) throws Exception { public final Optional<TableMapping> createMapping(TupleType inputType) throws Exception {
return Optional.ofNullable(new CreateMappingFunction(this, inputType).callAndGet()); return Optional.ofNullable(new CreateMappingFunction(this, inputType).callAndGet());
} }
@ -100,4 +78,25 @@ public abstract class TableDataSource<DS extends DataStore> extends DataSource<D
protected TableReadConnection newReadConnection() { protected TableReadConnection newReadConnection() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@NoArgsConstructor
private static class CreateMappingFunction extends SimpleProxyFunction<TableMapping> {
private TableDataSource<?> source;
private TupleType type;
private TableMapping mapping;
public CreateMappingFunction(TableDataSource<?> source, TupleType type) {
this.source = source;
this.type = type;
}
@SneakyThrows
public void callLocal() {
try (TableWriteConnection w = source.openWriteConnection(WriteMode.REPLACE)) {
w.init();
mapping = w.createMapping(type).orElse(null);
}
}
}
} }

View file

@ -13,6 +13,17 @@ import java.util.stream.IntStream;
@Getter @Getter
public class TableMapping { public class TableMapping {
protected final Integer[] columMap;
private final TupleType inputType;
private final TupleType outputType;
@JsonCreator
public TableMapping(TupleType inputType, TupleType outputType, Integer[] columMap) {
this.inputType = inputType;
this.outputType = outputType;
this.columMap = columMap;
}
private static Integer[] range(int size) { private static Integer[] range(int size) {
var array = new Integer[size]; var array = new Integer[size];
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -58,19 +69,6 @@ public class TableMapping {
return OptionalInt.empty(); return OptionalInt.empty();
} }
private final TupleType inputType;
private final TupleType outputType;
protected final Integer[] columMap;
@JsonCreator
public TableMapping(TupleType inputType, TupleType outputType, Integer[] columMap) {
this.inputType = inputType;
this.outputType = outputType;
this.columMap = columMap;
}
public boolean isIdentity() { public boolean isIdentity() {
return inputType.equals(outputType) return inputType.equals(outputType)
&& Arrays.equals(columMap, range(getInputType().getSize())); && Arrays.equals(columMap, range(getInputType().getSize()));

View file

@ -9,37 +9,39 @@ import java.util.ServiceLoader;
public class WriteMode extends JacksonizedValue { public class WriteMode extends JacksonizedValue {
public static final Replace REPLACE = new Replace();
public static final Append APPEND = new Append();
public static final Prepend PREPEND = new Prepend();
private static final List<WriteMode> ALL = new ArrayList<>(); private static final List<WriteMode> ALL = new ArrayList<>();
public static void init(ModuleLayer layer) { public static void init(ModuleLayer layer) {
if (ALL.size() == 0) { if (ALL.size() == 0) {
ALL.addAll(ServiceLoader.load(layer, WriteMode.class).stream() ALL.addAll(ServiceLoader.load(layer, WriteMode.class).stream()
.map(p -> p.get()) .map(p -> p.get())
.toList()); .toList());
} }
} }
@JsonTypeName("replace")
public static final class Replace extends WriteMode {}
@JsonTypeName("append")
public static final class Append extends WriteMode {}
@JsonTypeName("prepend")
public static final class Prepend extends WriteMode {}
public static final Replace REPLACE = new Replace();
public static final Append APPEND = new Append();
public static final Prepend PREPEND = new Prepend();
public final String getId() {
return getClass().getAnnotation(JsonTypeName.class).value();
}
public static WriteMode byId(String id) { public static WriteMode byId(String id) {
return ALL.stream() return ALL.stream()
.filter(writeMode -> writeMode.getId().equalsIgnoreCase(id)) .filter(writeMode -> writeMode.getId().equalsIgnoreCase(id))
.findFirst() .findFirst()
.orElseThrow(); .orElseThrow();
} }
public final String getId() {
return getClass().getAnnotation(JsonTypeName.class).value();
}
@JsonTypeName("replace")
public static final class Replace extends WriteMode {
}
@JsonTypeName("append")
public static final class Append extends WriteMode {
}
@JsonTypeName("prepend")
public static final class Prepend extends WriteMode {
}
} }

View file

@ -16,7 +16,10 @@ import java.util.Optional;
* *
* @see DataSource * @see DataSource
*/ */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
public interface DataStore { public interface DataStore {
default boolean shouldPersist() { default boolean shouldPersist() {
@ -61,23 +64,25 @@ public interface DataStore {
/** /**
* Performs a validation of this data store. * Performs a validation of this data store.
* * <p>
* This validation can include one of multiple things: * This validation can include one of multiple things:
* - Sanity checks of individual properties * - Sanity checks of individual properties
* - Existence checks * - Existence checks
* - Connection checks * - Connection checks
* * <p>
* All in all, a successful execution of this method should almost guarantee * All in all, a successful execution of this method should almost guarantee
* that the data store can be successfully accessed in the near future. * that the data store can be successfully accessed in the near future.
* * <p>
* Note that some checks may take a long time, for example if a connection has to be validated. * Note that some checks may take a long time, for example if a connection has to be validated.
* The caller should therefore expect a runtime of multiple seconds when calling this method. * The caller should therefore expect a runtime of multiple seconds when calling this method.
* *
* @throws Exception if any part of the validation went wrong * @throws Exception if any part of the validation went wrong
*/ */
default void validate() throws Exception {} default void validate() throws Exception {
}
default void checkComplete() throws Exception {} default void checkComplete() throws Exception {
}
default boolean delete() throws Exception { default boolean delete() throws Exception {
return false; return false;

View file

@ -36,7 +36,7 @@ public interface MachineStore extends FileSystemStore, ShellStore {
public default boolean mkdirs(String file) throws Exception { public default boolean mkdirs(String file) throws Exception {
try (var pc = create().command(proc -> proc.getShellType() try (var pc = create().command(proc -> proc.getShellType()
.flatten(proc.getShellType() .flatten(proc.getShellType()
.createMkdirsCommand(proc.getOsType().normalizeFileName(file)))) .createMkdirsCommand(proc.getOsType().normalizeFileName(file))))
.start()) { .start()) {
return pc.discardAndCheckExit(); return pc.discardAndCheckExit();
} }

View file

@ -28,9 +28,11 @@ public interface ShellStore extends DataStore {
return pc.getShellType(); return pc.getShellType();
} }
} }
@Override @Override
default void validate() throws Exception { default void validate() throws Exception {
try (ShellProcessControl pc = create().start()) {} try (ShellProcessControl pc = create().start()) {
}
} }
public default String queryMachineName() throws Exception { public default String queryMachineName() throws Exception {

View file

@ -4,11 +4,12 @@ import io.xpipe.core.util.DataStateProvider;
import java.util.function.Supplier; import java.util.function.Supplier;
public interface StatefulDataStore extends DataStore { public interface StatefulDataStore extends DataStore {
default <T> T getState(String key, Class<T> c, T def) { default <T> T getState(String key, Class<T> c, T def) {
return DataStateProvider.get().getState(this, key, c, () -> def); return DataStateProvider.get().getState(this, key, c, () -> def);
} }
default <T> T getOrComputeState(String key, Class<T> c, Supplier<T> def) { default <T> T getOrComputeState(String key, Class<T> c, Supplier<T> def) {
return DataStateProvider.get().getState(this, key, c, def); return DataStateProvider.get().getState(this, key, c, def);
} }

View file

@ -52,7 +52,8 @@ public class CoreJacksonModule extends SimpleModule {
new NamedType(BaseQueryElement.class), new NamedType(BaseQueryElement.class),
new NamedType(ChoiceElement.class), new NamedType(ChoiceElement.class),
new NamedType(BusyElement.class), new NamedType(BusyElement.class),
new NamedType(HeaderElement.class)); new NamedType(HeaderElement.class)
);
addSerializer(Charset.class, new CharsetSerializer()); addSerializer(Charset.class, new CharsetSerializer());
addDeserializer(Charset.class, new CharsetDeserializer()); addDeserializer(Charset.class, new CharsetDeserializer());
@ -197,12 +198,16 @@ public class CoreJacksonModule extends SimpleModule {
@JsonSerialize(as = Throwable.class) @JsonSerialize(as = Throwable.class)
public abstract static class ThrowableTypeMixIn { public abstract static class ThrowableTypeMixIn {
@JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class, property = "$id") @JsonIdentityInfo(
generator = ObjectIdGenerators.StringIdGenerator.class,
property = "$id"
)
private Throwable cause; private Throwable cause;
} }
@JsonSerialize(as = DataSourceReference.class) @JsonSerialize(as = DataSourceReference.class)
public abstract static class DataSourceReferenceTypeMixIn {} public abstract static class DataSourceReferenceTypeMixIn {
}
public class NullSerializer extends JsonSerializer<Object> { public class NullSerializer extends JsonSerializer<Object> {
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)

View file

@ -14,8 +14,8 @@ public abstract class DataStateProvider {
public static DataStateProvider get() { public static DataStateProvider get() {
if (INSTANCE == null) { if (INSTANCE == null) {
INSTANCE = ServiceLoader.load(ModuleLayer.boot(), DataStateProvider.class) INSTANCE = ServiceLoader.load(ModuleLayer.boot(), DataStateProvider.class)
.findFirst() .findFirst()
.orElseThrow(); .orElseThrow();
} }
return INSTANCE; return INSTANCE;

View file

@ -42,7 +42,9 @@ public class Deobfuscator {
deobfuscate(throwable.getCause()); deobfuscate(throwable.getCause());
} }
for (Throwable suppressed : throwable.getSuppressed()) { for (Throwable suppressed : throwable.getSuppressed()) {
if (suppressed != throwable) deobfuscate(suppressed); if (suppressed != throwable) {
deobfuscate(suppressed);
}
} }
} catch (Throwable ex) { } catch (Throwable ex) {
System.err.println("Deobfuscation failed"); System.err.println("Deobfuscation failed");
@ -65,9 +67,10 @@ public class Deobfuscator {
var file = Files.createTempFile("xpipe_stracktrace", null); var file = Files.createTempFile("xpipe_stracktrace", null);
Files.writeString(file, stackTrace); Files.writeString(file, stackTrace);
var proc = new ProcessBuilder( var proc = new ProcessBuilder(
"retrace." + (OsType.getLocal().equals(OsType.WINDOWS) ? "bat" : "sh"), "retrace." + (OsType.getLocal().equals(OsType.WINDOWS) ? "bat" : "sh"),
System.getenv("XPIPE_MAPPING"), System.getenv("XPIPE_MAPPING"),
file.toString()) file.toString()
)
.redirectErrorStream(true); .redirectErrorStream(true);
var active = proc.start(); var active = proc.start();
var out = new String(active.getInputStream().readAllBytes()).replaceAll("\r\n", NewLine.LF.getNewLineString()); var out = new String(active.getInputStream().readAllBytes()).replaceAll("\r\n", NewLine.LF.getNewLineString());
@ -91,7 +94,7 @@ public class Deobfuscator {
System.err.println(s); System.err.println(s);
} }
private static boolean canDeobfuscate() throws Exception { private static boolean canDeobfuscate() throws Exception {
if (!System.getenv().containsKey("XPIPE_MAPPING")) { if (!System.getenv().containsKey("XPIPE_MAPPING")) {
return false; return false;
} }

View file

@ -20,6 +20,7 @@ public class Identifiers {
String.join("", split), String.join("", split),
String.join(" ", split), String.join(" ", split),
String.join("_", split), String.join("_", split),
String.join("-", split)); String.join("-", split)
);
} }
} }

View file

@ -25,13 +25,13 @@ public class JacksonMapper {
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE); objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
objectMapper.setVisibility(objectMapper objectMapper.setVisibility(objectMapper
.getSerializationConfig() .getSerializationConfig()
.getDefaultVisibilityChecker() .getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY) .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE) .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE) .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE) .withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)); .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
var modules = findModules(ModuleLayer.boot()); var modules = findModules(ModuleLayer.boot());
objectMapper.registerModules(modules); objectMapper.registerModules(modules);

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