diff --git a/api/src/main/java/io/xpipe/api/DataSource.java b/api/src/main/java/io/xpipe/api/DataSource.java index 97f882b86..f80eccc47 100644 --- a/api/src/main/java/io/xpipe/api/DataSource.java +++ b/api/src/main/java/io/xpipe/api/DataSource.java @@ -1,9 +1,11 @@ package io.xpipe.api; import io.xpipe.api.impl.DataSourceImpl; +import io.xpipe.core.source.DataSourceConfig; import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceType; +import java.io.InputStream; import java.net.URL; import java.util.Map; @@ -34,6 +36,18 @@ public interface DataSource { return DataSourceImpl.get(id); } + static DataSource wrap(InputStream in, String type, Map configOptions) { + return DataSourceImpl.wrap(in, type, configOptions); + } + + static DataSource wrap(InputStream in, String type) { + return DataSourceImpl.wrap(in, type, Map.of()); + } + + static DataSource wrap(InputStream in) { + return DataSourceImpl.wrap(in, null, Map.of()); + } + /** * Retrieves a reference to the given local data source that is specified by a URL. * @@ -41,26 +55,38 @@ public interface DataSource { * i.e. it is not added to the XPipe data source storage. * * @param url the url that points to the data + * @param type the data source type * @param configOptions additional configuration options for the specific data source type * @return a reference to the data source that can be used to access the underlying data source */ - static DataSource wrap(URL url, Map configOptions) { - return null; + static DataSource wrap(URL url, String type, Map configOptions) { + return DataSourceImpl.wrap(url, type, configOptions); } /** - * Wrapper for {@link #wrap(URL, Map)} that passes no configuration options. + * Wrapper for {@link #wrap(URL, String, Map)} that passes no configuration options. + * As a result, the data source configuration is automatically determined by X-Pipe for the given type. + */ + static DataSource wrap(URL url, String type) { + return wrap(url, type, Map.of()); + } + + /** + * Wrapper for {@link #wrap(URL, String, Map)} that passes no type and no configuration options. + * As a result, the data source type and configuration is automatically determined by X-Pipe. */ static DataSource wrap(URL url) { - return wrap(url, Map.of()); + return wrap(url, null, Map.of()); } DataSourceId getId(); DataSourceType getType(); + DataSourceConfig getConfig(); + /** - * Attemps to cast this object to a {@link DataTable}. + * Attempts to cast this object to a {@link DataTable}. * * @throws UnsupportedOperationException if the data source is not a table */ diff --git a/api/src/main/java/io/xpipe/api/IntConverter.java b/api/src/main/java/io/xpipe/api/IntConverter.java deleted file mode 100644 index 61babeac9..000000000 --- a/api/src/main/java/io/xpipe/api/IntConverter.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.xpipe.api; - -import java.util.function.IntConsumer; - -public class IntConverter { - - private IntConsumer consumer; - - public IntConverter(IntConsumer consumer) { - this.consumer = consumer; - } - - public void onValue(byte[] value) { - if (value.length > 4) { - throw new IllegalArgumentException("Unable to fit " + value.length + " bytes into an integer"); - } - - int v = value[0] << 24 | (value[1] & 0xFF) << 16 | (value[2] & 0xFF) << 8 | (value[3] & 0xFF); - consumer.accept(v); - } -} diff --git a/api/src/main/java/io/xpipe/api/impl/DataSourceImpl.java b/api/src/main/java/io/xpipe/api/impl/DataSourceImpl.java index b796a0b0c..64cc12a58 100644 --- a/api/src/main/java/io/xpipe/api/impl/DataSourceImpl.java +++ b/api/src/main/java/io/xpipe/api/impl/DataSourceImpl.java @@ -1,15 +1,18 @@ package io.xpipe.api.impl; import io.xpipe.api.DataSource; -import io.xpipe.api.DataTable; import io.xpipe.api.XPipeApiConnector; import io.xpipe.beacon.BeaconClient; import io.xpipe.beacon.ClientException; import io.xpipe.beacon.ConnectorException; import io.xpipe.beacon.ServerException; import io.xpipe.beacon.exchange.ReadInfoExchange; +import io.xpipe.beacon.exchange.StoreResourceExchange; +import io.xpipe.beacon.exchange.StoreStreamExchange; +import io.xpipe.core.source.DataSourceConfig; import io.xpipe.core.source.DataSourceId; +import java.io.InputStream; import java.net.URL; import java.util.Map; @@ -25,7 +28,7 @@ public abstract class DataSourceImpl implements DataSource { switch (res.getType()) { case TABLE -> { var data = res.getTableData(); - source[0] = new DataTableImpl(res.getSourceId(), data.getRowCount(), data.getDataType()); + source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType()); } case STRUCTURE -> { } @@ -42,12 +45,35 @@ public abstract class DataSourceImpl implements DataSource { new XPipeApiConnector() { @Override protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException { - var req = ReadInfoExchange.Request.builder().sourceId(ds).build(); - ReadInfoExchange.Response res = performSimpleExchange(sc, req); - switch (res.getType()) { + var req = StoreResourceExchange.Request.builder() + .url(url).type(type).build(); + StoreResourceExchange.Response res = performSimpleExchange(sc, req); + switch (res.getSourceType()) { case TABLE -> { var data = res.getTableData(); - source[0] = new DataTableImpl(res.getSourceId(), data.getRowCount(), data.getDataType()); + source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType()); + } + case STRUCTURE -> { + } + case RAW -> { + } + } + } + }.execute(); + return source[0]; + } + + public static DataSource wrap(InputStream in, String type, Map config) { + final DataSource[] source = new DataSource[1]; + new XPipeApiConnector() { + @Override + protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException { + var req = StoreStreamExchange.Request.builder().type(type).build(); + StoreStreamExchange.Response res = performOutputExchange(sc, req, in::transferTo); + switch (res.getSourceType()) { + case TABLE -> { + var data = res.getTableData(); + source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType()); } case STRUCTURE -> { } @@ -60,13 +86,20 @@ public abstract class DataSourceImpl implements DataSource { } private final DataSourceId sourceId; + private final DataSourceConfig sourceConfig; - public DataSourceImpl(DataSourceId sourceId) { + public DataSourceImpl(DataSourceId sourceId, DataSourceConfig sourceConfig) { this.sourceId = sourceId; + this.sourceConfig = sourceConfig; } @Override public DataSourceId getId() { return sourceId; } + + @Override + public DataSourceConfig getConfig() { + return sourceConfig; + } } diff --git a/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java b/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java index 0e6802369..e96a321c8 100644 --- a/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java +++ b/api/src/main/java/io/xpipe/api/impl/DataTableImpl.java @@ -15,6 +15,7 @@ import io.xpipe.core.data.typed.TypedAbstractReader; import io.xpipe.core.data.typed.TypedDataStreamParser; import io.xpipe.core.data.typed.TypedDataStructureNodeReader; import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader; +import io.xpipe.core.source.DataSourceConfig; import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceType; @@ -31,8 +32,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable { private final int size; private final DataType dataType; - public DataTableImpl(DataSourceId id, int size, DataType dataType) { - super(id); + public DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, int size, DataType dataType) { + super(id, sourceConfig); this.id = id; this.size = size; this.dataType = dataType; diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/CliOptionPageExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/CliOptionPageExchange.java deleted file mode 100644 index 0f425f8fd..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/CliOptionPageExchange.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.message.RequestMessage; -import io.xpipe.beacon.message.ResponseMessage; -import io.xpipe.core.data.type.DataType; -import io.xpipe.core.source.DataSourceId; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class CliOptionPageExchange implements MessageExchange { - - @Override - public String getId() { - return "cliOptionPage"; - } - - @Override - public Class getRequestClass() { - return CliOptionPageExchange.Request.class; - } - - @Override - public Class getResponseClass() { - return CliOptionPageExchange.Response.class; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - DataSourceId newSourceId; - String type; - boolean hasInputStream; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - DataSourceId sourceId; - DataType dataType; - int rowCount; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/ReadInfoExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/ReadInfoExchange.java index 2d96b089f..713cf2653 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/ReadInfoExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/ReadInfoExchange.java @@ -3,6 +3,7 @@ package io.xpipe.beacon.exchange; import io.xpipe.beacon.message.RequestMessage; import io.xpipe.beacon.message.ResponseMessage; import io.xpipe.core.data.type.DataType; +import io.xpipe.core.source.DataSourceConfig; import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceType; import lombok.Builder; @@ -39,6 +40,7 @@ public class ReadInfoExchange implements MessageExchange { +public class StoreEditExchange implements MessageExchange { @Override public String getId() { - return "storeEnd"; + return "storeEdit"; } @Override - public Class getRequestClass() { - return StoreEndExchange.Request.class; + public Class getRequestClass() { + return StoreEditExchange.Request.class; } @Override - public Class getResponseClass() { - return StoreEndExchange.Response.class; + public Class getResponseClass() { + return StoreEditExchange.Response.class; } @Jacksonized @Builder @Value public static class Request implements RequestMessage { - UUID entryId; - Map values; + DataSourceId sourceId; + DataSourceConfig config; } @Jacksonized @Builder @Value public static class Response implements ResponseMessage { - DataSourceId sourceId; } } diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/StoreResourceExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/StoreResourceExchange.java new file mode 100644 index 000000000..07ee329b7 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/StoreResourceExchange.java @@ -0,0 +1,52 @@ +package io.xpipe.beacon.exchange; + +import io.xpipe.beacon.message.RequestMessage; +import io.xpipe.beacon.message.ResponseMessage; +import io.xpipe.core.source.DataSourceId; +import io.xpipe.core.source.DataSourceType; +import io.xpipe.core.source.DataSourceConfig; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.net.URL; + +public class StoreResourceExchange implements MessageExchange { + + @Override + public String getId() { + return "storeResource"; + } + + @Override + public Class getRequestClass() { + return StoreResourceExchange.Request.class; + } + + @Override + public Class getResponseClass() { + return StoreResourceExchange.Response.class; + } + + @Jacksonized + @Builder + @Value + public static class Request implements RequestMessage { + URL url; + String type; + } + + @Jacksonized + @Builder + @Value + public static class Response implements ResponseMessage { + DataSourceId sourceId; + DataSourceType sourceType; + DataSourceConfig config; + Object data; + + public ReadInfoExchange.TableData getTableData() { + return (ReadInfoExchange.TableData) data; + } + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStartExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStartExchange.java deleted file mode 100644 index 5ee1dd1b7..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStartExchange.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.message.RequestMessage; -import io.xpipe.beacon.message.ResponseMessage; -import io.xpipe.extension.cli.CliOptionPage; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class StoreStartExchange implements MessageExchange { - - @Override - public String getId() { - return "storeStart"; - } - - @Override - public Class getRequestClass() { - return StoreStartExchange.Request.class; - } - - @Override - public Class getResponseClass() { - return StoreStartExchange.Response.class; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - String type; - boolean hasInputStream; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - CliOptionPage page; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStreamExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStreamExchange.java new file mode 100644 index 000000000..82d15cc60 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/StoreStreamExchange.java @@ -0,0 +1,49 @@ +package io.xpipe.beacon.exchange; + +import io.xpipe.beacon.message.RequestMessage; +import io.xpipe.beacon.message.ResponseMessage; +import io.xpipe.core.source.DataSourceId; +import io.xpipe.core.source.DataSourceType; +import io.xpipe.core.source.DataSourceConfig; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class StoreStreamExchange implements MessageExchange { + + @Override + public String getId() { + return "storeStream"; + } + + @Override + public Class getRequestClass() { + return StoreStreamExchange.Request.class; + } + + @Override + public Class getResponseClass() { + return StoreStreamExchange.Response.class; + } + + @Jacksonized + @Builder + @Value + public static class Request implements RequestMessage { + String type; + } + + @Jacksonized + @Builder + @Value + public static class Response implements ResponseMessage { + DataSourceId sourceId; + DataSourceType sourceType; + DataSourceConfig config; + Object data; + + public ReadInfoExchange.TableData getTableData() { + return (ReadInfoExchange.TableData) data; + } + } +} diff --git a/core/src/main/java/io/xpipe/core/source/DataSourceConfig.java b/core/src/main/java/io/xpipe/core/source/DataSourceConfig.java new file mode 100644 index 000000000..550237b81 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/source/DataSourceConfig.java @@ -0,0 +1,49 @@ +package io.xpipe.core.source; + + +import java.util.List; + +public class DataSourceConfig { + + private String description; + private List> options; + + public DataSourceConfig(String description, List> options) { + this.description = description; + this.options = options; + } + + public String getDescription() { + return description; + } + + public List> getOptions() { + return options; + } + + public abstract static class Option { + + private final String name; + protected T value; + + public Option(String name) { + this.name = name; + this.value = null; + } + + public Option(String name, T value) { + this.name = name; + this.value = value; + } + + protected abstract String enterValue(String val); + + public String getName() { + return name; + } + + public T getValue() { + return value; + } + } +} diff --git a/extension/src/main/java/io/xpipe/extension/cli/CliOption.java b/extension/src/main/java/io/xpipe/extension/cli/CliOption.java deleted file mode 100644 index 4e03ca943..000000000 --- a/extension/src/main/java/io/xpipe/extension/cli/CliOption.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.xpipe.extension.cli; - -public abstract class CliOption { - - private final String name; - protected T value; - - public CliOption(String name) { - this.name = name; - this.value = null; - } - - public CliOption(String name, T value) { - this.name = name; - this.value = value; - } - - protected abstract String enterValue(String val); - - public String getName() { - return name; - } - - public T getValue() { - return value; - } -} diff --git a/extension/src/main/java/io/xpipe/extension/cli/CliOptionPage.java b/extension/src/main/java/io/xpipe/extension/cli/CliOptionPage.java deleted file mode 100644 index 4f53b4717..000000000 --- a/extension/src/main/java/io/xpipe/extension/cli/CliOptionPage.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.xpipe.extension.cli; - -import java.util.List; - -public class CliOptionPage { - - private String description; - private List> options; - - public CliOptionPage(String description, List> options) { - this.description = description; - this.options = options; - } - - public String getDescription() { - return description; - } - - public List> getOptions() { - return options; - } -} diff --git a/extension/src/main/java/module-info.java b/extension/src/main/java/module-info.java index 909e74343..a5c58e641 100644 --- a/extension/src/main/java/module-info.java +++ b/extension/src/main/java/module-info.java @@ -8,7 +8,6 @@ module io.xpipe.extension { requires javafx.graphics; exports io.xpipe.extension; - exports io.xpipe.extension.cli; uses DataSourceProvider; uses DataSourceGuiProvider; diff --git a/library/build.gradle b/library/build.gradle index 6a75e733a..38ff2f3da 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -11,7 +11,7 @@ apply from: "$rootDir/deps/javafx-static.gradle" version '0.1' group 'io.xpipe' -jar.archiveBaseName = 'xpipe' +archivesBaseName = 'xpipe' java { modularity.inferModulePath = true diff --git a/samples/sample_program/src/main/java/io/xpipe/sample/HomePricesSample.java b/samples/sample_program/src/main/java/io/xpipe/sample/HomePricesSample.java index 0ac6d034d..56406c2ba 100644 --- a/samples/sample_program/src/main/java/io/xpipe/sample/HomePricesSample.java +++ b/samples/sample_program/src/main/java/io/xpipe/sample/HomePricesSample.java @@ -19,6 +19,12 @@ public class HomePricesSample { // It allows us however to bundle the data with this sample program. homePricesTable = DataSource.wrap(resource).asTable(); + // As we didn't pass any configuration parameters, X-Pipe will try to automatically detect + // the correct configuration parameters. You can access these parameters like this: + System.out.println("Determined configuration: " + homePricesTable.getConfig()); + // In case these some parameters are not chosen correctly, you can pass the proper values + // to the wrap() method. + System.out.println("The highest selling house entry is: " + getHighestSellingHouse()); }