Added unit test for shard io.
This commit is contained in:
parent
4d40431bcd
commit
b92aedf872
|
@ -0,0 +1,113 @@
|
|||
### Java template
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Maven template
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
.idea/
|
||||
clusters/
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 4.2333333 4.2333333"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="cluster_node_icon.svg"
|
||||
inkscape:export-filename="A:\Programming\GitHub-andrewlalis\CrystalKeep\src\main\resources\ui\images\cluster_node_icon.png"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="31.678384"
|
||||
inkscape:cx="9.6523068"
|
||||
inkscape:cy="7.5940447"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-292.76667)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#f072ff;fill-opacity:1;stroke:none;stroke-width:0.07803907;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||
id="path817"
|
||||
sodipodi:sides="9"
|
||||
sodipodi:cx="2.1166666"
|
||||
sodipodi:cy="294.93815"
|
||||
sodipodi:r1="1.8178079"
|
||||
sodipodi:r2="1.2179312"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:arg2="0.87266463"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 3.6909344,295.84704 -0.7913968,0.0241 -0.1611441,0.77519 -0.6217269,-0.49025 -0.621727,0.49025 -0.1611441,-0.77519 -0.79139678,-0.0241 0.37483979,-0.69741 -0.59076328,-0.52715 0.73543197,-0.2933 -0.11370504,-0.78356 0.75190744,0.24804 0.416557,-0.67333 0.4165569,0.67333 0.7519075,-0.24804 -0.1137051,0.78356 0.735432,0.2933 -0.5907633,0.52715 z"
|
||||
inkscape:transform-center-x="0.06028767"
|
||||
inkscape:transform-center-y="0.030212626" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 4.2333333 4.2333333"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="shard_node_icon.svg"
|
||||
inkscape:export-filename="A:\Programming\GitHub-andrewlalis\CrystalKeep\src\main\resources\ui\images\shard_node_icon.png"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="31.678384"
|
||||
inkscape:cx="4.3963569"
|
||||
inkscape:cy="7.5940447"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
units="px" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-292.76667)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#72deff;fill-opacity:1;stroke:none;stroke-width:0.07803907;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"
|
||||
id="path817"
|
||||
sodipodi:sides="9"
|
||||
sodipodi:cx="2.1166666"
|
||||
sodipodi:cy="294.93815"
|
||||
sodipodi:r1="1.8178079"
|
||||
sodipodi:r2="1.2179312"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:arg2="0.87266463"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 3.6909344,295.84704 -0.7913968,0.0241 -0.1611441,0.77519 -0.6217269,-0.49025 -0.621727,0.49025 -0.1611441,-0.77519 -0.79139678,-0.0241 0.37483979,-0.69741 -0.59076328,-0.52715 0.73543197,-0.2933 -0.11370504,-0.78356 0.75190744,0.24804 0.416557,-0.67333 0.4165569,0.67333 0.7519075,-0.24804 -0.1137051,0.78356 0.735432,0.2933 -0.5907633,0.52715 z"
|
||||
inkscape:transform-center-x="0.06028767"
|
||||
inkscape:transform-center-y="0.030212626" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
13
pom.xml
13
pom.xml
|
@ -48,5 +48,18 @@
|
|||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>5.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -7,17 +7,13 @@ import javafx.stage.Stage;
|
|||
import nl.andrewlalis.crystalkeep.control.MainViewController;
|
||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||
import nl.andrewlalis.crystalkeep.model.Model;
|
||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||
import nl.andrewlalis.crystalkeep.model.serialization.ClusterLoader;
|
||||
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) {
|
||||
|
@ -41,10 +37,10 @@ public class CrystalKeep extends Application {
|
|||
System.out.println("Loaded existing root cluster.");
|
||||
} catch (IOException e) {
|
||||
rootCluster = new Cluster("Root");
|
||||
rootCluster.addShard(new TextShard(rootCluster, "Example Shard", LocalDateTime.now(), "Hello world!"));
|
||||
rootCluster.addShard(new LoginCredentialsShard(rootCluster, "Netflix", LocalDateTime.now(), "user", "secret password"));
|
||||
rootCluster.addShard(new TextShard("Example Shard", LocalDateTime.now(), "Hello world!"));
|
||||
rootCluster.addShard(new LoginCredentialsShard("Netflix", LocalDateTime.now(), "user", "secret password"));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
rootCluster.addShard(new TextShard(rootCluster, "test " + i, LocalDateTime.now(), "value: " + i));
|
||||
rootCluster.addShard(new TextShard("test " + i, LocalDateTime.now(), "value: " + i));
|
||||
}
|
||||
clusterLoader.saveDefault(rootCluster);
|
||||
System.out.println("Saved root cluster on first load.");
|
||||
|
@ -57,30 +53,4 @@ public class CrystalKeep extends Application {
|
|||
controller.init(model);
|
||||
System.out.println(rootCluster);
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
|
|||
|
||||
public void addShard(Shard shard) {
|
||||
this.shards.add(shard);
|
||||
shard.setCluster(this);
|
||||
}
|
||||
|
||||
public void addCluster(Cluster cluster) {
|
||||
|
|
|
@ -19,15 +19,12 @@ import java.util.Objects;
|
|||
*/
|
||||
@Getter
|
||||
public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
||||
@Setter
|
||||
private Cluster cluster;
|
||||
@Setter
|
||||
private String name;
|
||||
private final LocalDateTime createdAt;
|
||||
private final ShardType type;
|
||||
|
||||
public Shard(Cluster cluster, String name, LocalDateTime createdAt, ShardType type) {
|
||||
this.cluster = cluster;
|
||||
public Shard(String name, LocalDateTime createdAt, ShardType type) {
|
||||
this.name = name;
|
||||
this.createdAt = createdAt;
|
||||
this.type = type;
|
||||
|
@ -45,12 +42,12 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
|||
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();
|
||||
return getName().equals(shard.getName()) && getType() == shard.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getCluster(), getName(), getType());
|
||||
return Objects.hash(getName(), getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,6 +5,7 @@ import nl.andrewlalis.crystalkeep.model.Cluster;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
|
@ -14,12 +15,13 @@ public class ClusterLoader {
|
|||
|
||||
public Cluster loadDefault() throws IOException {
|
||||
InputStream is = new FileInputStream(DEFAULT_CLUSTER.toFile());
|
||||
return ClusterSerializer.clusterFromBytes(is, null);
|
||||
return ClusterSerializer.readCluster(is, null);
|
||||
}
|
||||
|
||||
public void saveDefault(Cluster cluster) throws IOException {
|
||||
Files.createDirectories(CLUSTER_PATH);
|
||||
byte[] bytes = ClusterSerializer.toBytes(cluster);
|
||||
Files.write(DEFAULT_CLUSTER, bytes);
|
||||
OutputStream os = Files.newOutputStream(DEFAULT_CLUSTER);
|
||||
ClusterSerializer.writeCluster(cluster, os);
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ 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.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
@ -33,31 +33,28 @@ public class ClusterSerializer {
|
|||
/**
|
||||
* Serializes a cluster to a byte array, including all shards and nested
|
||||
* clusters.
|
||||
* TODO: Use output stream instead of byte array.
|
||||
* @param cluster The cluster to serialize.
|
||||
* @return The byte array representing the cluster.
|
||||
* @param os The output stream to write to.
|
||||
* @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);
|
||||
public static void writeCluster(Cluster cluster, OutputStream os) throws IOException {
|
||||
ByteUtils.writeLengthPrefixed(cluster.getName(), os);
|
||||
|
||||
bos.write(ByteUtils.toBytes(cluster.getClusters().size()));
|
||||
os.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));
|
||||
writeCluster(child, os);
|
||||
}
|
||||
|
||||
bos.write(ByteUtils.toBytes(cluster.getShards().size()));
|
||||
os.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));
|
||||
writeShard(shard, os);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,16 +64,16 @@ public class ClusterSerializer {
|
|||
* @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 {
|
||||
public static Cluster readCluster(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));
|
||||
cluster.addCluster(readCluster(is, cluster));
|
||||
}
|
||||
int shardCount = toInt(is.readNBytes(4));
|
||||
for (int i = 0; i < shardCount; i++) {
|
||||
cluster.addShard(shardFromBytes(is, cluster));
|
||||
cluster.addShard(readShard(is));
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
@ -86,29 +83,26 @@ public class ClusterSerializer {
|
|||
* 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.
|
||||
* @param os The output stream to write to.
|
||||
* @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()));
|
||||
public static void writeShard(Shard shard, OutputStream os) throws IOException {
|
||||
ByteUtils.writeLengthPrefixed(shard.getName().getBytes(StandardCharsets.UTF_8), os);
|
||||
ByteUtils.writeLengthPrefixed(shard.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).getBytes(StandardCharsets.UTF_8), os);
|
||||
os.write(ByteUtils.toBytes(shard.getType().getValue()));
|
||||
ShardSerializer serializer = serializers.get(shard.getType());
|
||||
bos.write(serializer.serialize(shard));
|
||||
return bos.toByteArray();
|
||||
os.write(serializer.serialize(shard));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public static Shard readShard(InputStream is) 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)));
|
||||
|
@ -116,6 +110,6 @@ public class ClusterSerializer {
|
|||
if (serializer == null) {
|
||||
throw new IOException("Unsupported shard type.");
|
||||
}
|
||||
return serializer.deserialize(is, cluster, name, createdAt);
|
||||
return serializer.deserialize(is, name, createdAt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
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;
|
||||
|
@ -11,5 +9,5 @@ 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;
|
||||
T deserialize(InputStream is, String name, LocalDateTime createdAt) throws IOException;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package nl.andrewlalis.crystalkeep.model.shards;
|
|||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||
import nl.andrewlalis.crystalkeep.model.serialization.ByteUtils;
|
||||
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||
|
@ -17,8 +16,8 @@ public class LoginCredentialsShard extends Shard {
|
|||
private String username;
|
||||
private String password;
|
||||
|
||||
public LoginCredentialsShard(Cluster cluster, String name, LocalDateTime createdAt, String username, String password) {
|
||||
super(cluster, name, createdAt, ShardType.LOGIN_CREDENTIALS);
|
||||
public LoginCredentialsShard(String name, LocalDateTime createdAt, String username, String password) {
|
||||
super(name, createdAt, ShardType.LOGIN_CREDENTIALS);
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
@ -36,10 +35,10 @@ public class LoginCredentialsShard extends Shard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LoginCredentialsShard deserialize(InputStream is, Cluster cluster, String name, LocalDateTime createdAt) throws IOException {
|
||||
public LoginCredentialsShard deserialize(InputStream is, String name, LocalDateTime createdAt) throws IOException {
|
||||
String username = ByteUtils.readLengthPrefixedString(is);
|
||||
String password = ByteUtils.readLengthPrefixedString(is);
|
||||
return new LoginCredentialsShard(cluster, name, createdAt, username, password);
|
||||
return new LoginCredentialsShard(name, createdAt, username, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ import java.time.LocalDateTime;
|
|||
public class TextShard extends Shard {
|
||||
private String text;
|
||||
|
||||
public TextShard(Cluster cluster, String name, LocalDateTime createdAt, String text) {
|
||||
super(cluster, name, createdAt, ShardType.TEXT);
|
||||
public TextShard(String name, LocalDateTime createdAt, String text) {
|
||||
super(name, createdAt, ShardType.TEXT);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,9 @@ public class TextShard extends Shard {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TextShard deserialize(InputStream is, Cluster cluster, String name, LocalDateTime createdAt) throws IOException {
|
||||
public TextShard deserialize(InputStream is, String name, LocalDateTime createdAt) throws IOException {
|
||||
String text = ByteUtils.readLengthPrefixedString(is);
|
||||
return new TextShard(cluster, name, createdAt, text);
|
||||
return new TextShard(name, createdAt, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package nl.andrewlalis.crystalkeep.model.serialization;
|
||||
|
||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ClusterSerializerTest {
|
||||
private static List<Shard> testShardIOData() {
|
||||
return List.of(
|
||||
new TextShard("a", LocalDateTime.now(), "Hello world!"),
|
||||
new TextShard("Another", LocalDateTime.now(), "Testing"),
|
||||
new TextShard("", LocalDateTime.now(), ""),
|
||||
new LoginCredentialsShard("login", LocalDateTime.now(), "andrew", "password"),
|
||||
new LoginCredentialsShard("test", LocalDateTime.now(), "", "")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("testShardIOData")
|
||||
public void testShardIO(Shard s1) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ClusterSerializer.writeShard(s1, bos);
|
||||
byte[] data = bos.toByteArray();
|
||||
assertNotEquals(0, data.length, "Serialized shard should never result in empty bytes.");
|
||||
assertEquals(
|
||||
s1.getName().length(),
|
||||
ByteUtils.toInt(Arrays.copyOfRange(data, 0, 4)),
|
||||
"Serialized shard name length does not match expected."
|
||||
);
|
||||
assertEquals(
|
||||
s1.getName(),
|
||||
new String(Arrays.copyOfRange(data, 4, 4 + s1.getName().length())),
|
||||
"First letter of shard name does not match expected."
|
||||
);
|
||||
|
||||
Shard loadedS1 = ClusterSerializer.readShard(new ByteArrayInputStream(data));
|
||||
assertEquals(s1, loadedS1, "Loaded shard should equal original shard.");
|
||||
bos.reset();
|
||||
ClusterSerializer.writeShard(loadedS1, bos);
|
||||
byte[] data2 = bos.toByteArray();
|
||||
assertArrayEquals(data, data2, "Serialized data from a shard should not change.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* This package contains all tests for CrystalKeep.
|
||||
*/
|
||||
package nl.andrewlalis.crystalkeep;
|
Loading…
Reference in New Issue