mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-24 16:40:25 +00:00
Add more data sources and refactor some parts
This commit is contained in:
parent
bcc581c0bd
commit
2c041ecb0e
42 changed files with 775 additions and 196 deletions
16
api/src/main/java/io/xpipe/api/DataRaw.java
Normal file
16
api/src/main/java/io/xpipe/api/DataRaw.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package io.xpipe.api;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface DataRaw extends DataSource {
|
||||||
|
|
||||||
|
DataSourceInfo.Raw getInfo();
|
||||||
|
|
||||||
|
InputStream open();
|
||||||
|
|
||||||
|
byte[] readAll();
|
||||||
|
|
||||||
|
byte[] read(int maxBytes);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ 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.DataSourceConfig;
|
||||||
import io.xpipe.core.source.DataSourceId;
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceReference;
|
||||||
import io.xpipe.core.source.DataSourceType;
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -10,14 +11,22 @@ import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a reference to an XPipe data source.
|
* Represents a reference to a data source that is managed by X-Pipe.
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* By default, the lock is held until the calling program terminates and prevents
|
||||||
|
* other applications from modifying the data source in any way.
|
||||||
|
* To unlock the data source earlier, you can make use the {@link #unlock()} method.
|
||||||
*/
|
*/
|
||||||
public interface DataSource {
|
public interface DataSource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* NOT YET IMPLEMENTED!
|
||||||
|
*
|
||||||
* 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.
|
||||||
|
@ -29,28 +38,49 @@ public interface DataSource {
|
||||||
*
|
*
|
||||||
* @return the generator data source
|
* @return the generator data source
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static DataSource supplySource() {
|
static DataSource supplySource() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for {@link #get(DataSourceId)}.
|
* Wrapper for {@link #get(DataSourceReference)}.
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if {@code id} is not a valid data source id
|
* @throws IllegalArgumentException if {@code id} is not a valid data source id
|
||||||
*/
|
*/
|
||||||
static DataSource get(String id) {
|
static DataSource getById(String id) {
|
||||||
return get(DataSourceId.fromString(id));
|
return get(DataSourceReference.id(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link #get(DataSourceReference)} using the latest reference.
|
||||||
|
*/
|
||||||
|
static DataSource getLatest() {
|
||||||
|
return get(DataSourceReference.latest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link #get(DataSourceReference)} using a name reference.
|
||||||
|
*/
|
||||||
|
static DataSource getByName(String name) {
|
||||||
|
return get(DataSourceReference.name(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a reference to the given data source.
|
* Retrieves a reference to the given data source.
|
||||||
*
|
*
|
||||||
* @param id the data source id
|
* @param ref the data source reference
|
||||||
* @return a reference to the data source that can be used to access the underlying data source
|
|
||||||
*/
|
*/
|
||||||
static DataSource get(DataSourceId id) {
|
static DataSource get(DataSourceReference ref) {
|
||||||
return null;
|
return DataSourceImpl.get(ref);
|
||||||
//return DataSourceImpl.get(id);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the lock held by this program for this data source such
|
||||||
|
* that other applications can modify the data source again.
|
||||||
|
*/
|
||||||
|
static void unlock() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataSource wrap(InputStream in, String type, Map<String, String> configOptions) {
|
static DataSource wrap(InputStream in, String type, Map<String, String> configOptions) {
|
||||||
|
@ -110,4 +140,31 @@ public interface DataSource {
|
||||||
default DataTable asTable() {
|
default DataTable asTable() {
|
||||||
throw new UnsupportedOperationException("Data source is not a table");
|
throw new UnsupportedOperationException("Data source is not a table");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to cast this object to a {@link DataStructure}.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if the data source is not a structure
|
||||||
|
*/
|
||||||
|
default DataStructure asStructure() {
|
||||||
|
throw new UnsupportedOperationException("Data source is not a structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to cast this object to a {@link DataText}.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if the data source is not a text
|
||||||
|
*/
|
||||||
|
default DataText asText() {
|
||||||
|
throw new UnsupportedOperationException("Data source is not a text");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to cast this object to a {@link DataRaw}.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if the data source is not raw
|
||||||
|
*/
|
||||||
|
default DataRaw asRaw() {
|
||||||
|
throw new UnsupportedOperationException("Data source is not raw");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
api/src/main/java/io/xpipe/api/DataStructure.java
Normal file
11
api/src/main/java/io/xpipe/api/DataStructure.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package io.xpipe.api;
|
||||||
|
|
||||||
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
|
||||||
|
public interface DataStructure extends DataSource {
|
||||||
|
|
||||||
|
DataSourceInfo.Structure getInfo();
|
||||||
|
|
||||||
|
DataStructureNode read();
|
||||||
|
}
|
|
@ -2,28 +2,16 @@ package io.xpipe.api;
|
||||||
|
|
||||||
import io.xpipe.core.data.node.ArrayNode;
|
import io.xpipe.core.data.node.ArrayNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
|
||||||
import java.util.OptionalInt;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public interface DataTable extends Iterable<TupleNode>, DataSource {
|
public interface DataTable extends Iterable<TupleNode>, DataSource {
|
||||||
|
|
||||||
/**
|
DataSourceInfo.Table getInfo();
|
||||||
* @see DataSource#supplySource()
|
|
||||||
*/
|
|
||||||
static DataTable supplySource() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<TupleNode> stream();
|
Stream<TupleNode> stream();
|
||||||
|
|
||||||
int getRowCount();
|
|
||||||
|
|
||||||
OptionalInt getRowCountIfPresent();
|
|
||||||
|
|
||||||
TupleType getDataType();
|
|
||||||
|
|
||||||
ArrayNode readAll();
|
ArrayNode readAll();
|
||||||
|
|
||||||
ArrayNode read(int maxRows);
|
ArrayNode read(int maxRows);
|
||||||
|
|
28
api/src/main/java/io/xpipe/api/DataTableAccumulator.java
Normal file
28
api/src/main/java/io/xpipe/api/DataTableAccumulator.java
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package io.xpipe.api;
|
||||||
|
|
||||||
|
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||||
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An accumulator for table data.
|
||||||
|
*
|
||||||
|
* This class can be used to construct new table data sources by
|
||||||
|
* accumulating the rows using {@link #add(TupleNode)} or {@link #acceptor()} and then calling
|
||||||
|
* {@link #finish(DataSourceId)} to complete the construction process and create a new data source.
|
||||||
|
*/
|
||||||
|
public interface DataTableAccumulator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes the construction process and returns the data source reference.
|
||||||
|
*
|
||||||
|
* @param id the data source id to assign
|
||||||
|
*/
|
||||||
|
DataTable finish(DataSourceId id);
|
||||||
|
|
||||||
|
void add(TupleNode row);
|
||||||
|
|
||||||
|
DataStructureNodeAcceptor<TupleNode> acceptor();
|
||||||
|
|
||||||
|
int getCurrentRows();
|
||||||
|
}
|
18
api/src/main/java/io/xpipe/api/DataText.java
Normal file
18
api/src/main/java/io/xpipe/api/DataText.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package io.xpipe.api;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DataText extends DataSource, Iterable<String> {
|
||||||
|
|
||||||
|
DataSourceInfo.Text getInfo();
|
||||||
|
|
||||||
|
List<String> readAllLines();
|
||||||
|
|
||||||
|
List<String> readLines(int maxLines);
|
||||||
|
|
||||||
|
String readAll();
|
||||||
|
|
||||||
|
String read(int maxCharacters);
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
public class XPipeClientException extends RuntimeException {
|
|
||||||
|
|
||||||
public XPipeClientException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeClientException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeClientException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeClientException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
public class XPipeConnectException extends RuntimeException {
|
|
||||||
|
|
||||||
public XPipeConnectException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeConnectException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeConnectException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeConnectException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
import io.xpipe.core.data.node.DataStructureNode;
|
|
||||||
|
|
||||||
public interface XPipeDataStructureSource {
|
|
||||||
|
|
||||||
DataStructureNode read();
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
import io.xpipe.core.source.DataSourceId;
|
|
||||||
|
|
||||||
public abstract class XPipeDataTableBuilder {
|
|
||||||
|
|
||||||
private DataSourceId id;
|
|
||||||
|
|
||||||
public abstract void write();
|
|
||||||
|
|
||||||
public abstract void commit();
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
public class XPipeException extends RuntimeException {
|
|
||||||
|
|
||||||
public XPipeException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.xpipe.api;
|
|
||||||
|
|
||||||
public class XPipeServerException extends RuntimeException {
|
|
||||||
|
|
||||||
public XPipeServerException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeServerException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeServerException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public XPipeServerException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.xpipe.api;
|
package io.xpipe.api.connector;
|
||||||
|
|
||||||
import io.xpipe.beacon.*;
|
import io.xpipe.beacon.*;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonHelper;
|
||||||
|
@ -12,7 +12,7 @@ public abstract class XPipeApiConnector extends BeaconConnector {
|
||||||
var socket = constructSocket();
|
var socket = constructSocket();
|
||||||
handle(socket);
|
handle(socket);
|
||||||
} catch (Throwable ce) {
|
} catch (Throwable ce) {
|
||||||
throw new XPipeException(ce);
|
throw new RuntimeException(ce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
api/src/main/java/io/xpipe/api/impl/DataRawImpl.java
Normal file
49
api/src/main/java/io/xpipe/api/impl/DataRawImpl.java
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
|
import io.xpipe.api.DataRaw;
|
||||||
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class DataRawImpl extends DataSourceImpl implements DataRaw {
|
||||||
|
|
||||||
|
private final DataSourceInfo.Raw info;
|
||||||
|
|
||||||
|
public DataRawImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Raw info) {
|
||||||
|
super(sourceId, sourceConfig);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo.Raw getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream open() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] readAll() {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] read(int maxBytes) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataRaw asRaw() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package io.xpipe.api.impl;
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
import io.xpipe.api.DataSource;
|
import io.xpipe.api.DataSource;
|
||||||
import io.xpipe.api.XPipeApiConnector;
|
import io.xpipe.api.connector.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.InfoExchange;
|
import io.xpipe.beacon.exchange.QueryDataSourceExchange;
|
||||||
import io.xpipe.beacon.exchange.StoreResourceExchange;
|
import io.xpipe.beacon.exchange.StoreResourceExchange;
|
||||||
import io.xpipe.beacon.exchange.StoreStreamExchange;
|
import io.xpipe.beacon.exchange.StoreStreamExchange;
|
||||||
import io.xpipe.core.source.DataSourceConfig;
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
|
@ -24,9 +24,26 @@ 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 = InfoExchange.Request.builder().ref(ds).build();
|
var req = QueryDataSourceExchange.Request.builder().ref(ds).build();
|
||||||
InfoExchange.Response res = performSimpleExchange(sc, req);
|
QueryDataSourceExchange.Response res = performSimpleExchange(sc, req);
|
||||||
|
switch (res.getInfo().getType()) {
|
||||||
|
case TABLE -> {
|
||||||
|
var data = res.getInfo().asTable();
|
||||||
|
source[0] = new DataTableImpl(res.getId(), res.getConfig().getConfig(), data);
|
||||||
|
}
|
||||||
|
case STRUCTURE -> {
|
||||||
|
var info = res.getInfo().asStructure();
|
||||||
|
source[0] = new DataStructureImpl(res.getId(), res.getConfig().getConfig(), info);
|
||||||
|
}
|
||||||
|
case TEXT -> {
|
||||||
|
var info = res.getInfo().asText();
|
||||||
|
source[0] = new DataTextImpl(res.getId(), res.getConfig().getConfig(), info);
|
||||||
|
}
|
||||||
|
case RAW -> {
|
||||||
|
var info = res.getInfo().asRaw();
|
||||||
|
source[0] = new DataRawImpl(res.getId(), res.getConfig().getConfig(), info);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
return source[0];
|
return source[0];
|
||||||
|
|
38
api/src/main/java/io/xpipe/api/impl/DataStructureImpl.java
Normal file
38
api/src/main/java/io/xpipe/api/impl/DataStructureImpl.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
|
import io.xpipe.api.DataStructure;
|
||||||
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
|
||||||
|
public class DataStructureImpl extends DataSourceImpl implements DataStructure {
|
||||||
|
|
||||||
|
private final DataSourceInfo.Structure info;
|
||||||
|
|
||||||
|
public DataStructureImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Structure info) {
|
||||||
|
super(sourceId, sourceConfig);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.STRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStructure asStructure() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo.Structure getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStructureNode read() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
|
import io.xpipe.api.DataTable;
|
||||||
|
import io.xpipe.api.DataTableAccumulator;
|
||||||
|
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||||
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
|
||||||
|
public class DataTableAccumulatorImpl implements DataTableAccumulator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTable finish(DataSourceId id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(TupleNode row) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataStructureNodeAcceptor<TupleNode> acceptor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentRows() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.api.impl;
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
import io.xpipe.api.DataTable;
|
import io.xpipe.api.DataTable;
|
||||||
import io.xpipe.api.XPipeApiConnector;
|
import io.xpipe.api.connector.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;
|
||||||
|
@ -9,7 +9,6 @@ import io.xpipe.beacon.ServerException;
|
||||||
import io.xpipe.core.data.node.ArrayNode;
|
import io.xpipe.core.data.node.ArrayNode;
|
||||||
import io.xpipe.core.data.node.DataStructureNode;
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.data.node.TupleNode;
|
import io.xpipe.core.data.node.TupleNode;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
|
||||||
import io.xpipe.core.data.typed.TypedAbstractReader;
|
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.TypedReusableDataStructureNodeReader;
|
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
||||||
|
@ -27,12 +26,10 @@ import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
public class DataTableImpl extends DataSourceImpl implements DataTable {
|
public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
|
|
||||||
private final DataSourceId id;
|
|
||||||
private final DataSourceInfo.Table info;
|
private final DataSourceInfo.Table info;
|
||||||
|
|
||||||
public DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, DataSourceInfo.Table info) {
|
DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, DataSourceInfo.Table info) {
|
||||||
super(id, sourceConfig);
|
super(id, sourceConfig);
|
||||||
this.id = id;
|
|
||||||
this.info = info;
|
this.info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,40 +38,21 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo.Table getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
public Stream<TupleNode> stream() {
|
public Stream<TupleNode> stream() {
|
||||||
return StreamSupport.stream(
|
return StreamSupport.stream(
|
||||||
Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED), false);
|
Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSourceId getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceType getType() {
|
||||||
return DataSourceType.TABLE;
|
return DataSourceType.TABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRowCount() {
|
|
||||||
if (info.getRowCount() == -1) {
|
|
||||||
throw new UnsupportedOperationException("Row count is unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
return info.getRowCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OptionalInt getRowCountIfPresent() {
|
|
||||||
return info.getRowCount() != -1 ? OptionalInt.of(info.getRowCount()) : OptionalInt.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TupleType getDataType() {
|
|
||||||
return info.getDataType();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayNode readAll() {
|
public ArrayNode readAll() {
|
||||||
return read(Integer.MAX_VALUE);
|
return read(Integer.MAX_VALUE);
|
||||||
|
|
60
api/src/main/java/io/xpipe/api/impl/DataTextImpl.java
Normal file
60
api/src/main/java/io/xpipe/api/impl/DataTextImpl.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package io.xpipe.api.impl;
|
||||||
|
|
||||||
|
import io.xpipe.api.DataText;
|
||||||
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DataTextImpl extends DataSourceImpl implements DataText {
|
||||||
|
|
||||||
|
private final DataSourceInfo.Text info;
|
||||||
|
|
||||||
|
public DataTextImpl(DataSourceId sourceId, DataSourceConfig sourceConfig, DataSourceInfo.Text info) {
|
||||||
|
super(sourceId, sourceConfig);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataText asText() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo.Text getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> readAllLines() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> readLines(int maxLines) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readAll() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String read(int maxCharacters) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<String> iterator() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,4 +3,5 @@ module io.xpipe.api {
|
||||||
requires io.xpipe.beacon;
|
requires io.xpipe.beacon;
|
||||||
|
|
||||||
exports io.xpipe.api;
|
exports io.xpipe.api;
|
||||||
|
exports io.xpipe.api.connector;
|
||||||
}
|
}
|
|
@ -16,8 +16,8 @@ public class BeaconConfig {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||||
private static final int DEFAULT_PORT = 21721;
|
public static final int DEFAULT_PORT = 21721;
|
||||||
|
|
||||||
public static int getUsedPort() {
|
public static int getUsedPort() {
|
||||||
if (System.getProperty(BEACON_PORT_PROP) != null) {
|
if (System.getProperty(BEACON_PORT_PROP) != null) {
|
||||||
|
|
|
@ -2,30 +2,28 @@ 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.DataSourceConfigInstance;
|
import io.xpipe.core.source.*;
|
||||||
import io.xpipe.core.source.DataSourceInfo;
|
|
||||||
import io.xpipe.core.source.DataSourceReference;
|
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
public class InfoExchange implements MessageExchange<InfoExchange.Request, InfoExchange.Response> {
|
public class QueryDataSourceExchange implements MessageExchange<QueryDataSourceExchange.Request, QueryDataSourceExchange.Response> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return "info";
|
return "queryDataSource";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<InfoExchange.Request> getRequestClass() {
|
public Class<QueryDataSourceExchange.Request> getRequestClass() {
|
||||||
return InfoExchange.Request.class;
|
return QueryDataSourceExchange.Request.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<InfoExchange.Response> getResponseClass() {
|
public Class<QueryDataSourceExchange.Response> getResponseClass() {
|
||||||
return InfoExchange.Response.class;
|
return QueryDataSourceExchange.Response.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Jacksonized
|
@Jacksonized
|
||||||
|
@ -40,11 +38,15 @@ public class InfoExchange implements MessageExchange<InfoExchange.Request, InfoE
|
||||||
@Builder
|
@Builder
|
||||||
@Value
|
@Value
|
||||||
public static class Response implements ResponseMessage {
|
public static class Response implements ResponseMessage {
|
||||||
|
@NonNull
|
||||||
|
DataSourceId id;
|
||||||
@NonNull
|
@NonNull
|
||||||
DataSourceInfo info;
|
DataSourceInfo info;
|
||||||
@NonNull
|
@NonNull
|
||||||
DataStore store;
|
DataStore store;
|
||||||
@NonNull
|
@NonNull
|
||||||
|
DataSourceDescriptor<?> descriptor;
|
||||||
|
@NonNull
|
||||||
DataSourceConfigInstance config;
|
DataSourceConfigInstance config;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,7 +31,7 @@ module io.xpipe.beacon {
|
||||||
ReadPreparationExchange,
|
ReadPreparationExchange,
|
||||||
ReadExecuteExchange,
|
ReadExecuteExchange,
|
||||||
DialogExchange,
|
DialogExchange,
|
||||||
InfoExchange,
|
QueryDataSourceExchange,
|
||||||
PreStoreExchange,
|
PreStoreExchange,
|
||||||
EditPreparationExchange,
|
EditPreparationExchange,
|
||||||
EditExecuteExchange,
|
EditExecuteExchange,
|
||||||
|
|
|
@ -13,7 +13,6 @@ import java.util.List;
|
||||||
@Builder
|
@Builder
|
||||||
@Jacksonized
|
@Jacksonized
|
||||||
public class DataSourceConfig {
|
public class DataSourceConfig {
|
||||||
String description;
|
|
||||||
|
|
||||||
@Singular
|
@Singular
|
||||||
List<Option> options;
|
List<Option> options;
|
||||||
|
|
|
@ -7,6 +7,10 @@ import io.xpipe.core.data.type.TupleType;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data source info instances contains all required
|
* A data source info instances contains all required
|
||||||
* essential information of a specific data source type.
|
* essential information of a specific data source type.
|
||||||
|
@ -34,12 +38,86 @@ public abstract class DataSourceInfo {
|
||||||
this.rowCount = rowCount;
|
this.rowCount = rowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OptionalInt getRowCountIfPresent() {
|
||||||
|
return getRowCount() != -1 ? OptionalInt.of(getRowCount()) : OptionalInt.empty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceType getType() {
|
||||||
return DataSourceType.TABLE;
|
return DataSourceType.TABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("structure")
|
||||||
|
public static class Structure extends DataSourceInfo {
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Structure() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.STRUCTURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("text")
|
||||||
|
public static class Text extends DataSourceInfo {
|
||||||
|
Charset encoding;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Text(Charset encoding) {
|
||||||
|
this.encoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.TEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("raw")
|
||||||
|
public static class Raw extends DataSourceInfo {
|
||||||
|
int byteCount;
|
||||||
|
ByteOrder byteOrder;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Raw(int byteCount, ByteOrder byteOrder) {
|
||||||
|
this.byteCount = byteCount;
|
||||||
|
this.byteOrder = byteOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.RAW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("archive")
|
||||||
|
public static class Archive extends DataSourceInfo {
|
||||||
|
int contentCount;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Archive(int contentCount) {
|
||||||
|
this.contentCount = contentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Casts this instance to a table info.
|
* Casts this instance to a table info.
|
||||||
*/
|
*/
|
||||||
|
@ -50,4 +128,37 @@ public abstract class DataSourceInfo {
|
||||||
|
|
||||||
return (Table) this;
|
return (Table) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts this instance to a structure info.
|
||||||
|
*/
|
||||||
|
public Structure asStructure() {
|
||||||
|
if (!getType().equals(DataSourceType.STRUCTURE)) {
|
||||||
|
throw new IllegalStateException("Not a structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Structure) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts this instance to a text info.
|
||||||
|
*/
|
||||||
|
public Text asText() {
|
||||||
|
if (!getType().equals(DataSourceType.TEXT)) {
|
||||||
|
throw new IllegalStateException("Not a text");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Text) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts this instance to a raw info.
|
||||||
|
*/
|
||||||
|
public Raw asRaw() {
|
||||||
|
if (!getType().equals(DataSourceType.RAW)) {
|
||||||
|
throw new IllegalStateException("Not raw");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Raw) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,56 @@ import lombok.Value;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a reference to an X-Pipe data source.
|
||||||
|
* Using {@link DataSourceReference} instances instead of {@link DataSourceId}
|
||||||
|
* instances is mainly done for user convenience purposes.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* This convenience comes at the price of ambiguity and instability for other types of references.
|
||||||
|
*/
|
||||||
public interface DataSourceReference {
|
public interface DataSourceReference {
|
||||||
|
|
||||||
static DataSourceReference empty() {
|
/**
|
||||||
return new Empty();
|
* Creates a reference that always refers to the latest data source.
|
||||||
|
*
|
||||||
|
* @see Latest
|
||||||
|
*/
|
||||||
|
static DataSourceReference latest() {
|
||||||
|
return new Latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSourceReference parse(String s) {
|
/**
|
||||||
|
* Creates a reference using only the data source name.
|
||||||
|
*
|
||||||
|
* @see Name
|
||||||
|
*/
|
||||||
|
static DataSourceReference name(String name) {
|
||||||
|
return new Name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for {@link #id(DataSourceId)}
|
||||||
|
*
|
||||||
|
* @see DataSourceId#fromString(String)
|
||||||
|
*/
|
||||||
|
static DataSourceReference id(String id) {
|
||||||
|
return new Id(DataSourceId.fromString(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reference by using a canonical data source id.
|
||||||
|
*
|
||||||
|
* @see Id
|
||||||
|
*/
|
||||||
|
static DataSourceReference id(DataSourceId id) {
|
||||||
|
return new Id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DataSourceReference parse(String s) {
|
||||||
if (s == null || s.trim().length() == 0) {
|
if (s == null || s.trim().length() == 0) {
|
||||||
return new Empty();
|
return new Latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.contains(":")) {
|
if (s.contains(":")) {
|
||||||
|
@ -27,15 +68,23 @@ public interface DataSourceReference {
|
||||||
enum Type {
|
enum Type {
|
||||||
ID,
|
ID,
|
||||||
NAME,
|
NAME,
|
||||||
EMPTY
|
LATEST
|
||||||
}
|
}
|
||||||
|
|
||||||
Type getType();
|
Type getType();
|
||||||
DataSourceId getId();
|
DataSourceId getId();
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the internal string representation of this reference.
|
||||||
|
*/
|
||||||
String toRefString();
|
String toRefString();
|
||||||
|
|
||||||
String toString();
|
String toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper class for {@link DataSourceId} instances.
|
||||||
|
*/
|
||||||
@Value
|
@Value
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
static class Id implements DataSourceReference {
|
static class Id implements DataSourceReference {
|
||||||
|
@ -81,6 +130,11 @@ public interface DataSourceReference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using only the data source name allows for a shorthand way of referring to data sources.
|
||||||
|
* This works as long there are no two different data sources with the same name in different collections.
|
||||||
|
* If this name reference is ambiguous, the data source referral fails.
|
||||||
|
*/
|
||||||
@Value
|
@Value
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
static class Name implements DataSourceReference {
|
static class Name implements DataSourceReference {
|
||||||
|
@ -126,7 +180,12 @@ public interface DataSourceReference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Empty implements DataSourceReference {
|
/**
|
||||||
|
* Specifying the latest reference allows the user to always address the latest data source.
|
||||||
|
* Data source referral this way is unstable however as adding or
|
||||||
|
* removing data sources might change the referral behaviour and is therefore not recommended.
|
||||||
|
*/
|
||||||
|
static class Latest implements DataSourceReference {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toRefString() {
|
public String toRefString() {
|
||||||
|
@ -135,7 +194,7 @@ public interface DataSourceReference {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "none";
|
return "latest";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,7 +210,7 @@ public interface DataSourceReference {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return Type.EMPTY;
|
return Type.LATEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
public class TextDataSourceDescriptor<DS extends DataStore> implements DataSourceDescriptor<DS> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo determineInfo(DS store) throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.TEXT;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
public interface TextReadConnection extends DataSourceConnection {
|
||||||
|
|
||||||
|
Charset getEncoding();
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public interface TextWriteConnection extends DataSourceConnection {
|
||||||
|
|
||||||
|
OutputStream getOutputStream();
|
||||||
|
}
|
|
@ -11,8 +11,8 @@ public class DataSourceReferenceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseValidParameters() {
|
public void parseValidParameters() {
|
||||||
Assertions.assertEquals(DataSourceReference.parse(" ").getType(), DataSourceReference.Type.EMPTY);
|
Assertions.assertEquals(DataSourceReference.parse(" ").getType(), DataSourceReference.Type.LATEST);
|
||||||
Assertions.assertEquals(DataSourceReference.parse(null).getType(), DataSourceReference.Type.EMPTY);
|
Assertions.assertEquals(DataSourceReference.parse(null).getType(), DataSourceReference.Type.LATEST);
|
||||||
|
|
||||||
Assertions.assertEquals(DataSourceReference.parse("abc").getType(), DataSourceReference.Type.NAME);
|
Assertions.assertEquals(DataSourceReference.parse("abc").getType(), DataSourceReference.Type.NAME);
|
||||||
Assertions.assertEquals(DataSourceReference.parse(" abc_ d e").getName(), "abc_ d e");
|
Assertions.assertEquals(DataSourceReference.parse(" abc_ d e").getName(), "abc_ d e");
|
||||||
|
|
|
@ -8,6 +8,7 @@ plugins {
|
||||||
apply from: "$rootDir/deps/java.gradle"
|
apply from: "$rootDir/deps/java.gradle"
|
||||||
apply from: "$rootDir/deps/javafx.gradle"
|
apply from: "$rootDir/deps/javafx.gradle"
|
||||||
apply from: "$rootDir/deps/richtextfx.gradle"
|
apply from: "$rootDir/deps/richtextfx.gradle"
|
||||||
|
apply from: "$rootDir/deps/preferencesfx.gradle"
|
||||||
apply from: "$rootDir/deps/jackson.gradle"
|
apply from: "$rootDir/deps/jackson.gradle"
|
||||||
apply from: "$rootDir/deps/commons.gradle"
|
apply from: "$rootDir/deps/commons.gradle"
|
||||||
apply from: "$rootDir/deps/lombok.gradle"
|
apply from: "$rootDir/deps/lombok.gradle"
|
||||||
|
@ -26,4 +27,5 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':core')
|
implementation project(':core')
|
||||||
implementation project(':fxcomps')
|
implementation project(':fxcomps')
|
||||||
|
implementation group: 'com.dlsc.preferencesfx', name: 'preferencesfx-core', version: '11.8.0'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.extension;
|
package io.xpipe.extension;
|
||||||
|
|
||||||
import io.xpipe.core.source.DataSourceId;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
@ -13,13 +12,7 @@ public interface SupportedApplicationProvider {
|
||||||
APPLICATION
|
APPLICATION
|
||||||
}
|
}
|
||||||
|
|
||||||
Region createTableRetrieveInstructions(ObservableValue<DataSourceId> id);
|
Region createRetrieveInstructions(DataSourceProvider provider, ObservableValue<String> id);
|
||||||
|
|
||||||
Region createStructureRetrieveInstructions(ObservableValue<DataSourceId> id);
|
|
||||||
|
|
||||||
Region createTextRetrieveInstructions(ObservableValue<DataSourceId> id);
|
|
||||||
|
|
||||||
Region createRawRetrieveInstructions(ObservableValue<DataSourceId> id);
|
|
||||||
|
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
|
|
49
extension/src/main/java/io/xpipe/extension/Translatable.java
Normal file
49
extension/src/main/java/io/xpipe/extension/Translatable.java
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package io.xpipe.extension;
|
||||||
|
|
||||||
|
import javafx.beans.binding.StringBinding;
|
||||||
|
import javafx.beans.binding.StringExpression;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
|
||||||
|
public interface Translatable {
|
||||||
|
|
||||||
|
static <T extends Translatable> StringConverter<T> stringConverter() {
|
||||||
|
return new StringConverter<>() {
|
||||||
|
@Override public String toString(T t) {
|
||||||
|
return t == null ? null : t.toTranslatedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T fromString(String string) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T extends Translatable> StringExpression asTranslatedString(ObservableValue<T> observableValue) {
|
||||||
|
return new StringBinding() {
|
||||||
|
{
|
||||||
|
super.bind(observableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
super.unbind(observableValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String computeValue() {
|
||||||
|
final T value = observableValue.getValue();
|
||||||
|
return (value == null) ? "null" : value.toTranslatedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableList<ObservableValue<?>> getDependencies() {
|
||||||
|
return FXCollections.singletonObservableList(observableValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
String toTranslatedString();
|
||||||
|
}
|
|
@ -8,6 +8,10 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public record CodeSnippet(List<CodeSnippet.Line> lines) {
|
public record CodeSnippet(List<CodeSnippet.Line> lines) {
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getRawString();
|
||||||
|
}
|
||||||
|
|
||||||
public String getRawString() {
|
public String getRawString() {
|
||||||
return lines.stream().map(line -> line.elements().stream()
|
return lines.stream().map(line -> line.elements().stream()
|
||||||
.map(Element::text).collect(Collectors.joining()))
|
.map(Element::text).collect(Collectors.joining()))
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.extension.comp;
|
||||||
import io.xpipe.fxcomps.Comp;
|
import io.xpipe.fxcomps.Comp;
|
||||||
import io.xpipe.fxcomps.CompStructure;
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
import io.xpipe.fxcomps.util.PlatformUtil;
|
import io.xpipe.fxcomps.util.PlatformUtil;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
@ -23,8 +24,13 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
||||||
private final ObservableValue<Boolean> showLineNumbers;
|
private final ObservableValue<Boolean> showLineNumbers;
|
||||||
private final ObservableValue<CodeSnippet> value;
|
private final ObservableValue<CodeSnippet> value;
|
||||||
|
|
||||||
|
public CodeSnippetComp(boolean showLineNumbers, ObservableValue<CodeSnippet> value) {
|
||||||
|
this.showLineNumbers = new SimpleBooleanProperty(showLineNumbers);
|
||||||
|
this.value = PlatformUtil.wrap(value);
|
||||||
|
}
|
||||||
|
|
||||||
public CodeSnippetComp(ObservableValue<Boolean> showLineNumbers, ObservableValue<CodeSnippet> value) {
|
public CodeSnippetComp(ObservableValue<Boolean> showLineNumbers, ObservableValue<CodeSnippet> value) {
|
||||||
this.showLineNumbers = showLineNumbers;
|
this.showLineNumbers = PlatformUtil.wrap(showLineNumbers);
|
||||||
this.value = PlatformUtil.wrap(value);
|
this.value = PlatformUtil.wrap(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,10 +94,7 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
||||||
lineNumbers.getStyleClass().add("line-numbers");
|
lineNumbers.getStyleClass().add("line-numbers");
|
||||||
fillArea(lineNumbers, s);
|
fillArea(lineNumbers, s);
|
||||||
value.addListener((c,o,n) -> {
|
value.addListener((c,o,n) -> {
|
||||||
PlatformUtil.runLaterIfNeeded(() -> {
|
fillArea(lineNumbers, s);
|
||||||
fillArea(lineNumbers, s);
|
|
||||||
s.setMaxHeight(5);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var spacer = new Region();
|
var spacer = new Region();
|
||||||
|
@ -103,7 +106,7 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
||||||
content.getChildren().add(0, lineNumbers);
|
content.getChildren().add(0, lineNumbers);
|
||||||
content.getChildren().add(1, spacer);
|
content.getChildren().add(1, spacer);
|
||||||
}
|
}
|
||||||
PlatformUtil.wrap(showLineNumbers).addListener((c,o,n) -> {
|
showLineNumbers.addListener((c,o,n) -> {
|
||||||
if (n) {
|
if (n) {
|
||||||
content.getChildren().add(0, lineNumbers);
|
content.getChildren().add(0, lineNumbers);
|
||||||
content.getChildren().add(1, spacer);
|
content.getChildren().add(1, spacer);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import lombok.Getter;
|
||||||
import lombok.Singular;
|
import lombok.Singular;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
|
@ -18,6 +19,16 @@ public class TrackEvent {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TrackEventBuilder copy() {
|
||||||
|
var copy = builder();
|
||||||
|
copy.category = category;
|
||||||
|
copy.message = message;
|
||||||
|
copy.tags$key = new ArrayList<>(tags$key);
|
||||||
|
copy.tags$value = new ArrayList<>(tags$value);
|
||||||
|
copy.type = type;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
public void handle() {
|
public void handle() {
|
||||||
build().handle();
|
build().handle();
|
||||||
}
|
}
|
||||||
|
@ -35,6 +46,10 @@ public class TrackEvent {
|
||||||
return builder().type("info").message(message);
|
return builder().type("info").message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withWarn(String message) {
|
||||||
|
return builder().type("warn").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
public static TrackEventBuilder withTrace(String message) {
|
public static TrackEventBuilder withTrace(String message) {
|
||||||
return builder().type("trace").message(message);
|
return builder().type("trace").message(message);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +70,10 @@ public class TrackEvent {
|
||||||
return builder().type("debug").message(message);
|
return builder().type("debug").message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void debug(String cat, String message) {
|
||||||
|
builder().category(cat).type("debug").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
public static void debug(String message) {
|
public static void debug(String message) {
|
||||||
builder().type("debug").message(message).build().handle();
|
builder().type("debug").message(message).build().handle();
|
||||||
}
|
}
|
||||||
|
@ -63,6 +82,10 @@ public class TrackEvent {
|
||||||
builder().type("trace").message(message).build().handle();
|
builder().type("trace").message(message).build().handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void info(String cat, String message) {
|
||||||
|
builder().category(cat).type("info").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
public static void trace(String cat, String message) {
|
public static void trace(String cat, String message) {
|
||||||
builder().category(cat).type("trace").message(message).build().handle();
|
builder().category(cat).type("trace").message(message).build().handle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.xpipe.extension.prefs;
|
||||||
|
|
||||||
|
import io.xpipe.extension.I18n;
|
||||||
|
import io.xpipe.extension.Translatable;
|
||||||
|
|
||||||
|
public interface PrefsChoiceValue extends Translatable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String toTranslatedString() {
|
||||||
|
return I18n.get(getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package io.xpipe.extension.prefs;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PrefsChoiceValueModule extends SimpleModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupModule(SetupContext context) {
|
||||||
|
addSerializer(PrefsChoiceValue.class, new PrefsChoiceValueSerializer());
|
||||||
|
addDeserializer(PrefsChoiceValue.class, new PrefsChoiceValueDeserializer());
|
||||||
|
|
||||||
|
context.addSerializers(_serializers);
|
||||||
|
context.addDeserializers(_deserializers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PrefsChoiceValueSerializer extends JsonSerializer<PrefsChoiceValue> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(PrefsChoiceValue value, JsonGenerator jgen, SerializerProvider provider)
|
||||||
|
throws IOException {
|
||||||
|
jgen.writeString(value.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PrefsChoiceValueDeserializer extends JsonDeserializer<PrefsChoiceValue> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrefsChoiceValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||||
|
var id = p.getValueAsString();
|
||||||
|
Class<? extends PrefsChoiceValue> clazz = (Class<? extends PrefsChoiceValue>) ctxt.getContextualType().getRawClass();
|
||||||
|
try {
|
||||||
|
var list = (List<? extends PrefsChoiceValue>) clazz.getDeclaredField("SUPPORTED").get(null);
|
||||||
|
return list.stream().filter(v -> v.getId().equals(id)).findAny().orElse(null);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.xpipe.extension.prefs;
|
||||||
|
|
||||||
|
import com.dlsc.preferencesfx.model.Setting;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface PrefsHandler {
|
||||||
|
|
||||||
|
void addSetting(List<String> category, String group, Setting<?,?> setting);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.xpipe.extension.prefs;
|
||||||
|
|
||||||
|
public interface PrefsProvider {
|
||||||
|
|
||||||
|
void addPrefs(PrefsHandler handler);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package io.xpipe.extension.prefs;
|
||||||
|
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class PrefsProviders {
|
||||||
|
|
||||||
|
private static Set<PrefsProvider> ALL;
|
||||||
|
|
||||||
|
public static void init(ModuleLayer layer) {
|
||||||
|
if (ALL == null) {
|
||||||
|
ALL = ServiceLoader.load(layer, PrefsProvider.class).stream()
|
||||||
|
.map(ServiceLoader.Provider::get).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<PrefsProvider> getAll() {
|
||||||
|
return ALL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import io.xpipe.extension.DataSourceProvider;
|
import io.xpipe.extension.DataSourceProvider;
|
||||||
import io.xpipe.extension.SupportedApplicationProvider;
|
import io.xpipe.extension.SupportedApplicationProvider;
|
||||||
|
import io.xpipe.extension.prefs.PrefsChoiceValueModule;
|
||||||
|
|
||||||
module io.xpipe.extension {
|
module io.xpipe.extension {
|
||||||
requires io.xpipe.core;
|
requires io.xpipe.core;
|
||||||
|
@ -13,12 +15,18 @@ module io.xpipe.extension {
|
||||||
exports io.xpipe.extension;
|
exports io.xpipe.extension;
|
||||||
exports io.xpipe.extension.comp;
|
exports io.xpipe.extension.comp;
|
||||||
exports io.xpipe.extension.event;
|
exports io.xpipe.extension.event;
|
||||||
|
exports io.xpipe.extension.prefs;
|
||||||
|
|
||||||
uses DataSourceProvider;
|
uses DataSourceProvider;
|
||||||
uses SupportedApplicationProvider;
|
uses SupportedApplicationProvider;
|
||||||
uses io.xpipe.extension.I18n;
|
uses io.xpipe.extension.I18n;
|
||||||
uses io.xpipe.extension.event.EventHandler;
|
uses io.xpipe.extension.event.EventHandler;
|
||||||
|
uses io.xpipe.extension.prefs.PrefsProvider;
|
||||||
|
|
||||||
|
provides Module with PrefsChoiceValueModule;
|
||||||
|
|
||||||
|
requires com.dlsc.preferencesfx;
|
||||||
|
requires com.dlsc.formsfx;
|
||||||
requires java.desktop;
|
requires java.desktop;
|
||||||
requires org.fxmisc.richtext;
|
requires org.fxmisc.richtext;
|
||||||
requires org.fxmisc.flowless;
|
requires org.fxmisc.flowless;
|
||||||
|
@ -26,4 +34,5 @@ module io.xpipe.extension {
|
||||||
requires org.fxmisc.wellbehavedfx;
|
requires org.fxmisc.wellbehavedfx;
|
||||||
requires org.reactfx;
|
requires org.reactfx;
|
||||||
requires org.kordamp.ikonli.javafx;
|
requires org.kordamp.ikonli.javafx;
|
||||||
|
requires com.fasterxml.jackson.databind;
|
||||||
}
|
}
|
Loading…
Reference in a new issue