mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-09-30 00:56:56 +13:00
Rework many parts and move some components into the core module
This commit is contained in:
parent
e5a84a83db
commit
b192fd5b09
29 changed files with 644 additions and 67 deletions
|
@ -2,7 +2,7 @@ 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.DataType;
|
import io.xpipe.core.data.type.TupleType;
|
||||||
|
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
@ -15,7 +15,7 @@ public interface DataTable extends Iterable<TupleNode>, DataSource {
|
||||||
|
|
||||||
OptionalInt getRowCountIfPresent();
|
OptionalInt getRowCountIfPresent();
|
||||||
|
|
||||||
DataType getDataType();
|
TupleType getDataType();
|
||||||
|
|
||||||
ArrayNode readAll();
|
ArrayNode readAll();
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,7 @@ public abstract class DataSourceImpl implements DataSource {
|
||||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||||
var req = ReadInfoExchange.Request.builder().sourceId(ds).build();
|
var req = ReadInfoExchange.Request.builder().sourceId(ds).build();
|
||||||
ReadInfoExchange.Response res = performSimpleExchange(sc, req);
|
ReadInfoExchange.Response res = performSimpleExchange(sc, req);
|
||||||
switch (res.getType()) {
|
|
||||||
case TABLE -> {
|
|
||||||
var data = res.getTableData();
|
|
||||||
source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType());
|
|
||||||
}
|
|
||||||
case STRUCTURE -> {
|
|
||||||
}
|
|
||||||
case RAW -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
return source[0];
|
return source[0];
|
||||||
|
@ -53,10 +44,10 @@ public abstract class DataSourceImpl implements DataSource {
|
||||||
s.transferTo(out);
|
s.transferTo(out);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
switch (res.getSourceType()) {
|
switch (res.getInfo().getType()) {
|
||||||
case TABLE -> {
|
case TABLE -> {
|
||||||
var data = res.getTableData();
|
var data = res.getInfo().asTable();
|
||||||
source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType());
|
source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data);
|
||||||
}
|
}
|
||||||
case STRUCTURE -> {
|
case STRUCTURE -> {
|
||||||
}
|
}
|
||||||
|
@ -75,16 +66,7 @@ public abstract class DataSourceImpl implements DataSource {
|
||||||
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
protected void handle(BeaconClient sc) throws ClientException, ServerException, ConnectorException {
|
||||||
var req = StoreStreamExchange.Request.builder().type(type).build();
|
var req = StoreStreamExchange.Request.builder().type(type).build();
|
||||||
StoreStreamExchange.Response res = performOutputExchange(sc, req, in::transferTo);
|
StoreStreamExchange.Response res = performOutputExchange(sc, req, in::transferTo);
|
||||||
switch (res.getSourceType()) {
|
|
||||||
case TABLE -> {
|
|
||||||
var data = res.getTableData();
|
|
||||||
source[0] = new DataTableImpl(res.getSourceId(), res.getConfig(), data.getRowCount(), data.getDataType());
|
|
||||||
}
|
|
||||||
case STRUCTURE -> {
|
|
||||||
}
|
|
||||||
case RAW -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
return source[0];
|
return source[0];
|
||||||
|
|
|
@ -10,13 +10,14 @@ import io.xpipe.beacon.exchange.ReadTableDataExchange;
|
||||||
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.DataType;
|
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.TypedDataStructureNodeReader;
|
import io.xpipe.core.data.typed.TypedDataStructureNodeReader;
|
||||||
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
import io.xpipe.core.data.typed.TypedReusableDataStructureNodeReader;
|
||||||
import io.xpipe.core.source.DataSourceConfig;
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
import io.xpipe.core.source.DataSourceId;
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
import io.xpipe.core.source.DataSourceType;
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -29,14 +30,17 @@ 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 DataSourceId id;
|
||||||
private final int size;
|
private final DataSourceInfo.Table info;
|
||||||
private final DataType dataType;
|
|
||||||
|
|
||||||
public DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, int size, DataType dataType) {
|
public DataTableImpl(DataSourceId id, DataSourceConfig sourceConfig, DataSourceInfo.Table info) {
|
||||||
super(id, sourceConfig);
|
super(id, sourceConfig);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.size = size;
|
this.info = info;
|
||||||
this.dataType = dataType;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTable asTable() {
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<TupleNode> stream() {
|
public Stream<TupleNode> stream() {
|
||||||
|
@ -56,21 +60,21 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
if (size == -1) {
|
if (info.getRowCount() == -1) {
|
||||||
throw new UnsupportedOperationException("Row count is unknown");
|
throw new UnsupportedOperationException("Row count is unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return info.getRowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OptionalInt getRowCountIfPresent() {
|
public OptionalInt getRowCountIfPresent() {
|
||||||
return size != -1 ? OptionalInt.of(size) : OptionalInt.empty();
|
return info.getRowCount() != -1 ? OptionalInt.of(info.getRowCount()) : OptionalInt.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType() {
|
public TupleType getDataType() {
|
||||||
return dataType;
|
return info.getDataType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,7 +84,7 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArrayNode read(int maxRows) {
|
public ArrayNode read(int maxRows) {
|
||||||
int maxToRead = size == -1 ? maxRows : Math.min(size, maxRows);
|
int maxToRead = info.getRowCount() == -1 ? maxRows : Math.min(info.getRowCount(), maxRows);
|
||||||
|
|
||||||
List<DataStructureNode> nodes = new ArrayList<>();
|
List<DataStructureNode> nodes = new ArrayList<>();
|
||||||
new XPipeApiConnector() {
|
new XPipeApiConnector() {
|
||||||
|
@ -89,8 +93,9 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
var req = ReadTableDataExchange.Request.builder()
|
var req = ReadTableDataExchange.Request.builder()
|
||||||
.sourceId(id).maxRows(maxToRead).build();
|
.sourceId(id).maxRows(maxToRead).build();
|
||||||
performInputExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
performInputExchange(sc, req, (ReadTableDataExchange.Response res, InputStream in) -> {
|
||||||
var r = new TypedDataStreamParser(dataType);
|
var r = new TypedDataStreamParser(info.getDataType());
|
||||||
r.parseStructures(in, TypedDataStructureNodeReader.immutable(dataType), nodes::add);
|
r.parseStructures(in, TypedDataStructureNodeReader.immutable(info.getDataType()), nodes::add);
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -103,7 +108,7 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
|
|
||||||
private InputStream input;
|
private InputStream input;
|
||||||
private int read;
|
private int read;
|
||||||
private final int toRead = size;
|
private final int toRead = info.getRowCount();
|
||||||
private final TypedDataStreamParser parser;
|
private final TypedDataStreamParser parser;
|
||||||
private final TypedAbstractReader nodeReader;
|
private final TypedAbstractReader nodeReader;
|
||||||
|
|
||||||
|
@ -114,21 +119,33 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
var req = ReadTableDataExchange.Request.builder()
|
var req = ReadTableDataExchange.Request.builder()
|
||||||
.sourceId(id).maxRows(Integer.MAX_VALUE).build();
|
.sourceId(id).maxRows(Integer.MAX_VALUE).build();
|
||||||
performInputExchange(sc, req,
|
performInputExchange(sc, req,
|
||||||
(ReadTableDataExchange.Response res, InputStream in) -> input = in);
|
(ReadTableDataExchange.Response res, InputStream in) -> {
|
||||||
|
input = in;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
nodeReader = TypedReusableDataStructureNodeReader.create(dataType);
|
nodeReader = TypedReusableDataStructureNodeReader.create(info.getDataType());
|
||||||
parser = new TypedDataStreamParser(dataType);
|
parser = new TypedDataStreamParser(info.getDataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finish() {
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasKnownSize() {
|
private boolean hasKnownSize() {
|
||||||
return size != -1;
|
return info.getRowCount() != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
if (hasKnownSize() && read == toRead) {
|
if (hasKnownSize() && read == toRead) {
|
||||||
|
finish();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,8 +154,13 @@ public class DataTableImpl extends DataSourceImpl implements DataTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return parser.hasNext(input);
|
var hasNext = parser.hasNext(input);
|
||||||
|
if (!hasNext) {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
return hasNext;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
finish();
|
||||||
throw new UncheckedIOException(ex);
|
throw new UncheckedIOException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import io.xpipe.beacon.message.RequestMessage;
|
||||||
import io.xpipe.beacon.message.ResponseMessage;
|
import io.xpipe.beacon.message.ResponseMessage;
|
||||||
import io.xpipe.beacon.message.ServerErrorMessage;
|
import io.xpipe.beacon.message.ServerErrorMessage;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -25,12 +27,20 @@ import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR;
|
||||||
|
|
||||||
public class BeaconClient {
|
public class BeaconClient {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger("beacon");
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface FailableBiConsumer<T, U, E extends Throwable> {
|
public interface FailableBiConsumer<T, U, E extends Throwable> {
|
||||||
|
|
||||||
void accept(T var1, U var2) throws E;
|
void accept(T var1, U var2) throws E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface FailableBiPredicate<T, U, E extends Throwable> {
|
||||||
|
|
||||||
|
boolean test(T var1, U var2) throws E;
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface FailableConsumer<T, E extends Throwable> {
|
public interface FailableConsumer<T, E extends Throwable> {
|
||||||
|
|
||||||
|
@ -70,7 +80,7 @@ public class BeaconClient {
|
||||||
public <REQ extends RequestMessage, RES extends ResponseMessage> void exchange(
|
public <REQ extends RequestMessage, RES extends ResponseMessage> void exchange(
|
||||||
REQ req,
|
REQ req,
|
||||||
FailableConsumer<OutputStream, IOException> reqWriter,
|
FailableConsumer<OutputStream, IOException> reqWriter,
|
||||||
FailableBiConsumer<RES, InputStream, IOException> resReader)
|
FailableBiPredicate<RES, InputStream, IOException> resReader)
|
||||||
throws ConnectorException, ClientException, ServerException {
|
throws ConnectorException, ClientException, ServerException {
|
||||||
try {
|
try {
|
||||||
sendRequest(req);
|
sendRequest(req);
|
||||||
|
@ -85,11 +95,12 @@ public class BeaconClient {
|
||||||
throw new ConnectorException("Invalid body separator");
|
throw new ConnectorException("Invalid body separator");
|
||||||
}
|
}
|
||||||
|
|
||||||
resReader.accept(res, in);
|
if (resReader.test(res, in)) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't communicate with socket", ex);
|
|
||||||
} finally {
|
|
||||||
close();
|
close();
|
||||||
|
throw new ConnectorException("Couldn't communicate with socket", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +127,7 @@ public class BeaconClient {
|
||||||
var msg = JsonNodeFactory.instance.objectNode();
|
var msg = JsonNodeFactory.instance.objectNode();
|
||||||
msg.set("xPipeMessage", json);
|
msg.set("xPipeMessage", json);
|
||||||
|
|
||||||
|
log.atTrace().addKeyValue("class", req.getClass().getSimpleName()).log("Sending request to server");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var mapper = JacksonHelper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
var mapper = JacksonHelper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
|
||||||
|
|
|
@ -16,7 +16,7 @@ public abstract class BeaconConnector {
|
||||||
protected <REQ extends RequestMessage, RES extends ResponseMessage> void performInputExchange(
|
protected <REQ extends RequestMessage, RES extends ResponseMessage> void performInputExchange(
|
||||||
BeaconClient socket,
|
BeaconClient socket,
|
||||||
REQ req,
|
REQ req,
|
||||||
BeaconClient.FailableBiConsumer<RES, InputStream, IOException> responseConsumer) throws ServerException, ConnectorException, ClientException {
|
BeaconClient.FailableBiPredicate<RES, InputStream, IOException> responseConsumer) throws ServerException, ConnectorException, ClientException {
|
||||||
performInputOutputExchange(socket, req, null, responseConsumer);
|
performInputOutputExchange(socket, req, null, responseConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ public abstract class BeaconConnector {
|
||||||
BeaconClient socket,
|
BeaconClient socket,
|
||||||
REQ req,
|
REQ req,
|
||||||
BeaconClient.FailableConsumer<OutputStream, IOException> reqWriter,
|
BeaconClient.FailableConsumer<OutputStream, IOException> reqWriter,
|
||||||
BeaconClient.FailableBiConsumer<RES, InputStream, IOException> responseConsumer)
|
BeaconClient.FailableBiPredicate<RES, InputStream, IOException> responseConsumer)
|
||||||
throws ServerException, ConnectorException, ClientException {
|
throws ServerException, ConnectorException, ClientException {
|
||||||
socket.exchange(req, reqWriter, responseConsumer);
|
socket.exchange(req, reqWriter, responseConsumer);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public abstract class BeaconConnector {
|
||||||
AtomicReference<RES> response = new AtomicReference<>();
|
AtomicReference<RES> response = new AtomicReference<>();
|
||||||
socket.exchange(req, reqWriter, (RES res, InputStream in) -> {
|
socket.exchange(req, reqWriter, (RES res, InputStream in) -> {
|
||||||
response.set(res);
|
response.set(res);
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
return response.get();
|
return response.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,5 @@ public interface BeaconHandler {
|
||||||
|
|
||||||
public void sendServerErrorResponse(Throwable ex) throws Exception;
|
public void sendServerErrorResponse(Throwable ex) throws Exception;
|
||||||
|
|
||||||
InputStream getInputStream() throws Exception;
|
|
||||||
|
|
||||||
OutputStream getOutputStream() throws Exception;
|
OutputStream getOutputStream() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ 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.DataSourceId;
|
|
||||||
import io.xpipe.core.source.DataSourceType;
|
|
||||||
import io.xpipe.core.source.DataSourceConfig;
|
import io.xpipe.core.source.DataSourceConfig;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
@ -41,12 +41,7 @@ public class StoreResourceExchange implements MessageExchange<StoreResourceExcha
|
||||||
@Value
|
@Value
|
||||||
public static class Response implements ResponseMessage {
|
public static class Response implements ResponseMessage {
|
||||||
DataSourceId sourceId;
|
DataSourceId sourceId;
|
||||||
DataSourceType sourceType;
|
|
||||||
DataSourceConfig config;
|
DataSourceConfig config;
|
||||||
Object data;
|
DataSourceInfo info;
|
||||||
|
|
||||||
public ReadInfoExchange.TableData getTableData() {
|
|
||||||
return (ReadInfoExchange.TableData) data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,12 @@ public class SimpleTupleNode extends TupleNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataStructureNode forKey(String name) {
|
public DataStructureNode forKey(String name) {
|
||||||
return nodes.get(names.indexOf(name));
|
var index = names.indexOf(name);
|
||||||
|
if (index == -1) {
|
||||||
|
throw new IllegalArgumentException("Key " + name + " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodes.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,5 +10,7 @@ public interface DataSourceDescriptor<DS extends DataStore> {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataSourceInfo determineInfo(DS store) throws Exception;
|
||||||
|
|
||||||
DataSourceType getType();
|
DataSourceType getType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,6 @@ public class DataSourceId {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return collectionName + SEPARATOR + entryName;
|
return (collectionName != null ? collectionName : "") + SEPARATOR + entryName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
41
core/src/main/java/io/xpipe/core/source/DataSourceInfo.java
Normal file
41
core/src/main/java/io/xpipe/core/source/DataSourceInfo.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
|
import io.xpipe.core.data.type.TupleType;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
|
public abstract class DataSourceInfo {
|
||||||
|
|
||||||
|
public abstract DataSourceType getType();
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("table")
|
||||||
|
public static class Table extends DataSourceInfo {
|
||||||
|
TupleType dataType;
|
||||||
|
int rowCount;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Table(TupleType dataType, int rowCount) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.rowCount = rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.TABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Table asTable() {
|
||||||
|
if (!getType().equals(DataSourceType.TABLE)) {
|
||||||
|
throw new IllegalStateException("Not a table");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Table) this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,11 @@ import java.util.Optional;
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
public interface DataStore {
|
public interface DataStore {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
default <DS extends DataStore> DS asNeeded() {
|
||||||
|
return (DS) this;
|
||||||
|
}
|
||||||
|
|
||||||
default Optional<String> determineDefaultName() {
|
default Optional<String> determineDefaultName() {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package io.xpipe.core.util;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
@ -12,6 +11,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import io.xpipe.core.data.type.ArrayType;
|
import io.xpipe.core.data.type.ArrayType;
|
||||||
import io.xpipe.core.data.type.TupleType;
|
import io.xpipe.core.data.type.TupleType;
|
||||||
import io.xpipe.core.data.type.ValueType;
|
import io.xpipe.core.data.type.ValueType;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
import io.xpipe.core.store.LocalFileDataStore;
|
import io.xpipe.core.store.LocalFileDataStore;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -26,7 +26,8 @@ public class CoreJacksonModule extends SimpleModule {
|
||||||
new NamedType(LocalFileDataStore.class),
|
new NamedType(LocalFileDataStore.class),
|
||||||
new NamedType(ValueType.class),
|
new NamedType(ValueType.class),
|
||||||
new NamedType(TupleType.class),
|
new NamedType(TupleType.class),
|
||||||
new NamedType(ArrayType.class)
|
new NamedType(ArrayType.class),
|
||||||
|
new NamedType(DataSourceInfo.Table.class)
|
||||||
);
|
);
|
||||||
|
|
||||||
addSerializer(Charset.class, new CharsetSerializer());
|
addSerializer(Charset.class, new CharsetSerializer());
|
||||||
|
|
|
@ -11,6 +11,8 @@ java {
|
||||||
|
|
||||||
apply from: "$rootDir/deps/javafx.gradle"
|
apply from: "$rootDir/deps/javafx.gradle"
|
||||||
apply from: "$rootDir/deps/jackson.gradle"
|
apply from: "$rootDir/deps/jackson.gradle"
|
||||||
|
apply from: "$rootDir/deps/commons.gradle"
|
||||||
|
apply from: "$rootDir/deps/lombok.gradle"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -18,4 +20,5 @@ repositories {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':core')
|
implementation project(':core')
|
||||||
|
compileOnly project(':fxcomps')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package io.xpipe.extension;
|
package io.xpipe.extension;
|
||||||
|
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -11,6 +14,12 @@ public interface I18n {
|
||||||
return () -> get(s, vars);
|
return () -> get(s, vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ObservableValue<String> observable(String s, Object... vars) {
|
||||||
|
return Bindings.createStringBinding(() -> {
|
||||||
|
return get(s, vars);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static String get(String s, Object... vars) {
|
public static String get(String s, Object... vars) {
|
||||||
return INSTANCE.getLocalised(s, vars);
|
return INSTANCE.getLocalised(s, vars);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.fxcomps.store.DefaultValueStoreComp;
|
||||||
|
import io.xpipe.fxcomps.util.StrongBindings;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import org.apache.commons.collections4.BidiMap;
|
||||||
|
import org.apache.commons.collections4.bidimap.DualLinkedHashBidiMap;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class CharChoiceComp extends DefaultValueStoreComp<CompStructure<HBox>, Character> {
|
||||||
|
|
||||||
|
private final BidiMap<Character, Supplier<String>> range;
|
||||||
|
private final Supplier<String> customName;
|
||||||
|
|
||||||
|
public CharChoiceComp(Character defaultVal, BidiMap<Character, Supplier<String>> range, Supplier<String> customName) {
|
||||||
|
super(defaultVal);
|
||||||
|
this.range = range;
|
||||||
|
this.customName = customName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<HBox> createBase() {
|
||||||
|
var charChoice = new CharComp();
|
||||||
|
StrongBindings.bind(charChoice.valueProperty(), valueProperty());
|
||||||
|
|
||||||
|
var rangeCopy = new DualLinkedHashBidiMap<>(range);
|
||||||
|
rangeCopy.put(null, customName);
|
||||||
|
var choice = new ChoiceComp<Character>(value.getValue(), rangeCopy);
|
||||||
|
choice.set(getValue());
|
||||||
|
choice.valueProperty().addListener((c, o, n) -> {
|
||||||
|
set(n);
|
||||||
|
});
|
||||||
|
valueProperty().addListener((c, o, n) -> {
|
||||||
|
if (n != null && !range.containsKey(n)) {
|
||||||
|
choice.set(null);
|
||||||
|
} else {
|
||||||
|
choice.set(n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var charChoiceR = charChoice.createRegion();
|
||||||
|
var choiceR = choice.createRegion();
|
||||||
|
var box = new HBox(charChoiceR, choiceR);
|
||||||
|
box.setAlignment(Pos.CENTER);
|
||||||
|
choiceR.prefWidthProperty().bind(box.widthProperty().subtract(charChoiceR.widthProperty()));
|
||||||
|
box.getStyleClass().add("char-choice-comp");
|
||||||
|
return new CompStructure<>(box);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.fxcomps.store.ValueStoreComp;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
|
||||||
|
public class CharComp extends ValueStoreComp<CompStructure<TextField>, Character> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<TextField> createBase() {
|
||||||
|
var text = new TextField(getValue() != null ? getValue().toString() : null);
|
||||||
|
text.setOnKeyTyped(e -> {
|
||||||
|
text.setText(e.getCharacter());
|
||||||
|
});
|
||||||
|
text.textProperty().addListener((c, o, n) -> {
|
||||||
|
this.set(n != null && n.length() > 0 ? n.charAt(0) : null);
|
||||||
|
});
|
||||||
|
valueProperty().addListener((c, o, n) -> {
|
||||||
|
text.setText(n != null ? n.toString() : null);
|
||||||
|
});
|
||||||
|
return new CompStructure<>(text);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.bidimap.DualLinkedHashBidiMap;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class CharsetChoiceComp {
|
||||||
|
|
||||||
|
public static ChoiceComp<Charset> create() {
|
||||||
|
var map = new LinkedHashMap<Charset, Supplier<String>>();
|
||||||
|
for (var e : Charset.availableCharsets().entrySet()) {
|
||||||
|
map.put(e.getValue(), () -> e.getKey());
|
||||||
|
}
|
||||||
|
return new ChoiceComp<>(StandardCharsets.UTF_8, new DualLinkedHashBidiMap<>(map));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.fxcomps.store.DefaultValueStoreComp;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.scene.control.ChoiceBox;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
import org.apache.commons.collections4.BidiMap;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ChoiceComp<T> extends DefaultValueStoreComp<CompStructure<ChoiceBox<T>>, T> {
|
||||||
|
|
||||||
|
private final BidiMap<T, Supplier<String>> range;
|
||||||
|
|
||||||
|
public ChoiceComp(T defaultVal, BidiMap<T, Supplier<String>> range) {
|
||||||
|
super(defaultVal);
|
||||||
|
this.range = range;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isValid(T newValue) {
|
||||||
|
return range.containsKey(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BidiMap<T, Supplier<String>> getRange() {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<ChoiceBox<T>> createBase() {
|
||||||
|
var comp = this;
|
||||||
|
var list = FXCollections.observableArrayList(comp.getRange().keySet());
|
||||||
|
var cb = new ChoiceBox<>(list);
|
||||||
|
cb.setConverter(new StringConverter<>() {
|
||||||
|
@Override
|
||||||
|
public String toString(T object) {
|
||||||
|
return comp.getRange().get(object).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T fromString(String string) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cb.valueProperty().bindBidirectional(comp.valueProperty());
|
||||||
|
cb.getStyleClass().add("choice-comp");
|
||||||
|
return new CompStructure<>(cb);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.Comp;
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.geometry.Orientation;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.FlowPane;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class DynamicOptionsComp extends Comp<CompStructure<FlowPane>> {
|
||||||
|
|
||||||
|
private final List<Entry> entries;
|
||||||
|
|
||||||
|
public DynamicOptionsComp(List<Entry> entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<FlowPane> createBase() {
|
||||||
|
var flow = new FlowPane(Orientation.HORIZONTAL);
|
||||||
|
flow.setAlignment(Pos.CENTER);
|
||||||
|
flow.setHgap(7);
|
||||||
|
flow.setVgap(7);
|
||||||
|
|
||||||
|
var nameRegions = new ArrayList<Region>();
|
||||||
|
var compRegions = new ArrayList<Region>();
|
||||||
|
|
||||||
|
for (var entry : getEntries()) {
|
||||||
|
var line = new HBox();
|
||||||
|
line.setSpacing(5);
|
||||||
|
|
||||||
|
var name = new Label(entry.name().get());
|
||||||
|
name.prefHeightProperty().bind(line.heightProperty());
|
||||||
|
name.setMinWidth(Region.USE_PREF_SIZE);
|
||||||
|
name.setAlignment(Pos.CENTER_LEFT);
|
||||||
|
nameRegions.add(name);
|
||||||
|
line.getChildren().add(name);
|
||||||
|
|
||||||
|
var r = entry.comp().createRegion();
|
||||||
|
compRegions.add(r);
|
||||||
|
line.getChildren().add(r);
|
||||||
|
|
||||||
|
flow.getChildren().add(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
var compWidthBinding = Bindings.createDoubleBinding(() -> {
|
||||||
|
if (compRegions.stream().anyMatch(r -> r.getWidth() == 0)) {
|
||||||
|
return Region.USE_COMPUTED_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = compRegions.stream().map(Region::getWidth).max(Double::compareTo).orElse(0.0);
|
||||||
|
return m;
|
||||||
|
}, compRegions.stream().map(Region::widthProperty).toList().toArray(new Observable[0]));
|
||||||
|
compRegions.forEach(r -> r.prefWidthProperty().bind(compWidthBinding));
|
||||||
|
|
||||||
|
var nameWidthBinding = Bindings.createDoubleBinding(() -> {
|
||||||
|
if (nameRegions.stream().anyMatch(r -> r.getWidth() == 0)) {
|
||||||
|
return Region.USE_COMPUTED_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = nameRegions.stream().map(Region::getWidth).max(Double::compareTo).orElse(0.0);
|
||||||
|
return m;
|
||||||
|
}, nameRegions.stream().map(Region::widthProperty).toList().toArray(new Observable[0]));
|
||||||
|
nameRegions.forEach(r -> r.prefWidthProperty().bind(nameWidthBinding));
|
||||||
|
|
||||||
|
return new CompStructure<>(flow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Entry> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static record Entry(Supplier<String> name, Comp<?> comp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.fxcomps.store.DefaultValueStoreComp;
|
||||||
|
import javafx.scene.control.ToggleButton;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import org.apache.commons.collections4.BidiMap;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ToggleGroupComp<T> extends DefaultValueStoreComp<CompStructure<HBox>, T> {
|
||||||
|
|
||||||
|
private final BidiMap<T, Supplier<String>> range;
|
||||||
|
|
||||||
|
public ToggleGroupComp(T defaultVal, BidiMap<T, Supplier<String>> range) {
|
||||||
|
super(defaultVal);
|
||||||
|
this.range = range;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BidiMap<T, Supplier<String>> getRange() {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<HBox> createBase() {
|
||||||
|
var box = new HBox();
|
||||||
|
box.getStyleClass().add("toggle-group-comp");
|
||||||
|
ToggleGroup group = new ToggleGroup();
|
||||||
|
for (var entry : range.entrySet()) {
|
||||||
|
var b = new ToggleButton(entry.getValue().get());
|
||||||
|
b.setOnAction(e -> {
|
||||||
|
set(entry.getKey());
|
||||||
|
e.consume();
|
||||||
|
});
|
||||||
|
box.getChildren().add(b);
|
||||||
|
b.setToggleGroup(group);
|
||||||
|
valueProperty().addListener((c, o, n) -> {
|
||||||
|
b.setSelected(entry.equals(n));
|
||||||
|
});
|
||||||
|
if (entry.getKey().equals(getValue())) {
|
||||||
|
b.setSelected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
box.getChildren().get(0).getStyleClass().add("first");
|
||||||
|
box.getChildren().get(box.getChildren().size() - 1).getStyleClass().add("last");
|
||||||
|
|
||||||
|
group.selectedToggleProperty().addListener((obsVal, oldVal, newVal) -> {
|
||||||
|
if (newVal == null)
|
||||||
|
oldVal.setSelected(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new CompStructure<>(box);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package io.xpipe.extension.event;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Singular;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
public class ErrorEvent {
|
||||||
|
|
||||||
|
public static ErrorEventBuilder fromThrowable(Throwable t) {
|
||||||
|
return builder().throwable(t)
|
||||||
|
.description(ExceptionConverter.convertMessage(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ErrorEventBuilder fromThrowable(String msg, Throwable t) {
|
||||||
|
return builder().throwable(t)
|
||||||
|
.description(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle() {
|
||||||
|
EventHandler.get().handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private boolean terminal;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private boolean omitted = false;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private boolean reportable = true;
|
||||||
|
|
||||||
|
private Throwable throwable;
|
||||||
|
|
||||||
|
@Singular
|
||||||
|
private List<Path> diagnostics;
|
||||||
|
|
||||||
|
@Singular
|
||||||
|
private List<Path> sensitiveDiagnostics;
|
||||||
|
|
||||||
|
private final List<TrackEvent> trackEvents = EventHandler.get().snapshotEvents();
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package io.xpipe.extension.event;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
public abstract class EventHandler {
|
||||||
|
|
||||||
|
private static EventHandler INSTANCE;
|
||||||
|
|
||||||
|
private static void init() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = ServiceLoader.load(EventHandler.class).findFirst().orElseThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventHandler get() {
|
||||||
|
init();
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract List<TrackEvent> snapshotEvents();
|
||||||
|
|
||||||
|
public abstract void handle(TrackEvent te);
|
||||||
|
|
||||||
|
public abstract void handle(ErrorEvent ee);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package io.xpipe.extension.event;
|
||||||
|
|
||||||
|
import io.xpipe.extension.I18n;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
public class ExceptionConverter {
|
||||||
|
|
||||||
|
public static String convertMessage(Throwable ex) {
|
||||||
|
var msg = ex.getLocalizedMessage();
|
||||||
|
if (ex instanceof FileNotFoundException) {
|
||||||
|
return I18n.get("fileNotFound", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package io.xpipe.extension.event;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Singular;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
public class TrackEvent {
|
||||||
|
|
||||||
|
public static class TrackEventBuilder {
|
||||||
|
|
||||||
|
public TrackEventBuilder windowCategory() {
|
||||||
|
this.category("window");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder fromMessage(String type, String message) {
|
||||||
|
return builder().type(type).message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void simple(String type, String message) {
|
||||||
|
builder().type(type).message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withInfo(String message) {
|
||||||
|
return builder().type("info").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withTrace(String message) {
|
||||||
|
return builder().type("trace").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void info(String message) {
|
||||||
|
builder().type("info").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void warn(String message) {
|
||||||
|
builder().type("warn").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withDebug(String message) {
|
||||||
|
return builder().type("debug").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void debug(String message) {
|
||||||
|
builder().type("debug").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void trace(String message) {
|
||||||
|
builder().type("trace").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void trace(String cat, String message) {
|
||||||
|
builder().category(cat).type("trace").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withError(String message) {
|
||||||
|
return builder().type("error").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void error(String message) {
|
||||||
|
builder().type("error").message(message).build().handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Thread thread = Thread.currentThread();
|
||||||
|
private final Instant instant = Instant.now();
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
@Singular
|
||||||
|
private Map<String, Object> tags;
|
||||||
|
|
||||||
|
public void handle() {
|
||||||
|
EventHandler.get().handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
var s = message;
|
||||||
|
if (tags.size() > 0) {
|
||||||
|
s += " {\n";
|
||||||
|
for (var e : tags.entrySet()) {
|
||||||
|
s += " " + e.getKey() + "=" + e.getValue() + "\n";
|
||||||
|
}
|
||||||
|
s += "}";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,18 @@ module io.xpipe.extension {
|
||||||
requires io.xpipe.core;
|
requires io.xpipe.core;
|
||||||
requires javafx.base;
|
requires javafx.base;
|
||||||
requires javafx.graphics;
|
requires javafx.graphics;
|
||||||
|
requires javafx.controls;
|
||||||
|
requires io.xpipe.fxcomps;
|
||||||
|
requires org.apache.commons.collections4;
|
||||||
|
requires static lombok;
|
||||||
|
|
||||||
exports io.xpipe.extension;
|
exports io.xpipe.extension;
|
||||||
|
exports io.xpipe.extension.comp;
|
||||||
|
exports io.xpipe.extension.event;
|
||||||
|
|
||||||
uses DataSourceProvider;
|
uses DataSourceProvider;
|
||||||
uses DataSourceGuiProvider;
|
uses DataSourceGuiProvider;
|
||||||
uses SupportedApplicationProvider;
|
uses SupportedApplicationProvider;
|
||||||
uses io.xpipe.extension.I18n;
|
uses io.xpipe.extension.I18n;
|
||||||
|
uses io.xpipe.extension.event.EventHandler;
|
||||||
}
|
}
|
|
@ -2,11 +2,15 @@ plugins {
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'signing'
|
id 'signing'
|
||||||
|
id "org.moditect.gradleplugin" version "1.0.0-rc3"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: 'publish.gradle'
|
apply from: 'publish.gradle'
|
||||||
apply from: "$rootDir/deps/jackson.gradle"
|
apply from: "$rootDir/deps/jackson.gradle"
|
||||||
|
apply from: "$rootDir/deps/slf4j.gradle"
|
||||||
apply from: "$rootDir/deps/lombok.gradle"
|
apply from: "$rootDir/deps/lombok.gradle"
|
||||||
|
apply from: "$rootDir/deps/commons.gradle"
|
||||||
|
apply from: "$rootDir/deps/javafx.gradle"
|
||||||
apply from: "$rootDir/deps/javafx-static.gradle"
|
apply from: "$rootDir/deps/javafx-static.gradle"
|
||||||
|
|
||||||
version '0.1'
|
version '0.1'
|
||||||
|
@ -19,6 +23,10 @@ java {
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly project(':fxcomps')
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,28 @@ module io.xpipe {
|
||||||
opens io.xpipe.core.store;
|
opens io.xpipe.core.store;
|
||||||
opens io.xpipe.core.source;
|
opens io.xpipe.core.source;
|
||||||
opens io.xpipe.core.data.typed;
|
opens io.xpipe.core.data.typed;
|
||||||
|
opens io.xpipe.core.data.type;
|
||||||
|
|
||||||
// core services
|
// core services
|
||||||
uses com.fasterxml.jackson.databind.Module;
|
uses com.fasterxml.jackson.databind.Module;
|
||||||
provides com.fasterxml.jackson.databind.Module with io.xpipe.core.util.CoreJacksonModule;
|
provides com.fasterxml.jackson.databind.Module with io.xpipe.core.util.CoreJacksonModule;
|
||||||
|
|
||||||
|
// extension
|
||||||
|
requires static io.xpipe.fxcomps;
|
||||||
|
requires static javafx.base;
|
||||||
|
requires static javafx.graphics;
|
||||||
|
requires static javafx.controls;
|
||||||
|
requires static org.apache.commons.collections4;
|
||||||
|
exports io.xpipe.extension;
|
||||||
|
exports io.xpipe.extension.comp;
|
||||||
|
uses io.xpipe.extension.DataSourceProvider;
|
||||||
|
uses io.xpipe.extension.DataSourceGuiProvider;
|
||||||
|
uses io.xpipe.extension.SupportedApplicationProvider;
|
||||||
|
uses io.xpipe.extension.I18n;
|
||||||
|
|
||||||
requires com.fasterxml.jackson.core;
|
requires com.fasterxml.jackson.core;
|
||||||
requires com.fasterxml.jackson.databind;
|
requires com.fasterxml.jackson.databind;
|
||||||
requires com.fasterxml.jackson.module.paramnames;
|
requires com.fasterxml.jackson.module.paramnames;
|
||||||
|
requires org.slf4j;
|
||||||
requires static lombok;
|
requires static lombok;
|
||||||
requires static javafx.base;
|
|
||||||
requires static javafx.graphics;
|
|
||||||
}
|
}
|
|
@ -12,9 +12,11 @@ repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
apply from: "$rootDir/deps/jackson.gradle"
|
apply from: "$rootDir/deps/jackson.gradle"
|
||||||
|
apply from: "$rootDir/deps/slf4j.gradle"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation files(project(':library').jar.archivePath)
|
implementation files(project(':library').jar.archivePath)
|
||||||
|
implementation group: 'org.slf4j', name: 'slf4j-simple', version: '2.0.0-alpha1'
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava.dependsOn(project(':library').jar)
|
compileJava.dependsOn(project(':library').jar)
|
||||||
|
|
Loading…
Reference in a new issue