Added working serialization and starter javafx framework.
This commit is contained in:
parent
00c343e673
commit
7bd89c0e50
|
@ -1,7 +1,60 @@
|
||||||
package nl.andrewlalis.crystalkeep;
|
package nl.andrewlalis.crystalkeep;
|
||||||
|
|
||||||
public class CrystalKeep {
|
import javafx.application.Application;
|
||||||
public static void main(String[] args) {
|
import javafx.fxml.FXMLLoader;
|
||||||
System.out.println("Hello world!");
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.serialization.ClusterSerializer;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class CrystalKeep extends Application {
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage stage) throws Exception {
|
||||||
|
URL url = CrystalKeep.class.getClassLoader().getResource("ui/crystalkeep.fxml");
|
||||||
|
FXMLLoader loader = new FXMLLoader(url);
|
||||||
|
var scene = new Scene(loader.load());
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.setTitle("CrystalKeep");
|
||||||
|
stage.sizeToScene();
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test() throws IOException {
|
||||||
|
Cluster c = new Cluster("Test");
|
||||||
|
Shard s = new TextShard(c, "sample", LocalDateTime.now(), "Hello world!");
|
||||||
|
Shard s2 = new LoginCredentialsShard(c, "logs", LocalDateTime.now().plusHours(3), "andrew", "testing");
|
||||||
|
c.addShard(s);
|
||||||
|
c.addShard(s2);
|
||||||
|
Cluster c2 = new Cluster("Test2");
|
||||||
|
Shard s3 = new TextShard(c2, "another sample", LocalDateTime.now().plusMinutes(3), "Testing this stuff....");
|
||||||
|
c2.addShard(s3);
|
||||||
|
Cluster parent = new Cluster("Parent");
|
||||||
|
parent.addCluster(c);
|
||||||
|
parent.addCluster(c2);
|
||||||
|
|
||||||
|
System.out.println(parent);
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
byte[] cBytes = ClusterSerializer.toBytes(parent);
|
||||||
|
long dur = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("Duration: " + dur + " milliseconds");
|
||||||
|
System.out.println(Arrays.toString(cBytes));
|
||||||
|
|
||||||
|
Cluster cLoaded = ClusterSerializer.clusterFromBytes(new ByteArrayInputStream(cBytes), null);
|
||||||
|
System.out.println(cLoaded);
|
||||||
|
System.out.println(Arrays.toString(ClusterSerializer.toBytes(cLoaded)));
|
||||||
|
System.out.println(Arrays.equals(cBytes, ClusterSerializer.toBytes(cLoaded)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,71 @@
|
||||||
package nl.andrewlalis.crystalkeep.model;
|
package nl.andrewlalis.crystalkeep.model;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Cluster {
|
public class Cluster implements Comparable<Cluster> {
|
||||||
|
@Setter
|
||||||
|
private String name;
|
||||||
private final Set<Shard> shards;
|
private final Set<Shard> shards;
|
||||||
private final Set<Cluster> clusters;
|
private final Set<Cluster> clusters;
|
||||||
private final Cluster parent;
|
@Setter
|
||||||
|
private Cluster parent;
|
||||||
|
|
||||||
public Cluster(Set<Shard> shards, Set<Cluster> clusters, Cluster parent) {
|
public Cluster(String name, Set<Shard> shards, Set<Cluster> clusters, Cluster parent) {
|
||||||
|
this.name = name;
|
||||||
this.shards = shards;
|
this.shards = shards;
|
||||||
this.clusters = clusters;
|
this.clusters = clusters;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
if (this.parent != null) {
|
|
||||||
this.parent.addCluster(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cluster() {
|
public Cluster(String name) {
|
||||||
this(new HashSet<>(), new HashSet<>(), null);
|
this(name, new HashSet<>(), new HashSet<>(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addShard(Shard shard) {
|
public void addShard(Shard shard) {
|
||||||
if (!this.equals(shard.getCluster())) {
|
|
||||||
throw new IllegalArgumentException("Shard must have correct cluster set before adding it to shard.");
|
|
||||||
}
|
|
||||||
this.shards.add(shard);
|
this.shards.add(shard);
|
||||||
|
shard.setCluster(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCluster(Cluster cluster) {
|
public void addCluster(Cluster cluster) {
|
||||||
if (!this.equals(cluster.getParent())) {
|
|
||||||
throw new IllegalArgumentException("Cluster must have correct parent set before adding it to cluster.");
|
|
||||||
}
|
|
||||||
this.clusters.add(cluster);
|
this.clusters.add(cluster);
|
||||||
|
cluster.setParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Cluster o) {
|
||||||
|
return this.getName().compareTo(o.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Cluster cluster = (Cluster) o;
|
||||||
|
return getName().equals(cluster.getName()) && Objects.equals(getParent(), cluster.getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(getName(), getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Cluster: name=\"").append(this.getName()).append("\"\nShards:\n");
|
||||||
|
for (Shard s : this.getShards()) {
|
||||||
|
sb.append('\t').append(s.toString()).append('\n');
|
||||||
|
}
|
||||||
|
sb.append("Nested clusters:\n");
|
||||||
|
for (Cluster c : this.getClusters()) {
|
||||||
|
sb.append('\n').append(c.toString()).append('\n');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
package nl.andrewlalis.crystalkeep.model;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
public class ClusterSerializer {
|
|
||||||
public byte[] toBytes(Cluster cluster) throws IOException {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
bos.write(this.toBytes(cluster.getClusters().size()));
|
|
||||||
for (Cluster child : cluster.getClusters()) {
|
|
||||||
bos.write(this.toBytes(child));
|
|
||||||
}
|
|
||||||
bos.write(this.toBytes(cluster.getShards().size()));
|
|
||||||
for (Shard shard : cluster.getShards()) {
|
|
||||||
bos.write(shard.toBytes());
|
|
||||||
}
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cluster fromBytes(ByteArrayInputStream bis, Cluster parent) throws IOException {
|
|
||||||
Cluster cluster = new Cluster(new HashSet<>(), new HashSet<>(), parent);
|
|
||||||
int childCount = this.toInt(bis.readNBytes(4));
|
|
||||||
for (int i = 0; i < childCount; i++) {
|
|
||||||
cluster.addCluster(this.fromBytes(bis, cluster));
|
|
||||||
}
|
|
||||||
int shardCount = this.toInt(bis.readNBytes(4));
|
|
||||||
for (int i = 0; i < shardCount; i++) {
|
|
||||||
cluster.addShard(Shard.fromBytes(bis));
|
|
||||||
}
|
|
||||||
return cluster;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toBytes(int x) {
|
|
||||||
return ByteBuffer.allocate(4).putInt(x).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int toInt(byte[] bytes) {
|
|
||||||
assert(bytes.length == 4);
|
|
||||||
return ByteBuffer.wrap(bytes).getInt();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,22 +2,35 @@ package nl.andrewlalis.crystalkeep.model;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.ShardType;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shard is a single "piece" of information, such as a snippet of text, login
|
||||||
|
* credentials, an image, or a private key. All shards within a cluster should
|
||||||
|
* have unique names.
|
||||||
|
* <p>
|
||||||
|
* Due to the need to deserialize shards from byte arrays, it is required
|
||||||
|
* that this parent class holds a type discriminator value, which is used to
|
||||||
|
* decide which shard type to deserialize.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public abstract class Shard implements Comparable<Shard> {
|
public abstract class Shard implements Comparable<Shard> {
|
||||||
private final Cluster cluster;
|
@Setter
|
||||||
|
private Cluster cluster;
|
||||||
@Setter
|
@Setter
|
||||||
private String name;
|
private String name;
|
||||||
private final LocalDateTime createdAt;
|
private final LocalDateTime createdAt;
|
||||||
|
private final ShardType type;
|
||||||
|
|
||||||
public Shard(Cluster cluster, String name, LocalDateTime createdAt) {
|
public Shard(Cluster cluster, String name, LocalDateTime createdAt, ShardType type) {
|
||||||
this.cluster = cluster;
|
this.cluster = cluster;
|
||||||
this.cluster.addShard(this);
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,11 +40,21 @@ public abstract class Shard implements Comparable<Shard> {
|
||||||
return this.getCreatedAt().compareTo(o.getCreatedAt());
|
return this.getCreatedAt().compareTo(o.getCreatedAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toBytes() {
|
@Override
|
||||||
return new byte[0];
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Shard shard = (Shard) o;
|
||||||
|
return getCluster().equals(shard.getCluster()) && getName().equals(shard.getName()) && getType() == shard.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Shard fromBytes(ByteArrayInputStream bis) {
|
@Override
|
||||||
return null;
|
public int hashCode() {
|
||||||
|
return Objects.hash(getCluster(), getName(), getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Shard: name=\"" + this.name + "\", type=" + this.type + ", createdAt=" + this.createdAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.model.serialization;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class ByteUtils {
|
||||||
|
public static byte[] toBytes(int x) {
|
||||||
|
return ByteBuffer.allocate(4).putInt(x).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toInt(byte[] bytes) {
|
||||||
|
assert(bytes.length == 4);
|
||||||
|
return ByteBuffer.wrap(bytes).getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeLengthPrefixed(byte[] bytes, OutputStream os) throws IOException {
|
||||||
|
os.write(toBytes(bytes.length));
|
||||||
|
os.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeLengthPrefixed(String s, OutputStream os) throws IOException {
|
||||||
|
writeLengthPrefixed(s.getBytes(StandardCharsets.UTF_8), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] writeLengthPrefixedStrings(String[] strings) throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
for (String s : strings) {
|
||||||
|
writeLengthPrefixed(s, bos);
|
||||||
|
}
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readLengthPrefixed(InputStream is) throws IOException {
|
||||||
|
int count = toInt(is.readNBytes(4));
|
||||||
|
return is.readNBytes(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readLengthPrefixedString(InputStream is) throws IOException {
|
||||||
|
return new String(readLengthPrefixed(is), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.model.serialization;
|
||||||
|
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.ShardType;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static nl.andrewlalis.crystalkeep.model.serialization.ByteUtils.toInt;
|
||||||
|
|
||||||
|
public class ClusterSerializer {
|
||||||
|
private static final Map<ShardType, ShardSerializer<?>> serializers = new HashMap<>();
|
||||||
|
static {
|
||||||
|
serializers.put(ShardType.TEXT, new TextShard.Serializer());
|
||||||
|
serializers.put(ShardType.LOGIN_CREDENTIALS, new LoginCredentialsShard.Serializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a cluster to a byte array, including all shards and nested
|
||||||
|
* clusters.
|
||||||
|
* @param cluster The cluster to serialize.
|
||||||
|
* @return The byte array representing the cluster.
|
||||||
|
* @throws IOException If an error occurs while writing the cluster.
|
||||||
|
*/
|
||||||
|
public static byte[] toBytes(Cluster cluster) throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ByteUtils.writeLengthPrefixed(cluster.getName(), bos);
|
||||||
|
|
||||||
|
bos.write(ByteUtils.toBytes(cluster.getClusters().size()));
|
||||||
|
Cluster[] children = new Cluster[cluster.getClusters().size()];
|
||||||
|
cluster.getClusters().toArray(children);
|
||||||
|
Arrays.sort(children);
|
||||||
|
for (Cluster child : children) {
|
||||||
|
bos.write(toBytes(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
bos.write(ByteUtils.toBytes(cluster.getShards().size()));
|
||||||
|
Shard[] shards = new Shard[cluster.getShards().size()];
|
||||||
|
cluster.getShards().toArray(shards);
|
||||||
|
Arrays.sort(shards);
|
||||||
|
for (Shard shard : shards) {
|
||||||
|
bos.write(toBytes(shard));
|
||||||
|
}
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a cluster from an input stream.
|
||||||
|
* @param is The input stream to read from.
|
||||||
|
* @param parent The parent cluster of this cluster. This may be null.
|
||||||
|
* @return The cluster that was read.
|
||||||
|
* @throws IOException If data could not be read from the stream.
|
||||||
|
*/
|
||||||
|
public static Cluster clusterFromBytes(InputStream is, Cluster parent) throws IOException {
|
||||||
|
String name = ByteUtils.readLengthPrefixedString(is);
|
||||||
|
Cluster cluster = new Cluster(name, new HashSet<>(), new HashSet<>(), parent);
|
||||||
|
int childCount = toInt(is.readNBytes(4));
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
cluster.addCluster(clusterFromBytes(is, cluster));
|
||||||
|
}
|
||||||
|
int shardCount = toInt(is.readNBytes(4));
|
||||||
|
for (int i = 0; i < shardCount; i++) {
|
||||||
|
cluster.addShard(shardFromBytes(is, cluster));
|
||||||
|
}
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes a shard to a byte array. It does this by first writing the
|
||||||
|
* standard shard information, then using a specific {@link ShardSerializer}
|
||||||
|
* to get the bytes that represent the body of the shard.
|
||||||
|
* @param shard The shard to serialize.
|
||||||
|
* @return A byte array representing the shard.
|
||||||
|
* @throws IOException If byte array stream could not be written to.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public static byte[] toBytes(Shard shard) throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ByteUtils.writeLengthPrefixed(shard.getName().getBytes(StandardCharsets.UTF_8), bos);
|
||||||
|
ByteUtils.writeLengthPrefixed(shard.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).getBytes(StandardCharsets.UTF_8), bos);
|
||||||
|
bos.write(ByteUtils.toBytes(shard.getType().getValue()));
|
||||||
|
ShardSerializer serializer = serializers.get(shard.getType());
|
||||||
|
bos.write(serializer.serialize(shard));
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes a shard from a byte array that's being read by the given
|
||||||
|
* input stream.
|
||||||
|
* @param is The input stream to read from.
|
||||||
|
* @param cluster The cluster that the shard should belong to.
|
||||||
|
* @return The shard that was deserialized.
|
||||||
|
* @throws IOException If an error occurs while reading bytes.
|
||||||
|
*/
|
||||||
|
public static Shard shardFromBytes(InputStream is, Cluster cluster) throws IOException {
|
||||||
|
String name = ByteUtils.readLengthPrefixedString(is);
|
||||||
|
LocalDateTime createdAt = LocalDateTime.parse(ByteUtils.readLengthPrefixedString(is), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||||
|
ShardType type = ShardType.valueOf(ByteUtils.toInt(is.readNBytes(4)));
|
||||||
|
ShardSerializer<?> serializer = serializers.get(type);
|
||||||
|
if (serializer == null) {
|
||||||
|
throw new IOException("Unsupported shard type.");
|
||||||
|
}
|
||||||
|
return serializer.deserialize(is, cluster, name, createdAt);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.model.serialization;
|
||||||
|
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public interface ShardSerializer<T extends Shard> {
|
||||||
|
byte[] serialize(T shard) throws IOException;
|
||||||
|
|
||||||
|
T deserialize(InputStream bis, Cluster cluster, String name, LocalDateTime createdAt) throws IOException;
|
||||||
|
}
|
|
@ -4,7 +4,11 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -14,8 +18,28 @@ public class LoginCredentialsShard extends Shard {
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
public LoginCredentialsShard(Cluster cluster, String name, LocalDateTime createdAt, String username, String password) {
|
public LoginCredentialsShard(Cluster cluster, String name, LocalDateTime createdAt, String username, String password) {
|
||||||
super(cluster, name, createdAt);
|
super(cluster, name, createdAt, ShardType.LOGIN_CREDENTIALS);
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + ", username=\"" + this.username + "\", password=\"" + this.password + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Serializer implements ShardSerializer<LoginCredentialsShard> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(LoginCredentialsShard shard) throws IOException {
|
||||||
|
return ByteUtils.writeLengthPrefixedStrings(new String[]{shard.getUsername(), shard.getPassword()});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoginCredentialsShard deserialize(InputStream is, Cluster cluster, String name, LocalDateTime createdAt) throws IOException {
|
||||||
|
String username = ByteUtils.readLengthPrefixedString(is);
|
||||||
|
String password = ByteUtils.readLengthPrefixedString(is);
|
||||||
|
return new LoginCredentialsShard(cluster, name, createdAt, username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package nl.andrewlalis.crystalkeep.model.shards;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a distinct type of shard, and should correspond to exactly one
|
||||||
|
* subtype of {@link Shard}.
|
||||||
|
* <p>
|
||||||
|
* All types defined here should have a unique integer value, which is used
|
||||||
|
* for serialization and deserialization of shards.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum ShardType {
|
||||||
|
/**
|
||||||
|
* Represents a {@link TextShard}
|
||||||
|
*/
|
||||||
|
TEXT(1),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a {@link LoginCredentialsShard}
|
||||||
|
*/
|
||||||
|
LOGIN_CREDENTIALS(2);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
ShardType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShardType valueOf(int value) {
|
||||||
|
for (var type : values()) {
|
||||||
|
if (type.getValue() == value) return type;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Invalid value.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,39 @@
|
||||||
package nl.andrewlalis.crystalkeep.model.shards;
|
package nl.andrewlalis.crystalkeep.model.shards;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
||||||
|
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
public class TextShard extends Shard {
|
public class TextShard extends Shard {
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
public TextShard(Cluster cluster, String name, LocalDateTime createdAt, String text) {
|
public TextShard(Cluster cluster, String name, LocalDateTime createdAt, String text) {
|
||||||
super(cluster, name, createdAt);
|
super(cluster, name, createdAt, ShardType.TEXT);
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + ", text=\"" + this.text + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Serializer implements ShardSerializer<TextShard> {
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(TextShard shard) throws IOException {
|
||||||
|
return ByteUtils.writeLengthPrefixedStrings(new String[]{shard.getText()});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextShard deserialize(InputStream is, Cluster cluster, String name, LocalDateTime createdAt) throws IOException {
|
||||||
|
String text = ByteUtils.readLengthPrefixedString(is);
|
||||||
|
return new TextShard(cluster, name, createdAt, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,8 @@
|
||||||
<?import javafx.scene.control.*?>
|
<?import javafx.scene.control.*?>
|
||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
|
|
||||||
|
|
||||||
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
|
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
<center>
|
<left>
|
||||||
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
|
<TreeView prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
|
||||||
<tabs>
|
</left>
|
||||||
<Tab text="Shards" />
|
|
||||||
<Tab text="Untitled Tab 2" />
|
|
||||||
</tabs>
|
|
||||||
</TabPane>
|
|
||||||
</center>
|
|
||||||
</BorderPane>
|
</BorderPane>
|
Loading…
Reference in New Issue