diff --git a/core/pom.xml b/core/pom.xml
index dda1d65..d539d3b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
4.0.0
diff --git a/demo/pom.xml b/demo/pom.xml
index f65fc3e..4e28c80 100644
--- a/demo/pom.xml
+++ b/demo/pom.xml
@@ -5,7 +5,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
4.0.0
diff --git a/features/collections/pom.xml b/features/collections/pom.xml
index 3ca6f3f..e570019 100644
--- a/features/collections/pom.xml
+++ b/features/collections/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/commentable/pom.xml b/features/commentable/pom.xml
index 26073bb..92c9a75 100644
--- a/features/commentable/pom.xml
+++ b/features/commentable/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/file/pom.xml b/features/file/pom.xml
index 4f0326b..45c1f02 100644
--- a/features/file/pom.xml
+++ b/features/file/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/kotlin/pom.xml b/features/kotlin/pom.xml
index 2f06210..f66747a 100644
--- a/features/kotlin/pom.xml
+++ b/features/kotlin/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/multi/pom.xml b/features/multi/pom.xml
new file mode 100644
index 0000000..86c38a8
--- /dev/null
+++ b/features/multi/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+ cc.carm.lib
+ configured-parent
+ 4.2.1
+ ../../pom.xml
+
+
+ ${project.jdk.version}
+ ${project.jdk.version}
+ UTF-8
+ UTF-8
+ 2.3.10
+
+ configured-feature-multi
+ jar
+
+ Configured - Record Feature
+ https://github.com/CarmJos/configured
+ Provides Java record type support for the Configured framework.
+
+
+
+
+
+ cc.carm.lib
+ configured-core
+ ${project.version}
+
+
+
+
+ cc.carm.lib
+ configured-yaml
+ ${project.version}
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+
+
diff --git a/features/multi/src/main/java/cc/carm/lib/configuration/MultiConfiguration.java b/features/multi/src/main/java/cc/carm/lib/configuration/MultiConfiguration.java
new file mode 100644
index 0000000..9531b1e
--- /dev/null
+++ b/features/multi/src/main/java/cc/carm/lib/configuration/MultiConfiguration.java
@@ -0,0 +1,135 @@
+package cc.carm.lib.configuration;
+
+import cc.carm.lib.configuration.source.ConfigurationHolder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class MultiConfiguration {
+
+ protected final ConcurrentHashMap valuesCache = new ConcurrentHashMap<>();
+
+ public MultiConfiguration() {
+ }
+
+ /**
+ * Read the value of the key from the holder, and return the value.
+ *
+ * @param key The key of the value to read.
+ * @param holder The holder of the value to read.
+ * @return The value of the key, or null if the value is not exist.
+ */
+ public abstract T read(@NotNull K key, @NotNull ConfigurationHolder> holder);
+
+ /**
+ * Write (and save) the value of the key to the holder, then update the cache.
+ *
+ * @param holder The holder of the value to write.
+ * @param value The value to write, which should not be null.
+ */
+ public abstract void write(@NotNull ConfigurationHolder> holder, @NotNull T value);
+
+ /**
+ * Get all holders of the configuration, which should be a concurrent map to support concurrent access.
+ *
+ * @return All holders of the configuration.
+ */
+ public abstract @NotNull Map> holders();
+
+ /**
+ * Get the holder of the key.
+ * If the holder of the key is not exist,
+ * it should be created then return the created holder.
+ *
+ * @param key The key of the holder to get.
+ * @return The holder of the key.
+ */
+ public abstract @NotNull ConfigurationHolder> holder(@NotNull K key);
+
+ /**
+ * Remove the holder of the key, and remove the value of the key from the cache.
+ * Also delete the configuration file if necessary.
+ *
+ * @param key The key of the holder to remove.
+ */
+ public abstract void removeHolder(@NotNull K key);
+
+ public void loadAll() {
+ for (Map.Entry> entry : holders().entrySet()) {
+ K key = entry.getKey();
+ ConfigurationHolder> holder = entry.getValue();
+ try {
+ T loaded = read(key, holder);
+ if (loaded != null) {
+ valuesCache.put(key, loaded);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public void saveAll() {
+ for (Map.Entry entry : valuesCache.entrySet()) {
+ K key = entry.getKey();
+ T value = entry.getValue();
+ ConfigurationHolder> holder = holder(key);
+ try {
+ write(holder, value);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+
+ /**
+ * Get all keys in the cache.
+ *
+ * @return All keys in the cache.
+ */
+ public @NotNull Set keys() {
+ return valuesCache.keySet();
+ }
+
+ /**
+ * Get all values in the cache.
+ *
+ * @return All values in the cache.
+ */
+ public @NotNull Map values() {
+ return this.valuesCache;
+ }
+
+ /**
+ * Get the value of the key, or null if the value is not exist.
+ *
+ * @param key The key of the value to get.
+ * @return The value of the key, or null if the value is not exist.
+ */
+ public @Nullable T get(@NotNull K key) {
+ return valuesCache.get(key);
+ }
+
+ /**
+ * Update the value of the key, and return the old value.
+ *
+ * @param key The key of the value to update.
+ * @param value The new value, or null to remove the value.
+ * @return The old value, or null if the value is not exist.
+ */
+ public @Nullable T update(@NotNull K key, @Nullable T value) {
+ if (value == null) {
+ T current = valuesCache.remove(key);
+ removeHolder(key);
+ return current;
+ }
+ ConfigurationHolder> holder = holder(key);
+ write(holder, value);
+ return valuesCache.put(key, value);
+ }
+
+}
diff --git a/features/multi/src/test/java/cc/carm/lib/configuration/tests/ExampleUserStorage.java b/features/multi/src/test/java/cc/carm/lib/configuration/tests/ExampleUserStorage.java
new file mode 100644
index 0000000..666732d
--- /dev/null
+++ b/features/multi/src/test/java/cc/carm/lib/configuration/tests/ExampleUserStorage.java
@@ -0,0 +1,66 @@
+package cc.carm.lib.configuration.tests;
+
+import cc.carm.lib.configuration.MultiConfiguration;
+import cc.carm.lib.configuration.source.ConfigurationHolder;
+import cc.carm.lib.configuration.source.yaml.YAMLConfigFactory;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class ExampleUserStorage extends MultiConfiguration {
+
+ protected final @NotNull File dataFolder;
+ protected final ConcurrentHashMap> holders = new ConcurrentHashMap<>();
+
+ public ExampleUserStorage(@NotNull File dataFolder) {
+ this.dataFolder = dataFolder;
+
+ // Load existing configuration files
+ if (dataFolder.exists() && dataFolder.isDirectory()) {
+ File[] files = dataFolder.listFiles((dir, name) -> name.endsWith(".yml"));
+ if (files != null) {
+ for (File file : files) {
+ String fileName = file.getName();
+ String uuidStr = fileName.substring(0, fileName.length() - 4); // Remove ".yml"
+ try {
+ UUID uuid = UUID.fromString(uuidStr);
+ ConfigurationHolder> holder = YAMLConfigFactory.from(file).build();
+ holders.put(uuid, holder);
+ } catch (IllegalArgumentException e) {
+ System.err.println("Invalid UUID in file name: " + fileName);
+ }
+ }
+ }
+ }
+
+ loadAll();
+ }
+
+ @Override
+ public @NotNull Map> holders() {
+ return this.holders;
+ }
+
+ @Override
+ public @NotNull ConfigurationHolder> holder(@NotNull UUID key) {
+ ConfigurationHolder> loaded = holders.get(key);
+ if (loaded != null) return loaded;
+
+ ConfigurationHolder> created = YAMLConfigFactory.from(new File(dataFolder, key + ".yml")).build();
+ holders.put(key, created);
+ return created;
+ }
+
+ @Override
+ public void removeHolder(@NotNull UUID key) {
+ ConfigurationHolder> loaded = holders.remove(key);
+ if (loaded == null) return;
+
+ File file = new File(dataFolder, key + ".yml");
+ if (file.exists()) file.delete();
+ }
+
+}
diff --git a/features/multi/src/test/java/cc/carm/lib/configuration/tests/MultiFileTests.java b/features/multi/src/test/java/cc/carm/lib/configuration/tests/MultiFileTests.java
new file mode 100644
index 0000000..b995f11
--- /dev/null
+++ b/features/multi/src/test/java/cc/carm/lib/configuration/tests/MultiFileTests.java
@@ -0,0 +1,61 @@
+package cc.carm.lib.configuration.tests;
+
+import cc.carm.lib.configuration.source.ConfigurationHolder;
+import cc.carm.lib.configuration.source.section.ConfigureSection;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.UUID;
+
+public class MultiFileTests {
+
+
+ @Test
+ public void test() {
+
+ ProfileStorage storage = new ProfileStorage(new File(new File("target"), "test-profiles"));
+ UserProfile profile = new UserProfile(UUID.randomUUID(), "John Doe", "john@google.com", "123123123");
+ storage.update(profile.getUniqueId(), profile);
+
+ System.out.println("Current users: ");
+ storage.values().forEach((k, v) -> {
+ System.out.println("# " + k);
+ System.out.println("- " + v.getName() + " (" + v.getEmail() + ", " + v.getPhone() + ")");
+ });
+
+ }
+
+ public static class ProfileStorage extends ExampleUserStorage {
+
+ public ProfileStorage(@NotNull File dataFolder) {
+ super(dataFolder);
+ }
+
+ @Override
+ public UserProfile read(@NotNull UUID key, @NotNull ConfigurationHolder> holder) {
+ ConfigureSection conf = holder.config();
+ return new UserProfile(
+ key,
+ conf.getString("name", "Unknown"),
+ conf.getString("email", "unset"),
+ conf.getString("phone", "123123123")
+ );
+ }
+
+ @Override
+ public void write(@NotNull ConfigurationHolder> holder, @NotNull UserProfile value) {
+ ConfigureSection conf = holder.config();
+ conf.set("name", value.getName());
+ conf.set("email", value.getEmail());
+ conf.set("phone", value.getPhone());
+ try {
+ holder.save();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+}
diff --git a/features/multi/src/test/java/cc/carm/lib/configuration/tests/UserProfile.java b/features/multi/src/test/java/cc/carm/lib/configuration/tests/UserProfile.java
new file mode 100644
index 0000000..e6d68bd
--- /dev/null
+++ b/features/multi/src/test/java/cc/carm/lib/configuration/tests/UserProfile.java
@@ -0,0 +1,49 @@
+package cc.carm.lib.configuration.tests;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+import java.util.UUID;
+
+public class UserProfile {
+
+ protected final @NotNull UUID uuid;
+ protected final @NotNull String name;
+ protected final @NotNull String email;
+ protected final @NotNull String phone;
+
+ public UserProfile(@NotNull UUID uuid, @NotNull String name, @NotNull String email, @NotNull String phone) {
+ this.uuid = uuid;
+ this.name = name;
+ this.email = email;
+ this.phone = phone;
+ }
+
+ public @NotNull UUID getUniqueId() {
+ return uuid;
+ }
+
+ public @NotNull String getName() {
+ return name;
+ }
+
+ public @NotNull String getEmail() {
+ return email;
+ }
+
+ public @NotNull String getPhone() {
+ return phone;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof UserProfile)) return false;
+ UserProfile that = (UserProfile) o;
+ return Objects.equals(name, that.name) && Objects.equals(email, that.email) && Objects.equals(phone, that.phone);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, email, phone);
+ }
+}
diff --git a/features/record/pom.xml b/features/record/pom.xml
index 9fd6a38..a9d7cde 100644
--- a/features/record/pom.xml
+++ b/features/record/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/section/pom.xml b/features/section/pom.xml
index edd628a..76c0d92 100644
--- a/features/section/pom.xml
+++ b/features/section/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/text/pom.xml b/features/text/pom.xml
index faaf5de..ab2f8c6 100644
--- a/features/text/pom.xml
+++ b/features/text/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/validators/pom.xml b/features/validators/pom.xml
index a6ec66c..0ff7e83 100644
--- a/features/validators/pom.xml
+++ b/features/validators/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/features/versioned/pom.xml b/features/versioned/pom.xml
index f8af61f..750b3e3 100644
--- a/features/versioned/pom.xml
+++ b/features/versioned/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/pom.xml b/pom.xml
index 258d1d6..2f8e281 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
cc.carm.lib
configured-parent
pom
- 4.2.0
+ 4.2.1
core
features/section
@@ -37,6 +37,7 @@
providers/mongodb
demo
+ features/multi
configured
diff --git a/providers/gson/pom.xml b/providers/gson/pom.xml
index 3fdbdbd..179219e 100644
--- a/providers/gson/pom.xml
+++ b/providers/gson/pom.xml
@@ -5,7 +5,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
../../pom.xml
4.0.0
diff --git a/providers/hocon/pom.xml b/providers/hocon/pom.xml
index 042e9ed..2eaf84c 100644
--- a/providers/hocon/pom.xml
+++ b/providers/hocon/pom.xml
@@ -6,7 +6,7 @@
cc.carm.lib
configured-parent
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/providers/mongodb/pom.xml b/providers/mongodb/pom.xml
index 36785be..e5f428e 100644
--- a/providers/mongodb/pom.xml
+++ b/providers/mongodb/pom.xml
@@ -5,7 +5,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
../../pom.xml
4.0.0
diff --git a/providers/sql/pom.xml b/providers/sql/pom.xml
index 24497df..7873382 100644
--- a/providers/sql/pom.xml
+++ b/providers/sql/pom.xml
@@ -6,7 +6,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/providers/temp/pom.xml b/providers/temp/pom.xml
index 83a06c8..2403cb6 100644
--- a/providers/temp/pom.xml
+++ b/providers/temp/pom.xml
@@ -6,7 +6,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
../../pom.xml
diff --git a/providers/yaml/pom.xml b/providers/yaml/pom.xml
index 734da31..58a2b57 100644
--- a/providers/yaml/pom.xml
+++ b/providers/yaml/pom.xml
@@ -6,7 +6,7 @@
configured-parent
cc.carm.lib
- 4.2.0
+ 4.2.1
../../pom.xml