mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Rework
This commit is contained in:
parent
f12ce82933
commit
8d95f451bb
40 changed files with 471 additions and 191 deletions
|
@ -9,7 +9,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
|
||||||
import io.xpipe.beacon.exchange.MessageExchanges;
|
import io.xpipe.beacon.exchange.MessageExchanges;
|
||||||
import io.xpipe.beacon.exchange.data.ClientErrorMessage;
|
import io.xpipe.beacon.exchange.data.ClientErrorMessage;
|
||||||
import io.xpipe.beacon.exchange.data.ServerErrorMessage;
|
import io.xpipe.beacon.exchange.data.ServerErrorMessage;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
@ -96,7 +96,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends RequestMessage> void sendRequest(T req) throws ClientException, ConnectorException {
|
public <T extends RequestMessage> void sendRequest(T req) throws ClientException, ConnectorException {
|
||||||
ObjectNode json = JacksonHelper.newMapper().valueToTree(req);
|
ObjectNode json = JacksonMapper.newMapper().valueToTree(req);
|
||||||
var prov = MessageExchanges.byRequest(req);
|
var prov = MessageExchanges.byRequest(req);
|
||||||
if (prov.isEmpty()) {
|
if (prov.isEmpty()) {
|
||||||
throw new ClientException("Unknown request class " + req.getClass());
|
throw new ClientException("Unknown request class " + req.getClass());
|
||||||
|
@ -113,7 +113,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
var writer = new StringWriter();
|
var writer = new StringWriter();
|
||||||
var mapper = JacksonHelper.newMapper();
|
var mapper = JacksonMapper.newMapper();
|
||||||
try (JsonGenerator g = mapper.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) {
|
try (JsonGenerator g = mapper.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) {
|
||||||
g.writeTree(msg);
|
g.writeTree(msg);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
@ -136,7 +136,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
public <T extends ResponseMessage> T receiveResponse() throws ConnectorException, ClientException, ServerException {
|
public <T extends ResponseMessage> T receiveResponse() throws ConnectorException, ClientException, ServerException {
|
||||||
JsonNode node;
|
JsonNode node;
|
||||||
try (InputStream blockIn = BeaconFormat.readBlocks(in)) {
|
try (InputStream blockIn = BeaconFormat.readBlocks(in)) {
|
||||||
node = JacksonHelper.newMapper().readTree(blockIn);
|
node = JacksonMapper.newMapper().readTree(blockIn);
|
||||||
} catch (SocketException ex) {
|
} catch (SocketException ex) {
|
||||||
throw new ConnectorException("Connection to xpipe daemon closed unexpectedly", ex);
|
throw new ConnectorException("Connection to xpipe daemon closed unexpectedly", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
|
@ -172,7 +172,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var reader = JacksonHelper.newMapper().readerFor(ClientErrorMessage.class);
|
var reader = JacksonMapper.newMapper().readerFor(ClientErrorMessage.class);
|
||||||
return Optional.of(reader.readValue(content));
|
return Optional.of(reader.readValue(content));
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't parse client error message", ex);
|
throw new ConnectorException("Couldn't parse client error message", ex);
|
||||||
|
@ -186,7 +186,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var reader = JacksonHelper.newMapper().readerFor(ServerErrorMessage.class);
|
var reader = JacksonMapper.newMapper().readerFor(ServerErrorMessage.class);
|
||||||
return Optional.of(reader.readValue(content));
|
return Optional.of(reader.readValue(content));
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't parse server error message", ex);
|
throw new ConnectorException("Couldn't parse server error message", ex);
|
||||||
|
@ -212,7 +212,7 @@ public class BeaconClient implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var reader = JacksonHelper.newMapper().readerFor(prov.get().getResponseClass());
|
var reader = JacksonMapper.newMapper().readerFor(prov.get().getResponseClass());
|
||||||
return reader.readValue(content);
|
return reader.readValue(content);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new ConnectorException("Couldn't parse response", ex);
|
throw new ConnectorException("Couldn't parse response", ex);
|
||||||
|
|
|
@ -33,8 +33,10 @@ public abstract class ArrayNode extends DataStructureNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
var toReturn = getNodes().equals(that.getNodes()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
var toReturn = getNodes().equals(that.getNodes()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||||
|
|
||||||
|
// Useful for debugging
|
||||||
if (toReturn == false) {
|
if (toReturn == false) {
|
||||||
throw new AssertionError();
|
return false;
|
||||||
}
|
}
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import lombok.NonNull;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class SimpleImmutableValueNode extends ValueNode {
|
public class SimpleValueNode extends ValueNode {
|
||||||
|
|
||||||
private final byte @NonNull [] data;
|
private final byte @NonNull [] data;
|
||||||
|
|
||||||
SimpleImmutableValueNode(byte @NonNull [] data) {
|
SimpleValueNode(byte @NonNull [] data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,10 +18,6 @@ public class SimpleImmutableValueNode extends ValueNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final String asString() {
|
public final String asString() {
|
||||||
if (getRawData().length == 0 && !hasMetaAttribute(IS_TEXT)) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String(getRawData(), StandardCharsets.UTF_8);
|
return new String(getRawData(), StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,18 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof TupleNode that)) return false;
|
return true;
|
||||||
var toReturn = getKeyNames().equals(that.getKeyNames()) && getNodes().equals(that.getNodes()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
}
|
||||||
|
if (!(o instanceof TupleNode that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var toReturn = getKeyNames().equals(that.getKeyNames()) && getNodes().equals(that.getNodes()) &&
|
||||||
|
Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||||
|
|
||||||
|
// Useful for debugging
|
||||||
if (toReturn == false) {
|
if (toReturn == false) {
|
||||||
throw new AssertionError();
|
return false;
|
||||||
}
|
}
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +100,8 @@ public abstract class TupleNode extends DataStructureNode {
|
||||||
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
|
boolean hasKeys = entries.stream().anyMatch(kv -> kv.key() != null);
|
||||||
return hasKeys ? TupleNode.of(
|
return hasKeys ? TupleNode.of(
|
||||||
entries.stream().map(KeyValue::key).toList(),
|
entries.stream().map(KeyValue::key).toList(),
|
||||||
entries.stream().map(KeyValue::value).toList()) :
|
entries.stream().map(KeyValue::value).toList()
|
||||||
|
) :
|
||||||
TupleNode.of(entries.stream().map(KeyValue::value).toList());
|
TupleNode.of(entries.stream().map(KeyValue::value).toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,12 @@ public abstract class ValueNode extends DataStructureNode {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var toReturn = Arrays.equals(getRawData(), that.getRawData()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
var toReturn = Arrays.equals(getRawData(), that.getRawData()) && Objects.equals(getMetaAttributes(), that.getMetaAttributes());
|
||||||
|
|
||||||
|
// Useful for debugging
|
||||||
if (toReturn == false) {
|
if (toReturn == false) {
|
||||||
throw new AssertionError();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +39,7 @@ public abstract class ValueNode extends DataStructureNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValueNode nullValue() {
|
public static ValueNode nullValue() {
|
||||||
return new SimpleImmutableValueNode(new byte[0]).tag(IS_NULL).asValue();
|
return new SimpleValueNode(new byte[0]).tag(IS_NULL).asValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValueNode of(byte[] data) {
|
public static ValueNode of(byte[] data) {
|
||||||
|
@ -44,7 +47,7 @@ public abstract class ValueNode extends DataStructureNode {
|
||||||
return nullValue();
|
return nullValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SimpleImmutableValueNode(data);
|
return new SimpleValueNode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValueNode ofBytes(byte[] data) {
|
public static ValueNode ofBytes(byte[] data) {
|
||||||
|
|
|
@ -11,16 +11,19 @@ import java.util.List;
|
||||||
|
|
||||||
public abstract class BatchTableWriteConnection implements TableWriteConnection {
|
public abstract class BatchTableWriteConnection implements TableWriteConnection {
|
||||||
|
|
||||||
public static final int BATCH_SIZE = 2000;
|
public static final int DEFAULT_BATCH_SIZE = 2000;
|
||||||
|
|
||||||
|
protected final int batchSize = DEFAULT_BATCH_SIZE;
|
||||||
private final List<DataStructureNode> batch = new ArrayList<>();
|
private final List<DataStructureNode> batch = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor() {
|
public final DataStructureNodeAcceptor<TupleNode> writeLinesAcceptor() {
|
||||||
return node -> {
|
return node -> {
|
||||||
if (batch.size() < BATCH_SIZE) {
|
if (batch.size() < batchSize) {
|
||||||
batch.add(node);
|
batch.add(node);
|
||||||
return true;
|
if (batch.size() < batchSize) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var array = ArrayNode.of(batch);
|
var array = ArrayNode.of(batch);
|
||||||
|
@ -32,12 +35,15 @@ public abstract class BatchTableWriteConnection implements TableWriteConnection
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void close() throws Exception {
|
public final void close() throws Exception {
|
||||||
if (batch.size() > 0) {
|
try {
|
||||||
var array = ArrayNode.of(batch);
|
if (batch.size() > 0) {
|
||||||
var returned = writeBatchLinesAcceptor().accept(array);
|
var array = ArrayNode.of(batch);
|
||||||
batch.clear();
|
var returned = writeBatchLinesAcceptor().accept(array);
|
||||||
|
batch.clear();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
onClose();
|
||||||
}
|
}
|
||||||
onClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void onClose() throws Exception;
|
protected abstract void onClose() throws Exception;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.xpipe.core.impl;
|
package io.xpipe.core.impl;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||||
|
@ -10,7 +9,7 @@ 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.source.TableReadConnection;
|
import io.xpipe.core.source.TableReadConnection;
|
||||||
import io.xpipe.core.store.StreamDataStore;
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -35,7 +34,7 @@ public class XpbtReadConnection implements TableReadConnection {
|
||||||
|
|
||||||
var headerLength = header.getBytes(StandardCharsets.UTF_8).length;
|
var headerLength = header.getBytes(StandardCharsets.UTF_8).length;
|
||||||
this.inputStream.skip(headerLength + 1);
|
this.inputStream.skip(headerLength + 1);
|
||||||
List<String> names = JacksonHelper.newMapper()
|
List<String> names = JacksonMapper.newMapper()
|
||||||
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
|
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE)
|
||||||
.readerFor(new TypeReference<List<String>>() {
|
.readerFor(new TypeReference<List<String>>() {
|
||||||
}).readValue(header);
|
}).readValue(header);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import io.xpipe.core.data.type.TupleType;
|
||||||
import io.xpipe.core.data.typed.TypedDataStreamWriter;
|
import io.xpipe.core.data.typed.TypedDataStreamWriter;
|
||||||
import io.xpipe.core.source.TableWriteConnection;
|
import io.xpipe.core.source.TableWriteConnection;
|
||||||
import io.xpipe.core.store.StreamDataStore;
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -58,7 +58,7 @@ public class XpbtWriteConnection implements TableWriteConnection {
|
||||||
try (JsonGenerator g = f.createGenerator(writer)
|
try (JsonGenerator g = f.createGenerator(writer)
|
||||||
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||||
.setPrettyPrinter(new DefaultPrettyPrinter())) {
|
.setPrettyPrinter(new DefaultPrettyPrinter())) {
|
||||||
JacksonHelper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
JacksonMapper.newMapper().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
|
||||||
.writeValue(g, tupleNode.getKeyNames());
|
.writeValue(g, tupleNode.getKeyNames());
|
||||||
writer.append("\n");
|
writer.append("\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ import io.xpipe.core.impl.TextSource;
|
||||||
import io.xpipe.core.impl.XpbtSource;
|
import io.xpipe.core.impl.XpbtSource;
|
||||||
import io.xpipe.core.store.DataFlow;
|
import io.xpipe.core.store.DataFlow;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.util.JacksonHelper;
|
import io.xpipe.core.util.JacksonMapper;
|
||||||
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ import java.util.Optional;
|
||||||
use = JsonTypeInfo.Id.NAME,
|
use = JsonTypeInfo.Id.NAME,
|
||||||
property = "type"
|
property = "type"
|
||||||
)
|
)
|
||||||
public abstract class DataSource<DS extends DataStore> {
|
public abstract class DataSource<DS extends DataStore> extends JacksonizedValue {
|
||||||
|
|
||||||
|
|
||||||
public static DataSource<?> createInternalDataSource(DataSourceType t, DataStore store) {
|
public static DataSource<?> createInternalDataSource(DataSourceType t, DataStore store) {
|
||||||
|
@ -48,7 +49,7 @@ public abstract class DataSource<DS extends DataStore> {
|
||||||
|
|
||||||
|
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
store.test();
|
store.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate() throws Exception {
|
public void validate() throws Exception {
|
||||||
|
@ -56,7 +57,7 @@ public abstract class DataSource<DS extends DataStore> {
|
||||||
throw new IllegalStateException("Store cannot be null");
|
throw new IllegalStateException("Store cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
store.validate();
|
store.checkComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public WriteMode[] getAvailableWriteModes() {
|
public WriteMode[] getAvailableWriteModes() {
|
||||||
|
@ -79,38 +80,12 @@ public abstract class DataSource<DS extends DataStore> {
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends DataSource<DS>> T copy() {
|
public <T extends DataSource<DS>> T copy() {
|
||||||
var mapper = JacksonHelper.newMapper();
|
var mapper = JacksonMapper.newMapper();
|
||||||
TokenBuffer tb = new TokenBuffer(mapper, false);
|
TokenBuffer tb = new TokenBuffer(mapper, false);
|
||||||
mapper.writeValue(tb, this);
|
mapper.writeValue(tb, this);
|
||||||
return (T) mapper.readValue(tb.asParser(), getClass());
|
return (T) mapper.readValue(tb.asParser(), getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public final String toString() {
|
|
||||||
var tree = JacksonHelper.newMapper().valueToTree(this);
|
|
||||||
return tree.toPrettyString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tree = JacksonHelper.newMapper().valueToTree(this);
|
|
||||||
var otherTree = JacksonHelper.newMapper().valueToTree(o);
|
|
||||||
return tree.equals(otherTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
var tree = JacksonHelper.newMapper().valueToTree(this);
|
|
||||||
return tree.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DataSource<DS> withStore(DS store) {
|
public DataSource<DS> withStore(DS store) {
|
||||||
var c = copy();
|
var c = copy();
|
||||||
c.store = store;
|
c.store = store;
|
||||||
|
|
|
@ -21,6 +21,12 @@ public abstract class TableDataSource<DS extends DataStore> extends DataSource<D
|
||||||
}
|
}
|
||||||
|
|
||||||
public final TableReadConnection openReadConnection() throws Exception {
|
public final TableReadConnection openReadConnection() throws Exception {
|
||||||
|
try {
|
||||||
|
validate();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return TableReadConnection.empty();
|
||||||
|
}
|
||||||
|
|
||||||
var con = newReadConnection();
|
var con = newReadConnection();
|
||||||
con.init();
|
con.init();
|
||||||
return con;
|
return con;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
public abstract class CollectionEntryDataStore implements StreamDataStore, FilenameStore {
|
public abstract class CollectionEntryDataStore implements FilenameStore, StreamDataStore {
|
||||||
|
|
||||||
private final boolean directory;
|
private final boolean directory;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
|
@ -56,10 +56,10 @@ public interface DataStore {
|
||||||
*
|
*
|
||||||
* @throws Exception if any part of the validation went wrong
|
* @throws Exception if any part of the validation went wrong
|
||||||
*/
|
*/
|
||||||
default void test() throws Exception {
|
default void validate() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
default void validate() throws Exception {
|
default void checkComplete() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean delete() throws Exception {
|
default boolean delete() throws Exception {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Builder;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.Value;
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
import lombok.extern.jackson.Jacksonized;
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -12,11 +13,11 @@ import java.nio.file.Path;
|
||||||
/**
|
/**
|
||||||
* Represents a file located on a certain machine.
|
* Represents a file located on a certain machine.
|
||||||
*/
|
*/
|
||||||
@Value
|
|
||||||
@JsonTypeName("file")
|
@JsonTypeName("file")
|
||||||
@Builder
|
@SuperBuilder
|
||||||
@Jacksonized
|
@Jacksonized
|
||||||
public class FileStore implements StreamDataStore, FilenameStore {
|
@Getter
|
||||||
|
public class FileStore extends JacksonizedValue implements FilenameStore, StreamDataStore {
|
||||||
|
|
||||||
public static FileStore local(Path p) {
|
public static FileStore local(Path p) {
|
||||||
return new FileStore(new LocalStore(), p.toString());
|
return new FileStore(new LocalStore(), p.toString());
|
||||||
|
@ -32,8 +33,13 @@ public class FileStore implements StreamDataStore, FilenameStore {
|
||||||
MachineFileStore machine;
|
MachineFileStore machine;
|
||||||
String file;
|
String file;
|
||||||
|
|
||||||
|
public FileStore(MachineFileStore machine, String file) {
|
||||||
|
this.machine = machine;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws Exception {
|
public void checkComplete() throws Exception {
|
||||||
if (machine == null) {
|
if (machine == null) {
|
||||||
throw new IllegalStateException("Machine is missing");
|
throw new IllegalStateException("Machine is missing");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,25 +2,24 @@ package io.xpipe.core.store;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.Value;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.experimental.NonFinal;
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A store whose contents are stored in memory.
|
* A store whose contents are stored in memory.
|
||||||
*/
|
*/
|
||||||
@Value
|
|
||||||
@JsonTypeName("inMemory")
|
@JsonTypeName("inMemory")
|
||||||
public class InMemoryStore implements StreamDataStore {
|
@SuperBuilder
|
||||||
|
@Jacksonized
|
||||||
|
@Getter
|
||||||
|
public class InMemoryStore extends JacksonizedValue implements StreamDataStore {
|
||||||
|
|
||||||
@NonFinal
|
private byte[] value;
|
||||||
byte[] value;
|
|
||||||
|
|
||||||
public InMemoryStore() {
|
|
||||||
this.value = new byte[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public InMemoryStore(byte[] value) {
|
public InMemoryStore(byte[] value) {
|
||||||
|
@ -47,8 +46,4 @@ public class InMemoryStore implements StreamDataStore {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return new String(value, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@ package io.xpipe.core.store;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import io.xpipe.core.charsetter.NewLine;
|
import io.xpipe.core.charsetter.NewLine;
|
||||||
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import io.xpipe.core.util.SecretValue;
|
import io.xpipe.core.util.SecretValue;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Value;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
@ -16,9 +15,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@JsonTypeName("local")
|
@JsonTypeName("local")
|
||||||
@Value
|
public class LocalStore extends JacksonizedValue implements MachineFileStore, StandardShellStore {
|
||||||
@EqualsAndHashCode(callSuper = false)
|
|
||||||
public class LocalStore extends StandardShellStore implements MachineFileStore {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLocal() {
|
public boolean isLocal() {
|
||||||
|
|
|
@ -7,11 +7,6 @@ import java.io.OutputStream;
|
||||||
|
|
||||||
public interface MachineFileStore extends DataStore {
|
public interface MachineFileStore extends DataStore {
|
||||||
|
|
||||||
default boolean isLocal(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
InputStream openInput(String file) throws Exception;
|
InputStream openInput(String file) throws Exception;
|
||||||
|
|
||||||
OutputStream openOutput(String file) throws Exception;
|
OutputStream openOutput(String file) throws Exception;
|
||||||
|
|
|
@ -23,7 +23,7 @@ public final class NamedStore implements DataStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void test() throws Exception {
|
public void validate() throws Exception {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ public abstract class ProcessControl {
|
||||||
var errT = discardErr();
|
var errT = discardErr();
|
||||||
var string = new String(getStdout().readAllBytes(), getCharset());
|
var string = new String(getStdout().readAllBytes(), getCharset());
|
||||||
waitFor();
|
waitFor();
|
||||||
return string;
|
return string.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> readErrOnly() throws Exception {
|
public Optional<String> readErrOnly() throws Exception {
|
||||||
|
@ -34,7 +34,7 @@ public abstract class ProcessControl {
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
var ec = waitFor();
|
var ec = waitFor();
|
||||||
return ec != 0 ? Optional.of(read.get()) : Optional.empty();
|
return ec != 0 ? Optional.of(read.get().trim()) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Thread discardOut() {
|
public Thread discardOut() {
|
||||||
|
|
|
@ -2,28 +2,23 @@ package io.xpipe.core.store;
|
||||||
|
|
||||||
import io.xpipe.core.util.SecretValue;
|
import io.xpipe.core.util.SecretValue;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public abstract class ShellStore implements DataStore {
|
public interface ShellStore extends DataStore {
|
||||||
|
|
||||||
public Integer getTimeout() {
|
public default Integer getTimeout() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SecretValue> getInput() {
|
public default List<SecretValue> getInput() {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLocal() {
|
public default String executeAndRead(List<String> cmd, Integer timeout) throws Exception {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String executeAndRead(List<String> cmd, Integer timeout) throws Exception {
|
|
||||||
var pc = prepareCommand(List.of(), cmd, getEffectiveTimeOut(timeout));
|
var pc = prepareCommand(List.of(), cmd, getEffectiveTimeOut(timeout));
|
||||||
pc.start();
|
pc.start();
|
||||||
pc.discardErr();
|
pc.discardErr();
|
||||||
|
@ -31,7 +26,8 @@ public abstract class ShellStore implements DataStore {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String executeAndCheckOut(List<SecretValue> in, List<String> cmd, Integer timeout) throws ProcessOutputException, Exception {
|
public default String executeAndCheckOut(List<SecretValue> in, List<String> cmd, Integer timeout)
|
||||||
|
throws ProcessOutputException, Exception {
|
||||||
var pc = prepareCommand(in, cmd, getEffectiveTimeOut(timeout));
|
var pc = prepareCommand(in, cmd, getEffectiveTimeOut(timeout));
|
||||||
pc.start();
|
pc.start();
|
||||||
|
|
||||||
|
@ -47,15 +43,10 @@ public abstract class ShellStore implements DataStore {
|
||||||
errorThread.setDaemon(true);
|
errorThread.setDaemon(true);
|
||||||
errorThread.start();
|
errorThread.start();
|
||||||
|
|
||||||
var read = new ByteArrayOutputStream();
|
AtomicReference<String> read = new AtomicReference<>();
|
||||||
var t = new Thread(() -> {
|
var t = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
final byte[] buf = new byte[1];
|
read.set(new String(pc.getStdout().readAllBytes(), pc.getCharset()));
|
||||||
|
|
||||||
int length;
|
|
||||||
while ((length = pc.getStdout().read(buf)) > 0) {
|
|
||||||
read.write(buf, 0, length);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
|
@ -64,19 +55,18 @@ public abstract class ShellStore implements DataStore {
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
var ec = pc.waitFor();
|
var ec = pc.waitFor();
|
||||||
var readOut = read.toString(pc.getCharset());
|
|
||||||
if (ec == -1) {
|
if (ec == -1) {
|
||||||
throw new ProcessOutputException("Command timed out");
|
throw new ProcessOutputException("Command timed out");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ec == 0) {
|
if (ec == 0 && !(read.get().isEmpty() && !readError.get().isEmpty())) {
|
||||||
return readOut;
|
return read.get().trim();
|
||||||
} else {
|
} else {
|
||||||
throw new ProcessOutputException("Command returned with " + ec + ": " + readError.get());
|
throw new ProcessOutputException("Command returned with " + ec + ": " + readError.get().trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<String> executeAndCheckErr(List<SecretValue> in, List<String> cmd) throws Exception {
|
public default Optional<String> executeAndCheckErr(List<SecretValue> in, List<String> cmd) throws Exception {
|
||||||
var pc = prepareCommand(in, cmd, getTimeout());
|
var pc = prepareCommand(in, cmd, getTimeout());
|
||||||
pc.start();
|
pc.start();
|
||||||
var outT = pc.discardOut();
|
var outT = pc.discardOut();
|
||||||
|
@ -99,7 +89,7 @@ public abstract class ShellStore implements DataStore {
|
||||||
return ec != 0 ? Optional.of(read.get()) : Optional.empty();
|
return ec != 0 ? Optional.of(read.get()) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getEffectiveTimeOut(Integer timeout) {
|
public default Integer getEffectiveTimeOut(Integer timeout) {
|
||||||
if (this.getTimeout() == null) {
|
if (this.getTimeout() == null) {
|
||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
@ -109,17 +99,19 @@ public abstract class ShellStore implements DataStore {
|
||||||
return Math.min(getTimeout(), timeout);
|
return Math.min(getTimeout(), timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcessControl prepareCommand(List<String> cmd, Integer timeout) throws Exception {
|
public default ProcessControl prepareCommand(List<String> cmd, Integer timeout) throws Exception {
|
||||||
return prepareCommand(List.of(), cmd, timeout);
|
return prepareCommand(List.of(), cmd, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ProcessControl prepareCommand(List<SecretValue> input, List<String> cmd, Integer timeout) throws Exception;
|
public abstract ProcessControl prepareCommand(List<SecretValue> input, List<String> cmd, Integer timeout)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
public ProcessControl preparePrivilegedCommand(List<String> cmd, Integer timeout) throws Exception {
|
public default ProcessControl preparePrivilegedCommand(List<String> cmd, Integer timeout) throws Exception {
|
||||||
return preparePrivilegedCommand(List.of(), cmd, timeout);
|
return preparePrivilegedCommand(List.of(), cmd, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProcessControl preparePrivilegedCommand(List<SecretValue> input, List<String> cmd, Integer timeout) throws Exception {
|
public default ProcessControl preparePrivilegedCommand(List<SecretValue> input, List<String> cmd, Integer timeout)
|
||||||
|
throws Exception {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,8 +77,10 @@ public class ShellTypes {
|
||||||
var l = new ArrayList<>(cmd);
|
var l = new ArrayList<>(cmd);
|
||||||
l.add(0, "cmd.exe");
|
l.add(0, "cmd.exe");
|
||||||
l.add(1, "/c");
|
l.add(1, "/c");
|
||||||
l.add(2, "@chcp 65001>nul");
|
l.add(2, "@chcp 65001");
|
||||||
l.add(3, "&&");
|
l.add(3, ">");
|
||||||
|
l.add(4, "nul");
|
||||||
|
l.add(5, "&&");
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,11 @@ import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class StandardShellStore extends ShellStore implements MachineFileStore {
|
public interface StandardShellStore extends MachineFileStore, ShellStore {
|
||||||
|
|
||||||
|
public default boolean isLocal() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
public static interface ShellType {
|
public static interface ShellType {
|
||||||
|
@ -38,19 +42,19 @@ public abstract class StandardShellStore extends ShellStore implements MachineFi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public NewLine getNewLine() throws Exception {
|
public default NewLine getNewLine() throws Exception {
|
||||||
return determineType().getNewLine();
|
return determineType().getNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ShellType determineType() throws Exception;
|
public abstract ShellType determineType() throws Exception;
|
||||||
|
|
||||||
public final String querySystemName() throws Exception {
|
public default String querySystemName() throws Exception {
|
||||||
var result = executeAndCheckOut(List.of(), determineType().getOperatingSystemNameCommand(), getTimeout());
|
var result = executeAndCheckOut(List.of(), determineType().getOperatingSystemNameCommand(), getTimeout());
|
||||||
return result.strip();
|
return result.strip();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream openInput(String file) throws Exception {
|
public default InputStream openInput(String file) throws Exception {
|
||||||
var type = determineType();
|
var type = determineType();
|
||||||
var cmd = type.createFileReadCommand(file);
|
var cmd = type.createFileReadCommand(file);
|
||||||
var p = prepareCommand(List.of(), cmd, null);
|
var p = prepareCommand(List.of(), cmd, null);
|
||||||
|
@ -59,7 +63,7 @@ public abstract class StandardShellStore extends ShellStore implements MachineFi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream openOutput(String file) throws Exception {
|
public default OutputStream openOutput(String file) throws Exception {
|
||||||
return null;
|
return null;
|
||||||
// var type = determineType();
|
// var type = determineType();
|
||||||
// var cmd = type.createFileWriteCommand(file);
|
// var cmd = type.createFileWriteCommand(file);
|
||||||
|
@ -69,7 +73,8 @@ public abstract class StandardShellStore extends ShellStore implements MachineFi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean exists(String file) throws Exception {
|
|
||||||
|
public default boolean exists(String file) throws Exception {
|
||||||
var type = determineType();
|
var type = determineType();
|
||||||
var cmd = type.createFileExistsCommand(file);
|
var cmd = type.createFileExistsCommand(file);
|
||||||
var p = prepareCommand(List.of(), cmd, null);
|
var p = prepareCommand(List.of(), cmd, null);
|
||||||
|
@ -78,7 +83,7 @@ public abstract class StandardShellStore extends ShellStore implements MachineFi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mkdirs(String file) throws Exception {
|
public default void mkdirs(String file) throws Exception {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.EqualsAndHashCode;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.Value;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
@EqualsAndHashCode
|
|
||||||
@Value
|
|
||||||
@JsonTypeName("stdin")
|
@JsonTypeName("stdin")
|
||||||
public class StdinDataStore implements StreamDataStore {
|
@SuperBuilder
|
||||||
|
public class StdinDataStore extends JacksonizedValue implements StreamDataStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isContentExclusivelyAccessible() {
|
public boolean isContentExclusivelyAccessible() {
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.core.store;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
import lombok.EqualsAndHashCode;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import lombok.Value;
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
@EqualsAndHashCode
|
|
||||||
@Value
|
|
||||||
@JsonTypeName("stdout")
|
@JsonTypeName("stdout")
|
||||||
public class StdoutDataStore implements StreamDataStore {
|
@SuperBuilder
|
||||||
|
public class StdoutDataStore extends JacksonizedValue implements StreamDataStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canOpen() throws Exception {
|
public boolean canOpen() throws Exception {
|
||||||
|
|
|
@ -10,35 +10,40 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
public class JacksonHelper {
|
public class JacksonMapper {
|
||||||
|
|
||||||
private static final ObjectMapper BASE = new ObjectMapper();
|
private static final ObjectMapper BASE = new ObjectMapper();
|
||||||
private static ObjectMapper INSTANCE = new ObjectMapper();
|
private static ObjectMapper INSTANCE = new ObjectMapper();
|
||||||
|
private static final ObjectMapper DEFAULT;
|
||||||
private static boolean init = false;
|
private static boolean init = false;
|
||||||
private static List<Module> MODULES;
|
|
||||||
|
|
||||||
public static synchronized void initClassBased() {
|
|
||||||
initModularized(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void initModularized(ModuleLayer layer) {
|
|
||||||
MODULES = findModules(layer);
|
|
||||||
|
|
||||||
|
static {
|
||||||
ObjectMapper objectMapper = BASE;
|
ObjectMapper objectMapper = BASE;
|
||||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||||
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||||
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||||
objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
|
objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
|
||||||
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
|
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
|
||||||
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
|
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
|
||||||
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
|
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||||
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
|
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
|
||||||
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
|
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
|
||||||
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
|
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
|
||||||
|
|
||||||
|
var modules = findModules(ModuleLayer.boot());
|
||||||
|
objectMapper.registerModules(modules);
|
||||||
|
|
||||||
INSTANCE = BASE.copy();
|
INSTANCE = BASE.copy();
|
||||||
INSTANCE.registerModules(MODULES);
|
DEFAULT = BASE.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void initClassBased() {
|
||||||
|
initModularized(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void initModularized(ModuleLayer layer) {
|
||||||
|
List<Module> MODULES = findModules(layer);
|
||||||
|
INSTANCE.registerModules(MODULES);
|
||||||
init = true;
|
init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +61,8 @@ public class JacksonHelper {
|
||||||
* Constructs a new ObjectMapper that is able to map all required X-Pipe classes and also possible extensions.
|
* Constructs a new ObjectMapper that is able to map all required X-Pipe classes and also possible extensions.
|
||||||
*/
|
*/
|
||||||
public static ObjectMapper newMapper() {
|
public static ObjectMapper newMapper() {
|
||||||
if (!JacksonHelper.isInit()) {
|
if (!JacksonMapper.isInit()) {
|
||||||
JacksonHelper.initModularized(ModuleLayer.boot());
|
return DEFAULT;
|
||||||
}
|
}
|
||||||
return INSTANCE.copy();
|
return INSTANCE.copy();
|
||||||
}
|
}
|
38
core/src/main/java/io/xpipe/core/util/JacksonizedValue.java
Normal file
38
core/src/main/java/io/xpipe/core/util/JacksonizedValue.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package io.xpipe.core.util;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
public class JacksonizedValue {
|
||||||
|
|
||||||
|
public JacksonizedValue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public final String toString() {
|
||||||
|
var tree = JacksonMapper.newMapper().valueToTree(this);
|
||||||
|
return tree.toPrettyString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o != null && getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tree = JacksonMapper.newMapper().valueToTree(this);
|
||||||
|
var otherTree = JacksonMapper.newMapper().valueToTree(o);
|
||||||
|
return tree.equals(otherTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
var tree = JacksonMapper.newMapper().valueToTree(this);
|
||||||
|
return tree.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,10 @@ public class SecretValue {
|
||||||
if (value.length() < 2) {
|
if (value.length() < 2) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
return new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8);
|
return new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,10 +61,17 @@ public interface DataSourceProvider<T extends DataSource<?>> {
|
||||||
return i18n("displayDescription");
|
return i18n("displayDescription");
|
||||||
}
|
}
|
||||||
|
|
||||||
default String getDisplayIconFileName() {
|
default String getModuleName() {
|
||||||
return getId() + ":icon.png";
|
var n = getClass().getPackageName();
|
||||||
|
var i = n.lastIndexOf('.');
|
||||||
|
return i != -1 ? n.substring(i + 1) : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String getDisplayIconFileName() {
|
||||||
|
return getModuleName() + ":" + getId() + "_icon.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default String getSourceDescription(T source) {
|
default String getSourceDescription(T source) {
|
||||||
return getDisplayName();
|
return getDisplayName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.xpipe.extension;
|
||||||
|
|
||||||
import io.xpipe.core.dialog.Dialog;
|
import io.xpipe.core.dialog.Dialog;
|
||||||
import io.xpipe.core.store.*;
|
import io.xpipe.core.store.*;
|
||||||
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -14,6 +15,16 @@ public interface DataStoreProvider {
|
||||||
DATABASE;
|
DATABASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void validate() throws Exception {
|
||||||
|
getCategory();
|
||||||
|
for (Class<?> storeClass : getStoreClasses()) {
|
||||||
|
if (!JacksonizedValue.class.isAssignableFrom(storeClass)) {
|
||||||
|
throw new ExtensionException(String.format("Store class %s is not a Jacksonized value", storeClass.getSimpleName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default Category getCategory() {
|
default Category getCategory() {
|
||||||
var c = getStoreClasses().get(0);
|
var c = getStoreClasses().get(0);
|
||||||
if (StreamDataStore.class.isAssignableFrom(c)) {
|
if (StreamDataStore.class.isAssignableFrom(c)) {
|
||||||
|
|
|
@ -19,9 +19,12 @@ public class DataStoreProviders {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
ALL.removeIf(p -> {
|
ALL.removeIf(p -> {
|
||||||
try {
|
try {
|
||||||
return !p.init();
|
p.init();
|
||||||
|
p.validate();
|
||||||
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ErrorEvent.fromThrowable(e).handle();
|
ErrorEvent.fromThrowable(e)
|
||||||
|
.handle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -56,17 +59,17 @@ public class DataStoreProviders {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends DataStoreProvider> T byStore(DataStore store) {
|
public static <T extends DataStoreProvider> T byStore(DataStore store) {
|
||||||
return (T) byStoreClass(store.getClass());
|
return (T) byStoreClass(store.getClass()).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends DataStoreProvider> T byStoreClass(Class<?> c) {
|
public static <T extends DataStoreProvider> Optional<T> byStoreClass(Class<?> c) {
|
||||||
if (ALL == null) {
|
if (ALL == null) {
|
||||||
throw new IllegalStateException("Not initialized");
|
throw new IllegalStateException("Not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (T) ALL.stream().filter(d -> d.getStoreClasses().contains(c)).findAny().orElseThrow();
|
return (Optional<T>) ALL.stream().filter(d -> d.getStoreClasses().contains(c)).findAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<DataStoreProvider> getAll() {
|
public static List<DataStoreProvider> getAll() {
|
||||||
|
|
|
@ -80,7 +80,10 @@ public class FancyTooltipAugment<S extends CompStructure<?>> implements Augment<
|
||||||
public void hide() {
|
public void hide() {
|
||||||
Window owner = getOwnerWindow();
|
Window owner = getOwnerWindow();
|
||||||
if (owner == null || owner.isFocused()) {
|
if (owner == null || owner.isFocused()) {
|
||||||
super.hide();
|
try {
|
||||||
|
super.hide();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@ public class FilterComp extends Comp<FilterComp.Structure> {
|
||||||
|
|
||||||
var stack = new StackPane(bgLabel, filter);
|
var stack = new StackPane(bgLabel, filter);
|
||||||
stack.getStyleClass().add("filter-comp");
|
stack.getStyleClass().add("filter-comp");
|
||||||
bgLabel.prefHeightProperty().bind(stack.heightProperty());
|
|
||||||
filter.prefHeightProperty().bind(stack.heightProperty());
|
|
||||||
|
|
||||||
return Structure.builder().inactiveIcon(fi).inactiveText(bgLabel).text(filter).pane(stack).build();
|
return Structure.builder().inactiveIcon(fi).inactiveText(bgLabel).text(filter).pane(stack).build();
|
||||||
}
|
}
|
||||||
|
|
124
extension/src/main/java/io/xpipe/extension/comp/SvgComp.java
Normal file
124
extension/src/main/java/io/xpipe/extension/comp/SvgComp.java
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package io.xpipe.extension.comp;
|
||||||
|
|
||||||
|
import io.xpipe.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.fxcomps.util.PlatformThread;
|
||||||
|
import io.xpipe.fxcomps.util.SimpleChangeListener;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.css.Size;
|
||||||
|
import javafx.css.SizeUnits;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.web.WebView;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class SvgComp {
|
||||||
|
|
||||||
|
private static Size parseSize(String string) {
|
||||||
|
for (SizeUnits unit : SizeUnits.values()) {
|
||||||
|
if (string.endsWith(unit.toString())) {
|
||||||
|
return new Size(
|
||||||
|
Double.parseDouble(string.substring(
|
||||||
|
0, string.length() - unit.toString().length())),
|
||||||
|
unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Size(Double.parseDouble(string), SizeUnits.PX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static SvgComp create(ObservableValue<String> content) {
|
||||||
|
var widthProperty = new SimpleIntegerProperty();
|
||||||
|
var heightProperty = new SimpleIntegerProperty();
|
||||||
|
SimpleChangeListener.apply(content, val -> {
|
||||||
|
var regularExpression = Pattern.compile("<svg.+?width=\"([^\s]+)\"", Pattern.DOTALL);
|
||||||
|
var matcher = regularExpression.matcher(val);
|
||||||
|
matcher.find();
|
||||||
|
var width = matcher.group(1);
|
||||||
|
regularExpression = Pattern.compile("<svg.+?height=\"([^\s]+)\"", Pattern.DOTALL);
|
||||||
|
matcher = regularExpression.matcher(val);
|
||||||
|
matcher.find();
|
||||||
|
var height = matcher.group(1);
|
||||||
|
var widthInteger = parseSize(width).pixels();
|
||||||
|
var heightInteger = parseSize(height).pixels();
|
||||||
|
widthProperty.set((int) Math.ceil(widthInteger));
|
||||||
|
heightProperty.set((int) Math.ceil(heightInteger));
|
||||||
|
});
|
||||||
|
return new SvgComp(widthProperty, heightProperty, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@Builder
|
||||||
|
public static class Structure implements CompStructure<StackPane> {
|
||||||
|
StackPane pane;
|
||||||
|
WebView webView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StackPane get() {
|
||||||
|
return pane;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ObservableValue<Number> width;
|
||||||
|
private final ObservableValue<Number> height;
|
||||||
|
private final ObservableValue<String> svgContent;
|
||||||
|
|
||||||
|
public SvgComp(ObservableValue<Number> width, ObservableValue<Number> height, ObservableValue<String> svgContent) {
|
||||||
|
this.width = PlatformThread.sync(width);
|
||||||
|
this.height = PlatformThread.sync(height);
|
||||||
|
this.svgContent = PlatformThread.sync(svgContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getHtml(String content) {
|
||||||
|
return "<html><body style='margin: 0; padding: 0; border: none;' >" + content + "</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private WebView createWebView() {
|
||||||
|
var wv = new WebView();
|
||||||
|
wv.setPageFill(Color.TRANSPARENT);
|
||||||
|
wv.setDisable(true);
|
||||||
|
|
||||||
|
wv.getEngine().loadContent(getHtml(svgContent.getValue()));
|
||||||
|
svgContent.addListener((c, o, n) -> {
|
||||||
|
wv.getEngine().loadContent(getHtml(n));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide scrollbars that popup on every content change. Bug in WebView?
|
||||||
|
wv.getChildrenUnmodifiable().addListener((ListChangeListener<Node>) change -> {
|
||||||
|
Set<Node> scrolls = wv.lookupAll(".scroll-bar");
|
||||||
|
for (Node scroll : scrolls) {
|
||||||
|
scroll.setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// As the aspect ratio of the WebView is kept constant, we can compute the zoom only using the width
|
||||||
|
wv.zoomProperty()
|
||||||
|
.bind(Bindings.createDoubleBinding(
|
||||||
|
() -> {
|
||||||
|
return wv.getWidth() / width.getValue().doubleValue();
|
||||||
|
},
|
||||||
|
wv.widthProperty(),
|
||||||
|
width));
|
||||||
|
|
||||||
|
wv.maxWidthProperty().bind(wv.prefWidthProperty());
|
||||||
|
wv.maxHeightProperty().bind(wv.prefHeightProperty());
|
||||||
|
return wv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public WebView createWebview() {
|
||||||
|
var wv = createWebView();
|
||||||
|
wv.getStyleClass().add("svg-comp");
|
||||||
|
return wv;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.synedra.validatorfx.Check;
|
import net.synedra.validatorfx.Check;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@ -28,19 +29,41 @@ public class WriteModeChoiceComp extends SimpleComp implements Validatable {
|
||||||
public WriteModeChoiceComp(Property<WriteMode> selected, WriteMode[] available) {
|
public WriteModeChoiceComp(Property<WriteMode> selected, WriteMode[] available) {
|
||||||
this.selected = selected;
|
this.selected = selected;
|
||||||
this.available = available;
|
this.available = available;
|
||||||
|
if (available.length == 1) {
|
||||||
|
selected.setValue(available[0]);
|
||||||
|
}
|
||||||
check = Validators.nonNull(validator, I18n.observable("mode"), selected);
|
check = Validators.nonNull(validator, I18n.observable("mode"), selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Region createSimple() {
|
protected Region createSimple() {
|
||||||
|
var a = Arrays.asList(available);
|
||||||
var map = new LinkedHashMap<WriteMode, ObservableValue<String>>();
|
var map = new LinkedHashMap<WriteMode, ObservableValue<String>>();
|
||||||
map.put(WriteMode.REPLACE, I18n.observable("replace"));
|
var replaceIndex = -1;
|
||||||
map.put(WriteMode.APPEND, I18n.observable("append"));
|
if (a.contains(WriteMode.REPLACE)) {
|
||||||
map.put(WriteMode.PREPEND, I18n.observable("prepend"));
|
map.put(WriteMode.REPLACE, I18n.observable("replace"));
|
||||||
|
replaceIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var appendIndex = -1;
|
||||||
|
if (a.contains(WriteMode.APPEND)) {
|
||||||
|
map.put(WriteMode.APPEND, I18n.observable("append"));
|
||||||
|
appendIndex = replaceIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prependIndex = -1;
|
||||||
|
if (a.contains(WriteMode.PREPEND)) {
|
||||||
|
map.put(WriteMode.PREPEND, I18n.observable("prepend"));
|
||||||
|
prependIndex = Math.max(replaceIndex, appendIndex) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int finalReplaceIndex = replaceIndex;
|
||||||
|
int finalAppendIndex = appendIndex;
|
||||||
|
int finalPrependIndex = prependIndex;
|
||||||
return new ToggleGroupComp<>(selected, map).apply(struc -> {
|
return new ToggleGroupComp<>(selected, map).apply(struc -> {
|
||||||
new FancyTooltipAugment<>("extension.replaceDescription").augment(struc.get().getChildren().get(0));
|
if (finalReplaceIndex != -1) new FancyTooltipAugment<>("extension.replaceDescription").augment(struc.get().getChildren().get(0));
|
||||||
new FancyTooltipAugment<>("extension.appendDescription").augment(struc.get().getChildren().get(1));
|
if (finalAppendIndex != -1) new FancyTooltipAugment<>("extension.appendDescription").augment(struc.get().getChildren().get(finalAppendIndex));
|
||||||
new FancyTooltipAugment<>("extension.prependDescription").augment(struc.get().getChildren().get(2));
|
if (finalPrependIndex != -1) new FancyTooltipAugment<>("extension.prependDescription").augment(struc.get().getChildren().get(finalPrependIndex));
|
||||||
}).apply(struc -> check.decorates(struc.get())).createRegion();
|
}).apply(struc -> check.decorates(struc.get())).createRegion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,5 @@ public interface PrefsChoiceValue extends Translatable {
|
||||||
return I18n.get(getId());
|
return I18n.get(getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
default String toDefaultString() {
|
|
||||||
return I18n.get(getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String getId();
|
String getId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,8 +101,6 @@ public class CustomComboBoxBuilder<T> {
|
||||||
cb.valueProperty().addListener((c, o, n) -> {
|
cb.valueProperty().addListener((c, o, n) -> {
|
||||||
if (nodeMap.containsKey(n)) {
|
if (nodeMap.containsKey(n)) {
|
||||||
if (veto != null && !veto.test(nodeMap.get(n))) {
|
if (veto != null && !veto.test(nodeMap.get(n))) {
|
||||||
cb.setValue(o);
|
|
||||||
;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selected.setValue(nodeMap.get(n));
|
selected.setValue(nodeMap.get(n));
|
||||||
|
|
|
@ -1,15 +1,85 @@
|
||||||
package io.xpipe.extension.util;
|
package io.xpipe.extension.util;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Orientation;
|
import javafx.geometry.Orientation;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.scene.control.MultipleSelectionModel;
|
||||||
import javafx.scene.control.ScrollBar;
|
import javafx.scene.control.ScrollBar;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class PrettyListView<T> extends ListView<T> {
|
public class PrettyListView<T> extends ListView<T> {
|
||||||
|
|
||||||
|
public static class NoSelectionModel<T> extends MultipleSelectionModel<T> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableList<Integer> getSelectedIndices() {
|
||||||
|
return FXCollections.emptyObservableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObservableList<T> getSelectedItems() {
|
||||||
|
return FXCollections.emptyObservableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectIndices(int index, int... indices) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectAll() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectFirst() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectLast() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAndSelect(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void select(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void select(T obj) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearSelection(int index) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearSelection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSelected(int index) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectPrevious() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectNext() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final ScrollBar vBar = new ScrollBar();
|
private final ScrollBar vBar = new ScrollBar();
|
||||||
private final ScrollBar hBar = new ScrollBar();
|
private final ScrollBar hBar = new ScrollBar();
|
||||||
|
|
||||||
|
@ -34,6 +104,10 @@ public class PrettyListView<T> extends ListView<T> {
|
||||||
hBar.visibleProperty().setValue(false);
|
hBar.visibleProperty().setValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void disableSelection() {
|
||||||
|
setSelectionModel(new NoSelectionModel<>());
|
||||||
|
}
|
||||||
|
|
||||||
private void bindScrollBars() {
|
private void bindScrollBars() {
|
||||||
final Set<Node> nodes = lookupAll("VirtualScrollBar");
|
final Set<Node> nodes = lookupAll("VirtualScrollBar");
|
||||||
for (Node node : nodes) {
|
for (Node node : nodes) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package io.xpipe.extension.util;
|
package io.xpipe.extension.util;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
import io.xpipe.core.store.LocalStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.core.store.ShellStore;
|
||||||
import io.xpipe.extension.I18n;
|
import io.xpipe.extension.I18n;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
@ -11,7 +13,7 @@ public class Validators {
|
||||||
|
|
||||||
public static Check nonNull(Validator v, ObservableValue<String> name, ObservableValue<?> s) {
|
public static Check nonNull(Validator v, ObservableValue<String> name, ObservableValue<?> s) {
|
||||||
return v.createCheck().dependsOn("val", s).withMethod(c -> {
|
return v.createCheck().dependsOn("val", s).withMethod(c -> {
|
||||||
if (c.get("val") == null ) {
|
if (c.get("val") == null) {
|
||||||
c.error(I18n.get("extension.mustNotBeEmpty", name.getValue()));
|
c.error(I18n.get("extension.mustNotBeEmpty", name.getValue()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -23,6 +25,12 @@ public class Validators {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void namedStoreExists(DataStore store, String name) {
|
||||||
|
if (!XPipeDaemon.getInstance().getNamedStores().contains(store) && !(store instanceof LocalStore)) {
|
||||||
|
throw new IllegalArgumentException(I18n.get("extension.missingStore", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void hostFeature(ShellStore host, Predicate<ShellStore> predicate, String name) {
|
public static void hostFeature(ShellStore host, Predicate<ShellStore> predicate, String name) {
|
||||||
if (!predicate.test(host)) {
|
if (!predicate.test(host)) {
|
||||||
throw new IllegalArgumentException(I18n.get("extension.hostFeatureUnsupported", name));
|
throw new IllegalArgumentException(I18n.get("extension.hostFeatureUnsupported", name));
|
||||||
|
|
|
@ -25,7 +25,9 @@ public interface XPipeDaemon {
|
||||||
|
|
||||||
public Image image(String file);
|
public Image image(String file);
|
||||||
|
|
||||||
<T extends Comp<?> & Validatable> T streamStoreChooser(Property<DataStore> storeProperty, Property<DataSourceProvider<?>> provider);
|
<T extends Comp<?> & Validatable> T streamStoreChooser(Property<DataStore> storeProperty, Property<DataSourceProvider<?>> provider,
|
||||||
|
boolean showAnonymous,
|
||||||
|
boolean showSaved);
|
||||||
|
|
||||||
<T extends Comp<?> & Validatable> T namedStoreChooser(
|
<T extends Comp<?> & Validatable> T namedStoreChooser(
|
||||||
ObservableValue<Predicate<DataStore>> filter, Property<? extends DataStore> selected, DataStoreProvider.Category category
|
ObservableValue<Predicate<DataStore>> filter, Property<? extends DataStore> selected, DataStoreProvider.Category category
|
||||||
|
|
|
@ -18,6 +18,7 @@ open module io.xpipe.extension {
|
||||||
requires static javafx.base;
|
requires static javafx.base;
|
||||||
requires static javafx.graphics;
|
requires static javafx.graphics;
|
||||||
requires static javafx.controls;
|
requires static javafx.controls;
|
||||||
|
requires static javafx.web;
|
||||||
requires static io.xpipe.fxcomps;
|
requires static io.xpipe.fxcomps;
|
||||||
requires static lombok;
|
requires static lombok;
|
||||||
requires static org.controlsfx.controls;
|
requires static org.controlsfx.controls;
|
||||||
|
|
|
@ -7,6 +7,7 @@ nullPointer=Null Pointer: $MSG$
|
||||||
mustNotBeEmpty=$NAME$ must not be empty
|
mustNotBeEmpty=$NAME$ must not be empty
|
||||||
null=$VALUE$ must be not null
|
null=$VALUE$ must be not null
|
||||||
hostFeatureUnsupported=Host does not support the feature $FEATURE$
|
hostFeatureUnsupported=Host does not support the feature $FEATURE$
|
||||||
|
missingStore=$NAME$ does not exist
|
||||||
namedHostFeatureUnsupported=$HOST$ does not support this feature
|
namedHostFeatureUnsupported=$HOST$ does not support this feature
|
||||||
namedHostNotActive=$HOST$ is not active
|
namedHostNotActive=$HOST$ is not active
|
||||||
noInformationAvailable=No information available
|
noInformationAvailable=No information available
|
||||||
|
|
Loading…
Reference in a new issue