Made the project modular.

This commit is contained in:
Andrew Lalis 2021-05-29 12:34:40 +02:00
parent 7ccb0494ee
commit f7df8a1eaf
19 changed files with 116 additions and 68 deletions

14
pom.xml
View File

@ -24,8 +24,14 @@
<version>0.0.4</version> <version>0.0.4</version>
<configuration> <configuration>
<mainClass>nl.andrewlalis.crystalkeep.CrystalKeep</mainClass> <mainClass>nl.andrewlalis.crystalkeep.CrystalKeep</mainClass>
<launcher>crystalkeep.exe</launcher>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins> </plugins>
</build> </build>
@ -40,14 +46,6 @@
<artifactId>javafx-fxml</artifactId> <artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version> <version>${javafx.version}</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine --> <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>

View File

@ -0,0 +1,8 @@
module crystalkeep {
requires javafx.fxml;
requires javafx.controls;
opens nl.andrewlalis.crystalkeep;
exports nl.andrewlalis.crystalkeep.control to javafx.fxml;
}

View File

@ -22,7 +22,7 @@ public class CrystalKeep extends Application {
@Override @Override
public void start(Stage stage) throws Exception { public void start(Stage stage) throws Exception {
URL url = CrystalKeep.class.getClassLoader().getResource("ui/crystalkeep.fxml"); URL url = getClass().getResource("/nl/andrewlalis/crystalkeep/ui/crystalkeep.fxml");
FXMLLoader loader = new FXMLLoader(url); FXMLLoader loader = new FXMLLoader(url);
Model model = new Model(); Model model = new Model();
var scene = new Scene(loader.load()); var scene = new Scene(loader.load());

View File

@ -1,28 +1,37 @@
package nl.andrewlalis.crystalkeep.model; package nl.andrewlalis.crystalkeep.model;
import lombok.Getter;
import lombok.Setter;
import java.util.*; import java.util.*;
@Getter
public class Cluster implements Comparable<Cluster>, CrystalItem { public class Cluster implements Comparable<Cluster>, CrystalItem {
@Setter
private String name; private String name;
private final Set<Shard> shards; private final Set<Shard> shards;
private final Set<Cluster> clusters; private final Set<Cluster> clusters;
@Setter
private Cluster parent;
public Cluster(String name, Set<Shard> shards, Set<Cluster> clusters, Cluster parent) { public Cluster(String name, Set<Shard> shards, Set<Cluster> clusters) {
this.name = name; this.name = name;
this.shards = shards; this.shards = shards;
this.clusters = clusters; this.clusters = clusters;
this.parent = parent;
} }
public Cluster(String name) { public Cluster(String name) {
this(name, new HashSet<>(), new HashSet<>(), null); this(name, new HashSet<>(), new HashSet<>());
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Shard> getShards() {
return shards;
}
public Set<Cluster> getClusters() {
return clusters;
} }
public void addShard(Shard shard) { public void addShard(Shard shard) {
@ -31,7 +40,6 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
public void addCluster(Cluster cluster) { public void addCluster(Cluster cluster) {
this.clusters.add(cluster); this.clusters.add(cluster);
cluster.setParent(this);
} }
public List<Cluster> getClustersOrdered() { public List<Cluster> getClustersOrdered() {
@ -56,12 +64,12 @@ public class Cluster implements Comparable<Cluster>, 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;
Cluster cluster = (Cluster) o; Cluster cluster = (Cluster) o;
return getName().equals(cluster.getName()) && Objects.equals(getParent(), cluster.getParent()); return getName().equals(cluster.getName());
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(getName(), getParent()); return Objects.hash(getName());
} }
@Override @Override
@ -80,6 +88,6 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
@Override @Override
public String getIconPath() { public String getIconPath() {
return "ui/images/cluster_node_icon.png"; return "/nl/andrewlalis/crystalkeep/ui/images/cluster_node_icon.png";
} }
} }

View File

@ -1,16 +1,18 @@
package nl.andrewlalis.crystalkeep.model; package nl.andrewlalis.crystalkeep.model;
import lombok.Getter;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@Getter
public class Model { public class Model {
private Cluster activeCluster; private Cluster activeCluster;
private final Set<ModelListener> listeners = new HashSet<>(); private final Set<ModelListener> listeners = new HashSet<>();
public Cluster getActiveCluster() {
return activeCluster;
}
public void addListener(ModelListener listener) { public void addListener(ModelListener listener) {
this.listeners.add(listener); this.listeners.add(listener);
} }

View File

@ -1,7 +1,5 @@
package nl.andrewlalis.crystalkeep.model; package nl.andrewlalis.crystalkeep.model;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.crystalkeep.model.shards.ShardType; import nl.andrewlalis.crystalkeep.model.shards.ShardType;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -17,9 +15,7 @@ import java.util.Objects;
* decide which shard type to deserialize. * decide which shard type to deserialize.
* </p> * </p>
*/ */
@Getter
public abstract class Shard implements Comparable<Shard>, CrystalItem { public abstract class Shard implements Comparable<Shard>, CrystalItem {
@Setter
private String name; private String name;
private final LocalDateTime createdAt; private final LocalDateTime createdAt;
private final ShardType type; private final ShardType type;
@ -30,6 +26,23 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
this.type = type; this.type = type;
} }
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public ShardType getType() {
return type;
}
@Override @Override
public int compareTo(Shard o) { public int compareTo(Shard o) {
int r = this.getName().compareTo(o.getName()); int r = this.getName().compareTo(o.getName());
@ -57,6 +70,6 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
@Override @Override
public String getIconPath() { public String getIconPath() {
return "ui/images/shard_node_icon.png"; return "/nl/andrewlalis/crystalkeep/ui/images/shard_node_icon.png";
} }
} }

View File

@ -15,7 +15,7 @@ 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.readCluster(is, null); return ClusterSerializer.readCluster(is);
} }
public void saveDefault(Cluster cluster) throws IOException { public void saveDefault(Cluster cluster) throws IOException {

View File

@ -39,20 +39,12 @@ public class ClusterSerializer {
*/ */
public static void writeCluster(Cluster cluster, OutputStream os) throws IOException { public static void writeCluster(Cluster cluster, OutputStream os) throws IOException {
ByteUtils.writeLengthPrefixed(cluster.getName(), os); ByteUtils.writeLengthPrefixed(cluster.getName(), os);
os.write(ByteUtils.toBytes(cluster.getClusters().size())); os.write(ByteUtils.toBytes(cluster.getClusters().size()));
Cluster[] children = new Cluster[cluster.getClusters().size()]; for (Cluster child : cluster.getClustersOrdered()) {
cluster.getClusters().toArray(children);
Arrays.sort(children);
for (Cluster child : children) {
writeCluster(child, os); writeCluster(child, os);
} }
os.write(ByteUtils.toBytes(cluster.getShards().size())); os.write(ByteUtils.toBytes(cluster.getShards().size()));
Shard[] shards = new Shard[cluster.getShards().size()]; for (Shard shard : cluster.getShardsOrdered()) {
cluster.getShards().toArray(shards);
Arrays.sort(shards);
for (Shard shard : shards) {
writeShard(shard, os); writeShard(shard, os);
} }
} }
@ -60,16 +52,15 @@ public class ClusterSerializer {
/** /**
* Reads a cluster from an input stream. * Reads a cluster from an input stream.
* @param is The input stream to read from. * @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. * @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 readCluster(InputStream is, Cluster parent) throws IOException { public static Cluster readCluster(InputStream is) 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<>());
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(readCluster(is, cluster)); cluster.addCluster(readCluster(is));
} }
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++) {

View File

@ -1,7 +1,5 @@
package nl.andrewlalis.crystalkeep.model.shards; package nl.andrewlalis.crystalkeep.model.shards;
import lombok.Getter;
import lombok.Setter;
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;
@ -10,8 +8,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Getter
@Setter
public class LoginCredentialsShard extends Shard { public class LoginCredentialsShard extends Shard {
private String username; private String username;
private String password; private String password;
@ -22,6 +18,22 @@ public class LoginCredentialsShard extends Shard {
this.password = password; this.password = password;
} }
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override @Override
public String toString() { public String toString() {
return super.toString() + ", username=\"" + this.username + "\", password=\"" + this.password + "\""; return super.toString() + ", username=\"" + this.username + "\", password=\"" + this.password + "\"";

View File

@ -1,6 +1,5 @@
package nl.andrewlalis.crystalkeep.model.shards; package nl.andrewlalis.crystalkeep.model.shards;
import lombok.Getter;
import nl.andrewlalis.crystalkeep.model.Shard; import nl.andrewlalis.crystalkeep.model.Shard;
/** /**
@ -22,13 +21,16 @@ public enum ShardType {
*/ */
LOGIN_CREDENTIALS(2); LOGIN_CREDENTIALS(2);
@Getter
private final int value; private final int value;
ShardType(int value) { ShardType(int value) {
this.value = value; this.value = value;
} }
public int getValue() {
return value;
}
public static ShardType valueOf(int value) { public static ShardType valueOf(int value) {
for (var type : values()) { for (var type : values()) {
if (type.getValue() == value) return type; if (type.getValue() == value) return type;

View File

@ -1,7 +1,5 @@
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.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;
@ -10,7 +8,6 @@ import java.io.IOException;
import java.io.InputStream; 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;
@ -19,6 +16,14 @@ public class TextShard extends Shard {
this.text = text; this.text = text;
} }
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override @Override
public String toString() { public String toString() {
return super.toString() + ", text=\"" + this.text + "\""; return super.toString() + ", text=\"" + this.text + "\"";

View File

@ -1,21 +1,18 @@
package nl.andrewlalis.crystalkeep.view; package nl.andrewlalis.crystalkeep.view;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.image.ImageView;
import lombok.Getter;
import nl.andrewlalis.crystalkeep.model.Cluster; import nl.andrewlalis.crystalkeep.model.Cluster;
import nl.andrewlalis.crystalkeep.model.CrystalItem; import nl.andrewlalis.crystalkeep.model.CrystalItem;
public class ClusterTreeItem extends TreeItem<CrystalItem> { public class ClusterTreeItem extends TreeItem<CrystalItem> {
@Getter
private final Cluster cluster; private final Cluster cluster;
public ClusterTreeItem(Cluster cluster) { public ClusterTreeItem(Cluster cluster) {
super(cluster); super(cluster);
this.cluster = cluster; this.cluster = cluster;
ImageView clusterIcon = new ImageView("ui/images/cluster_node_icon.png"); }
clusterIcon.setFitHeight(16);
clusterIcon.setPreserveRatio(true); public Cluster getCluster() {
super.setGraphic(clusterIcon); return cluster;
} }
} }

View File

@ -3,10 +3,13 @@ package nl.andrewlalis.crystalkeep.view;
import javafx.scene.control.ContextMenu; import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeCell; import javafx.scene.control.TreeCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import nl.andrewlalis.crystalkeep.model.CrystalItem; import nl.andrewlalis.crystalkeep.model.CrystalItem;
import nl.andrewlalis.crystalkeep.model.Shard; import nl.andrewlalis.crystalkeep.model.Shard;
import java.io.InputStream;
public class CrystalItemTreeCell extends TreeCell<CrystalItem> { public class CrystalItemTreeCell extends TreeCell<CrystalItem> {
private final ContextMenu contextMenu; private final ContextMenu contextMenu;
@ -21,10 +24,13 @@ public class CrystalItemTreeCell extends TreeCell<CrystalItem> {
if (!empty) { if (!empty) {
this.setText(item.getName()); this.setText(item.getName());
ImageView icon = new ImageView(item.getIconPath()); InputStream is = getClass().getResourceAsStream(item.getIconPath());
icon.setFitHeight(16); if (is != null) {
icon.setPreserveRatio(true); ImageView icon = new ImageView(new Image(is));
this.setGraphic(icon); icon.setFitHeight(16);
icon.setPreserveRatio(true);
this.setGraphic(icon);
}
if (item instanceof Shard) { if (item instanceof Shard) {
this.setContextMenu(this.contextMenu); this.setContextMenu(this.contextMenu);
} }

View File

@ -1,16 +1,18 @@
package nl.andrewlalis.crystalkeep.view; package nl.andrewlalis.crystalkeep.view;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import lombok.Getter;
import nl.andrewlalis.crystalkeep.model.CrystalItem; import nl.andrewlalis.crystalkeep.model.CrystalItem;
import nl.andrewlalis.crystalkeep.model.Shard; import nl.andrewlalis.crystalkeep.model.Shard;
public class ShardTreeItem extends TreeItem<CrystalItem> { public class ShardTreeItem extends TreeItem<CrystalItem> {
@Getter
private final Shard shard; private final Shard shard;
public ShardTreeItem(Shard shard) { public ShardTreeItem(Shard shard) {
super(shard); super(shard);
this.shard = shard; this.shard = shard;
} }
public Shard getShard() {
return shard;
}
} }

View File

Before

Width:  |  Height:  |  Size: 803 B

After

Width:  |  Height:  |  Size: 803 B

View File

Before

Width:  |  Height:  |  Size: 795 B

After

Width:  |  Height:  |  Size: 795 B

View File

@ -17,6 +17,10 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
/**
* Tests the functionality of the {@link ClusterSerializer}, which handles
* transforming key model components to and from byte arrays for storage.
*/
public class ClusterSerializerTest { public class ClusterSerializerTest {
private static List<Shard> testShardIOData() { private static List<Shard> testShardIOData() {
return List.of( return List.of(
@ -92,7 +96,7 @@ public class ClusterSerializerTest {
"Cluster name does not match expected." "Cluster name does not match expected."
); );
Cluster loaded = ClusterSerializer.readCluster(new ByteArrayInputStream(data), null); Cluster loaded = ClusterSerializer.readCluster(new ByteArrayInputStream(data));
assertEquals(c, loaded, "Loaded cluster should equal original cluster."); assertEquals(c, loaded, "Loaded cluster should equal original cluster.");
bos.reset(); bos.reset();
ClusterSerializer.writeCluster(loaded, bos); ClusterSerializer.writeCluster(loaded, bos);