diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..8e4aca6
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,21 @@
+# Copyright 2023 Korandoru Contributors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root = true
+
+[*]
+end_of_line = lf
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/pom.xml b/pom.xml
index 9c6f98c..fa191d6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,8 +14,15 @@
17
UTF-8
+
+ 3.24.2
+ 5.9.2
+ 1.18.26
2.4.1
1.7.36
+
+
+ 3.0.0-M7
diff --git a/zeronos-bom/pom.xml b/zeronos-bom/pom.xml
index 6c45132..96f4f7b 100644
--- a/zeronos-bom/pom.xml
+++ b/zeronos-bom/pom.xml
@@ -15,6 +15,11 @@
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
org.slf4j
slf4j-api
diff --git a/zeronos-parent/pom.xml b/zeronos-parent/pom.xml
index 872b327..646b6d8 100644
--- a/zeronos-parent/pom.xml
+++ b/zeronos-parent/pom.xml
@@ -25,4 +25,51 @@
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ org.apache.ratis
+ ratis-server-api
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.version}
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+
diff --git a/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNode.java b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNode.java
new file mode 100644
index 0000000..d6877bc
--- /dev/null
+++ b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNode.java
@@ -0,0 +1,33 @@
+package io.korandoru.zeronos.server;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class DataNode {
+
+ private final Deque revisions = new LinkedList<>();
+
+ public DataNode(DataNodeEntry entry) {
+ this.revisions.addLast(entry);
+ }
+
+ public DataNodeEntry readNodeLatest() {
+ // TODO - check if removed
+ return this.revisions.getLast();
+ }
+
+ public void createNode(DataNodeEntry entry) {
+ // TODO - check if exist
+ this.revisions.addLast(entry);
+ }
+
+ public void updateNode(DataNodeEntry entry) {
+ // TODO - check if exist
+ this.revisions.addLast(entry);
+ }
+
+ public void deleteNode(DataNodeEntry entry) {
+ // TODO - check if exist
+ this.revisions.addLast(entry);
+ }
+}
diff --git a/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNodeEntry.java b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNodeEntry.java
new file mode 100644
index 0000000..0e6aaf2
--- /dev/null
+++ b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataNodeEntry.java
@@ -0,0 +1,9 @@
+package io.korandoru.zeronos.server;
+
+import lombok.Data;
+
+@Data
+public class DataNodeEntry {
+ private final long revision;
+ private final byte[] data;
+}
diff --git a/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataTree.java b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataTree.java
new file mode 100644
index 0000000..0dbe800
--- /dev/null
+++ b/zeronos-server/src/main/java/io/korandoru/zeronos/server/DataTree.java
@@ -0,0 +1,38 @@
+package io.korandoru.zeronos.server;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+public class DataTree {
+
+ private final SortedMap nodes = new TreeMap<>();
+
+ public DataTree() {
+ this.nodes.put("", new DataNode(new DataNodeEntry(0, new byte[0])));
+ }
+
+ public void createNode(String path, byte[] data, long revision) {
+ final int slash = path.lastIndexOf('/');
+ final String parentPath = path.substring(0, slash);
+
+ final DataNode parent = nodes.get(parentPath);
+ if (parent == null) {
+ throw new RuntimeException("NoNode");
+ }
+
+ final DataNode child = nodes.get(path);
+ if (child == null) {
+ nodes.put(path, new DataNode(new DataNodeEntry(revision, data)));
+ } else {
+ child.createNode(new DataNodeEntry(revision, data));
+ }
+ }
+
+ public DataNodeEntry readNode(String path) {
+ final DataNode node = nodes.get(path);
+ if (node == null) {
+ throw new RuntimeException("NoNode");
+ }
+ return node.readNodeLatest();
+ }
+}
diff --git a/zeronos-server/src/test/java/io/korandoru/zeronos/server/DataTreeTest.java b/zeronos-server/src/test/java/io/korandoru/zeronos/server/DataTreeTest.java
new file mode 100644
index 0000000..485e5b9
--- /dev/null
+++ b/zeronos-server/src/test/java/io/korandoru/zeronos/server/DataTreeTest.java
@@ -0,0 +1,27 @@
+package io.korandoru.zeronos.server;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicLong;
+import org.junit.jupiter.api.Test;
+
+class DataTreeTest {
+
+ @Test
+ void testCreateNode() {
+ final DataTree tree = new DataTree();
+ final AtomicLong revision = new AtomicLong();
+ final byte[][] datas = new byte[][]{
+ "zero".getBytes(StandardCharsets.UTF_8),
+ "one".getBytes(StandardCharsets.UTF_8),
+ "two".getBytes(StandardCharsets.UTF_8),
+ };
+ tree.createNode("/zeronos", datas[0], revision.incrementAndGet());
+ tree.createNode("/zeronos/altair", datas[1], revision.incrementAndGet());
+ tree.createNode("/zeronos/vega", datas[2], revision.incrementAndGet());
+ assertThat(tree.readNode("/zeronos")).isEqualTo(new DataNodeEntry(1, datas[0]));
+ assertThat(tree.readNode("/zeronos/altair")).isEqualTo(new DataNodeEntry(2, datas[1]));
+ assertThat(tree.readNode("/zeronos/vega")).isEqualTo(new DataNodeEntry(3, datas[2]));
+ }
+
+}