This commit is contained in:
Christopher Schnick 2022-01-02 17:24:51 +01:00
parent 08bd127695
commit 8bb6f8be3d
16 changed files with 244 additions and 183 deletions

View file

@ -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<String, String> 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<String, String> configOptions) {
return null;
static DataSource wrap(URL url, String type, Map<String, String> 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
*/

View file

@ -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);
}
}

View file

@ -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<String,String> 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;
}
}

View file

@ -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;

View file

@ -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<CliOptionPageExchange.Request, CliOptionPageExchange.Response> {
@Override
public String getId() {
return "cliOptionPage";
}
@Override
public Class<CliOptionPageExchange.Request> getRequestClass() {
return CliOptionPageExchange.Request.class;
}
@Override
public Class<CliOptionPageExchange.Response> 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;
}
}

View file

@ -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<ReadInfoExchange.Reques
public static class Response implements ResponseMessage {
DataSourceId sourceId;
DataSourceType type;
DataSourceConfig config;
Object data;
public TableData getTableData() {

View file

@ -2,43 +2,43 @@ package io.xpipe.beacon.exchange;
import io.xpipe.beacon.message.RequestMessage;
import io.xpipe.beacon.message.ResponseMessage;
import io.xpipe.core.source.DataSourceConfig;
import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceType;
import lombok.Builder;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import java.util.Map;
import java.util.UUID;
import java.net.URL;
public class StoreEndExchange implements MessageExchange<StoreEndExchange.Request, StoreEndExchange.Response> {
public class StoreEditExchange implements MessageExchange<StoreEditExchange.Request, StoreEditExchange.Response> {
@Override
public String getId() {
return "storeEnd";
return "storeEdit";
}
@Override
public Class<StoreEndExchange.Request> getRequestClass() {
return StoreEndExchange.Request.class;
public Class<StoreEditExchange.Request> getRequestClass() {
return StoreEditExchange.Request.class;
}
@Override
public Class<StoreEndExchange.Response> getResponseClass() {
return StoreEndExchange.Response.class;
public Class<StoreEditExchange.Response> getResponseClass() {
return StoreEditExchange.Response.class;
}
@Jacksonized
@Builder
@Value
public static class Request implements RequestMessage {
UUID entryId;
Map<String, String> values;
DataSourceId sourceId;
DataSourceConfig config;
}
@Jacksonized
@Builder
@Value
public static class Response implements ResponseMessage {
DataSourceId sourceId;
}
}

View file

@ -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<StoreResourceExchange.Request, StoreResourceExchange.Response> {
@Override
public String getId() {
return "storeResource";
}
@Override
public Class<StoreResourceExchange.Request> getRequestClass() {
return StoreResourceExchange.Request.class;
}
@Override
public Class<StoreResourceExchange.Response> 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;
}
}
}

View file

@ -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<StoreStartExchange.Request, StoreStartExchange.Response> {
@Override
public String getId() {
return "storeStart";
}
@Override
public Class<StoreStartExchange.Request> getRequestClass() {
return StoreStartExchange.Request.class;
}
@Override
public Class<StoreStartExchange.Response> 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;
}
}

View file

@ -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<StoreStreamExchange.Request, StoreStreamExchange.Response> {
@Override
public String getId() {
return "storeStream";
}
@Override
public Class<StoreStreamExchange.Request> getRequestClass() {
return StoreStreamExchange.Request.class;
}
@Override
public Class<StoreStreamExchange.Response> 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;
}
}
}

View file

@ -0,0 +1,49 @@
package io.xpipe.core.source;
import java.util.List;
public class DataSourceConfig {
private String description;
private List<Option<?>> options;
public DataSourceConfig(String description, List<Option<?>> options) {
this.description = description;
this.options = options;
}
public String getDescription() {
return description;
}
public List<Option<?>> getOptions() {
return options;
}
public abstract static class Option<T> {
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;
}
}
}

View file

@ -1,27 +0,0 @@
package io.xpipe.extension.cli;
public abstract class CliOption<T> {
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;
}
}

View file

@ -1,22 +0,0 @@
package io.xpipe.extension.cli;
import java.util.List;
public class CliOptionPage {
private String description;
private List<CliOption<?>> options;
public CliOptionPage(String description, List<CliOption<?>> options) {
this.description = description;
this.options = options;
}
public String getDescription() {
return description;
}
public List<CliOption<?>> getOptions() {
return options;
}
}

View file

@ -8,7 +8,6 @@ module io.xpipe.extension {
requires javafx.graphics;
exports io.xpipe.extension;
exports io.xpipe.extension.cli;
uses DataSourceProvider;
uses DataSourceGuiProvider;

View file

@ -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

View file

@ -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());
}