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; package io.xpipe.api;
import io.xpipe.api.impl.DataSourceImpl; import io.xpipe.api.impl.DataSourceImpl;
import io.xpipe.core.source.DataSourceConfig;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceType; import io.xpipe.core.source.DataSourceType;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.Map; import java.util.Map;
@ -34,6 +36,18 @@ public interface DataSource {
return DataSourceImpl.get(id); 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. * 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. * i.e. it is not added to the XPipe data source storage.
* *
* @param url the url that points to the data * @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 * @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 * @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) { static DataSource wrap(URL url, String type, Map<String, String> configOptions) {
return null; 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) { static DataSource wrap(URL url) {
return wrap(url, Map.of()); return wrap(url, null, Map.of());
} }
DataSourceId getId(); DataSourceId getId();
DataSourceType getType(); 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 * @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; package io.xpipe.api.impl;
import io.xpipe.api.DataSource; import io.xpipe.api.DataSource;
import io.xpipe.api.DataTable;
import io.xpipe.api.XPipeApiConnector; import io.xpipe.api.XPipeApiConnector;
import io.xpipe.beacon.BeaconClient; import io.xpipe.beacon.BeaconClient;
import io.xpipe.beacon.ClientException; import io.xpipe.beacon.ClientException;
import io.xpipe.beacon.ConnectorException; import io.xpipe.beacon.ConnectorException;
import io.xpipe.beacon.ServerException; import io.xpipe.beacon.ServerException;
import io.xpipe.beacon.exchange.ReadInfoExchange; 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 io.xpipe.core.source.DataSourceId;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.Map; import java.util.Map;
@ -25,7 +28,7 @@ public abstract class DataSourceImpl implements DataSource {
switch (res.getType()) { switch (res.getType()) {
case TABLE -> { case TABLE -> {
var data = res.getTableData(); 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 STRUCTURE -> {
} }
@ -42,12 +45,35 @@ public abstract class DataSourceImpl implements DataSource {
new XPipeApiConnector() { new XPipeApiConnector() {
@Override @Override
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException { protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
var req = ReadInfoExchange.Request.builder().sourceId(ds).build(); var req = StoreResourceExchange.Request.builder()
ReadInfoExchange.Response res = performSimpleExchange(sc, req); .url(url).type(type).build();
switch (res.getType()) { StoreResourceExchange.Response res = performSimpleExchange(sc, req);
switch (res.getSourceType()) {
case TABLE -> { case TABLE -> {
var data = res.getTableData(); 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 -> { case STRUCTURE -> {
} }
@ -60,13 +86,20 @@ public abstract class DataSourceImpl implements DataSource {
} }
private final DataSourceId sourceId; private final DataSourceId sourceId;
private final DataSourceConfig sourceConfig;
public DataSourceImpl(DataSourceId sourceId) { public DataSourceImpl(DataSourceId sourceId, DataSourceConfig sourceConfig) {
this.sourceId = sourceId; this.sourceId = sourceId;
this.sourceConfig = sourceConfig;
} }
@Override @Override
public DataSourceId getId() { public DataSourceId getId() {
return sourceId; 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.TypedDataStreamParser;
import io.xpipe.core.data.typed.TypedDataStructureNodeReader; import io.xpipe.core.data.typed.TypedDataStructureNodeReader;
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader; import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
import io.xpipe.core.source.DataSourceConfig;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceType; import io.xpipe.core.source.DataSourceType;
@ -31,8 +32,8 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
private final int size; private final int size;
private final DataType dataType; private final DataType dataType;
public DataTableImpl(DataSourceId id, int size, DataType dataType) { public DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, int size, DataType dataType) {
super(id); super(id, sourceConfig);
this.id = id; this.id = id;
this.size = size; this.size = size;
this.dataType = dataType; 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.RequestMessage;
import io.xpipe.beacon.message.ResponseMessage; import io.xpipe.beacon.message.ResponseMessage;
import io.xpipe.core.data.type.DataType; import io.xpipe.core.data.type.DataType;
import io.xpipe.core.source.DataSourceConfig;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceType; import io.xpipe.core.source.DataSourceType;
import lombok.Builder; import lombok.Builder;
@ -39,6 +40,7 @@ public class ReadInfoExchange implements MessageExchange<ReadInfoExchange.Reques
public static class Response implements ResponseMessage { public static class Response implements ResponseMessage {
DataSourceId sourceId; DataSourceId sourceId;
DataSourceType type; DataSourceType type;
DataSourceConfig config;
Object data; Object data;
public TableData getTableData() { 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.RequestMessage;
import io.xpipe.beacon.message.ResponseMessage; import io.xpipe.beacon.message.ResponseMessage;
import io.xpipe.core.source.DataSourceConfig;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;
import io.xpipe.core.source.DataSourceType;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import lombok.extern.jackson.Jacksonized; import lombok.extern.jackson.Jacksonized;
import java.util.Map; import java.net.URL;
import java.util.UUID;
public class StoreEndExchange implements MessageExchange<StoreEndExchange.Request, StoreEndExchange.Response> { public class StoreEditExchange implements MessageExchange<StoreEditExchange.Request, StoreEditExchange.Response> {
@Override @Override
public String getId() { public String getId() {
return "storeEnd"; return "storeEdit";
} }
@Override @Override
public Class<StoreEndExchange.Request> getRequestClass() { public Class<StoreEditExchange.Request> getRequestClass() {
return StoreEndExchange.Request.class; return StoreEditExchange.Request.class;
} }
@Override @Override
public Class<StoreEndExchange.Response> getResponseClass() { public Class<StoreEditExchange.Response> getResponseClass() {
return StoreEndExchange.Response.class; return StoreEditExchange.Response.class;
} }
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Request implements RequestMessage { public static class Request implements RequestMessage {
UUID entryId; DataSourceId sourceId;
Map<String, String> values; DataSourceConfig config;
} }
@Jacksonized @Jacksonized
@Builder @Builder
@Value @Value
public static class Response implements ResponseMessage { 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; requires javafx.graphics;
exports io.xpipe.extension; exports io.xpipe.extension;
exports io.xpipe.extension.cli;
uses DataSourceProvider; uses DataSourceProvider;
uses DataSourceGuiProvider; uses DataSourceGuiProvider;

View file

@ -11,7 +11,7 @@ apply from: "$rootDir/deps/javafx-static.gradle"
version '0.1' version '0.1'
group 'io.xpipe' group 'io.xpipe'
jar.archiveBaseName = 'xpipe' archivesBaseName = 'xpipe'
java { java {
modularity.inferModulePath = true modularity.inferModulePath = true

View file

@ -19,6 +19,12 @@ public class HomePricesSample {
// It allows us however to bundle the data with this sample program. // It allows us however to bundle the data with this sample program.
homePricesTable = DataSource.wrap(resource).asTable(); 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()); System.out.println("The highest selling house entry is: " + getHighestSellingHouse());
} }