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>
<configuration>
<mainClass>nl.andrewlalis.crystalkeep.CrystalKeep</mainClass>
<launcher>crystalkeep.exe</launcher>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
@ -40,14 +46,6 @@
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</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 -->
<dependency>
<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
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);
Model model = new Model();
var scene = new Scene(loader.load());

View File

@ -1,28 +1,37 @@
package nl.andrewlalis.crystalkeep.model;
import lombok.Getter;
import lombok.Setter;
import java.util.*;
@Getter
public class Cluster implements Comparable<Cluster>, CrystalItem {
@Setter
private String name;
private final Set<Shard> shards;
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.shards = shards;
this.clusters = clusters;
this.parent = parent;
}
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) {
@ -31,7 +40,6 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
public void addCluster(Cluster cluster) {
this.clusters.add(cluster);
cluster.setParent(this);
}
public List<Cluster> getClustersOrdered() {
@ -56,12 +64,12 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
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());
return getName().equals(cluster.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getParent());
return Objects.hash(getName());
}
@Override
@ -80,6 +88,6 @@ public class Cluster implements Comparable<Cluster>, CrystalItem {
@Override
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;
import lombok.Getter;
import java.util.HashSet;
import java.util.Set;
@Getter
public class Model {
private Cluster activeCluster;
private final Set<ModelListener> listeners = new HashSet<>();
public Cluster getActiveCluster() {
return activeCluster;
}
public void addListener(ModelListener listener) {
this.listeners.add(listener);
}

View File

@ -1,7 +1,5 @@
package nl.andrewlalis.crystalkeep.model;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.crystalkeep.model.shards.ShardType;
import java.time.LocalDateTime;
@ -17,9 +15,7 @@ import java.util.Objects;
* decide which shard type to deserialize.
* </p>
*/
@Getter
public abstract class Shard implements Comparable<Shard>, CrystalItem {
@Setter
private String name;
private final LocalDateTime createdAt;
private final ShardType type;
@ -30,6 +26,23 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
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
public int compareTo(Shard o) {
int r = this.getName().compareTo(o.getName());
@ -57,6 +70,6 @@ public abstract class Shard implements Comparable<Shard>, CrystalItem {
@Override
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 {
InputStream is = new FileInputStream(DEFAULT_CLUSTER.toFile());
return ClusterSerializer.readCluster(is, null);
return ClusterSerializer.readCluster(is);
}
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 {
ByteUtils.writeLengthPrefixed(cluster.getName(), os);
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) {
for (Cluster child : cluster.getClustersOrdered()) {
writeCluster(child, os);
}
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) {
for (Shard shard : cluster.getShardsOrdered()) {
writeShard(shard, os);
}
}
@ -60,16 +52,15 @@ public class ClusterSerializer {
/**
* 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 readCluster(InputStream is, Cluster parent) throws IOException {
public static Cluster readCluster(InputStream is) throws IOException {
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));
for (int i = 0; i < childCount; i++) {
cluster.addCluster(readCluster(is, cluster));
cluster.addCluster(readCluster(is));
}
int shardCount = toInt(is.readNBytes(4));
for (int i = 0; i < shardCount; i++) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,18 @@
package nl.andrewlalis.crystalkeep.view;
import javafx.scene.control.TreeItem;
import lombok.Getter;
import nl.andrewlalis.crystalkeep.model.CrystalItem;
import nl.andrewlalis.crystalkeep.model.Shard;
public class ShardTreeItem extends TreeItem<CrystalItem> {
@Getter
private final Shard shard;
public ShardTreeItem(Shard shard) {
super(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.*;
/**
* Tests the functionality of the {@link ClusterSerializer}, which handles
* transforming key model components to and from byte arrays for storage.
*/
public class ClusterSerializerTest {
private static List<Shard> testShardIOData() {
return List.of(
@ -92,7 +96,7 @@ public class ClusterSerializerTest {
"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.");
bos.reset();
ClusterSerializer.writeCluster(loaded, bos);