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>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
</project>
|
</project>
|
|
@ -7,17 +7,13 @@ import javafx.stage.Stage;
|
||||||
import nl.andrewlalis.crystalkeep.control.MainViewController;
|
import nl.andrewlalis.crystalkeep.control.MainViewController;
|
||||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import nl.andrewlalis.crystalkeep.model.Model;
|
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.ClusterLoader;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ClusterSerializer;
|
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
import nl.andrewlalis.crystalkeep.model.shards.LoginCredentialsShard;
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class CrystalKeep extends Application {
|
public class CrystalKeep extends Application {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -41,10 +37,10 @@ public class CrystalKeep extends Application {
|
||||||
System.out.println("Loaded existing root cluster.");
|
System.out.println("Loaded existing root cluster.");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
rootCluster = new Cluster("Root");
|
rootCluster = new Cluster("Root");
|
||||||
rootCluster.addShard(new TextShard(rootCluster, "Example Shard", LocalDateTime.now(), "Hello world!"));
|
rootCluster.addShard(new TextShard("Example Shard", LocalDateTime.now(), "Hello world!"));
|
||||||
rootCluster.addShard(new LoginCredentialsShard(rootCluster, "Netflix", LocalDateTime.now(), "user", "secret password"));
|
rootCluster.addShard(new LoginCredentialsShard("Netflix", LocalDateTime.now(), "user", "secret password"));
|
||||||
for (int i = 0; i < 100; i++) {
|
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);
|
clusterLoader.saveDefault(rootCluster);
|
||||||
System.out.println("Saved root cluster on first load.");
|
System.out.println("Saved root cluster on first load.");
|
||||||
|
@ -57,30 +53,4 @@ public class CrystalKeep extends Application {
|
||||||
controller.init(model);
|
controller.init(model);
|
||||||
System.out.println(rootCluster);
|
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) {
|
public void addShard(Shard shard) {
|
||||||
this.shards.add(shard);
|
this.shards.add(shard);
|
||||||
shard.setCluster(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCluster(Cluster cluster) {
|
public void addCluster(Cluster cluster) {
|
||||||
|
|
|
@ -19,15 +19,12 @@ import java.util.Objects;
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
||||||
@Setter
|
|
||||||
private Cluster cluster;
|
|
||||||
@Setter
|
@Setter
|
||||||
private String name;
|
private String name;
|
||||||
private final LocalDateTime createdAt;
|
private final LocalDateTime createdAt;
|
||||||
private final ShardType type;
|
private final ShardType type;
|
||||||
|
|
||||||
public Shard(Cluster cluster, String name, LocalDateTime createdAt, ShardType type) {
|
public Shard(String name, LocalDateTime createdAt, ShardType type) {
|
||||||
this.cluster = cluster;
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.createdAt = createdAt;
|
this.createdAt = createdAt;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -45,12 +42,12 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
Shard shard = (Shard) o;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(getCluster(), getName(), getType());
|
return Objects.hash(getName(), getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,6 +5,7 @@ import nl.andrewlalis.crystalkeep.model.Cluster;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
@ -14,12 +15,13 @@ public class ClusterLoader {
|
||||||
|
|
||||||
public Cluster loadDefault() throws IOException {
|
public Cluster loadDefault() throws IOException {
|
||||||
InputStream is = new FileInputStream(DEFAULT_CLUSTER.toFile());
|
InputStream is = new FileInputStream(DEFAULT_CLUSTER.toFile());
|
||||||
return ClusterSerializer.clusterFromBytes(is, null);
|
return ClusterSerializer.readCluster(is, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveDefault(Cluster cluster) throws IOException {
|
public void saveDefault(Cluster cluster) throws IOException {
|
||||||
Files.createDirectories(CLUSTER_PATH);
|
Files.createDirectories(CLUSTER_PATH);
|
||||||
byte[] bytes = ClusterSerializer.toBytes(cluster);
|
OutputStream os = Files.newOutputStream(DEFAULT_CLUSTER);
|
||||||
Files.write(DEFAULT_CLUSTER, bytes);
|
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.ShardType;
|
||||||
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
import nl.andrewlalis.crystalkeep.model.shards.TextShard;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
@ -33,31 +33,28 @@ public class ClusterSerializer {
|
||||||
/**
|
/**
|
||||||
* Serializes a cluster to a byte array, including all shards and nested
|
* Serializes a cluster to a byte array, including all shards and nested
|
||||||
* clusters.
|
* clusters.
|
||||||
* TODO: Use output stream instead of byte array.
|
|
||||||
* @param cluster The cluster to serialize.
|
* @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.
|
* @throws IOException If an error occurs while writing the cluster.
|
||||||
*/
|
*/
|
||||||
public static byte[] toBytes(Cluster cluster) throws IOException {
|
public static void writeCluster(Cluster cluster, OutputStream os) throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteUtils.writeLengthPrefixed(cluster.getName(), os);
|
||||||
ByteUtils.writeLengthPrefixed(cluster.getName(), bos);
|
|
||||||
|
|
||||||
bos.write(ByteUtils.toBytes(cluster.getClusters().size()));
|
os.write(ByteUtils.toBytes(cluster.getClusters().size()));
|
||||||
Cluster[] children = new Cluster[cluster.getClusters().size()];
|
Cluster[] children = new Cluster[cluster.getClusters().size()];
|
||||||
cluster.getClusters().toArray(children);
|
cluster.getClusters().toArray(children);
|
||||||
Arrays.sort(children);
|
Arrays.sort(children);
|
||||||
for (Cluster child : 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()];
|
Shard[] shards = new Shard[cluster.getShards().size()];
|
||||||
cluster.getShards().toArray(shards);
|
cluster.getShards().toArray(shards);
|
||||||
Arrays.sort(shards);
|
Arrays.sort(shards);
|
||||||
for (Shard shard : 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.
|
* @return The cluster that was read.
|
||||||
* @throws IOException If data could not be read from the stream.
|
* @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);
|
String name = ByteUtils.readLengthPrefixedString(is);
|
||||||
Cluster cluster = new Cluster(name, new HashSet<>(), new HashSet<>(), parent);
|
Cluster cluster = new Cluster(name, new HashSet<>(), new HashSet<>(), parent);
|
||||||
int childCount = toInt(is.readNBytes(4));
|
int childCount = toInt(is.readNBytes(4));
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
cluster.addCluster(clusterFromBytes(is, cluster));
|
cluster.addCluster(readCluster(is, cluster));
|
||||||
}
|
}
|
||||||
int shardCount = toInt(is.readNBytes(4));
|
int shardCount = toInt(is.readNBytes(4));
|
||||||
for (int i = 0; i < shardCount; i++) {
|
for (int i = 0; i < shardCount; i++) {
|
||||||
cluster.addShard(shardFromBytes(is, cluster));
|
cluster.addShard(readShard(is));
|
||||||
}
|
}
|
||||||
return cluster;
|
return cluster;
|
||||||
}
|
}
|
||||||
|
@ -86,29 +83,26 @@ public class ClusterSerializer {
|
||||||
* standard shard information, then using a specific {@link ShardSerializer}
|
* standard shard information, then using a specific {@link ShardSerializer}
|
||||||
* to get the bytes that represent the body of the shard.
|
* to get the bytes that represent the body of the shard.
|
||||||
* @param shard The shard to serialize.
|
* @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.
|
* @throws IOException If byte array stream could not be written to.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public static byte[] toBytes(Shard shard) throws IOException {
|
public static void writeShard(Shard shard, OutputStream os) throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteUtils.writeLengthPrefixed(shard.getName().getBytes(StandardCharsets.UTF_8), os);
|
||||||
ByteUtils.writeLengthPrefixed(shard.getName().getBytes(StandardCharsets.UTF_8), bos);
|
ByteUtils.writeLengthPrefixed(shard.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).getBytes(StandardCharsets.UTF_8), os);
|
||||||
ByteUtils.writeLengthPrefixed(shard.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).getBytes(StandardCharsets.UTF_8), bos);
|
os.write(ByteUtils.toBytes(shard.getType().getValue()));
|
||||||
bos.write(ByteUtils.toBytes(shard.getType().getValue()));
|
|
||||||
ShardSerializer serializer = serializers.get(shard.getType());
|
ShardSerializer serializer = serializers.get(shard.getType());
|
||||||
bos.write(serializer.serialize(shard));
|
os.write(serializer.serialize(shard));
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes a shard from a byte array that's being read by the given
|
* Deserializes a shard from a byte array that's being read by the given
|
||||||
* input stream.
|
* input stream.
|
||||||
* @param is The input stream to read from.
|
* @param is The input stream to read from.
|
||||||
* @param cluster The cluster that the shard should belong to.
|
|
||||||
* @return The shard that was deserialized.
|
* @return The shard that was deserialized.
|
||||||
* @throws IOException If an error occurs while reading bytes.
|
* @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);
|
String name = ByteUtils.readLengthPrefixedString(is);
|
||||||
LocalDateTime createdAt = LocalDateTime.parse(ByteUtils.readLengthPrefixedString(is), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
LocalDateTime createdAt = LocalDateTime.parse(ByteUtils.readLengthPrefixedString(is), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||||
ShardType type = ShardType.valueOf(ByteUtils.toInt(is.readNBytes(4)));
|
ShardType type = ShardType.valueOf(ByteUtils.toInt(is.readNBytes(4)));
|
||||||
|
@ -116,6 +110,6 @@ public class ClusterSerializer {
|
||||||
if (serializer == null) {
|
if (serializer == null) {
|
||||||
throw new IOException("Unsupported shard type.");
|
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;
|
package nl.andrewlalis.crystalkeep.model.serialization;
|
||||||
|
|
||||||
import nl.andrewlalis.crystalkeep.model.Cluster;
|
|
||||||
import nl.andrewlalis.crystalkeep.model.Shard;
|
import nl.andrewlalis.crystalkeep.model.Shard;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -11,5 +9,5 @@ import java.time.LocalDateTime;
|
||||||
public interface ShardSerializer<T extends Shard> {
|
public interface ShardSerializer<T extends Shard> {
|
||||||
byte[] serialize(T shard) throws IOException;
|
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.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
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.ByteUtils;
|
||||||
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
import nl.andrewlalis.crystalkeep.model.serialization.ShardSerializer;
|
||||||
|
@ -17,8 +16,8 @@ public class LoginCredentialsShard extends Shard {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
public LoginCredentialsShard(Cluster cluster, String name, LocalDateTime createdAt, String username, String password) {
|
public LoginCredentialsShard(String name, LocalDateTime createdAt, String username, String password) {
|
||||||
super(cluster, name, createdAt, ShardType.LOGIN_CREDENTIALS);
|
super(name, createdAt, ShardType.LOGIN_CREDENTIALS);
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
@ -36,10 +35,10 @@ public class LoginCredentialsShard extends Shard {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 username = ByteUtils.readLengthPrefixedString(is);
|
||||||
String password = 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 {
|
public class TextShard extends Shard {
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
public TextShard(Cluster cluster, String name, LocalDateTime createdAt, String text) {
|
public TextShard(String name, LocalDateTime createdAt, String text) {
|
||||||
super(cluster, name, createdAt, ShardType.TEXT);
|
super(name, createdAt, ShardType.TEXT);
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ public class TextShard extends Shard {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
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