mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 15:10:23 +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.core.source.DataSourceConfig;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import io.xpipe.core.source.DataSourceType;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -10,14 +11,22 @@ import java.net.URL;
|
|||
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.
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* NOT YET IMPLEMENTED!
|
||||
*
|
||||
* 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
|
||||
* least once to register that it actually generates a data source.
|
||||
|
@ -29,28 +38,49 @@ public interface DataSource {
|
|||
*
|
||||
* @return the generator data source
|
||||
*/
|
||||
@Deprecated
|
||||
static DataSource supplySource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link #get(DataSourceId)}.
|
||||
* Wrapper for {@link #get(DataSourceReference)}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code id} is not a valid data source id
|
||||
*/
|
||||
static DataSource get(String id) {
|
||||
return get(DataSourceId.fromString(id));
|
||||
static DataSource getById(String 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.
|
||||
*
|
||||
* @param id the data source id
|
||||
* @return a reference to the data source that can be used to access the underlying data source
|
||||
* @param ref the data source reference
|
||||
*/
|
||||
static DataSource get(DataSourceId id) {
|
||||
return null;
|
||||
//return DataSourceImpl.get(id);
|
||||
static DataSource get(DataSourceReference ref) {
|
||||
return DataSourceImpl.get(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
@ -110,4 +140,31 @@ public interface DataSource {
|
|||
default DataTable asTable() {
|
||||
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.TupleNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.source.DataSourceInfo;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface DataTable extends Iterable<TupleNode>, DataSource {
|
||||
|
||||
/**
|
||||
* @see DataSource#supplySource()
|
||||
*/
|
||||
static DataTable supplySource() {
|
||||
return null;
|
||||
}
|
||||
DataSourceInfo.Table getInfo();
|
||||
|
||||
Stream<TupleNode> stream();
|
||||
|
||||
int getRowCount();
|
||||
|
||||
OptionalInt getRowCountIfPresent();
|
||||
|
||||
TupleType getDataType();
|
||||
|
||||
ArrayNode readAll();
|
||||
|
||||
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.core.util.JacksonHelper;
|
||||
|
@ -12,7 +12,7 @@ public abstract class XPipeApiConnector extends BeaconConnector {
|
|||
var socket = constructSocket();
|
||||
handle(socket);
|
||||
} 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;
|
||||
|
||||
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.ClientException;
|
||||
import io.xpipe.beacon.ConnectorException;
|
||||
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.StoreStreamExchange;
|
||||
import io.xpipe.core.source.DataSourceConfig;
|
||||
|
@ -24,9 +24,26 @@ public abstract class DataSourceImpl implements DataSource {
|
|||
new XPipeApiConnector() {
|
||||
@Override
|
||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||
var req = InfoExchange.Request.builder().ref(ds).build();
|
||||
InfoExchange.Response res = performSimpleExchange(sc, req);
|
||||
|
||||
var req = QueryDataSourceExchange.Request.builder().ref(ds).build();
|
||||
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();
|
||||
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;
|
||||
|
||||
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.ClientException;
|
||||
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.DataStructureNode;
|
||||
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.TypedDataStreamParser;
|
||||
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
||||
|
@ -27,12 +26,10 @@ import java.util.stream.StreamSupport;
|
|||
|
||||
public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||
|
||||
private final DataSourceId id;
|
||||
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);
|
||||
this.id = id;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
|
@ -41,40 +38,21 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceInfo.Table getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public Stream<TupleNode> stream() {
|
||||
return StreamSupport.stream(
|
||||
Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceType getType() {
|
||||
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
|
||||
public ArrayNode readAll() {
|
||||
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;
|
||||
|
||||
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";
|
||||
private static final int DEFAULT_PORT = 21721;
|
||||
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||
public static final int DEFAULT_PORT = 21721;
|
||||
|
||||
public static int getUsedPort() {
|
||||
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.ResponseMessage;
|
||||
import io.xpipe.core.source.DataSourceConfigInstance;
|
||||
import io.xpipe.core.source.DataSourceInfo;
|
||||
import io.xpipe.core.source.DataSourceReference;
|
||||
import io.xpipe.core.source.*;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import lombok.Builder;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
public class InfoExchange implements MessageExchange<InfoExchange.Request, InfoExchange.Response> {
|
||||
public class QueryDataSourceExchange implements MessageExchange<QueryDataSourceExchange.Request, QueryDataSourceExchange.Response> {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "info";
|
||||
return "queryDataSource";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<InfoExchange.Request> getRequestClass() {
|
||||
return InfoExchange.Request.class;
|
||||
public Class<QueryDataSourceExchange.Request> getRequestClass() {
|
||||
return QueryDataSourceExchange.Request.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<InfoExchange.Response> getResponseClass() {
|
||||
return InfoExchange.Response.class;
|
||||
public Class<QueryDataSourceExchange.Response> getResponseClass() {
|
||||
return QueryDataSourceExchange.Response.class;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
|
@ -40,11 +38,15 @@ public class InfoExchange implements MessageExchange<InfoExchange.Request, InfoE
|
|||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
@NonNull
|
||||
DataSourceId id;
|
||||
@NonNull
|
||||
DataSourceInfo info;
|
||||
@NonNull
|
||||
DataStore store;
|
||||
@NonNull
|
||||
DataSourceDescriptor<?> descriptor;
|
||||
@NonNull
|
||||
DataSourceConfigInstance config;
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ module io.xpipe.beacon {
|
|||
ReadPreparationExchange,
|
||||
ReadExecuteExchange,
|
||||
DialogExchange,
|
||||
InfoExchange,
|
||||
QueryDataSourceExchange,
|
||||
PreStoreExchange,
|
||||
EditPreparationExchange,
|
||||
EditExecuteExchange,
|
||||
|
|
|
@ -13,7 +13,6 @@ import java.util.List;
|
|||
@Builder
|
||||
@Jacksonized
|
||||
public class DataSourceConfig {
|
||||
String description;
|
||||
|
||||
@Singular
|
||||
List<Option> options;
|
||||
|
|
|
@ -7,6 +7,10 @@ import io.xpipe.core.data.type.TupleType;
|
|||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* A data source info instances contains all required
|
||||
* essential information of a specific data source type.
|
||||
|
@ -34,12 +38,86 @@ public abstract class DataSourceInfo {
|
|||
this.rowCount = rowCount;
|
||||
}
|
||||
|
||||
public OptionalInt getRowCountIfPresent() {
|
||||
return getRowCount() != -1 ? OptionalInt.of(getRowCount()) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceType getType() {
|
||||
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.
|
||||
*/
|
||||
|
@ -50,4 +128,37 @@ public abstract class DataSourceInfo {
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
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) {
|
||||
return new Empty();
|
||||
return new Latest();
|
||||
}
|
||||
|
||||
if (s.contains(":")) {
|
||||
|
@ -27,15 +68,23 @@ public interface DataSourceReference {
|
|||
enum Type {
|
||||
ID,
|
||||
NAME,
|
||||
EMPTY
|
||||
LATEST
|
||||
}
|
||||
|
||||
Type getType();
|
||||
DataSourceId getId();
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the internal string representation of this reference.
|
||||
*/
|
||||
String toRefString();
|
||||
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* A wrapper class for {@link DataSourceId} instances.
|
||||
*/
|
||||
@Value
|
||||
@AllArgsConstructor
|
||||
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
|
||||
@AllArgsConstructor
|
||||
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
|
||||
public String toRefString() {
|
||||
|
@ -135,7 +194,7 @@ public interface DataSourceReference {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "none";
|
||||
return "latest";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -151,7 +210,7 @@ public interface DataSourceReference {
|
|||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.EMPTY;
|
||||
return Type.LATEST;
|
||||
}
|
||||
|
||||
@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
|
||||
public void parseValidParameters() {
|
||||
Assertions.assertEquals(DataSourceReference.parse(" ").getType(), DataSourceReference.Type.EMPTY);
|
||||
Assertions.assertEquals(DataSourceReference.parse(null).getType(), DataSourceReference.Type.EMPTY);
|
||||
Assertions.assertEquals(DataSourceReference.parse(" ").getType(), DataSourceReference.Type.LATEST);
|
||||
Assertions.assertEquals(DataSourceReference.parse(null).getType(), DataSourceReference.Type.LATEST);
|
||||
|
||||
Assertions.assertEquals(DataSourceReference.parse("abc").getType(), DataSourceReference.Type.NAME);
|
||||
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/javafx.gradle"
|
||||
apply from: "$rootDir/deps/richtextfx.gradle"
|
||||
apply from: "$rootDir/deps/preferencesfx.gradle"
|
||||
apply from: "$rootDir/deps/jackson.gradle"
|
||||
apply from: "$rootDir/deps/commons.gradle"
|
||||
apply from: "$rootDir/deps/lombok.gradle"
|
||||
|
@ -26,4 +27,5 @@ repositories {
|
|||
dependencies {
|
||||
implementation project(':core')
|
||||
implementation project(':fxcomps')
|
||||
implementation group: 'com.dlsc.preferencesfx', name: 'preferencesfx-core', version: '11.8.0'
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.extension;
|
||||
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
|
@ -13,13 +12,7 @@ public interface SupportedApplicationProvider {
|
|||
APPLICATION
|
||||
}
|
||||
|
||||
Region createTableRetrieveInstructions(ObservableValue<DataSourceId> id);
|
||||
|
||||
Region createStructureRetrieveInstructions(ObservableValue<DataSourceId> id);
|
||||
|
||||
Region createTextRetrieveInstructions(ObservableValue<DataSourceId> id);
|
||||
|
||||
Region createRawRetrieveInstructions(ObservableValue<DataSourceId> id);
|
||||
Region createRetrieveInstructions(DataSourceProvider provider, ObservableValue<String> id);
|
||||
|
||||
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 String toString() {
|
||||
return getRawString();
|
||||
}
|
||||
|
||||
public String getRawString() {
|
||||
return lines.stream().map(line -> line.elements().stream()
|
||||
.map(Element::text).collect(Collectors.joining()))
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.extension.comp;
|
|||
import io.xpipe.fxcomps.Comp;
|
||||
import io.xpipe.fxcomps.CompStructure;
|
||||
import io.xpipe.fxcomps.util.PlatformUtil;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
|
@ -23,8 +24,13 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
|||
private final ObservableValue<Boolean> showLineNumbers;
|
||||
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) {
|
||||
this.showLineNumbers = showLineNumbers;
|
||||
this.showLineNumbers = PlatformUtil.wrap(showLineNumbers);
|
||||
this.value = PlatformUtil.wrap(value);
|
||||
}
|
||||
|
||||
|
@ -88,10 +94,7 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
|||
lineNumbers.getStyleClass().add("line-numbers");
|
||||
fillArea(lineNumbers, s);
|
||||
value.addListener((c,o,n) -> {
|
||||
PlatformUtil.runLaterIfNeeded(() -> {
|
||||
fillArea(lineNumbers, s);
|
||||
s.setMaxHeight(5);
|
||||
});
|
||||
fillArea(lineNumbers, s);
|
||||
});
|
||||
|
||||
var spacer = new Region();
|
||||
|
@ -103,7 +106,7 @@ public class CodeSnippetComp extends Comp<CompStructure<StackPane>> {
|
|||
content.getChildren().add(0, lineNumbers);
|
||||
content.getChildren().add(1, spacer);
|
||||
}
|
||||
PlatformUtil.wrap(showLineNumbers).addListener((c,o,n) -> {
|
||||
showLineNumbers.addListener((c,o,n) -> {
|
||||
if (n) {
|
||||
content.getChildren().add(0, lineNumbers);
|
||||
content.getChildren().add(1, spacer);
|
||||
|
|
|
@ -5,6 +5,7 @@ import lombok.Getter;
|
|||
import lombok.Singular;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
@Builder
|
||||
|
@ -18,6 +19,16 @@ public class TrackEvent {
|
|||
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() {
|
||||
build().handle();
|
||||
}
|
||||
|
@ -35,6 +46,10 @@ public class TrackEvent {
|
|||
return builder().type("info").message(message);
|
||||
}
|
||||
|
||||
public static TrackEventBuilder withWarn(String message) {
|
||||
return builder().type("warn").message(message);
|
||||
}
|
||||
|
||||
public static TrackEventBuilder withTrace(String message) {
|
||||
return builder().type("trace").message(message);
|
||||
}
|
||||
|
@ -55,6 +70,10 @@ public class TrackEvent {
|
|||
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) {
|
||||
builder().type("debug").message(message).build().handle();
|
||||
}
|
||||
|
@ -63,6 +82,10 @@ public class TrackEvent {
|
|||
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) {
|
||||
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.SupportedApplicationProvider;
|
||||
import io.xpipe.extension.prefs.PrefsChoiceValueModule;
|
||||
|
||||
module io.xpipe.extension {
|
||||
requires io.xpipe.core;
|
||||
|
@ -13,12 +15,18 @@ module io.xpipe.extension {
|
|||
exports io.xpipe.extension;
|
||||
exports io.xpipe.extension.comp;
|
||||
exports io.xpipe.extension.event;
|
||||
exports io.xpipe.extension.prefs;
|
||||
|
||||
uses DataSourceProvider;
|
||||
uses SupportedApplicationProvider;
|
||||
uses io.xpipe.extension.I18n;
|
||||
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 org.fxmisc.richtext;
|
||||
requires org.fxmisc.flowless;
|
||||
|
@ -26,4 +34,5 @@ module io.xpipe.extension {
|
|||
requires org.fxmisc.wellbehavedfx;
|
||||
requires org.reactfx;
|
||||
requires org.kordamp.ikonli.javafx;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
}
|
Loading…
Reference in a new issue