mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 00:50:31 +00:00
Add support for more data source types
This commit is contained in:
parent
7dec1afdb4
commit
100438744e
34 changed files with 669 additions and 92 deletions
|
@ -11,6 +11,10 @@ apply from: "$rootDir/deps/lombok.gradle"
|
||||||
apply from: 'publish.gradle'
|
apply from: 'publish.gradle'
|
||||||
apply from: "$rootDir/deps/publish-base.gradle"
|
apply from: "$rootDir/deps/publish-base.gradle"
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly.extendsFrom(dep)
|
||||||
|
}
|
||||||
|
|
||||||
version = file('../version').text
|
version = file('../version').text
|
||||||
group = 'io.xpipe'
|
group = 'io.xpipe'
|
||||||
archivesBaseName = 'beacon'
|
archivesBaseName = 'beacon'
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package io.xpipe.beacon.exchange.cli;
|
||||||
|
|
||||||
|
import io.xpipe.beacon.exchange.MessageExchange;
|
||||||
|
import io.xpipe.beacon.message.RequestMessage;
|
||||||
|
import io.xpipe.beacon.message.ResponseMessage;
|
||||||
|
import io.xpipe.core.source.DataSourceConfigInstance;
|
||||||
|
import io.xpipe.core.source.DataSourceId;
|
||||||
|
import io.xpipe.core.source.DataSourceReference;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.jackson.Jacksonized;
|
||||||
|
|
||||||
|
public class ConvertExchange implements MessageExchange<ConvertExchange.Request, ConvertExchange.Response> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "convert";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ConvertExchange.Request> getRequestClass() {
|
||||||
|
return ConvertExchange.Request.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ConvertExchange.Response> getResponseClass() {
|
||||||
|
return ConvertExchange.Response.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Jacksonized
|
||||||
|
@Builder
|
||||||
|
@Value
|
||||||
|
public static class Request implements RequestMessage {
|
||||||
|
@NonNull
|
||||||
|
DataSourceReference ref;
|
||||||
|
|
||||||
|
@NonNull DataSourceId copyId;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
DataSourceConfigInstance config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Jacksonized
|
||||||
|
@Builder
|
||||||
|
@Value
|
||||||
|
public static class Response implements ResponseMessage {
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,12 +33,14 @@ module io.xpipe.beacon {
|
||||||
WriteExecuteExchange,
|
WriteExecuteExchange,
|
||||||
SelectExchange,
|
SelectExchange,
|
||||||
ReadPreparationExchange,
|
ReadPreparationExchange,
|
||||||
|
QueryTextDataExchange,
|
||||||
ReadExecuteExchange,
|
ReadExecuteExchange,
|
||||||
DialogExchange,
|
DialogExchange,
|
||||||
QueryDataSourceExchange,
|
QueryDataSourceExchange,
|
||||||
StoreStreamExchange,
|
StoreStreamExchange,
|
||||||
EditPreparationExchange,
|
EditPreparationExchange,
|
||||||
EditExecuteExchange,
|
EditExecuteExchange,
|
||||||
|
ConvertExchange,
|
||||||
QueryTableDataExchange,
|
QueryTableDataExchange,
|
||||||
VersionExchange;
|
VersionExchange;
|
||||||
}
|
}
|
|
@ -12,6 +12,10 @@ apply from: "$rootDir/deps/junit.gradle"
|
||||||
apply from: 'publish.gradle'
|
apply from: 'publish.gradle'
|
||||||
apply from: "$rootDir/deps/publish-base.gradle"
|
apply from: "$rootDir/deps/publish-base.gradle"
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly.extendsFrom(dep)
|
||||||
|
}
|
||||||
|
|
||||||
version = file('../version').text
|
version = file('../version').text
|
||||||
group = 'io.xpipe'
|
group = 'io.xpipe'
|
||||||
archivesBaseName = 'core'
|
archivesBaseName = 'core'
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
public interface CollectionDataSourceDescriptor<DS extends DataStore> extends DataSourceDescriptor<DS> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DataSourceInfo determineInfo(DS store) throws Exception {
|
||||||
|
try (var con = openReadConnection(store)) {
|
||||||
|
var c = (int) con.listEntries().count();
|
||||||
|
return new DataSourceInfo.Structure(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default CollectionReadConnection openReadConnection(DS store) throws Exception {
|
||||||
|
var con = newReadConnection(store);
|
||||||
|
con.init();
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
default CollectionWriteConnection openWriteConnection(DS store) throws Exception {
|
||||||
|
var con = newWriteConnection(store);
|
||||||
|
con.init();
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionWriteConnection newWriteConnection(DS store);
|
||||||
|
|
||||||
|
CollectionReadConnection newReadConnection(DS store);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public interface CollectionReadConnection extends DataSourceReadConnection {
|
||||||
|
|
||||||
|
<T extends DataSourceReadConnection> T open(String entry) throws Exception;
|
||||||
|
|
||||||
|
Stream<String> listEntries() throws Exception;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
default void forward(DataSourceConnection con) throws Exception {
|
||||||
|
try (var tCon = (CollectionWriteConnection) con) {
|
||||||
|
tCon.init();
|
||||||
|
listEntries().forEach(s -> {
|
||||||
|
try (var subCon = open(s)) {
|
||||||
|
((CollectionWriteConnection) con).write(s, subCon);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
public interface CollectionWriteConnection extends DataSourceConnection {
|
||||||
|
|
||||||
|
void write(String entry, DataSourceReadConnection con) throws Exception;
|
||||||
|
}
|
|
@ -27,11 +27,6 @@ public interface DataSourceDescriptor<DS extends DataStore> {
|
||||||
*/
|
*/
|
||||||
DataSourceInfo determineInfo(DS store) throws Exception;
|
DataSourceInfo determineInfo(DS store) throws Exception;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the general data source type.
|
|
||||||
*/
|
|
||||||
DataSourceType getType();
|
|
||||||
|
|
||||||
DataSourceReadConnection openReadConnection(DS store) throws Exception;
|
DataSourceReadConnection openReadConnection(DS store) throws Exception;
|
||||||
|
|
||||||
DataSourceConnection openWriteConnection(DS store) throws Exception;
|
DataSourceConnection openWriteConnection(DS store) throws Exception;
|
||||||
|
|
|
@ -7,8 +7,6 @@ import io.xpipe.core.data.type.TupleType;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,8 +51,11 @@ public abstract class DataSourceInfo {
|
||||||
@JsonTypeName("structure")
|
@JsonTypeName("structure")
|
||||||
public static class Structure extends DataSourceInfo {
|
public static class Structure extends DataSourceInfo {
|
||||||
|
|
||||||
|
int entries;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public Structure() {
|
public Structure(int entries) {
|
||||||
|
this.entries = entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,17 +64,32 @@ public abstract class DataSourceInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Value
|
||||||
|
@JsonTypeName("collection")
|
||||||
|
public static class Collection extends DataSourceInfo {
|
||||||
|
|
||||||
|
int entries;
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public Collection(int entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getType() {
|
||||||
|
return DataSourceType.COLLECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Value
|
@Value
|
||||||
@JsonTypeName("text")
|
@JsonTypeName("text")
|
||||||
public static class Text extends DataSourceInfo {
|
public static class Text extends DataSourceInfo {
|
||||||
Charset charset;
|
|
||||||
|
|
||||||
int lineCount;
|
int lineCount;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public Text(Charset charset, int lineCount) {
|
public Text(int lineCount) {
|
||||||
this.charset = charset;
|
|
||||||
this.lineCount = lineCount;
|
this.lineCount = lineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,12 +105,10 @@ public abstract class DataSourceInfo {
|
||||||
@JsonTypeName("raw")
|
@JsonTypeName("raw")
|
||||||
public static class Raw extends DataSourceInfo {
|
public static class Raw extends DataSourceInfo {
|
||||||
int byteCount;
|
int byteCount;
|
||||||
ByteOrder byteOrder;
|
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public Raw(int byteCount, ByteOrder byteOrder) {
|
public Raw(int byteCount) {
|
||||||
this.byteCount = byteCount;
|
this.byteCount = byteCount;
|
||||||
this.byteOrder = byteOrder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,5 +18,8 @@ public enum DataSourceType {
|
||||||
TEXT,
|
TEXT,
|
||||||
|
|
||||||
@JsonProperty("raw")
|
@JsonProperty("raw")
|
||||||
RAW
|
RAW,
|
||||||
|
|
||||||
|
@JsonProperty("collection")
|
||||||
|
COLLECTION
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
public abstract class RawDataSourceDescriptor <DS extends DataStore> implements DataSourceDescriptor<DS> {
|
||||||
|
|
||||||
|
private static final int MAX_BYTES_READ = 100000;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceInfo determineInfo(DS store) throws Exception {
|
||||||
|
try (var con = openReadConnection(store)) {
|
||||||
|
var b = con.readBytes(MAX_BYTES_READ);
|
||||||
|
int usedCount = b.length == MAX_BYTES_READ ? -1 : b.length;
|
||||||
|
return new DataSourceInfo.Raw(usedCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RawReadConnection openReadConnection(DS store) throws Exception {
|
||||||
|
var con = newReadConnection(store);
|
||||||
|
con.init();
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RawWriteConnection openWriteConnection(DS store) throws Exception {
|
||||||
|
var con = newWriteConnection(store);
|
||||||
|
con.init();
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RawWriteConnection newWriteConnection(DS store);
|
||||||
|
|
||||||
|
protected abstract RawReadConnection newReadConnection(DS store);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
public interface RawReadConnection extends DataSourceReadConnection {
|
||||||
|
|
||||||
|
byte[] readBytes(int max) throws Exception;
|
||||||
|
|
||||||
|
int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
default void forward(DataSourceConnection con) throws Exception {
|
||||||
|
try (var tCon = (RawWriteConnection) con) {
|
||||||
|
tCon.init();
|
||||||
|
byte[] b;
|
||||||
|
while ((b = readBytes(BUFFER_SIZE)).length > 0) {
|
||||||
|
tCon.write(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
public interface RawWriteConnection extends DataSourceConnection {
|
||||||
|
|
||||||
|
void write(byte[] bytes) throws Exception;
|
||||||
|
}
|
|
@ -1,27 +1,43 @@
|
||||||
package io.xpipe.core.source;
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
|
import io.xpipe.core.data.node.DataStructureNode;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
public abstract class StructureDataSourceDescriptor<DS extends DataStore> implements DataSourceDescriptor<DS> {
|
public interface StructureDataSourceDescriptor<DS extends DataStore> extends DataSourceDescriptor<DS> {
|
||||||
|
|
||||||
public final StructureReadConnection openReadConnection(DS store) throws Exception {
|
private int countEntries(DataStructureNode n) {
|
||||||
|
if (n.isValue()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
for (int i = 0; i < n.size(); i++) {
|
||||||
|
c += countEntries(n.at(i));
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DataSourceInfo determineInfo(DS store) throws Exception {
|
||||||
|
try (var con = openReadConnection(store)) {
|
||||||
|
var n = con.read();
|
||||||
|
var c = countEntries(n);
|
||||||
|
return new DataSourceInfo.Structure(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default StructureReadConnection openReadConnection(DS store) throws Exception {
|
||||||
var con = newReadConnection(store);
|
var con = newReadConnection(store);
|
||||||
con.init();
|
con.init();
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final StructureWriteConnection openWriteConnection(DS store) throws Exception {
|
default StructureWriteConnection openWriteConnection(DS store) throws Exception {
|
||||||
var con = newWriteConnection(store);
|
var con = newWriteConnection(store);
|
||||||
con.init();
|
con.init();
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
StructureWriteConnection newWriteConnection(DS store);
|
||||||
|
|
||||||
protected abstract StructureWriteConnection newWriteConnection(DS store);
|
StructureReadConnection newReadConnection(DS store);
|
||||||
|
|
||||||
protected abstract StructureReadConnection newReadConnection(DS store);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSourceType getType() {
|
|
||||||
return DataSourceType.STRUCTURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,4 @@ public abstract class TableDataSourceDescriptor<DS extends DataStore> implements
|
||||||
protected abstract TableWriteConnection newWriteConnection(DS store);
|
protected abstract TableWriteConnection newWriteConnection(DS store);
|
||||||
|
|
||||||
protected abstract TableReadConnection newReadConnection(DS store);
|
protected abstract TableReadConnection newReadConnection(DS store);
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSourceType getType() {
|
|
||||||
return DataSourceType.TABLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,15 @@ import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
public abstract class TextDataSourceDescriptor<DS extends DataStore> implements DataSourceDescriptor<DS> {
|
public abstract class TextDataSourceDescriptor<DS extends DataStore> implements DataSourceDescriptor<DS> {
|
||||||
|
|
||||||
|
private static final int MAX_LINE_READ = 1000;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourceType getType() {
|
public DataSourceInfo determineInfo(DS store) throws Exception {
|
||||||
return DataSourceType.TEXT;
|
try (var con = openReadConnection(store)) {
|
||||||
|
int count = (int) con.lines().limit(MAX_LINE_READ).count();
|
||||||
|
int usedCount = count == MAX_LINE_READ ? -1 : count;
|
||||||
|
return new DataSourceInfo.Text(usedCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
package io.xpipe.core.source;
|
package io.xpipe.core.source;
|
||||||
|
|
||||||
import java.util.List;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public interface TextReadConnection extends DataSourceReadConnection {
|
public interface TextReadConnection extends DataSourceReadConnection {
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the complete contents.
|
|
||||||
*/
|
|
||||||
String readAll() throws Exception;
|
|
||||||
|
|
||||||
List<String> readAllLines() throws Exception;
|
|
||||||
|
|
||||||
String readLine() throws Exception;
|
|
||||||
|
|
||||||
Stream<String> lines() throws Exception;
|
Stream<String> lines() throws Exception;
|
||||||
|
|
||||||
boolean isFinished() throws Exception;
|
boolean isFinished() throws Exception;
|
||||||
|
|
||||||
|
default void forwardLines(OutputStream out, int maxLines) throws Exception {
|
||||||
|
if (maxLines == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
for (var it = lines().iterator(); it.hasNext(); counter++) {
|
||||||
|
if (counter == maxLines) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(it.next().getBytes(StandardCharsets.UTF_8));
|
||||||
|
out.write("\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default void forward(DataSourceConnection con) throws Exception {
|
default void forward(DataSourceConnection con) throws Exception {
|
||||||
try (var tCon = (TextWriteConnection) con) {
|
try (var tCon = (TextWriteConnection) con) {
|
||||||
tCon.init();
|
tCon.init();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.xpipe.core.util;
|
package io.xpipe.core.util;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.Module;
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
@ -22,6 +23,7 @@ public class JacksonHelper {
|
||||||
ObjectMapper objectMapper = INSTANCE;
|
ObjectMapper objectMapper = INSTANCE;
|
||||||
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.registerModules(findModules(layer));
|
objectMapper.registerModules(findModules(layer));
|
||||||
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
|
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
|
||||||
|
|
|
@ -17,6 +17,10 @@ apply from: "$rootDir/deps/slf4j.gradle"
|
||||||
apply from: 'publish.gradle'
|
apply from: 'publish.gradle'
|
||||||
apply from: "$rootDir/deps/publish-base.gradle"
|
apply from: "$rootDir/deps/publish-base.gradle"
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly.extendsFrom(dep)
|
||||||
|
}
|
||||||
|
|
||||||
version = file('../version').text
|
version = file('../version').text
|
||||||
group = 'io.xpipe'
|
group = 'io.xpipe'
|
||||||
archivesBaseName = 'extension'
|
archivesBaseName = 'extension'
|
||||||
|
|
|
@ -12,31 +12,74 @@ import javafx.scene.layout.Region;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public interface DataSourceProvider {
|
public interface DataSourceProvider {
|
||||||
|
|
||||||
|
default String i18n(String key) {
|
||||||
|
return I18n.get(getId() + "." + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
default String i18nKey(String key) {
|
||||||
|
return getId() + "." + key;
|
||||||
|
}
|
||||||
|
|
||||||
|
default Region createConfigOptions(DataStore input, Property<? extends DataSourceDescriptor<?>> source) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getDisplayName() {
|
||||||
|
return i18n("displayName");
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getDisplayImageFile() {
|
||||||
|
return "logo.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getDescription(DataSourceDescriptor<?> source) {
|
||||||
|
return i18n("description");
|
||||||
|
}
|
||||||
|
|
||||||
interface FileProvider {
|
interface FileProvider {
|
||||||
|
|
||||||
String getFileName();
|
String getFileName();
|
||||||
|
|
||||||
Map<Supplier<String>, String> getFileExtensions();
|
Map<String, List<String>> getFileExtensions();
|
||||||
}
|
|
||||||
|
|
||||||
interface GuiProvider {
|
|
||||||
|
|
||||||
Region createConfigOptions(DataStore input, Property<? extends DataSourceDescriptor<?>> source);
|
|
||||||
|
|
||||||
String getDisplayName();
|
|
||||||
|
|
||||||
String getDisplayImage();
|
|
||||||
|
|
||||||
Supplier<String> getDescription(DataSourceDescriptor<?> source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfigProvider {
|
interface ConfigProvider {
|
||||||
|
|
||||||
|
static ConfigProvider empty(List<String> names, Supplier<DataSourceDescriptor<?>> supplier) {
|
||||||
|
return new ConfigProvider() {
|
||||||
|
@Override
|
||||||
|
public ConfigOptionSet getConfig() {
|
||||||
|
return ConfigOptionSet.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceDescriptor<?> toDescriptor(Map<String, String> values) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> toConfigOptions(DataSourceDescriptor<?> desc) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<ConfigOption, Function<String, ?>> getConverters() {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getPossibleNames() {
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ConfigOption
|
ConfigOption
|
||||||
CHARSET_OPTION = new ConfigOption("Charset", "charset");
|
CHARSET_OPTION = new ConfigOption("Charset", "charset");
|
||||||
Function<String, Charset>
|
Function<String, Charset>
|
||||||
|
@ -87,19 +130,45 @@ public interface DataSourceProvider {
|
||||||
List<String> getPossibleNames();
|
List<String> getPossibleNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSourceType getType();
|
default boolean isHidden() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSourceType getPrimaryType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this provider prefers a certain kind of store.
|
||||||
|
* This is important for the correct autodetection of a store.
|
||||||
|
*/
|
||||||
boolean prefersStore(DataStore store);
|
boolean prefersStore(DataStore store);
|
||||||
|
|
||||||
boolean supportsStore(DataStore store);
|
/**
|
||||||
|
* Checks whether this provider supports the store in principle.
|
||||||
|
* This method should not perform any further checks,
|
||||||
|
* just check whether it may be possible that the store is supported.
|
||||||
|
*
|
||||||
|
* This method will be called for validation purposes.
|
||||||
|
*/
|
||||||
|
boolean couldSupportStore(DataStore store);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a deep inspection to check whether this provider supports a given store.
|
||||||
|
*
|
||||||
|
* This functionality will be used in case no preferred provider has been found.
|
||||||
|
*/
|
||||||
|
default boolean supportsStore(DataStore store) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
FileProvider getFileProvider();
|
FileProvider getFileProvider();
|
||||||
|
|
||||||
GuiProvider getGuiProvider();
|
|
||||||
|
|
||||||
ConfigProvider getConfigProvider();
|
ConfigProvider getConfigProvider();
|
||||||
|
|
||||||
String getId();
|
default String getId() {
|
||||||
|
var n = getClass().getPackageName();
|
||||||
|
var i = n.lastIndexOf('.');
|
||||||
|
return i != -1 ? n.substring(i + 1) : n;
|
||||||
|
}
|
||||||
|
|
||||||
DataSourceDescriptor<?> createDefaultDescriptor();
|
DataSourceDescriptor<?> createDefaultDescriptor();
|
||||||
|
|
||||||
|
@ -112,4 +181,6 @@ public interface DataSourceProvider {
|
||||||
DataSourceDescriptor<?> createDefaultWriteDescriptor(DataStore input, DataSourceInfo info) throws Exception;
|
DataSourceDescriptor<?> createDefaultWriteDescriptor(DataStore input, DataSourceInfo info) throws Exception;
|
||||||
|
|
||||||
Class<? extends DataSourceDescriptor<?>> getDescriptorClass();
|
Class<? extends DataSourceDescriptor<?>> getDescriptorClass();
|
||||||
|
|
||||||
|
Optional<String> determineDefaultName(DataStore store);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package io.xpipe.extension;
|
package io.xpipe.extension;
|
||||||
|
|
||||||
import io.xpipe.core.data.type.TupleType;
|
import io.xpipe.core.data.type.TupleType;
|
||||||
import io.xpipe.core.source.DataSourceType;
|
import io.xpipe.core.source.*;
|
||||||
import io.xpipe.core.source.TableDataSourceDescriptor;
|
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.LocalFileDataStore;
|
import io.xpipe.core.store.LocalFileDataStore;
|
||||||
import io.xpipe.extension.event.ErrorEvent;
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -23,35 +24,54 @@ public class DataSourceProviders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSourceProvider getNativeProviderForType(DataSourceType t) {
|
@SuppressWarnings("unchecked")
|
||||||
switch (t) {
|
public static DataSourceDescriptor<StreamDataStore> getNativeDataSourceDescriptorForType(DataSourceType t) {
|
||||||
case TABLE -> {
|
try {
|
||||||
return DataSourceProviders.byId("xpbt").orElseThrow();
|
return switch (t) {
|
||||||
}
|
case TABLE -> (DataSourceDescriptor<StreamDataStore>) DataSourceProviders.byId("xpbt").orElseThrow()
|
||||||
case STRUCTURE -> {
|
.getDescriptorClass().getConstructors()[0].newInstance();
|
||||||
return DataSourceProviders.byId("xpbs").orElseThrow();
|
case STRUCTURE -> (DataSourceDescriptor<StreamDataStore>) DataSourceProviders.byId("xpbs").orElseThrow()
|
||||||
}
|
.getDescriptorClass().getConstructors()[0].newInstance();
|
||||||
case TEXT -> {
|
case TEXT -> (DataSourceDescriptor<StreamDataStore>) DataSourceProviders.byId("text").orElseThrow()
|
||||||
return DataSourceProviders.byId("xpbx").orElseThrow();
|
.getDescriptorClass().getConstructors()[0].newInstance(StandardCharsets.UTF_8);
|
||||||
}
|
case RAW -> (DataSourceDescriptor<StreamDataStore>) DataSourceProviders.byId("xpbr").orElseThrow()
|
||||||
case RAW -> {
|
.getDescriptorClass().getConstructors()[0].newInstance();
|
||||||
return DataSourceProviders.byId("xpbb").orElseThrow();
|
};
|
||||||
}
|
} catch (Exception ex) {
|
||||||
|
throw new AssertionError(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@SneakyThrows
|
||||||
|
public static StructureDataSourceDescriptor<LocalFileDataStore> createLocalStructureDescriptor() {
|
||||||
|
return (StructureDataSourceDescriptor<LocalFileDataStore>)
|
||||||
|
DataSourceProviders.byId("json").orElseThrow().getDescriptorClass()
|
||||||
|
.getDeclaredConstructors()[0].newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@SneakyThrows
|
||||||
|
public static RawDataSourceDescriptor<LocalFileDataStore> createLocalRawDescriptor() {
|
||||||
|
return (RawDataSourceDescriptor<LocalFileDataStore>)
|
||||||
|
DataSourceProviders.byId("binary").orElseThrow().getDescriptorClass()
|
||||||
|
.getDeclaredConstructors()[0].newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@SneakyThrows
|
||||||
|
public static TextDataSourceDescriptor<LocalFileDataStore> createLocalTextDescriptor() {
|
||||||
|
return (TextDataSourceDescriptor<LocalFileDataStore>)
|
||||||
|
DataSourceProviders.byId("text").orElseThrow().getDescriptorClass()
|
||||||
|
.getDeclaredConstructors()[0].newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@SneakyThrows
|
||||||
public static TableDataSourceDescriptor<LocalFileDataStore> createLocalTableDescriptor(TupleType type) {
|
public static TableDataSourceDescriptor<LocalFileDataStore> createLocalTableDescriptor(TupleType type) {
|
||||||
try {
|
return (TableDataSourceDescriptor<LocalFileDataStore>)
|
||||||
return (TableDataSourceDescriptor<LocalFileDataStore>)
|
DataSourceProviders.byId("xpbt").orElseThrow().getDescriptorClass()
|
||||||
DataSourceProviders.byId("xpbt").orElseThrow().getDescriptorClass()
|
.getDeclaredConstructors()[0].newInstance(type);
|
||||||
.getDeclaredConstructors()[0].newInstance(type);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ErrorEvent.fromThrowable(ex).terminal(true).build().handle();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<DataSourceProvider> byDescriptorClass(Class<?> clazz) {
|
public static Optional<DataSourceProvider> byDescriptorClass(Class<?> clazz) {
|
||||||
|
@ -85,7 +105,7 @@ public class DataSourceProviders {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ALL.stream().filter(d -> d.getFileProvider() != null)
|
return ALL.stream().filter(d -> d.getFileProvider() != null)
|
||||||
.filter(d -> d.supportsStore(store)).findAny();
|
.filter(d -> d.couldSupportStore(store)).findAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<DataSourceProvider> getAll() {
|
public static Set<DataSourceProvider> getAll() {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package io.xpipe.extension;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
import io.xpipe.core.store.FileDataStore;
|
||||||
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface SimpleFileDataSourceProvider extends DataSourceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Optional<String> determineDefaultName(DataStore store) {
|
||||||
|
if (store instanceof FileDataStore l) {
|
||||||
|
var n = l.getFileName();
|
||||||
|
var i = n.lastIndexOf('.');
|
||||||
|
return Optional.of(i != -1 ? n.substring(0, i) : n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean prefersStore(DataStore store) {
|
||||||
|
for (var e : getSupportedExtensions().entrySet()) {
|
||||||
|
if (e.getValue() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store instanceof FileDataStore l) {
|
||||||
|
return l.getFileName().matches("\\." + e.getValue() + "$");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean couldSupportStore(DataStore store) {
|
||||||
|
return store instanceof StreamDataStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getNameI18nKey() {
|
||||||
|
return i18nKey("displayName");
|
||||||
|
}
|
||||||
|
Map<String, List<String>> getSupportedExtensions();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default FileProvider getFileProvider() {
|
||||||
|
return new FileProvider() {
|
||||||
|
@Override
|
||||||
|
public String getFileName() {
|
||||||
|
return I18n.get(getNameI18nKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getFileExtensions() {
|
||||||
|
var map = new LinkedHashMap<>(getSupportedExtensions());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.xpipe.extension;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.DataSourceDescriptor;
|
||||||
|
import io.xpipe.core.source.DataSourceInfo;
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface UniformDataSourceProvider extends DataSourceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default ConfigProvider getConfigProvider() {
|
||||||
|
return ConfigProvider.empty(List.of(getId()), this::createDefaultDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DataSourceDescriptor<?> createDefaultDescriptor() {
|
||||||
|
try {
|
||||||
|
return (DataSourceDescriptor<?>) getDescriptorClass().getDeclaredConstructors()[0].newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DataSourceDescriptor<?> createDefaultDescriptor(DataStore input) throws Exception {
|
||||||
|
return createDefaultDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default DataSourceDescriptor<?> createDefaultWriteDescriptor(DataStore input, DataSourceInfo info) throws Exception {
|
||||||
|
return createDefaultDescriptor();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,10 @@ module io.xpipe.extension {
|
||||||
exports io.xpipe.extension.event;
|
exports io.xpipe.extension.event;
|
||||||
exports io.xpipe.extension.prefs;
|
exports io.xpipe.extension.prefs;
|
||||||
|
|
||||||
requires io.xpipe.core;
|
requires transitive io.xpipe.core;
|
||||||
requires javafx.base;
|
requires transitive javafx.base;
|
||||||
requires javafx.graphics;
|
requires javafx.graphics;
|
||||||
requires javafx.controls;
|
requires transitive javafx.controls;
|
||||||
requires io.xpipe.fxcomps;
|
requires io.xpipe.fxcomps;
|
||||||
requires org.apache.commons.collections4;
|
requires org.apache.commons.collections4;
|
||||||
requires static lombok;
|
requires static lombok;
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id "org.moditect.gradleplugin" version "1.0.0-rc3"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/deps/java.gradle"
|
||||||
|
apply from: "$rootDir/deps/javafx.gradle"
|
||||||
|
apply from: "$rootDir/deps/lombok.gradle"
|
||||||
|
apply from: "$rootDir/deps/extension.gradle"
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly.extendsFrom(dep)
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.xpipe.ext.json;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.RawDataSourceDescriptor;
|
||||||
|
import io.xpipe.core.source.RawReadConnection;
|
||||||
|
import io.xpipe.core.source.RawWriteConnection;
|
||||||
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
|
|
||||||
|
public class MyRawFileDescriptor extends RawDataSourceDescriptor<StreamDataStore> {
|
||||||
|
@Override
|
||||||
|
protected RawWriteConnection newWriteConnection(StreamDataStore store) {
|
||||||
|
return new MyRawFileWriteConnection(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RawReadConnection newReadConnection(StreamDataStore store) {
|
||||||
|
return new MyRawFileReadConnection(store);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package io.xpipe.ext.json;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.DataSourceDescriptor;
|
||||||
|
import io.xpipe.core.source.DataSourceType;
|
||||||
|
import io.xpipe.extension.DataSourceProvider;
|
||||||
|
import io.xpipe.extension.SimpleFileDataSourceProvider;
|
||||||
|
import io.xpipe.extension.UniformDataSourceProvider;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MyRawFileProvider implements UniformDataSourceProvider, SimpleFileDataSourceProvider, DataSourceProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSourceType getPrimaryType() {
|
||||||
|
return DataSourceType.RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getSupportedExtensions() {
|
||||||
|
var map = new LinkedHashMap<String, String>();
|
||||||
|
map.put(i18nKey("fileName"), "myf");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends DataSourceDescriptor<?>> getDescriptorClass() {
|
||||||
|
return MyRawFileDescriptor.class;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package io.xpipe.ext.json;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.RawReadConnection;
|
||||||
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class MyRawFileReadConnection implements RawReadConnection {
|
||||||
|
|
||||||
|
private InputStream inputStream;
|
||||||
|
private final StreamDataStore store;
|
||||||
|
|
||||||
|
public MyRawFileReadConnection(StreamDataStore store) {
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws Exception {
|
||||||
|
if (inputStream != null) {
|
||||||
|
throw new IllegalStateException("Already initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream = store.openInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalStateException("Not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] readBytes(int max) throws Exception {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalStateException("Not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputStream.readNBytes(max);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package io.xpipe.ext.json;
|
||||||
|
|
||||||
|
import io.xpipe.core.source.RawWriteConnection;
|
||||||
|
import io.xpipe.core.store.StreamDataStore;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class MyRawFileWriteConnection implements RawWriteConnection {
|
||||||
|
|
||||||
|
private final StreamDataStore store;
|
||||||
|
private OutputStream outputStream;
|
||||||
|
|
||||||
|
public MyRawFileWriteConnection(StreamDataStore store) {
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws Exception {
|
||||||
|
if (outputStream != null) {
|
||||||
|
throw new IllegalStateException("Already initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream = store.openOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IllegalStateException("Not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] bytes) throws Exception {
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IllegalStateException("Not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStream.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import io.xpipe.ext.json.MyRawFileProvider;
|
||||||
|
import io.xpipe.extension.DataSourceProvider;
|
||||||
|
|
||||||
|
module io.xpipe.ext.file_data_source_sample {
|
||||||
|
exports io.xpipe.ext.json;
|
||||||
|
|
||||||
|
opens io.xpipe.ext.json;
|
||||||
|
|
||||||
|
requires io.xpipe.core;
|
||||||
|
requires io.xpipe.extension;
|
||||||
|
|
||||||
|
provides DataSourceProvider with MyRawFileProvider;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
displayName=Mein Dateiformat
|
||||||
|
description=Meine Dateiformat-Beschreibung
|
||||||
|
fileName=Mein Dateiformat Datei
|
|
@ -0,0 +1,3 @@
|
||||||
|
displayName=My file format
|
||||||
|
description=My file format description
|
||||||
|
fileName=My file format file
|
Loading…
Reference in a new issue