mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-21 15:10:23 +00:00
Cleanup, some documentation, and refactoring
This commit is contained in:
parent
f5cccd5687
commit
f7b37412b4
49 changed files with 234 additions and 270 deletions
|
@ -24,11 +24,6 @@ dependencies {
|
|||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
exceptionFormat = 'full'
|
||||
showStandardStreams = true
|
||||
}
|
||||
workingDir = rootDir
|
||||
|
||||
// Daemon properties
|
||||
|
@ -38,10 +33,11 @@ test {
|
|||
" -Dio.xpipe.app.dataDir=$projectDir/local/" +
|
||||
" -Dio.xpipe.storage.persist=false" +
|
||||
" -Dio.xpipe.app.writeSysOut=true" +
|
||||
" -Dio.xpipe.beacon.debugOutput=true" +
|
||||
// " -Dio.xpipe.beacon.debugOutput=true" +
|
||||
" -Dio.xpipe.app.logLevel=trace"
|
||||
|
||||
// API properties
|
||||
// systemProperty 'io.xpipe.beacon.debugOutput', "true"
|
||||
systemProperty 'io.xpipe.beacon.debugExecOutput', "true"
|
||||
systemProperty "io.xpipe.beacon.port", "21722"
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ publishing {
|
|||
from components.java
|
||||
|
||||
pom {
|
||||
name = 'X-Pipe API'
|
||||
description = 'Contains everything necessary to use and interact with X-Pipe.'
|
||||
name = 'X-Pipe Java API'
|
||||
description = 'Contains everything necessary to interact with X-Pipe from Java applications.'
|
||||
url = 'https://github.com/xpipe-io/xpipe_java/api'
|
||||
licenses {
|
||||
license {
|
||||
|
@ -25,10 +25,6 @@ publishing {
|
|||
developerConnection = 'scm:git:ssh://github.com/xpipe-io/xpipe_java.git'
|
||||
url = 'https://github.com/xpipe-io/xpipe_java'
|
||||
}
|
||||
|
||||
withXml {
|
||||
//asNode().appendNode('dependencies').appendNode('dependency').appendNode('my-property', 'my-value')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package io.xpipe.api;
|
|||
import io.xpipe.api.impl.DataTableAccumulatorImpl;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
import io.xpipe.core.data.node.TupleNode;
|
||||
import io.xpipe.core.data.type.TupleType;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
|
||||
|
@ -11,7 +10,7 @@ import io.xpipe.core.source.DataSourceId;
|
|||
* An accumulator for table data.
|
||||
*
|
||||
* This class can be used to construct new table data sources by
|
||||
* accumulating the rows using {@link #add(TupleNode)} or {@link #acceptor()} and then calling
|
||||
* accumulating the rows using {@link #add(DataStructureNode)} or {@link #acceptor()} and then calling
|
||||
* {@link #finish(DataSourceId)} to complete the construction process and create a new data source.
|
||||
*/
|
||||
public interface DataTableAccumulator {
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.xpipe.api.impl;
|
|||
|
||||
import io.xpipe.api.DataSource;
|
||||
import io.xpipe.api.connector.XPipeConnection;
|
||||
import io.xpipe.beacon.exchange.PreStoreExchange;
|
||||
import io.xpipe.beacon.exchange.StoreStreamExchange;
|
||||
import io.xpipe.beacon.exchange.QueryDataSourceExchange;
|
||||
import io.xpipe.beacon.exchange.ReadExecuteExchange;
|
||||
import io.xpipe.beacon.exchange.ReadPreparationExchange;
|
||||
|
@ -43,8 +43,8 @@ public abstract class DataSourceImpl implements DataSource {
|
|||
|
||||
public static DataSource create(DataSourceId id, String type, Map<String,String> config, InputStream in) {
|
||||
var res = XPipeConnection.execute(con -> {
|
||||
var req = PreStoreExchange.Request.builder().build();
|
||||
PreStoreExchange.Response r = con.performOutputExchange(req, out -> in.transferTo(out));
|
||||
var req = StoreStreamExchange.Request.builder().build();
|
||||
StoreStreamExchange.Response r = con.performOutputExchange(req, out -> in.transferTo(out));
|
||||
return r;
|
||||
});
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import io.xpipe.api.DataTable;
|
|||
import io.xpipe.api.DataTableAccumulator;
|
||||
import io.xpipe.api.connector.XPipeConnection;
|
||||
import io.xpipe.api.util.TypeDescriptor;
|
||||
import io.xpipe.beacon.exchange.PreStoreExchange;
|
||||
import io.xpipe.beacon.exchange.StoreStreamExchange;
|
||||
import io.xpipe.beacon.exchange.ReadExecuteExchange;
|
||||
import io.xpipe.core.data.node.DataStructureNode;
|
||||
import io.xpipe.core.data.node.DataStructureNodeAcceptor;
|
||||
|
@ -29,14 +29,14 @@ public class DataTableAccumulatorImpl implements DataTableAccumulator {
|
|||
public DataTableAccumulatorImpl(TupleType type) {
|
||||
this.type = type;
|
||||
connection = XPipeConnection.open();
|
||||
connection.sendRequest(PreStoreExchange.Request.builder().build());
|
||||
connection.sendRequest(StoreStreamExchange.Request.builder().build());
|
||||
connection.sendBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DataTable finish(DataSourceId id) {
|
||||
connection.withOutputStream(OutputStream::close);
|
||||
PreStoreExchange.Response res = connection.receiveResponse();
|
||||
StoreStreamExchange.Response res = connection.receiveResponse();
|
||||
connection.close();
|
||||
|
||||
var req = ReadExecuteExchange.Request.builder()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
module io.xpipe.api {
|
||||
exports io.xpipe.api;
|
||||
|
||||
requires transitive io.xpipe.core;
|
||||
requires io.xpipe.beacon;
|
||||
|
||||
exports io.xpipe.api;
|
||||
exports io.xpipe.api.connector;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
cd ..\app\
|
||||
SET "dir=%~dp0test_env"
|
||||
CALL ..\gradlew.bat run -Dio.xpipe.storage.dir=%dir% -Dio.xpipe.beacon.port=21722 -Dio.xpipe.daemon.mode=gui
|
||||
pause
|
36
beacon/README.md
Normal file
36
beacon/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
## X-Pipe Beacon
|
||||
|
||||
The X-Pipe beacon component is responsible for handling all communications between the X-Pipe daemon
|
||||
and the various programming language APIs and the CLI. It provides an API that supports all kinds
|
||||
of different operations.
|
||||
The underlying inter-process communication is realized through TCP sockets on port `21721`.
|
||||
|
||||
The data structures and exchange protocols are specified in the `io.xpipe.beacon.exchange` package.
|
||||
Every exchange is initiated from the outside by sending a request message to the daemon.
|
||||
The daemon then always sends a response message.
|
||||
|
||||
The header information of a message is formatted in the json format.
|
||||
As a result, all data structures exchanged must be serializable/deserializable with jackson.
|
||||
|
||||
Both the requests and responses can optionally include content in a body.
|
||||
A body is initiated with two new lines (`\n`).
|
||||
The body is split into segments of max length `65536`.
|
||||
Each segment is preceded by four bytes that specify the length of the next segment.
|
||||
In case the next segment has a length of less than `65536` bytes, we know that the end of the body has been reached.
|
||||
This way the socket communication can handle payloads of unknown length.
|
||||
|
||||
### Configuration
|
||||
|
||||
The default port used by the beacon implementation of the X-Pipe daemon and APIs is `21721`.
|
||||
It can be changed by passing the property `io.xpipe.beacon.port=<port>` to both the daemon and APIs.
|
||||
|
||||
The beacon API also supports launching the daemon automatically in case it is not started yet.
|
||||
By default, it launches the daemon of the local X-Pipe installation.
|
||||
It is possible to pass a custom launch command with the property `io.xpipe.beacon.exec=<cmd>`.
|
||||
This allows for a custom launch behaviour in a testing/development environment.
|
||||
|
||||
By passing the property `io.xpipe.beacon.debugOutput=true`, it is possible to print debug information
|
||||
about the underlying communications.
|
||||
In case the `io.xpipe.beacon.exec` property is set, the output of the custom exec command can also be
|
||||
printed by passing the property `io.xpipe.beacon.debugExecOutput=true`.
|
||||
|
|
@ -4,8 +4,8 @@ publishing {
|
|||
from components.java
|
||||
|
||||
pom {
|
||||
name = 'X-Pipe beacon'
|
||||
description = 'The socket-based implementation used for the communication with X-Pipe.'
|
||||
name = 'X-Pipe Beacon'
|
||||
description = 'The socket-based implementation used for the communication with the X-Pipe daemon.'
|
||||
url = 'https://github.com/xpipe-io/xpipe_java/beacon'
|
||||
licenses {
|
||||
license {
|
||||
|
|
|
@ -68,10 +68,6 @@ public class BeaconClient implements AutoCloseable {
|
|||
out = socket.getOutputStream();
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return socket.isClosed();
|
||||
}
|
||||
|
||||
public void close() throws ConnectorException {
|
||||
try {
|
||||
socket.close();
|
||||
|
@ -132,14 +128,14 @@ public class BeaconClient implements AutoCloseable {
|
|||
throw new ClientException("Unknown request class " + req.getClass());
|
||||
}
|
||||
|
||||
json.set("type", new TextNode(prov.get().getId()));
|
||||
json.set("phase", new TextNode("request"));
|
||||
json.set("messageType", new TextNode(prov.get().getId()));
|
||||
json.set("messagePhase", new TextNode("request"));
|
||||
//json.set("id", new TextNode(UUID.randomUUID().toString()));
|
||||
var msg = JsonNodeFactory.instance.objectNode();
|
||||
msg.set("xPipeMessage", json);
|
||||
|
||||
if (BeaconConfig.debugEnabled()) {
|
||||
System.out.println("Sending request to server of type " + req.getClass().getSimpleName());
|
||||
System.out.println("Sending request to server of type " + req.getClass().getName());
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -163,7 +159,7 @@ public class BeaconClient implements AutoCloseable {
|
|||
}
|
||||
|
||||
if (BeaconConfig.debugEnabled()) {
|
||||
System.out.println("Recieved response:");
|
||||
System.out.println("Received response:");
|
||||
System.out.println(read.toPrettyString());
|
||||
}
|
||||
|
||||
|
@ -211,14 +207,14 @@ public class BeaconClient implements AutoCloseable {
|
|||
private <T extends ResponseMessage> T parseResponse(JsonNode header) throws ConnectorException {
|
||||
ObjectNode content = (ObjectNode) header.required("xPipeMessage");
|
||||
|
||||
var type = content.required("type").textValue();
|
||||
var phase = content.required("phase").textValue();
|
||||
var type = content.required("messageType").textValue();
|
||||
var phase = content.required("messagePhase").textValue();
|
||||
//var requestId = UUID.fromString(content.required("id").textValue());
|
||||
if (!phase.equals("response")) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
content.remove("type");
|
||||
content.remove("phase");
|
||||
content.remove("messageType");
|
||||
content.remove("messagePhase");
|
||||
//content.remove("id");
|
||||
|
||||
var prov = MessageExchanges.byId(type);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@UtilityClass
|
||||
public class BeaconConfig {
|
||||
|
||||
public static final byte[] BODY_SEPARATOR = "\n\n".getBytes(StandardCharsets.UTF_8);
|
||||
|
@ -15,6 +18,16 @@ public class BeaconConfig {
|
|||
}
|
||||
|
||||
|
||||
private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.debugExecOutput";
|
||||
|
||||
public static boolean execDebugEnabled() {
|
||||
if (System.getProperty(EXEC_DEBUG_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(EXEC_DEBUG_PROP));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||
public static final int DEFAULT_PORT = 21721;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
/**
|
||||
* An unchecked exception that will be thrown in any case of an underlying exception.
|
||||
*/
|
||||
public class BeaconException extends RuntimeException {
|
||||
|
||||
public BeaconException() {
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@UtilityClass
|
||||
public class BeaconFormat {
|
||||
|
||||
private static final int SEGMENT_SIZE = 65536;
|
||||
|
||||
public static OutputStream writeBlocks(Socket socket) throws IOException {
|
||||
int size = 65536 - 4;
|
||||
var out = socket.getOutputStream();
|
||||
return new OutputStream() {
|
||||
private final byte[] currentBytes = new byte[size];
|
||||
private final byte[] currentBytes = new byte[SEGMENT_SIZE];
|
||||
private int index;
|
||||
|
||||
@Override
|
||||
|
@ -43,21 +47,9 @@ public class BeaconFormat {
|
|||
index = 0;
|
||||
}
|
||||
};
|
||||
// while (true) {
|
||||
// var bytes = in.readNBytes(size);
|
||||
// int length = bytes.length;
|
||||
// var lengthBuffer = ByteBuffer.allocate(4).putInt(length);
|
||||
// socket.getOutputStream().write(lengthBuffer.array());
|
||||
// socket.getOutputStream().write(bytes);
|
||||
//
|
||||
// if (length == 0) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public static InputStream readBlocks(Socket socket) throws IOException {
|
||||
int size = 65536 - 4;
|
||||
var in = socket.getInputStream();
|
||||
return new InputStream() {
|
||||
|
||||
|
@ -90,7 +82,7 @@ public class BeaconFormat {
|
|||
|
||||
currentBytes = in.readNBytes(lengthInt);
|
||||
index = 0;
|
||||
if (lengthInt < size) {
|
||||
if (lengthInt < SEGMENT_SIZE) {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,29 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* An exchange handler responsible for properly handling a request and sending a response.
|
||||
*/
|
||||
public interface BeaconHandler {
|
||||
|
||||
/**
|
||||
* Execute a Runnable after the initial response has been sent.
|
||||
*
|
||||
* @param r the runnable to execute
|
||||
*/
|
||||
void postResponse(BeaconClient.FailableRunnable<Exception> r);
|
||||
|
||||
/**
|
||||
* Prepares to attach a body to a response.
|
||||
*
|
||||
* @return the output stream that can be used to write the body payload
|
||||
*/
|
||||
OutputStream sendBody() throws IOException;
|
||||
|
||||
/**
|
||||
* Prepares to read an attached body of a request.
|
||||
*
|
||||
* @return the input stream that can be used to read the body payload
|
||||
*/
|
||||
InputStream receiveBody() throws IOException;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
import io.xpipe.beacon.exchange.StopExchange;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
@ -11,10 +12,14 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Contains basic functionality to start, communicate, and stop a beacon server.
|
||||
*/
|
||||
@UtilityClass
|
||||
public class BeaconServer {
|
||||
|
||||
private static boolean isPortAvailable(int port) {
|
||||
try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) {
|
||||
try (var ignored = new ServerSocket(port); var ignored1 = new DatagramSocket(port)) {
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
|
@ -27,15 +32,18 @@ public class BeaconServer {
|
|||
}
|
||||
|
||||
private static void startFork(String custom) throws IOException {
|
||||
boolean print = true;
|
||||
boolean print = BeaconConfig.execDebugEnabled();
|
||||
var proc = Runtime.getRuntime().exec(custom);
|
||||
new Thread(null, () -> {
|
||||
try {
|
||||
InputStreamReader isr = new InputStreamReader(proc.getInputStream());
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = null;
|
||||
while ((line = br.readLine()) != null)
|
||||
System.out.println("[xpiped] " + line);
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (print) {
|
||||
System.out.println("[xpiped] " + line);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
@ -70,7 +78,7 @@ public class BeaconServer {
|
|||
|
||||
private static Optional<Path> getPortableLauncherExecutable() {
|
||||
var env = System.getenv("XPIPE_HOME");
|
||||
Path file = null;
|
||||
Path file;
|
||||
|
||||
// Prepare for invalid XPIPE_HOME path value
|
||||
try {
|
||||
|
@ -92,7 +100,7 @@ public class BeaconServer {
|
|||
}
|
||||
|
||||
try {
|
||||
Path file = null;
|
||||
Path file;
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
file = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe", "xpipe_launcher.exe");
|
||||
} else {
|
||||
|
@ -106,7 +114,7 @@ public class BeaconServer {
|
|||
|
||||
public static Optional<Path> getDaemonExecutable() {
|
||||
try {
|
||||
Path file = null;
|
||||
Path file;
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
file = Path.of(System.getenv("LOCALAPPDATA"), "X-Pipe", "app", "xpipe.exe");
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
/**
|
||||
* Indicates that a client request caused an issue.
|
||||
*/
|
||||
public class ClientException extends Exception {
|
||||
|
||||
public ClientException() {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
/**
|
||||
* Indicates that a connection error occurred.
|
||||
*/
|
||||
public class ConnectorException extends Exception {
|
||||
|
||||
public ConnectorException() {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package io.xpipe.beacon;
|
||||
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
/**
|
||||
* Indicates that an internal server error occurred.
|
||||
*/
|
||||
@StandardException
|
||||
public class ServerException extends Exception {
|
||||
|
||||
public ServerException() {
|
||||
|
|
|
@ -9,6 +9,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Performs an edit for a data source.
|
||||
*/
|
||||
public class EditExecuteExchange implements MessageExchange<EditExecuteExchange.Request, EditExecuteExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,6 +9,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Requests to edit a data source.
|
||||
*/
|
||||
public class EditPreparationExchange implements MessageExchange<EditPreparationExchange.Request, EditPreparationExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,12 +2,30 @@ package io.xpipe.beacon.exchange;
|
|||
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* A message exchange scheme that implements a certain functionality.
|
||||
*/
|
||||
public interface MessageExchange<RQ extends RequestMessage, RP extends ResponseMessage> {
|
||||
|
||||
/**
|
||||
* The unique id of this exchange that will be included in the messages.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
Class<RQ> getRequestClass();
|
||||
/**
|
||||
* Returns the request class, needed for serialization.
|
||||
*/
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
default Class<RQ> getRequestClass() {
|
||||
var name = getClass().getName() + "$Request";
|
||||
return (Class<RQ>) Class.forName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response class, needed for serialization.
|
||||
*/
|
||||
Class<RP> getResponseClass();
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
||||
import io.xpipe.core.store.StreamDataStore;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
public class PreStoreExchange implements MessageExchange<PreStoreExchange.Request, PreStoreExchange.Response> {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "preStore";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PreStoreExchange.Request> getRequestClass() {
|
||||
return PreStoreExchange.Request.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<PreStoreExchange.Response> getResponseClass() {
|
||||
return PreStoreExchange.Response.class;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
StreamDataStore store;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Queries general information about a data source.
|
||||
*/
|
||||
public class QueryDataSourceExchange implements MessageExchange<QueryDataSourceExchange.Request, QueryDataSourceExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Sends stream-based data to a daemon.
|
||||
*/
|
||||
public class ReadExecuteExchange implements MessageExchange<ReadExecuteExchange.Request, ReadExecuteExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,6 +9,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Prepares a client to send stream-based data to a daemon.
|
||||
*/
|
||||
public class ReadPreparationExchange implements MessageExchange<ReadPreparationExchange.Request, ReadPreparationExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,9 @@ import lombok.Builder;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Requests the daemon to stop.
|
||||
*/
|
||||
public class StopExchange implements MessageExchange<StopExchange.Request, StopExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
||||
import io.xpipe.core.source.DataSourceConfigOptions;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
public class StoreEditExchange implements MessageExchange<StoreEditExchange.Request, StoreEditExchange.Response> {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "storeEdit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<StoreEditExchange.Request> getRequestClass() {
|
||||
return StoreEditExchange.Request.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<StoreEditExchange.Response> getResponseClass() {
|
||||
return StoreEditExchange.Response.class;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
DataSourceId sourceId;
|
||||
DataSourceConfigOptions config;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
}
|
||||
}
|
|
@ -2,13 +2,14 @@ package io.xpipe.beacon.exchange;
|
|||
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
||||
import io.xpipe.core.source.DataSourceId;
|
||||
import io.xpipe.core.source.DataSourceType;
|
||||
import io.xpipe.core.source.DataSourceConfigOptions;
|
||||
import io.xpipe.core.store.StreamDataStore;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Stores a stream of data in a storage.
|
||||
*/
|
||||
public class StoreStreamExchange implements MessageExchange<StoreStreamExchange.Request, StoreStreamExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
@ -30,16 +31,12 @@ public class StoreStreamExchange implements MessageExchange<StoreStreamExchange.
|
|||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
String type;
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
DataSourceId sourceId;
|
||||
DataSourceType sourceType;
|
||||
DataSourceConfigOptions config;
|
||||
Object data;
|
||||
StreamDataStore store;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Queries data of a table data source in the xpbt format.
|
||||
*/
|
||||
public class QueryTableDataExchange implements MessageExchange<QueryTableDataExchange.Request, QueryTableDataExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.CollectionListEntry;
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
package io.xpipe.beacon.exchange.cli;
|
||||
|
||||
import io.xpipe.beacon.exchange.MessageExchange;
|
||||
import io.xpipe.beacon.exchange.data.EntryListEntry;
|
||||
import io.xpipe.beacon.message.RequestMessage;
|
||||
import io.xpipe.beacon.message.ResponseMessage;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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 lombok.Builder;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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.DataSourceReference;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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 lombok.Builder;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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 lombok.Builder;
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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;
|
||||
|
@ -10,6 +11,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Output the data source contents.
|
||||
*/
|
||||
public class WriteExecuteExchange implements MessageExchange<WriteExecuteExchange.Request, WriteExecuteExchange.Response> {
|
||||
|
||||
@Override
|
|
@ -1,5 +1,6 @@
|
|||
package io.xpipe.beacon.exchange;
|
||||
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;
|
||||
|
@ -10,6 +11,9 @@ import lombok.NonNull;
|
|||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
/**
|
||||
* Prepares a client to output the data source contents.
|
||||
*/
|
||||
public class WritePreparationExchange implements MessageExchange<WritePreparationExchange.Request, WritePreparationExchange.Response> {
|
||||
|
||||
@Override
|
||||
|
@ -31,7 +35,7 @@ public class WritePreparationExchange implements MessageExchange<WritePreparatio
|
|||
@Builder
|
||||
@Value
|
||||
public static class Request implements RequestMessage {
|
||||
String providerType;
|
||||
String type;
|
||||
String output;
|
||||
@NonNull
|
||||
DataSourceReference ref;
|
||||
|
@ -41,7 +45,7 @@ public class WritePreparationExchange implements MessageExchange<WritePreparatio
|
|||
@Builder
|
||||
@Value
|
||||
public static class Response implements ResponseMessage {
|
||||
DataStore dataStore;
|
||||
DataStore store;
|
||||
|
||||
@NonNull
|
||||
DataSourceConfigInstance config;
|
|
@ -1,5 +1,6 @@
|
|||
import io.xpipe.beacon.exchange.*;
|
||||
import io.xpipe.beacon.exchange.api.QueryTableDataExchange;
|
||||
import io.xpipe.beacon.exchange.api.*;
|
||||
import io.xpipe.beacon.exchange.cli.*;
|
||||
|
||||
module io.xpipe.beacon {
|
||||
exports io.xpipe.beacon;
|
||||
|
@ -7,12 +8,14 @@ module io.xpipe.beacon {
|
|||
exports io.xpipe.beacon.message;
|
||||
exports io.xpipe.beacon.exchange.api;
|
||||
exports io.xpipe.beacon.exchange.data;
|
||||
exports io.xpipe.beacon.exchange.cli;
|
||||
|
||||
opens io.xpipe.beacon;
|
||||
opens io.xpipe.beacon.exchange;
|
||||
opens io.xpipe.beacon.exchange.api;
|
||||
opens io.xpipe.beacon.message;
|
||||
opens io.xpipe.beacon.exchange.data;
|
||||
opens io.xpipe.beacon.exchange.cli;
|
||||
|
||||
requires com.fasterxml.jackson.core;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
|
@ -33,7 +36,7 @@ module io.xpipe.beacon {
|
|||
ReadExecuteExchange,
|
||||
DialogExchange,
|
||||
QueryDataSourceExchange,
|
||||
PreStoreExchange,
|
||||
StoreStreamExchange,
|
||||
EditPreparationExchange,
|
||||
EditExecuteExchange,
|
||||
QueryTableDataExchange,
|
||||
|
|
|
@ -4,8 +4,8 @@ publishing {
|
|||
from components.java
|
||||
|
||||
pom {
|
||||
name = 'X-Pipe core'
|
||||
description = 'Core classes ued by all X-Pipe components.'
|
||||
name = 'X-Pipe Core'
|
||||
description = 'Core classes used by all X-Pipe components.'
|
||||
url = 'https://github.com/xpipe-io/xpipe_java/core'
|
||||
licenses {
|
||||
license {
|
||||
|
|
|
@ -11,12 +11,12 @@ public abstract class TupleNode extends DataStructureNode {
|
|||
return new Builder();
|
||||
}
|
||||
|
||||
public static TupleNode of(List<? extends DataStructureNode> nodes) {
|
||||
public static TupleNode of(List<DataStructureNode> nodes) {
|
||||
if (nodes == null) {
|
||||
throw new IllegalArgumentException("Nodes must be not null");
|
||||
}
|
||||
|
||||
return new NoKeyTupleNode(true, (List<DataStructureNode>) nodes);
|
||||
return new NoKeyTupleNode(true, nodes);
|
||||
}
|
||||
|
||||
public static TupleNode of(List<String> names, List<DataStructureNode> nodes) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
|
@ -19,27 +18,7 @@ public class OutputStreamStore implements StreamDataStore {
|
|||
|
||||
@Override
|
||||
public OutputStream openOutput() throws Exception {
|
||||
return new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
out.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
out.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
|
@ -103,6 +105,9 @@ public class CoreJacksonModule extends SimpleModule {
|
|||
|
||||
@JsonSerialize(as = Throwable.class)
|
||||
public abstract static class ThrowableTypeMixIn {
|
||||
|
||||
@JsonIdentityInfo(generator= ObjectIdGenerators.StringIdGenerator.class, property="$id")
|
||||
private Throwable cause;
|
||||
}
|
||||
|
||||
@JsonSerialize(as = DataSourceReference.class)
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
import io.xpipe.core.util.CoreJacksonModule;
|
||||
|
||||
module io.xpipe.core {
|
||||
requires com.fasterxml.jackson.core;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
|
||||
requires static lombok;
|
||||
|
||||
exports io.xpipe.core.store;
|
||||
exports io.xpipe.core.source;
|
||||
exports io.xpipe.core.data.generic;
|
||||
exports io.xpipe.core.data.type;
|
||||
exports io.xpipe.core.util;
|
||||
exports io.xpipe.core.data.node;
|
||||
exports io.xpipe.core.data.typed;
|
||||
|
||||
opens io.xpipe.core.store;
|
||||
opens io.xpipe.core.source;
|
||||
opens io.xpipe.core.data.type;
|
||||
opens io.xpipe.core.data.generic;
|
||||
exports io.xpipe.core.util;
|
||||
opens io.xpipe.core.util;
|
||||
exports io.xpipe.core.data.node;
|
||||
opens io.xpipe.core.data.node;
|
||||
exports io.xpipe.core.data.typed;
|
||||
opens io.xpipe.core.data.typed;
|
||||
|
||||
requires com.fasterxml.jackson.core;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires static lombok;
|
||||
|
||||
uses com.fasterxml.jackson.databind.Module;
|
||||
provides com.fasterxml.jackson.databind.Module with CoreJacksonModule;
|
||||
}
|
|
@ -27,5 +27,4 @@ repositories {
|
|||
dependencies {
|
||||
implementation project(':core')
|
||||
implementation project(':fxcomps')
|
||||
implementation group: 'com.dlsc.preferencesfx', name: 'preferencesfx-core', version: '11.8.0'
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ publishing {
|
|||
from components.java
|
||||
|
||||
pom {
|
||||
name = 'X-Pipe extension base'
|
||||
name = 'X-Pipe Extension Base'
|
||||
description = 'Classes required to create X-Pipe extensions.'
|
||||
url = 'https://github.com/xpipe-io/xpipe_java/extension'
|
||||
licenses {
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package io.xpipe.extension.prefs;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class PrefsChoiceValueModule extends SimpleModule {
|
||||
|
||||
@Override
|
||||
public void setupModule(SetupContext context) {
|
||||
addSerializer(PrefsChoiceValue.class, new PrefsChoiceValueSerializer());
|
||||
addDeserializer(PrefsChoiceValue.class, new PrefsChoiceValueDeserializer());
|
||||
|
||||
context.addSerializers(_serializers);
|
||||
context.addDeserializers(_deserializers);
|
||||
}
|
||||
|
||||
public static class PrefsChoiceValueSerializer extends JsonSerializer<PrefsChoiceValue> {
|
||||
|
||||
@Override
|
||||
public void serialize(PrefsChoiceValue value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
jgen.writeString(value.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PrefsChoiceValueDeserializer extends JsonDeserializer<PrefsChoiceValue> {
|
||||
|
||||
@Override
|
||||
public PrefsChoiceValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
var id = p.getValueAsString();
|
||||
Class<? extends PrefsChoiceValue> clazz = (Class<? extends PrefsChoiceValue>) ctxt.getContextualType().getRawClass();
|
||||
try {
|
||||
var list = (List<? extends PrefsChoiceValue>) clazz.getDeclaredField("SUPPORTED").get(null);
|
||||
return list.stream().filter(v -> v.getId().equals(id)).findAny().orElse(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
import com.fasterxml.jackson.databind.Module;
|
||||
import io.xpipe.extension.DataSourceProvider;
|
||||
import io.xpipe.extension.SupportedApplicationProvider;
|
||||
import io.xpipe.extension.prefs.PrefsChoiceValueModule;
|
||||
|
||||
module io.xpipe.extension {
|
||||
exports io.xpipe.extension;
|
||||
exports io.xpipe.extension.comp;
|
||||
exports io.xpipe.extension.event;
|
||||
exports io.xpipe.extension.prefs;
|
||||
|
||||
requires io.xpipe.core;
|
||||
requires javafx.base;
|
||||
requires javafx.graphics;
|
||||
|
@ -11,20 +14,6 @@ module io.xpipe.extension {
|
|||
requires io.xpipe.fxcomps;
|
||||
requires org.apache.commons.collections4;
|
||||
requires static lombok;
|
||||
|
||||
exports io.xpipe.extension;
|
||||
exports io.xpipe.extension.comp;
|
||||
exports io.xpipe.extension.event;
|
||||
exports io.xpipe.extension.prefs;
|
||||
|
||||
uses DataSourceProvider;
|
||||
uses SupportedApplicationProvider;
|
||||
uses io.xpipe.extension.I18n;
|
||||
uses io.xpipe.extension.event.EventHandler;
|
||||
uses io.xpipe.extension.prefs.PrefsProvider;
|
||||
|
||||
provides Module with PrefsChoiceValueModule;
|
||||
|
||||
requires com.dlsc.preferencesfx;
|
||||
requires com.dlsc.formsfx;
|
||||
requires java.desktop;
|
||||
|
@ -35,4 +24,10 @@ module io.xpipe.extension {
|
|||
requires org.reactfx;
|
||||
requires org.kordamp.ikonli.javafx;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
|
||||
uses DataSourceProvider;
|
||||
uses SupportedApplicationProvider;
|
||||
uses io.xpipe.extension.I18n;
|
||||
uses io.xpipe.extension.event.EventHandler;
|
||||
uses io.xpipe.extension.prefs.PrefsProvider;
|
||||
}
|
2
version
2
version
|
@ -1 +1 @@
|
|||
0.1
|
||||
0.1-SNAPSHOT
|
Loading…
Reference in a new issue