From 90a3388728d2f5510c8d261c3f0af44fd5fa1180 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Tue, 28 Mar 2023 16:56:30 +0800 Subject: [PATCH 1/9] refactor: Abstract handle class and improve node handling --- .../MultiverseCore/api/MVConfig.java | 5 +- .../commands/ConfigCommand.java | 26 +- .../commandtools/MVCommandContexts.java | 10 +- .../MultiverseCore/config/MVCoreConfig.java | 12 +- .../config/MVCoreConfigNodes.java | 51 ++- .../configuration/ConfigHandle.java | 360 ------------------ .../handle/CommentedYamlConfigHandle.java | 68 ++++ .../handle/FileConfigHandle.java | 208 ++++++++++ .../handle/YamlConfigHandle.java | 68 ++++ .../migration/BooleanMigratorAction.java | 8 +- .../migration/ConfigMigrator.java | 23 +- .../migration/IntegerMigratorAction.java | 9 +- .../migration/InvertBoolMigratorAction.java | 8 +- .../migration/MigratorAction.java | 6 +- .../migration/MoveMigratorAction.java | 10 +- .../migration/VersionMigrator.java | 8 +- .../configuration/node/CommentedNode.java | 13 + .../configuration/node/ConfigHeaderNode.java | 83 ++++ .../{MVValueNode.java => ConfigNode.java} | 48 ++- .../configuration/node/EnhancedValueNode.java | 29 -- .../configuration/node/MVCommentedNode.java | 91 ----- .../configuration/node/Node.java | 13 + .../configuration/node/NodeGroup.java | 41 +- .../configuration/node/ValueNode.java | 45 +++ .../multiverse/core/config/ConfigTest.kt | 24 +- 25 files changed, 644 insertions(+), 623 deletions(-) delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigHandle.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/CommentedNode.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java rename src/main/java/com/onarandombox/MultiverseCore/configuration/node/{MVValueNode.java => ConfigNode.java} (79%) delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/EnhancedValueNode.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVCommentedNode.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/Node.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java index 090fc296..315d7f0d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java @@ -2,6 +2,7 @@ package com.onarandombox.MultiverseCore.api; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.placeholders.MultiverseCorePlaceholders; +import io.vavr.control.Try; import org.jvnet.hk2.annotations.Contract; @Contract @@ -37,7 +38,7 @@ public interface MVConfig { * @param name The name of the property. * @return The value of the property. */ - Object getProperty(String name); + Try getProperty(String name); /** * Sets a property in the config. @@ -46,7 +47,7 @@ public interface MVConfig { * @param value The value of the property. * @return True if the property was set successfully. */ - boolean setProperty(String name, Object value); + Try setProperty(String name, Object value); /** * Sets world access permissions should be enforced. diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java index 484a3228..f63ce1c3 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java @@ -14,6 +14,7 @@ import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue; import com.onarandombox.MultiverseCore.config.MVCoreConfig; +import io.vavr.control.Try; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -55,20 +56,21 @@ public class ConfigCommand extends MultiverseCommand { } private void showConfigValue(BukkitCommandIssuer issuer, String name) { - Object currentValue = config.getProperty(name); - if (currentValue == null) { - issuer.sendMessage("No such config option: " + name); - return; - } - issuer.sendMessage(name + "is currently set to " + config.getProperty(name)); + config.getProperty(name) + .onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value)) + .onFailure(throwable -> issuer.sendMessage("Unable to get " + name + ": " + throwable.getMessage())); } private void updateConfigValue(BukkitCommandIssuer issuer, String name, Object value) { - if (!config.setProperty(name, value)) { - issuer.sendMessage("Unable to set " + name + " to " + value); - return; - } - config.save(); - issuer.sendMessage("Successfully set " + name + " to " + value); + config.setProperty(name, value) + .onSuccess(success -> { + if (success) { + config.save(); + issuer.sendMessage("Successfully set " + name + " to " + value); + } else { + issuer.sendMessage("Unable to set " + name + " to " + value); + } + }) + .onFailure(throwable -> issuer.sendMessage("Unable to set " + name + " to " + value + ": " + throwable.getMessage())); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java index 3b1ea6b9..ee810d70 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java @@ -15,14 +15,14 @@ import com.onarandombox.MultiverseCore.api.MVWorldManager; import com.onarandombox.MultiverseCore.commandtools.context.GameRuleValue; import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue; import com.onarandombox.MultiverseCore.config.MVCoreConfig; +import com.onarandombox.MultiverseCore.configuration.node.Node; +import com.onarandombox.MultiverseCore.configuration.node.ValueNode; import com.onarandombox.MultiverseCore.destination.DestinationsProvider; import com.onarandombox.MultiverseCore.destination.ParsedDestination; import com.onarandombox.MultiverseCore.display.filters.ContentFilter; import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter; import com.onarandombox.MultiverseCore.utils.PlayerFinder; -import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; -import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode; import jakarta.inject.Inject; import org.bukkit.GameRule; import org.bukkit.entity.Player; @@ -123,7 +123,7 @@ public class MVCommandContexts extends PaperCommandContexts { if (Strings.isNullOrEmpty(configName)) { throw new InvalidCommandArgument("No config name specified."); } - Optional node = config.getNodes().findNode(configName); + Optional node = config.getNodes().findNode(configName); if (node.isEmpty()) { throw new InvalidCommandArgument("The config " + configName + " is not valid."); } @@ -133,12 +133,12 @@ public class MVCommandContexts extends PaperCommandContexts { throw new InvalidCommandArgument("No config value specified."); } - if (!(node.get() instanceof TypedValueNode)) { + if (!(node.get() instanceof ValueNode)) { context.popFirstArg(); return new MVConfigValue(valueString); } - ContextResolver resolver = getResolver(((TypedValueNode) node.get()).getType()); + ContextResolver resolver = getResolver(((ValueNode) node.get()).getType()); if (resolver == null) { context.popFirstArg(); return new MVConfigValue(valueString); diff --git a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java index 27613587..446ea970 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java @@ -7,7 +7,7 @@ import java.nio.file.Path; import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MVConfig; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import com.onarandombox.MultiverseCore.configuration.handle.CommentedYamlConfigHandle; import com.onarandombox.MultiverseCore.configuration.migration.BooleanMigratorAction; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; import com.onarandombox.MultiverseCore.configuration.migration.IntegerMigratorAction; @@ -15,6 +15,7 @@ import com.onarandombox.MultiverseCore.configuration.migration.InvertBoolMigrato import com.onarandombox.MultiverseCore.configuration.migration.MoveMigratorAction; import com.onarandombox.MultiverseCore.configuration.migration.VersionMigrator; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; +import io.vavr.control.Try; import jakarta.inject.Inject; import org.bukkit.plugin.PluginManager; import org.jetbrains.annotations.NotNull; @@ -27,15 +28,14 @@ public class MVCoreConfig implements MVConfig { private final Path configPath; private final MVCoreConfigNodes configNodes; - private final ConfigHandle configHandle; + private final CommentedYamlConfigHandle configHandle; @Inject MVCoreConfig(@NotNull MultiverseCore core, @NotNull PluginManager pluginManager) { this.configPath = Path.of(core.getDataFolder().getPath(), CONFIG_FILENAME); this.configNodes = new MVCoreConfigNodes(pluginManager); - this.configHandle = ConfigHandle.builder(configPath) + this.configHandle = CommentedYamlConfigHandle.builder(configPath, configNodes.getNodes()) .logger(Logging.getLogger()) - .nodes(configNodes.getNodes()) .migrator(ConfigMigrator.builder(configNodes.VERSION) .addVersionMigrator(VersionMigrator.builder(5.0) .addAction(MoveMigratorAction.of("multiverse-configuration.enforceaccess", "world.enforce-access")) @@ -110,12 +110,12 @@ public class MVCoreConfig implements MVConfig { } @Override - public Object getProperty(String name) { + public Try getProperty(String name) { return configHandle.get(name); } @Override - public boolean setProperty(String name, Object value) { + public Try setProperty(String name, Object value) { return configHandle.set(name, value); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfigNodes.java b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfigNodes.java index ae027b4e..4aa05878 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfigNodes.java +++ b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfigNodes.java @@ -1,14 +1,13 @@ package com.onarandombox.MultiverseCore.config; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.node.MVCommentedNode; -import com.onarandombox.MultiverseCore.configuration.node.MVValueNode; +import com.onarandombox.MultiverseCore.configuration.node.ConfigHeaderNode; +import com.onarandombox.MultiverseCore.configuration.node.ConfigNode; +import com.onarandombox.MultiverseCore.configuration.node.Node; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.event.MVDebugModeEvent; import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; -import jakarta.inject.Inject; import org.bukkit.plugin.PluginManager; -import org.jvnet.hk2.annotations.Service; class MVCoreConfigNodes { @@ -23,12 +22,12 @@ class MVCoreConfigNodes { return nodes; } - private N node(N node) { + private N node(N node) { nodes.add(node); return node; } - private final MVCommentedNode HEADER = node(MVCommentedNode.builder("world") // TODO hacky way to get the header to the top of the file + private final ConfigHeaderNode HEADER = node(ConfigHeaderNode.builder("world") // TODO hacky way to get the header to the top of the file .comment("####################################################################################################") .comment("# #") .comment("# █▀▄▀█ █░█ █░░ ▀█▀ █ █░█ █▀▀ █▀█ █▀ █▀▀   █▀▀ █▀█ █▀█ █▀▀ #") @@ -52,12 +51,12 @@ class MVCoreConfigNodes { .comment("") .build()); -// private final MVCommentedNode WORLD_HEADER = node(MVCommentedNode.builder("world") +// private final ConfigHeaderNode WORLD_HEADER = node(ConfigHeaderNode.builder("world") // .comment("") // .comment("") // .build()); - public final MVValueNode ENFORCE_ACCESS = node(MVValueNode.builder("world.enforce-access", Boolean.class) + public final ConfigNode ENFORCE_ACCESS = node(ConfigNode.builder("world.enforce-access", Boolean.class) .comment("This setting will prevent players from entering worlds they don't have access to.") .comment("If this is set to false, players will be able to enter any world they want.") .comment("If this is set to true, players will only be able to enter worlds they have") @@ -66,7 +65,7 @@ class MVCoreConfigNodes { .name("enforce-access") .build()); - public final MVValueNode ENFORCE_GAMEMODE = node(MVValueNode.builder("world.enforce-gamemode", Boolean.class) + public final ConfigNode ENFORCE_GAMEMODE = node(ConfigNode.builder("world.enforce-gamemode", Boolean.class) .comment("") .comment("Sets whether Multiverse will should enforce gamemode on world change.") .comment("If enabled, players will be forced into the gamemode of the world they are entering, unless they have") @@ -75,14 +74,14 @@ class MVCoreConfigNodes { .name("enforce-gamemode") .build()); - public final MVValueNode AUTO_PURGE_ENTITIES = node(MVValueNode.builder("world.auto-purge-entities", Boolean.class) + public final ConfigNode AUTO_PURGE_ENTITIES = node(ConfigNode.builder("world.auto-purge-entities", Boolean.class) .comment("") .comment("Sets whether Multiverse will purge mobs and entities with be automatically.") .defaultValue(false) .name("auto-purge-entities") .build()); - public final MVValueNode TELEPORT_INTERCEPT = node(MVValueNode.builder("world.teleport-intercept", Boolean.class) + public final ConfigNode TELEPORT_INTERCEPT = node(ConfigNode.builder("world.teleport-intercept", Boolean.class) .comment("") .comment("If this is set to true, Multiverse will enforce access permissions for all teleportation,") .comment("including teleportation from other plugins.") @@ -90,12 +89,12 @@ class MVCoreConfigNodes { .name("teleport-intercept") .build()); - private final MVCommentedNode SPAWN_HEADER = node(MVCommentedNode.builder("spawn") + private final ConfigHeaderNode SPAWN_HEADER = node(ConfigHeaderNode.builder("spawn") .comment("") .comment("") .build()); - public final MVValueNode FIRST_SPAWN_OVERRIDE = node(MVValueNode.builder("spawn.first-spawn-override", Boolean.class) + public final ConfigNode FIRST_SPAWN_OVERRIDE = node(ConfigNode.builder("spawn.first-spawn-override", Boolean.class) .comment("Sets whether Multiverse will override the first spawn location of a world.") .comment("If enabled, Multiverse will set the first spawn location of a world to the spawn location of the world.") .comment("If disabled, it will default to server.properties settings.") @@ -103,7 +102,7 @@ class MVCoreConfigNodes { .name("first-spawn-override") .build()); - public final MVValueNode FIRST_SPAWN_LOCATION = node(MVValueNode.builder("spawn.first-spawn-location", String.class) + public final ConfigNode FIRST_SPAWN_LOCATION = node(ConfigNode.builder("spawn.first-spawn-location", String.class) .comment("") .comment("Sets the world that Multiverse will use as the location for players that first join the server.") .comment("This only applies if first-spawn-override is set to true.") @@ -111,19 +110,19 @@ class MVCoreConfigNodes { .name("first-spawn-location") .build()); - private final MVCommentedNode PORTAL_HEADER = node(MVCommentedNode.builder("portal") + private final ConfigHeaderNode PORTAL_HEADER = node(ConfigHeaderNode.builder("portal") .comment("") .comment("") .build()); - public final MVValueNode USE_CUSTOM_PORTAL_SEARCH = node(MVValueNode.builder("portal.use-custom-portal-search", Boolean.class) + public final ConfigNode USE_CUSTOM_PORTAL_SEARCH = node(ConfigNode.builder("portal.use-custom-portal-search", Boolean.class) .comment("This config option defines whether or not Multiverse should interfere with's Bukkit's default portal search radius.") .comment("Setting it to false would mean you want to simply let Bukkit decides the search radius itself.") .defaultValue(false) .name("use-custom-portal-search") .build()); - public final MVValueNode CUSTOM_PORTAL_SEARCH_RADIUS = node(MVValueNode.builder("portal.custom-portal-search-radius", Integer.class) + public final ConfigNode CUSTOM_PORTAL_SEARCH_RADIUS = node(ConfigNode.builder("portal.custom-portal-search-radius", Integer.class) .comment("") .comment("This config option defines the search radius Multiverse should use when searching for a portal.") .comment("This only applies if use-custom-portal-search is set to true.") @@ -132,19 +131,19 @@ class MVCoreConfigNodes { .validator(value -> value >= 0) .build()); - private final MVCommentedNode MESSAGING_HEADER = node(MVCommentedNode.builder("messaging") + private final ConfigHeaderNode MESSAGING_HEADER = node(ConfigHeaderNode.builder("messaging") .comment("") .comment("") .build()); - public final MVValueNode ENABLE_CHAT_PREFIX = node(MVValueNode.builder("messaging.enable-chat-prefix", Boolean.class) + public final ConfigNode ENABLE_CHAT_PREFIX = node(ConfigNode.builder("messaging.enable-chat-prefix", Boolean.class) .comment("This config option defines whether or not Multiverse should prefix the chat with the world name.") .comment("This only applies if use-custom-portal-search is set to true.") .defaultValue(false) .name("enable-chat-prefix") .build()); - public final MVValueNode CHAT_PREFIX_FORMAT = node(MVValueNode.builder("messaging.chat-prefix-format", String.class) + public final ConfigNode CHAT_PREFIX_FORMAT = node(ConfigNode.builder("messaging.chat-prefix-format", String.class) .comment("") .comment("This config option defines the format Multiverse should use when prefixing the chat with the world name.") .comment("This only applies if enable-chat-prefix is set to true.") @@ -152,7 +151,7 @@ class MVCoreConfigNodes { .name("chat-prefix-format") .build()); - public final MVValueNode REGISTER_PAPI_HOOK = node(MVValueNode.builder("messaging.register-papi-hook", Boolean.class) + public final ConfigNode REGISTER_PAPI_HOOK = node(ConfigNode.builder("messaging.register-papi-hook", Boolean.class) .comment("") .comment("This config option defines whether or not Multiverse should register the PlaceholderAPI hook.") .comment("This only applies if PlaceholderAPI is installed.") @@ -160,12 +159,12 @@ class MVCoreConfigNodes { .name("register-papi-hook") .build()); - private final MVCommentedNode MISC_HEADER = node(MVCommentedNode.builder("misc") + private final ConfigHeaderNode MISC_HEADER = node(ConfigHeaderNode.builder("misc") .comment("") .comment("") .build()); - public final MVValueNode GLOBAL_DEBUG = node(MVValueNode.builder("misc.global-debug", Integer.class) + public final ConfigNode GLOBAL_DEBUG = node(ConfigNode.builder("misc.global-debug", Integer.class) .comment("This is our debug flag to help identify issues with Multiverse.") .comment("If you are having issues with Multiverse, please set this to 3 and then post your log to pastebin.com") .comment("Otherwise, there's no need to touch this. If not instructed by a wiki page or developer.") @@ -185,7 +184,7 @@ class MVCoreConfigNodes { }) .build()); - public final MVValueNode SILENT_START = node(MVValueNode.builder("misc.silent-start", Boolean.class) + public final ConfigNode SILENT_START = node(ConfigNode.builder("misc.silent-start", Boolean.class) .comment("") .comment("If true, the startup console messages will no longer show.") .defaultValue(false) @@ -193,14 +192,14 @@ class MVCoreConfigNodes { .onSetValue((oldValue, newValue) -> Logging.setShowingConfig(!newValue)) .build()); - public final MVValueNode SHOW_DONATION_MESSAGE = node(MVValueNode.builder("misc.show-donation-message", Boolean.class) + public final ConfigNode SHOW_DONATION_MESSAGE = node(ConfigNode.builder("misc.show-donation-message", Boolean.class) .comment("") .comment("If you don't want to donate, you can set this to false and Multiverse will stop nagging you.") .defaultValue(true) .name("show-donation-message") .build()); - public final MVValueNode VERSION = node(MVValueNode.builder("version", Double.class) + public final ConfigNode VERSION = node(ConfigNode.builder("version", Double.class) .comment("") .comment("") .comment("This just signifies the version number so we can see what version of config you have.") diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigHandle.java deleted file mode 100644 index 4aabb2d7..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/ConfigHandle.java +++ /dev/null @@ -1,360 +0,0 @@ -package com.onarandombox.MultiverseCore.configuration; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.util.logging.Logger; - -import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; -import com.onarandombox.MultiverseCore.configuration.node.EnhancedValueNode; -import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; -import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration; -import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; -import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode; -import io.github.townyadvanced.commentedconfiguration.setting.ValueNode; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * A class that makes use of CommentedConfiguration to provide a simple way to load and save with node objects. - */ -public class ConfigHandle { - - /** - * A builder class for creating a ConfigHandle. - * - * @param configPath The path to the configuration file in string. - * @return A new Builder instance. - */ - public static Builder builder(String configPath) { - return new Builder(configPath); - } - - /** - * A builder class for creating a ConfigHandle. - * - * @param configPath The path to the configuration file. - * @return A new Builder instance. - */ - public static Builder builder(Path configPath) { - return new Builder(configPath); - } - - @NotNull - protected final Path configPath; - @Nullable - protected final Logger logger; - @NotNull - protected final NodeGroup nodes; - - protected final ConfigMigrator migrator; - - protected CommentedConfiguration config; - - /** - * Creates a new MVSettings instance that makes use of CommentedConfiguration. - * - * @param configPath The path to the configuration file. - * @param logger The Logger to use for error messages. - * @param nodes All the node path and values for the configuration. - * @param migrator The migrator to use for migrating the configuration. - */ - protected ConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, ConfigMigrator migrator) { - this.configPath = configPath; - this.nodes = nodes; - this.logger = logger; - this.migrator = migrator; - } - - /** - * Loads the configuration. - * - * @return True if the configuration was loaded successfully, false otherwise. - */ - public boolean load() { - if (!createConfigFile()) { - return false; - } - this.config = new CommentedConfiguration(configPath, logger); - if (!config.load()) { - return false; - } - migrateConfig(); - parseAllNodes(); - return true; - } - - /** - * Create a new config file if file does not exist - * - * @return True if file exist or created successfully, otherwise false. - */ - protected boolean createConfigFile() { - File configFile = configPath.toFile(); - if (configFile.exists()) { - return true; - } - try { - if (!configFile.createNewFile()) { - return false; - } - Logging.info("Created new config file: %s", configFile.getName()); - } catch (IOException e) { - return false; - } - return true; - } - - /** - * Migration of the configuration based on {@link ConfigMigrator}. - */ - protected void migrateConfig() { - migrator.migrate(this); - } - - /** - * Adds default node values to the configuration if they are not already present. - */ - protected void parseAllNodes() { - CommentedConfiguration oldConfig = config; - this.config = new CommentedConfiguration(configPath, logger); - for (CommentedNode node : nodes) { - if (node.getComments().length > 0) { - config.addComment(node.getPath(), node.getComments()); - } - if (node instanceof TypedValueNode typedNode) { - if (!set(typedNode, oldConfig.getObject(node.getPath(), typedNode.getType(), typedNode.getDefaultValue()))) { - Logging.warning("Invalid value for node: %s, resetting to default...", node.getPath()); - setDefault(typedNode); - } - } else if (node instanceof ValueNode valueNode) { - if (!set(valueNode, oldConfig.get(node.getPath(), valueNode.getDefaultValue()))) { - Logging.warning("Invalid value for node: %s, resetting to default...", node.getPath()); - setDefault(valueNode); - } - } - } - } - - /** - * Saves the configuration. - */ - public void save() { - config.save(); - } - - /** - * Checks if the configuration is loaded. - * - * @return True if the configuration is loaded, false otherwise. - */ - public boolean isLoaded() { - return config != null; - } - - /** - * Gets the value of a node, if the node has a default value, it will be returned if the node is not found. - * - * @param node The node to get the value of. - * @return The value of the node. - */ - public Object get(@NotNull ValueNode node) { - return config.get(node.getPath(), node.getDefaultValue()); - } - - /** - * Get the value of the node by name. - * - * @param name The name of the node to get the value of. - * @return The value of the node. - */ - public Object get(@NotNull String name) { - return nodes.findNode(name) - .map(node -> (node instanceof ValueNode) ? get((ValueNode) node) : null) - .orElse(null); - } - - /** - * Gets the value of a node, if the node has a default value, it will be returned if the node is not found. - * - * @param node The node to get the value of. - * @param type The type of the node value. - * @param The type of the node value. - * @return The value of the node. - */ - public T get(@NotNull ValueNode node, Class type) { - return config.getObject(node.getPath(), type, (T) node.getDefaultValue()); - } - - /** - * Gets the value of a node, if the node has a default value, it will be returned if the node is not found. - * - * @param node The node to get the value of. - * @param The type of the node value. - * @return The value of the node. - */ - public T get(@NotNull TypedValueNode node) { - return config.getObject(node.getPath(), node.getType(), node.getDefaultValue()); - } - - /** - * Set the value of the node by name. - * - * @param name The name of the node to set the value of. - * @param value The value to set. - */ - public boolean set(@NotNull String name, Object value) { - return nodes.findNode(name) - .map(node -> node instanceof ValueNode && set((ValueNode) node, value)) - .orElse(false); - } - - /** - * Sets the value of a node, if the validator is not null, it will be tested first. - * - * @param node The node to set the value of. - * @param value The value to set. - */ - public boolean set(@NotNull ValueNode node, Object value) { - if (node instanceof TypedValueNode typedValueNode) { - return set(typedValueNode, value); - } - config.set(node.getPath(), value); - return true; - } - - /** - * Sets the value of a node, if the validator is not null, it will be tested first. - * - * @param node The node to set the value of. - * @param value The value to set. - * @param The type of the node value. - */ - public boolean set(@NotNull TypedValueNode node, T value) { - if (node instanceof EnhancedValueNode enhancedValueNode) { - return set(enhancedValueNode, value); - } - config.set(node.getPath(), value); - return true; - } - - /** - * Sets the value of a node, if the validator is not null, it will be tested first. - * - * @param node The node to set the value of. - * @param value The value to set. - * @return True if the value was set, false otherwise. - * @param The type of the node value. - */ - public boolean set(@NotNull EnhancedValueNode node, T value) { - if (!node.isValid(value)) { - return false; - } - T oldValue = get(node); - config.set(node.getPath(), value); - node.onSetValue(oldValue, get(node)); - return true; - } - - /** - * Sets the default value of a node. - * - * @param node The node to set the default value of. - */ - public void setDefault(@NotNull ValueNode node) { - config.set(node.getPath(), node.getDefaultValue()); - } - - /** - * Gets the inner configuration object. - * - * @return The configuration object. - */ - public @NotNull CommentedConfiguration getConfig() { - return config; - } - - /** - * Gets the path of the configuration file. - */ - public static class Builder { - - private final Path configPath; - private Logger logger; - private NodeGroup nodes; - - private ConfigMigrator migrator; - - /** - * Creates a new builder. - * - * @param configPath The path of the configuration file. - */ - public Builder(String configPath) { - this.configPath = Path.of(configPath); - } - - /** - * Creates a new builder. - * - * @param configPath The path of the configuration file. - */ - public Builder(Path configPath) { - this.configPath = configPath; - } - - /** - * Sets the logger to use. - * - * @param plugin The plugin to get the logger from. - * @return The builder. - */ - public Builder logger(@NotNull Plugin plugin) { - return logger(plugin.getLogger()); - } - - /** - * Sets the logger to use. - * - * @param logger The logger to use. - * @return The builder. - */ - public Builder logger(@Nullable Logger logger) { - this.logger = logger; - return this; - } - - /** - * Sets the nodes to use. - * - * @param nodes The nodes to use. - * @return The builder. - */ - public Builder nodes(@Nullable NodeGroup nodes) { - this.nodes = nodes; - return this; - } - - /** - * Sets the migrator to use. - * - * @param migrator The migrator to use. - * @return The builder. - */ - public Builder migrator(@Nullable ConfigMigrator migrator) { - this.migrator = migrator; - return this; - } - - /** - * Builds the settings. - * - * @return The built settings. - */ - public ConfigHandle build() { - return new ConfigHandle(configPath, logger, nodes, migrator); - } - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java new file mode 100644 index 00000000..d2f49f09 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java @@ -0,0 +1,68 @@ +package com.onarandombox.MultiverseCore.configuration.handle; + +import java.nio.file.Path; +import java.util.logging.Logger; + +import com.dumptruckman.minecraft.util.Logging; +import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; +import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; +import com.onarandombox.MultiverseCore.configuration.node.CommentedNode; +import com.onarandombox.MultiverseCore.configuration.node.ValueNode; +import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CommentedYamlConfigHandle extends FileConfigHandle { + + public static @NotNull Builder builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + return new Builder(configPath, nodes); + } + + protected CommentedYamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + super(configPath, logger, nodes, migrator); + } + + @Override + protected boolean loadConfigObject() { + config = new CommentedConfiguration(configPath, logger); + return config.load(); + } + + @Override + protected void setUpNodes() { + CommentedConfiguration oldConfig = config; + this.config = new CommentedConfiguration(configPath, logger); + + nodes.forEach(node -> { + if (node instanceof CommentedNode typedNode) { + if (typedNode.getComments().length > 0) { + config.addComment(typedNode.getPath(), typedNode.getComments()); + } + } + if (node instanceof ValueNode valueNode) { + set(valueNode, oldConfig.getObject(valueNode.getPath(), valueNode.getType(), valueNode.getDefaultValue())).onFailure(e -> { + Logging.warning("Failed to set node " + valueNode.getPath() + " to " + valueNode.getDefaultValue()); + setDefault(valueNode); + }); + } + }); + } + + @Override + public boolean save() { + config.save(); + return true; + } + + public static class Builder extends FileConfigHandle.Builder { + + protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + super(configPath, nodes); + } + + @Override + public @NotNull CommentedYamlConfigHandle build() { + return new CommentedYamlConfigHandle(configPath, logger, nodes, migrator); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java new file mode 100644 index 00000000..058ff757 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -0,0 +1,208 @@ +package com.onarandombox.MultiverseCore.configuration.handle; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.logging.Logger; + +import com.dumptruckman.minecraft.util.Logging; +import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; +import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; +import com.onarandombox.MultiverseCore.configuration.node.ValueNode; +import io.vavr.control.Try; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +abstract class FileConfigHandle { + + protected final @NotNull Path configPath; + protected final @NotNull File configFile; + protected final @Nullable Logger logger; + protected final @NotNull NodeGroup nodes; + protected final @Nullable ConfigMigrator migrator; + + protected C config; + + protected FileConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + this.configPath = configPath; + this.configFile = configPath.toFile(); + this.logger = logger; + this.nodes = nodes; + this.migrator = migrator; + } + + /** + * Loads the configuration. + * + * @return True if the configuration was loaded successfully, false otherwise. + */ + public boolean load() { + if (!createConfigFile()) { + Logging.severe("Failed to create config file: %s", configFile.getName()); + return false; + } + if (!loadConfigObject()) { + Logging.severe("Failed to load config file: %s", configFile.getName()); + return false; + } + migrateConfig(); + setUpNodes(); + return true; + } + + /** + * Create a new config file if file does not exist + * + * @return True if file exist or created successfully, otherwise false. + */ + protected boolean createConfigFile() { + if (configFile.exists()) { + return true; + } + try { + if (!configFile.createNewFile()) { + return false; + } + Logging.info("Created new config file: %s", configFile.getName()); + } catch (IOException e) { + return false; + } + return true; + } + + protected abstract boolean loadConfigObject(); + + protected void migrateConfig() { + if (migrator != null) { + migrator.migrate(config); + } + } + + protected abstract void setUpNodes(); + + /** + * Saves the configuration. + */ + public abstract boolean save(); + + /** + * Checks if the configuration is loaded. + * + * @return True if the configuration is loaded, false otherwise. + */ + public boolean isLoaded() { + return config != null; + } + + /** + * Gets the configuration. + * + * @return The configuration. + */ + public C getConfig() { + return config; + } + + public Try get(@Nullable String name) { + return nodes.findNode(name, ValueNode.class) + .map(node -> Try.of(() -> get(node))) + .orElse(Try.failure(new Exception("Node not found"))); + } + + /** + * Gets the value of a node, if the node has a default value, it will be returned if the node is not found. + * + * @param node The node to get the value of. + * @return The value of the node. + */ + public T get(@NotNull ValueNode node) { + return config.getObject(node.getPath(), node.getType(), node.getDefaultValue()); + } + + public Try set(@Nullable String name, Object value) { + return nodes.findNode(name, ValueNode.class) + .map(node -> (Try) set(node, value)) + .orElse(Try.failure(new Exception("Node not found"))); + } + + /** + * Sets the value of a node, if the validator is not null, it will be tested first. + * + * @param node The node to set the value of. + * @param value The value to set. + * @return True if the value was set, false otherwise. + * @param The type of the node value. + */ + public Try set(@NotNull ValueNode node, T value) { + if (!node.validate(value)) { + return Try.failure(new Exception("Validation failed")); + } + T oldValue = get(node); + config.set(node.getPath(), value); + node.onSetValue(oldValue, get(node)); + return Try.success(true); + } + + /** + * Sets the default value of a node. + * + * @param node The node to set the default value of. + */ + public void setDefault(@NotNull ValueNode node) { + config.set(node.getPath(), node.getDefaultValue()); + } + + public static abstract class Builder> { + + protected @NotNull Path configPath; + protected @Nullable Logger logger; + protected @NotNull NodeGroup nodes; + protected @Nullable ConfigMigrator migrator; + + protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + this.configPath = configPath; + this.nodes = nodes; + } + + /** + * Sets the logger. + * + * @param logger The logger. + * @return The builder. + */ + public B logger(@Nullable Logger logger) { + this.logger = logger; + return self(); + } + + public B logger(Plugin plugin) { + this.logger = plugin.getLogger(); + return self(); + } + + /** + * Sets the migrator. + * + * @param migrator The migrator. + * @return The builder. + */ + public B migrator(@Nullable ConfigMigrator migrator) { + this.migrator = migrator; + return self(); + } + + /** + * Builds the configuration handle. + * + * @return The configuration handle. + */ + public abstract @NotNull FileConfigHandle build(); + + @SuppressWarnings("unchecked") + protected B self() { + return (B) this; + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java new file mode 100644 index 00000000..167c33cb --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java @@ -0,0 +1,68 @@ +package com.onarandombox.MultiverseCore.configuration.handle; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.logging.Logger; + +import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; +import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; +import com.onarandombox.MultiverseCore.configuration.node.ValueNode; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class YamlConfigHandle extends FileConfigHandle { + + public static @NotNull Builder builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + return new Builder<>(configPath, nodes); + } + + protected YamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + super(configPath, logger, nodes, migrator); + } + + @Override + protected boolean loadConfigObject() { + config = new YamlConfiguration(); + try { + config.load(configFile); + } catch (IOException | InvalidConfigurationException e) { + return false; + } + return true; + } + + @Override + protected void setUpNodes() { + YamlConfiguration oldConfig = config; + config = new YamlConfiguration(); + nodes.forEach(node -> { + if (node instanceof ValueNode valueNode) { + set(valueNode, oldConfig.getObject(valueNode.getPath(), valueNode.getType(), valueNode.getDefaultValue())); + } + }); + } + + @Override + public boolean save() { + try { + config.save(configFile); + } catch (IOException e) { + return false; + } + return true; + } + + public static class Builder> extends FileConfigHandle.Builder { + + protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + super(configPath, nodes); + } + + @Override + public @NotNull YamlConfigHandle build() { + return new YamlConfigHandle(configPath, logger, nodes, migrator); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/BooleanMigratorAction.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/BooleanMigratorAction.java index b4546215..f89eeb47 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/BooleanMigratorAction.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/BooleanMigratorAction.java @@ -2,7 +2,7 @@ package com.onarandombox.MultiverseCore.configuration.migration; import co.aikar.commands.ACFUtil; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import org.bukkit.configuration.file.FileConfiguration; /** * Single migrator action that converts a string value to a boolean. @@ -20,9 +20,9 @@ public class BooleanMigratorAction implements MigratorAction { } @Override - public void migrate(ConfigHandle settings) { - settings.getConfig().set(path, ACFUtil.isTruthy(settings.getConfig().getString(path, ""))); - Logging.info("Converted %s to boolean %s", path, settings.getConfig().getBoolean(path)); + public void migrate(FileConfiguration config) { + config.set(path, ACFUtil.isTruthy(config.getString(path, ""))); + Logging.info("Converted %s to boolean %s", path, config.getBoolean(path)); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/ConfigMigrator.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/ConfigMigrator.java index 6d7faac3..09381979 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/ConfigMigrator.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/ConfigMigrator.java @@ -4,8 +4,9 @@ import java.util.ArrayList; import java.util.List; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import com.onarandombox.MultiverseCore.configuration.node.ValueNode; import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode; +import org.bukkit.configuration.file.FileConfiguration; /** * Helper class for migrating configs to the latest config version. @@ -19,14 +20,14 @@ public class ConfigMigrator { * Default value should be the current latest version number. * @return The builder instance. */ - public static Builder builder(TypedValueNode versionNode) { + public static Builder builder(ValueNode versionNode) { return new Builder(versionNode); } - private final TypedValueNode versionNode; + private final ValueNode versionNode; private final List versionMigrators; - protected ConfigMigrator(TypedValueNode versionNode, List versionMigrators) { + protected ConfigMigrator(ValueNode versionNode, List versionMigrators) { this.versionNode = versionNode; this.versionMigrators = versionMigrators; } @@ -34,25 +35,25 @@ public class ConfigMigrator { /** * Migrates the config to the latest version if necessary. * - * @param settings The target settings instance to migrate. + * @param config The target settings instance to migrate. */ - public void migrate(ConfigHandle settings) { - double versionNumber = settings.getConfig().getDouble(versionNode.getPath()); + public void migrate(FileConfiguration config) { + double versionNumber = config.getDouble(versionNode.getPath()); for (VersionMigrator versionMigrator : versionMigrators) { if (versionNumber < versionMigrator.getVersion()) { Logging.info("Migrating config from version %s to %s...", versionNumber, versionMigrator.getVersion()); - versionMigrator.migrate(settings); + versionMigrator.migrate(config); } } // Set the version number to the latest version number - settings.setDefault(versionNode); + config.set(versionNode.getPath(), versionNode.getDefaultValue()); } /** * A builder for a ConfigMigrator. */ public static class Builder { - private final TypedValueNode versionNode; + private final ValueNode versionNode; private final List versionMigrators; /** @@ -61,7 +62,7 @@ public class ConfigMigrator { * @param versionNode The node that stores the version number of the config. * Default value should be the current latest version number. */ - public Builder(TypedValueNode versionNode) { + public Builder(ValueNode versionNode) { this.versionNode = versionNode; this.versionMigrators = new ArrayList<>(); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/IntegerMigratorAction.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/IntegerMigratorAction.java index 964187c1..2c2eef07 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/IntegerMigratorAction.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/IntegerMigratorAction.java @@ -2,8 +2,7 @@ package com.onarandombox.MultiverseCore.configuration.migration; import co.aikar.commands.ACFUtil; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; -import org.bukkit.util.NumberConversions; +import org.bukkit.configuration.file.FileConfiguration; /** * Single migrator action that converts a string value to an integer. @@ -21,8 +20,8 @@ public class IntegerMigratorAction implements MigratorAction { } @Override - public void migrate(ConfigHandle settings) { - settings.getConfig().set(path, ACFUtil.parseInt(settings.getConfig().getString(path))); - Logging.info("Converted %s to integer %s", path, settings.getConfig().getInt(path)); + public void migrate(FileConfiguration config) { + config.set(path, ACFUtil.parseInt(config.getString(path))); + Logging.info("Converted %s to integer %s", path, config.getInt(path)); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/InvertBoolMigratorAction.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/InvertBoolMigratorAction.java index e5709242..72366d7d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/InvertBoolMigratorAction.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/InvertBoolMigratorAction.java @@ -1,7 +1,7 @@ package com.onarandombox.MultiverseCore.configuration.migration; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import org.bukkit.configuration.file.FileConfiguration; /** * Single migrator action that inverts a boolean value for a given path. @@ -28,9 +28,9 @@ public class InvertBoolMigratorAction implements MigratorAction { * {@inheritDoc} */ @Override - public void migrate(ConfigHandle settings) { - boolean boolValue = !settings.getConfig().getBoolean(path); - settings.getConfig().set(path, boolValue); + public void migrate(FileConfiguration config) { + boolean boolValue = !config.getBoolean(path); + config.set(path, boolValue); Logging.info("Inverted %s to boolean %s", path, boolValue); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MigratorAction.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MigratorAction.java index 1f3fdbe8..3aaed4e4 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MigratorAction.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MigratorAction.java @@ -1,6 +1,6 @@ package com.onarandombox.MultiverseCore.configuration.migration; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import org.bukkit.configuration.file.FileConfiguration; /** * A migrator action is a single action that is performed when migrating a config. @@ -10,7 +10,7 @@ public interface MigratorAction { /** * Performs the migration action. * - * @param settings The target settings instance to migrate. + * @param config The target settings instance to migrate. */ - void migrate(ConfigHandle settings); + void migrate(FileConfiguration config); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MoveMigratorAction.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MoveMigratorAction.java index 662d5685..498c440b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MoveMigratorAction.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/MoveMigratorAction.java @@ -3,7 +3,7 @@ package com.onarandombox.MultiverseCore.configuration.migration; import java.util.Optional; import com.dumptruckman.minecraft.util.Logging; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import org.bukkit.configuration.file.FileConfiguration; /** * Single migrator action that moves a value from one path to another. @@ -33,11 +33,11 @@ public class MoveMigratorAction implements MigratorAction { * {@inheritDoc} */ @Override - public void migrate(ConfigHandle settings) { - Optional.ofNullable(settings.getConfig().get(fromPath)) + public void migrate(FileConfiguration config) { + Optional.ofNullable(config.get(fromPath)) .ifPresent(value -> { - settings.getConfig().set(toPath, value); - settings.getConfig().set(fromPath, null); + config.set(toPath, value); + config.set(fromPath, null); Logging.config("Moved path %s to %s", fromPath, toPath); }); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/VersionMigrator.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/VersionMigrator.java index e0aacbfd..0bb072a0 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/VersionMigrator.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/migration/VersionMigrator.java @@ -3,7 +3,7 @@ package com.onarandombox.MultiverseCore.configuration.migration; import java.util.ArrayList; import java.util.List; -import com.onarandombox.MultiverseCore.configuration.ConfigHandle; +import org.bukkit.configuration.file.FileConfiguration; /** * A version migrator is a collection of migrator actions that are performed when migrating a config to a specific version. @@ -31,10 +31,10 @@ public class VersionMigrator { /** * Performs all the migrator actions. * - * @param settings The target settings instance to migrate. + * @param config The target settings instance to migrate. */ - public void migrate(ConfigHandle settings) { - actions.forEach(action -> action.migrate(settings)); + public void migrate(FileConfiguration config) { + actions.forEach(action -> action.migrate(config)); } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/CommentedNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/CommentedNode.java new file mode 100644 index 00000000..80a085ed --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/CommentedNode.java @@ -0,0 +1,13 @@ +package com.onarandombox.MultiverseCore.configuration.node; + +import org.jetbrains.annotations.NotNull; + +public interface CommentedNode extends Node { + + /** + * Gets the comment of the node. + * + * @return The comment of the node. + */ + @NotNull String[] getComments(); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java new file mode 100644 index 00000000..da65fcfe --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java @@ -0,0 +1,83 @@ +package com.onarandombox.MultiverseCore.configuration.node; + +import java.util.ArrayList; +import java.util.Collections; + +import com.google.common.base.Strings; +import org.jetbrains.annotations.NotNull; + +public class ConfigHeaderNode implements CommentedNode { + + /** + * Creates a new builder for a {@link ConfigHeaderNode}. + * + * @param path The path of the node. + * @return The new builder. + */ + public static Builder builder(String path) { + return new Builder<>(path); + } + + private final String path; + private final String[] comments; + + protected ConfigHeaderNode(String path, String[] comments) { + this.path = path; + this.comments = comments; + } + + /** + * {@inheritDoc} + */ + @Override + public @NotNull String getPath() { + return path; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getComments() { + return comments; + } + + public static class Builder> { + + protected final String path; + protected final ArrayList comments; + + public Builder(String path) { + this.path = path; + this.comments = new ArrayList<>(); + } + + /** + * Adds a comment line to the node. + * + * @param comment The comment to add. + * @return This builder. + */ + public B comment(String comment) { + if (!Strings.isNullOrEmpty(comment) && !comment.startsWith("#")) { + comment = "# " + comment; + } + comments.add(comment); + return (B) this; + } + + public B comment(String... comments) { + Collections.addAll(this.comments, comments); + return (B) this; + } + + public B comment(Iterable comments) { + comments.forEach(this.comments::add); + return (B) this; + } + + public ConfigHeaderNode build() { + return new ConfigHeaderNode(path, comments.toArray(new String[0])); + } + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVValueNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java similarity index 79% rename from src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVValueNode.java rename to src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java index c8b9d9df..1e7982a4 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVValueNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java @@ -7,39 +7,43 @@ import java.util.function.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -/** - * Implementation of {@link EnhancedValueNode}. - * @param The type of the value. - */ -public class MVValueNode extends MVCommentedNode implements EnhancedValueNode { +public class ConfigNode extends ConfigHeaderNode implements ValueNode { /** - * Creates a new builder for a {@link MVValueNode}. + * Creates a new builder for a {@link ConfigNode}. * * @param path The path of the node. * @param type The type of the value. * @return The new builder. * @param The type of the value. */ - public static Builder builder(String path, Class type) { - return new Builder<>(path, type); + public static ConfigNode.Builder builder(String path, Class type) { + return new ConfigNode.Builder<>(path, type); } + protected final String name; protected final Class type; protected final T defaultValue; - protected final String name; protected final Function validator; protected final BiConsumer onSetValue; - protected MVValueNode(String path, String[] comments, Class type, T defaultValue, String name, Function validator, BiConsumer onSetValue) { + protected ConfigNode(String path, String[] comments, String name, Class type, T defaultValue, Function validator, BiConsumer onSetValue) { super(path, comments); + this.name = name; this.type = type; this.defaultValue = defaultValue; - this.name = name; this.validator = validator; this.onSetValue = onSetValue; } + /** + * {@inheritDoc} + */ + @Override + public Optional getName() { + return Optional.ofNullable(name); + } + /** * {@inheritDoc} */ @@ -60,15 +64,7 @@ public class MVValueNode extends MVCommentedNode implements EnhancedValueNode * {@inheritDoc} */ @Override - public Optional getName() { - return Optional.ofNullable(name); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isValid(T value) { + public boolean validate(T value) { if (validator != null) { return validator.apply(value); } @@ -86,16 +82,16 @@ public class MVValueNode extends MVCommentedNode implements EnhancedValueNode } /** - * Builder for {@link MVValueNode}. + * Builder for {@link ConfigNode}. * * @param The type of the value. * @param The type of the builder. */ - public static class Builder> extends MVCommentedNode.Builder { + public static class Builder> extends ConfigHeaderNode.Builder { + protected String name; protected final Class type; protected T defaultValue; - protected String name; protected Function validator; protected BiConsumer onSetValue; @@ -107,8 +103,8 @@ public class MVValueNode extends MVCommentedNode implements EnhancedValueNode */ protected Builder(@NotNull String path, @NotNull Class type) { super(path); - this.type = type; this.name = path; + this.type = type; } /** @@ -153,8 +149,8 @@ public class MVValueNode extends MVCommentedNode implements EnhancedValueNode * {@inheritDoc} */ @Override - public MVValueNode build() { - return new MVValueNode<>(path, comments.toArray(new String[0]), type, defaultValue, name, validator, onSetValue); + public ConfigNode build() { + return new ConfigNode<>(path, comments.toArray(new String[0]), name, type, defaultValue, validator, onSetValue); } } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/EnhancedValueNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/EnhancedValueNode.java deleted file mode 100644 index c29ecf17..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/EnhancedValueNode.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.onarandombox.MultiverseCore.configuration.node; - -import java.util.Optional; - -import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode; - -/** - * A {@link TypedValueNode} that has a name, validation, and action to be performed when the value is set. - * - * @param The type of the node's value. - */ -public interface EnhancedValueNode extends TypedValueNode { - /** - * Gets the name of this node. Used for identifying the node from user input. - * - * @return The name of this node. - */ - Optional getName(); - - boolean isValid(T value); - - /** - * Called when the value of this node is set. - * - * @param oldValue The old value. - * @param newValue The new value. - */ - void onSetValue(T oldValue, T newValue); -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVCommentedNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVCommentedNode.java deleted file mode 100644 index eaf2637c..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/MVCommentedNode.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.onarandombox.MultiverseCore.configuration.node; - -import java.util.ArrayList; -import java.util.List; - -import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; -import org.jetbrains.annotations.NotNull; - -/** - * Implementation of {@link CommentedNode} that allows for comments to be added to the node. - */ -public class MVCommentedNode implements CommentedNode { - - /** - * Creates a new builder for a {@link MVCommentedNode}. - * - * @param path The path of the node. - * @return The new builder. - */ - public static Builder builder(String path) { - return new Builder<>(path); - } - - protected final String path; - protected final String[] comments; - - protected MVCommentedNode(String path, String[] comments) { - this.path = path; - this.comments = comments; - } - - /** - * {@inheritDoc} - */ - @Override - public @NotNull String getPath() { - return path; - } - - /** - * {@inheritDoc} - */ - @Override - public @NotNull String[] getComments() { - return comments; - } - - /** - * Builder for {@link MVCommentedNode}. - * - * @param The type of the builder. - */ - public static class Builder { - protected final String path; - protected final List comments; - - /** - * Creates a new builder for a {@link MVCommentedNode}. - * - * @param path The path of the node. - */ - protected Builder(String path) { - this.path = path; - this.comments = new ArrayList<>(); - } - - /** - * Adds a comment line to the node. - * - * @param comment The comment to add. - * @return This builder. - */ - public B comment(@NotNull String comment) { - if (!comment.isEmpty() && !comment.trim().startsWith("#")) { - // Automatically add a comment prefix if the comment doesn't start with one. - comment = "# " + comment; - } - this.comments.add(comment); - return (B) this; - } - - /** - * Builds the node. - * - * @return The built node. - */ - public MVCommentedNode build() { - return new MVCommentedNode(path, comments.toArray(new String[0])); - } - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/Node.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/Node.java new file mode 100644 index 00000000..790b2de4 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/Node.java @@ -0,0 +1,13 @@ +package com.onarandombox.MultiverseCore.configuration.node; + +import org.jetbrains.annotations.NotNull; + +public interface Node { + + /** + * Gets the YAML path of the node. + * + * @return The YAML path of the node. + */ + @NotNull String getPath(); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java index 810d5c2b..ad929e97 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java @@ -13,30 +13,30 @@ import org.jetbrains.annotations.NotNull; /** * A collection of {@link CommentedNode}s, with mappings to nodes by name. */ -public class NodeGroup implements Collection { - private final Collection nodes; - private final Map nodesMap; +public class NodeGroup implements Collection { + private final Collection nodes; + private final Map nodesMap; public NodeGroup() { this.nodes = new ArrayList<>(); this.nodesMap = new HashMap<>(); } - public NodeGroup(Collection nodes) { + public NodeGroup(Collection nodes) { this.nodes = nodes; this.nodesMap = new HashMap<>(nodes.size()); nodes.forEach(this::addNodeIndex); } - private void addNodeIndex(CommentedNode node) { - if (node instanceof EnhancedValueNode) { - ((EnhancedValueNode) node).getName().ifPresent(name -> nodesMap.put(name, node)); + private void addNodeIndex(Node node) { + if (node instanceof ValueNode) { + ((ValueNode) node).getName().ifPresent(name -> nodesMap.put(name, node)); } } - private void removeNodeIndex(CommentedNode node) { - if (node instanceof EnhancedValueNode) { - ((EnhancedValueNode) node).getName().ifPresent(nodesMap::remove); + private void removeNodeIndex(Node node) { + if (node instanceof ValueNode) { + ((ValueNode) node).getName().ifPresent(nodesMap::remove); } } @@ -49,14 +49,19 @@ public class NodeGroup implements Collection { return nodesMap.keySet(); } + public Optional findNode(String name) { + return Optional.ofNullable(nodesMap.get(name)); + } + /** * Gets the node with the given name. * * @param name The name of the node to get. * @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists. */ - public Optional findNode(String name) { - return Optional.ofNullable(nodesMap.get(name)); + public Optional findNode(String name, Class type) { + return Optional.ofNullable(nodesMap.get(name)) + .map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null); } @Override @@ -76,7 +81,7 @@ public class NodeGroup implements Collection { @NotNull @Override - public Iterator iterator() { + public Iterator iterator() { return nodes.iterator(); } @@ -91,9 +96,9 @@ public class NodeGroup implements Collection { } @Override - public boolean add(CommentedNode commentedNode) { - if (nodes.add(commentedNode)) { - addNodeIndex(commentedNode); + public boolean add(Node node) { + if (nodes.add(node)) { + addNodeIndex(node); return true; } return false; @@ -102,7 +107,7 @@ public class NodeGroup implements Collection { @Override public boolean remove(Object o) { if (nodes.remove(o) && o instanceof CommentedNode) { - removeNodeIndex((CommentedNode) o); + removeNodeIndex((Node) o); return true; } return false; @@ -114,7 +119,7 @@ public class NodeGroup implements Collection { } @Override - public boolean addAll(@NotNull Collection collection) { + public boolean addAll(@NotNull Collection collection) { return nodes.addAll(collection); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java new file mode 100644 index 00000000..aa183b6f --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java @@ -0,0 +1,45 @@ +package com.onarandombox.MultiverseCore.configuration.node; + +import java.util.Optional; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface ValueNode extends Node { + /** + * Gets the name of this node. Used for identifying the node from user input. + * + * @return The name of this node. + */ + Optional getName(); + + /** + * Gets the class type {@link T} of the node value. + * + * @return The class type of the node value. + */ + @NotNull Class getType(); + + /** + * Gets the default value with type {@link T} of the node. + * + * @return The default value of the node. + */ + @Nullable T getDefaultValue(); + + /** + * Validates the value of this node. + * + * @param value The value to validate. + * @return True if the value is valid, false otherwise. + */ + boolean validate(T value); + + /** + * Called when the value of this node is set. + * + * @param oldValue The old value. + * @param newValue The new value. + */ + void onSetValue(T oldValue, T newValue); +} diff --git a/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt b/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt index d106b727..8f5578fc 100644 --- a/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt +++ b/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt @@ -59,14 +59,14 @@ class ConfigTest : TestWithMockBukkit() { @Test fun `Getting existing config property with getProperty returns expected value`() { - assertEquals(false, config.getProperty("enforce-access")) - assertEquals("world", config.getProperty("first-spawn-location")) + assertEquals(false, config.getProperty("enforce-access").get()) + assertEquals("world", config.getProperty("first-spawn-location").get()) } @Test fun `Getting non-existing config property with getProperty returns null`() { - assertNull(config.getProperty("invalid-property")) - assertNull(config.getProperty("version")) + assertTrue(config.getProperty("invalid-property").isFailure) + assertTrue(config.getProperty("version").isFailure) } @Test @@ -77,19 +77,19 @@ class ConfigTest : TestWithMockBukkit() { @Test fun `Updating an existing config property with setProperty reflects the changes in getProperty`() { - assertTrue(config.setProperty("enforce-access", true)) - assertEquals(true, config.getProperty("enforce-access")) + assertTrue(config.setProperty("enforce-access", true).get()) + assertEquals(true, config.getProperty("enforce-access").get()) - assertTrue(config.setProperty("first-spawn-location", "world2")) - assertEquals("world2", config.getProperty("first-spawn-location")) + assertTrue(config.setProperty("first-spawn-location", "world2").get()) + assertEquals("world2", config.getProperty("first-spawn-location").get()) - assertTrue(config.setProperty("global-debug", 1)) - assertEquals(1, config.getProperty("global-debug")) + assertTrue(config.setProperty("global-debug", 1).get()) + assertEquals(1, config.getProperty("global-debug").get()) } @Test fun `Updating a non-existing property with setProperty returns false`() { - assertFalse(config.setProperty("invalid-property", false)) - assertFalse(config.setProperty("version", 1.1)) + assertTrue(config.setProperty("invalid-property", false).isFailure) + assertTrue(config.setProperty("version", 1.1).isFailure) } } From 5cc5e6828f02331ffe7718f0a3316148da501ed3 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:15:15 +0800 Subject: [PATCH 2/9] refactor: Allow for nullable NodeGroup --- .../MultiverseCore/config/MVCoreConfig.java | 3 ++- .../handle/CommentedYamlConfigHandle.java | 14 ++++++---- .../handle/FileConfigHandle.java | 20 ++++++++++---- .../handle/YamlConfigHandle.java | 26 +++++++++++++++---- 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java index 446ea970..725e54e1 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java @@ -34,8 +34,9 @@ public class MVCoreConfig implements MVConfig { MVCoreConfig(@NotNull MultiverseCore core, @NotNull PluginManager pluginManager) { this.configPath = Path.of(core.getDataFolder().getPath(), CONFIG_FILENAME); this.configNodes = new MVCoreConfigNodes(pluginManager); - this.configHandle = CommentedYamlConfigHandle.builder(configPath, configNodes.getNodes()) + this.configHandle = CommentedYamlConfigHandle.builder(configPath) .logger(Logging.getLogger()) + .nodes(configNodes.getNodes()) .migrator(ConfigMigrator.builder(configNodes.VERSION) .addVersionMigrator(VersionMigrator.builder(5.0) .addAction(MoveMigratorAction.of("multiverse-configuration.enforceaccess", "world.enforce-access")) diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java index d2f49f09..47adcbbc 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java @@ -14,11 +14,11 @@ import org.jetbrains.annotations.Nullable; public class CommentedYamlConfigHandle extends FileConfigHandle { - public static @NotNull Builder builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { - return new Builder(configPath, nodes); + public static @NotNull Builder builder(@NotNull Path configPath) { + return new Builder(configPath); } - protected CommentedYamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + protected CommentedYamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) { super(configPath, logger, nodes, migrator); } @@ -30,6 +30,10 @@ public class CommentedYamlConfigHandle extends FileConfigHandle { - protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { - super(configPath, nodes); + protected Builder(@NotNull Path configPath) { + super(configPath); } @Override diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java index 058ff757..f6dc4342 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -20,12 +20,12 @@ abstract class FileConfigHandle { protected final @NotNull Path configPath; protected final @NotNull File configFile; protected final @Nullable Logger logger; - protected final @NotNull NodeGroup nodes; + protected final @Nullable NodeGroup nodes; protected final @Nullable ConfigMigrator migrator; protected C config; - protected FileConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + protected FileConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) { this.configPath = configPath; this.configFile = configPath.toFile(); this.logger = logger; @@ -158,12 +158,11 @@ abstract class FileConfigHandle { protected @NotNull Path configPath; protected @Nullable Logger logger; - protected @NotNull NodeGroup nodes; + protected @Nullable NodeGroup nodes; protected @Nullable ConfigMigrator migrator; - protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { + protected Builder(@NotNull Path configPath) { this.configPath = configPath; - this.nodes = nodes; } /** @@ -177,11 +176,22 @@ abstract class FileConfigHandle { return self(); } + /** + * Sets the logger. + * + * @param plugin The plugin to get the logger from. + * @return The builder. + */ public B logger(Plugin plugin) { this.logger = plugin.getLogger(); return self(); } + public B nodes(@Nullable NodeGroup nodes) { + this.nodes = nodes; + return self(); + } + /** * Sets the migrator. * diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java index 167c33cb..5cd24015 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java @@ -14,14 +14,17 @@ import org.jetbrains.annotations.Nullable; public class YamlConfigHandle extends FileConfigHandle { - public static @NotNull Builder builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { - return new Builder<>(configPath, nodes); + public static @NotNull Builder builder(@NotNull Path configPath) { + return new Builder<>(configPath); } - protected YamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @NotNull NodeGroup nodes, @Nullable ConfigMigrator migrator) { + protected YamlConfigHandle(@NotNull Path configPath, @Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) { super(configPath, logger, nodes, migrator); } + /** + * {@inheritDoc} + */ @Override protected boolean loadConfigObject() { config = new YamlConfiguration(); @@ -33,8 +36,15 @@ public class YamlConfigHandle extends FileConfigHandle { return true; } + /** + * {@inheritDoc} + */ @Override protected void setUpNodes() { + if (nodes == null || nodes.isEmpty()) { + return; + } + YamlConfiguration oldConfig = config; config = new YamlConfiguration(); nodes.forEach(node -> { @@ -44,6 +54,9 @@ public class YamlConfigHandle extends FileConfigHandle { }); } + /** + * {@inheritDoc} + */ @Override public boolean save() { try { @@ -56,10 +69,13 @@ public class YamlConfigHandle extends FileConfigHandle { public static class Builder> extends FileConfigHandle.Builder { - protected Builder(@NotNull Path configPath, @NotNull NodeGroup nodes) { - super(configPath, nodes); + protected Builder(@NotNull Path configPath) { + super(configPath); } + /** + * {@inheritDoc} + */ @Override public @NotNull YamlConfigHandle build() { return new YamlConfigHandle(configPath, logger, nodes, migrator); From a19fe76cbce92763276d9458e5e306f2646f1fd8 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:50:00 +0800 Subject: [PATCH 3/9] chore: Add docs and remove some unused methods --- .../handle/CommentedYamlConfigHandle.java | 21 ++++++++++ .../handle/FileConfigHandle.java | 39 +++++++++++++++++++ .../handle/YamlConfigHandle.java | 13 +++++++ .../configuration/node/ConfigHeaderNode.java | 19 ++++----- .../configuration/node/ConfigNode.java | 4 ++ .../configuration/node/NodeGroup.java | 7 ++++ 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java index 47adcbbc..f43a2a86 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/CommentedYamlConfigHandle.java @@ -12,8 +12,17 @@ import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Configuration handle for commented YAML files. + */ public class CommentedYamlConfigHandle extends FileConfigHandle { + /** + * Creates a new builder for a {@link CommentedYamlConfigHandle}. + * + * @param configPath The path to the config file. + * @return The builder. + */ public static @NotNull Builder builder(@NotNull Path configPath) { return new Builder(configPath); } @@ -22,12 +31,18 @@ public class CommentedYamlConfigHandle extends FileConfigHandle The configuration type. + */ abstract class FileConfigHandle { protected final @NotNull Path configPath; @@ -72,14 +76,25 @@ abstract class FileConfigHandle { return true; } + /** + * Loads the configuration object. + * + * @return True if the configuration was loaded successfully, false otherwise. + */ protected abstract boolean loadConfigObject(); + /** + * Migrates the configuration. + */ protected void migrateConfig() { if (migrator != null) { migrator.migrate(config); } } + /** + * Sets up the nodes. + */ protected abstract void setUpNodes(); /** @@ -105,6 +120,11 @@ abstract class FileConfigHandle { return config; } + /** + * Gets the value of a node, if the node has a default value, it will be returned if the node is not found. + * @param name The name of the node. + * @return The value of the node. + */ public Try get(@Nullable String name) { return nodes.findNode(name, ValueNode.class) .map(node -> Try.of(() -> get(node))) @@ -121,6 +141,13 @@ abstract class FileConfigHandle { return config.getObject(node.getPath(), node.getType(), node.getDefaultValue()); } + /** + * Sets the value of a node, if the validator is not null, it will be tested first. + * + * @param name The name of the node. + * @param value The value to set. + * @return True if the value was set, false otherwise. + */ public Try set(@Nullable String name, Object value) { return nodes.findNode(name, ValueNode.class) .map(node -> (Try) set(node, value)) @@ -154,6 +181,12 @@ abstract class FileConfigHandle { config.set(node.getPath(), node.getDefaultValue()); } + /** + * Builder for {@link FileConfigHandle}. + * + * @param The configuration type. + * @param The builder type. + */ public static abstract class Builder> { protected @NotNull Path configPath; @@ -187,6 +220,12 @@ abstract class FileConfigHandle { return self(); } + /** + * Sets the nodes. + * + * @param nodes The nodes. + * @return The builder. + */ public B nodes(@Nullable NodeGroup nodes) { this.nodes = nodes; return self(); diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java index 5cd24015..cfc385b8 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/YamlConfigHandle.java @@ -12,8 +12,17 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Configuration handle for YAML files. + */ public class YamlConfigHandle extends FileConfigHandle { + /** + * Creates a new builder for {@link YamlConfigHandle}. + * + * @param configPath The path to the config file. + * @return The builder. + */ public static @NotNull Builder builder(@NotNull Path configPath) { return new Builder<>(configPath); } @@ -67,6 +76,10 @@ public class YamlConfigHandle extends FileConfigHandle { return true; } + /** + * Builder for {@link YamlConfigHandle}. + * @param The type of the builder. + */ public static class Builder> extends FileConfigHandle.Builder { protected Builder(@NotNull Path configPath) { diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java index da65fcfe..1d121b0c 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java @@ -1,11 +1,13 @@ package com.onarandombox.MultiverseCore.configuration.node; import java.util.ArrayList; -import java.util.Collections; import com.google.common.base.Strings; import org.jetbrains.annotations.NotNull; +/** + * A node that represents a header without any value. + */ public class ConfigHeaderNode implements CommentedNode { /** @@ -66,16 +68,11 @@ public class ConfigHeaderNode implements CommentedNode { return (B) this; } - public B comment(String... comments) { - Collections.addAll(this.comments, comments); - return (B) this; - } - - public B comment(Iterable comments) { - comments.forEach(this.comments::add); - return (B) this; - } - + /** + * Builds the node. + * + * @return The built node. + */ public ConfigHeaderNode build() { return new ConfigHeaderNode(path, comments.toArray(new String[0])); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java index 1e7982a4..4a945fed 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java @@ -7,6 +7,10 @@ import java.util.function.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * A node that contains a value. + * @param The type of the value. + */ public class ConfigNode extends ConfigHeaderNode implements ValueNode { /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java index ad929e97..80e8b56e 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java @@ -49,6 +49,12 @@ public class NodeGroup implements Collection { return nodesMap.keySet(); } + /** + * Gets the node with the given name. + * + * @param name The name of the node to get. + * @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists. + */ public Optional findNode(String name) { return Optional.ofNullable(nodesMap.get(name)); } @@ -57,6 +63,7 @@ public class NodeGroup implements Collection { * Gets the node with the given name. * * @param name The name of the node to get. + * @param type The type of the node to get. * @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists. */ public Optional findNode(String name, Class type) { From 63078270bf29f087046a96c43e16121d419ecd0d Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Tue, 28 Mar 2023 16:22:50 -0400 Subject: [PATCH 4/9] Use Option instead of Optional in NodeGroup. --- .../commandtools/MVCommandContexts.java | 3 ++- .../configuration/handle/FileConfigHandle.java | 8 ++++---- .../configuration/node/NodeGroup.java | 15 +++++++-------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java index ee810d70..1f490ba8 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandtools/MVCommandContexts.java @@ -23,6 +23,7 @@ import com.onarandombox.MultiverseCore.display.filters.ContentFilter; import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter; import com.onarandombox.MultiverseCore.utils.PlayerFinder; +import io.vavr.control.Option; import jakarta.inject.Inject; import org.bukkit.GameRule; import org.bukkit.entity.Player; @@ -123,7 +124,7 @@ public class MVCommandContexts extends PaperCommandContexts { if (Strings.isNullOrEmpty(configName)) { throw new InvalidCommandArgument("No config name specified."); } - Optional node = config.getNodes().findNode(configName); + Option node = config.getNodes().findNode(configName); if (node.isEmpty()) { throw new InvalidCommandArgument("The config " + configName + " is not valid."); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java index 87eb7d40..a9dd8b1b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -127,8 +127,8 @@ abstract class FileConfigHandle { */ public Try get(@Nullable String name) { return nodes.findNode(name, ValueNode.class) - .map(node -> Try.of(() -> get(node))) - .orElse(Try.failure(new Exception("Node not found"))); + .map(node -> get((ValueNode) node)) + .toTry(() -> new Exception("Node not found")); } /** @@ -150,8 +150,8 @@ abstract class FileConfigHandle { */ public Try set(@Nullable String name, Object value) { return nodes.findNode(name, ValueNode.class) - .map(node -> (Try) set(node, value)) - .orElse(Try.failure(new Exception("Node not found"))); + .toTry(() -> new Exception("Node not found")) + .flatMap(node -> set(node, value)); } /** diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java index 80e8b56e..051a9770 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java @@ -5,9 +5,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Optional; import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode; +import io.vavr.control.Option; import org.jetbrains.annotations.NotNull; /** @@ -53,10 +53,10 @@ public class NodeGroup implements Collection { * Gets the node with the given name. * * @param name The name of the node to get. - * @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists. + * @return The node with the given name, or {@link Option.None} if no node with the given name exists. */ - public Optional findNode(String name) { - return Optional.ofNullable(nodesMap.get(name)); + public Option findNode(String name) { + return Option.of(nodesMap.get(name)); } /** @@ -64,11 +64,10 @@ public class NodeGroup implements Collection { * * @param name The name of the node to get. * @param type The type of the node to get. - * @return The node with the given name, or {@link Optional#empty()} if no node with the given name exists. + * @return The node with the given name, or {@link Option.None} if no node with the given name exists. */ - public Optional findNode(String name, Class type) { - return Optional.ofNullable(nodesMap.get(name)) - .map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null); + public Option findNode(String name, Class type) { + return Option.of(nodesMap.get(name)).map(node -> type.isAssignableFrom(node.getClass()) ? (T) node : null); } @Override From 0cc3f93e0b76ce96798c5cca0f6420b5ddb74c60 Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Tue, 28 Mar 2023 16:38:35 -0400 Subject: [PATCH 5/9] Use Option instead of Optional for ValueNode#getName. Also clean up nullability annotations in ConfigNode and co. --- .../configuration/node/ConfigHeaderNode.java | 21 +++---- .../configuration/node/ConfigNode.java | 55 +++++++++++-------- .../configuration/node/NodeGroup.java | 4 +- .../configuration/node/ValueNode.java | 12 ++-- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java index 1d121b0c..00b330ab 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigHeaderNode.java @@ -1,6 +1,7 @@ package com.onarandombox.MultiverseCore.configuration.node; import java.util.ArrayList; +import java.util.List; import com.google.common.base.Strings; import org.jetbrains.annotations.NotNull; @@ -16,14 +17,14 @@ public class ConfigHeaderNode implements CommentedNode { * @param path The path of the node. * @return The new builder. */ - public static Builder builder(String path) { + public static @NotNull Builder> builder(String path) { return new Builder<>(path); } - private final String path; - private final String[] comments; + private final @NotNull String path; + private final @NotNull String[] comments; - protected ConfigHeaderNode(String path, String[] comments) { + protected ConfigHeaderNode(@NotNull String path, @NotNull String[] comments) { this.path = path; this.comments = comments; } @@ -40,16 +41,16 @@ public class ConfigHeaderNode implements CommentedNode { * {@inheritDoc} */ @Override - public String[] getComments() { + public @NotNull String[] getComments() { return comments; } public static class Builder> { - protected final String path; - protected final ArrayList comments; + protected final @NotNull String path; + protected final @NotNull List comments; - public Builder(String path) { + public Builder(@NotNull String path) { this.path = path; this.comments = new ArrayList<>(); } @@ -60,7 +61,7 @@ public class ConfigHeaderNode implements CommentedNode { * @param comment The comment to add. * @return This builder. */ - public B comment(String comment) { + public @NotNull B comment(@NotNull String comment) { if (!Strings.isNullOrEmpty(comment) && !comment.startsWith("#")) { comment = "# " + comment; } @@ -73,7 +74,7 @@ public class ConfigHeaderNode implements CommentedNode { * * @return The built node. */ - public ConfigHeaderNode build() { + public @NotNull ConfigHeaderNode build() { return new ConfigHeaderNode(path, comments.toArray(new String[0])); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java index 4a945fed..42d3f12f 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNode.java @@ -1,9 +1,9 @@ package com.onarandombox.MultiverseCore.configuration.node; -import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Function; +import io.vavr.control.Option; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,17 +21,28 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * @return The new builder. * @param The type of the value. */ - public static ConfigNode.Builder builder(String path, Class type) { + public static @NotNull ConfigNode.Builder> builder( + @NotNull String path, + @NotNull Class type + ) { return new ConfigNode.Builder<>(path, type); } - protected final String name; - protected final Class type; - protected final T defaultValue; - protected final Function validator; - protected final BiConsumer onSetValue; + protected final @Nullable String name; + protected final @NotNull Class type; + protected final @Nullable T defaultValue; + protected final @Nullable Function validator; + protected final @Nullable BiConsumer onSetValue; - protected ConfigNode(String path, String[] comments, String name, Class type, T defaultValue, Function validator, BiConsumer onSetValue) { + protected ConfigNode( + @NotNull String path, + @NotNull String[] comments, + @Nullable String name, + @NotNull Class type, + @Nullable T defaultValue, + @Nullable Function validator, + @Nullable BiConsumer onSetValue + ) { super(path, comments); this.name = name; this.type = type; @@ -44,8 +55,8 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * {@inheritDoc} */ @Override - public Optional getName() { - return Optional.ofNullable(name); + public @NotNull Option getName() { + return Option.of(name); } /** @@ -68,7 +79,7 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * {@inheritDoc} */ @Override - public boolean validate(T value) { + public boolean validate(@Nullable T value) { if (validator != null) { return validator.apply(value); } @@ -79,7 +90,7 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * {@inheritDoc} */ @Override - public void onSetValue(T oldValue, T newValue) { + public void onSetValue(@Nullable T oldValue, @Nullable T newValue) { if (onSetValue != null) { onSetValue.accept(oldValue, newValue); } @@ -93,11 +104,11 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { */ public static class Builder> extends ConfigHeaderNode.Builder { - protected String name; - protected final Class type; - protected T defaultValue; - protected Function validator; - protected BiConsumer onSetValue; + protected @Nullable String name; + protected @NotNull final Class type; + protected @Nullable T defaultValue; + protected @Nullable Function validator; + protected @Nullable BiConsumer onSetValue; /** * Creates a new builder. @@ -117,7 +128,7 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * @param defaultValue The default value. * @return This builder. */ - public B defaultValue(@NotNull T defaultValue) { + public @NotNull B defaultValue(@NotNull T defaultValue) { this.defaultValue = defaultValue; return (B) this; } @@ -128,12 +139,12 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * @param name The name of this node. * @return This builder. */ - public B name(@Nullable String name) { + public @NotNull B name(@Nullable String name) { this.name = name; return (B) this; } - public B validator(@Nullable Function validator) { + public @NotNull B validator(@NotNull Function validator) { this.validator = validator; return (B) this; } @@ -144,7 +155,7 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * @param onSetValue The action to be performed. * @return This builder. */ - public B onSetValue(@Nullable BiConsumer onSetValue) { + public @NotNull B onSetValue(@NotNull BiConsumer onSetValue) { this.onSetValue = onSetValue; return (B) this; } @@ -153,7 +164,7 @@ public class ConfigNode extends ConfigHeaderNode implements ValueNode { * {@inheritDoc} */ @Override - public ConfigNode build() { + public @NotNull ConfigNode build() { return new ConfigNode<>(path, comments.toArray(new String[0]), name, type, defaultValue, validator, onSetValue); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java index 051a9770..ffac0065 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/NodeGroup.java @@ -30,13 +30,13 @@ public class NodeGroup implements Collection { private void addNodeIndex(Node node) { if (node instanceof ValueNode) { - ((ValueNode) node).getName().ifPresent(name -> nodesMap.put(name, node)); + ((ValueNode) node).getName().peek(name -> nodesMap.put(name, node)); } } private void removeNodeIndex(Node node) { if (node instanceof ValueNode) { - ((ValueNode) node).getName().ifPresent(nodesMap::remove); + ((ValueNode) node).getName().peek(nodesMap::remove); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java index aa183b6f..6ef0cf81 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ValueNode.java @@ -1,17 +1,17 @@ package com.onarandombox.MultiverseCore.configuration.node; -import java.util.Optional; - +import io.vavr.control.Option; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface ValueNode extends Node { + /** * Gets the name of this node. Used for identifying the node from user input. * - * @return The name of this node. + * @return An {@link Option} containing the name of this node, or {@link Option.None} if the node has no name. */ - Optional getName(); + @NotNull Option getName(); /** * Gets the class type {@link T} of the node value. @@ -33,7 +33,7 @@ public interface ValueNode extends Node { * @param value The value to validate. * @return True if the value is valid, false otherwise. */ - boolean validate(T value); + boolean validate(@Nullable T value); /** * Called when the value of this node is set. @@ -41,5 +41,5 @@ public interface ValueNode extends Node { * @param oldValue The old value. * @param newValue The new value. */ - void onSetValue(T oldValue, T newValue); + void onSetValue(@Nullable T oldValue, @Nullable T newValue); } From 94251be0488c71e0359bc2ce4e0469ec64a70361 Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Tue, 28 Mar 2023 17:02:20 -0400 Subject: [PATCH 6/9] Change call order in FileConfigHandle.get for consistency. --- .../MultiverseCore/configuration/handle/FileConfigHandle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java index a9dd8b1b..1156c38b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -127,8 +127,8 @@ abstract class FileConfigHandle { */ public Try get(@Nullable String name) { return nodes.findNode(name, ValueNode.class) - .map(node -> get((ValueNode) node)) - .toTry(() -> new Exception("Node not found")); + .toTry(() -> new Exception("Node not found")) + .map(node -> get((ValueNode) node)); } /** From e5bb6bc23b6ee3e6399064235bfe48071260cce1 Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Tue, 28 Mar 2023 17:25:48 -0400 Subject: [PATCH 7/9] Use Try rather than Try for ConfigHandle#set. --- .../MultiverseCore/api/MVConfig.java | 2 +- .../MultiverseCore/commands/ConfigCommand.java | 16 +++++----------- .../MultiverseCore/config/MVCoreConfig.java | 2 +- .../configuration/handle/FileConfigHandle.java | 6 +++--- .../multiverse/core/config/ConfigTest.kt | 6 +++--- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java index 315d7f0d..95a0baf5 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java @@ -47,7 +47,7 @@ public interface MVConfig { * @param value The value of the property. * @return True if the property was set successfully. */ - Try setProperty(String name, Object value); + Try setProperty(String name, Object value); /** * Sets world access permissions should be enforced. diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java index f63ce1c3..fc1e5cdf 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java @@ -9,12 +9,10 @@ import co.aikar.commands.annotation.Optional; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; -import com.onarandombox.MultiverseCore.api.MVConfig; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue; import com.onarandombox.MultiverseCore.config.MVCoreConfig; -import io.vavr.control.Try; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -58,19 +56,15 @@ public class ConfigCommand extends MultiverseCommand { private void showConfigValue(BukkitCommandIssuer issuer, String name) { config.getProperty(name) .onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value)) - .onFailure(throwable -> issuer.sendMessage("Unable to get " + name + ": " + throwable.getMessage())); + .onFailure(e -> issuer.sendMessage("Unable to get " + name + ": " + e.getMessage())); } private void updateConfigValue(BukkitCommandIssuer issuer, String name, Object value) { config.setProperty(name, value) - .onSuccess(success -> { - if (success) { - config.save(); - issuer.sendMessage("Successfully set " + name + " to " + value); - } else { - issuer.sendMessage("Unable to set " + name + " to " + value); - } + .onSuccess(ignore -> { + config.save(); + issuer.sendMessage("Successfully set " + name + " to " + value); }) - .onFailure(throwable -> issuer.sendMessage("Unable to set " + name + " to " + value + ": " + throwable.getMessage())); + .onFailure(e -> issuer.sendMessage("Unable to set " + name + " to " + value + ": " + e.getMessage())); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java index 725e54e1..8afb8a18 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/config/MVCoreConfig.java @@ -116,7 +116,7 @@ public class MVCoreConfig implements MVConfig { } @Override - public Try setProperty(String name, Object value) { + public Try setProperty(String name, Object value) { return configHandle.set(name, value); } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java index 1156c38b..a3d60a55 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -148,7 +148,7 @@ abstract class FileConfigHandle { * @param value The value to set. * @return True if the value was set, false otherwise. */ - public Try set(@Nullable String name, Object value) { + public Try set(@Nullable String name, Object value) { return nodes.findNode(name, ValueNode.class) .toTry(() -> new Exception("Node not found")) .flatMap(node -> set(node, value)); @@ -162,14 +162,14 @@ abstract class FileConfigHandle { * @return True if the value was set, false otherwise. * @param The type of the node value. */ - public Try set(@NotNull ValueNode node, T value) { + public Try set(@NotNull ValueNode node, T value) { if (!node.validate(value)) { return Try.failure(new Exception("Validation failed")); } T oldValue = get(node); config.set(node.getPath(), value); node.onSetValue(oldValue, get(node)); - return Try.success(true); + return Try.success(null); } /** diff --git a/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt b/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt index 8f5578fc..221c6e2a 100644 --- a/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt +++ b/src/test/java/org/mvplugins/multiverse/core/config/ConfigTest.kt @@ -77,13 +77,13 @@ class ConfigTest : TestWithMockBukkit() { @Test fun `Updating an existing config property with setProperty reflects the changes in getProperty`() { - assertTrue(config.setProperty("enforce-access", true).get()) + assertTrue(config.setProperty("enforce-access", true).isSuccess) assertEquals(true, config.getProperty("enforce-access").get()) - assertTrue(config.setProperty("first-spawn-location", "world2").get()) + assertTrue(config.setProperty("first-spawn-location", "world2").isSuccess) assertEquals("world2", config.getProperty("first-spawn-location").get()) - assertTrue(config.setProperty("global-debug", 1).get()) + assertTrue(config.setProperty("global-debug", 1).isSuccess) assertEquals(1, config.getProperty("global-debug").get()) } From c32b2a4b511c4ddb587c8e51fff4ad6d61ec1f58 Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Tue, 28 Mar 2023 17:36:02 -0400 Subject: [PATCH 8/9] Update Javadoc for MVConfig. --- .../com/onarandombox/MultiverseCore/api/MVConfig.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java index 95a0baf5..55d11a78 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java +++ b/src/main/java/com/onarandombox/MultiverseCore/api/MVConfig.java @@ -35,8 +35,9 @@ public interface MVConfig { /** * Gets a property from the config. * - * @param name The name of the property. - * @return The value of the property. + * @param name The name of the property. + * @return A {@link Try} with the value of the property, otherwise a {@link Try.Failure} if there is no property by + * that name. */ Try getProperty(String name); @@ -45,7 +46,8 @@ public interface MVConfig { * * @param name The name of the property. * @param value The value of the property. - * @return True if the property was set successfully. + * @return An empty {@link Try} if the property was set successfully, otherwise a {@link Try.Failure} with the + * exception explaining why the property could not be set. */ Try setProperty(String name, Object value); From 259189f23e007f6a2ee39dc5e503167729919d6a Mon Sep 17 00:00:00 2001 From: Jeremy Wood Date: Thu, 30 Mar 2023 01:41:25 -0400 Subject: [PATCH 9/9] Use specific exception for not found node. --- .../commands/ConfigCommand.java | 19 ++++++++++++++----- .../handle/FileConfigHandle.java | 8 +++++--- .../node/ConfigNodeNotFoundException.java | 14 ++++++++++++++ .../MultiverseCore/utils/MVCorei18n.java | 1 + .../resources/multiverse-core_en.properties | 2 +- 5 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNodeNotFoundException.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java index fc1e5cdf..60c14b5b 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commands/ConfigCommand.java @@ -1,6 +1,5 @@ package com.onarandombox.MultiverseCore.commands; -import co.aikar.commands.BukkitCommandIssuer; import co.aikar.commands.annotation.CommandAlias; import co.aikar.commands.annotation.CommandCompletion; import co.aikar.commands.annotation.CommandPermission; @@ -9,10 +8,12 @@ import co.aikar.commands.annotation.Optional; import co.aikar.commands.annotation.Single; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; +import com.onarandombox.MultiverseCore.commandtools.MVCommandIssuer; import com.onarandombox.MultiverseCore.commandtools.MVCommandManager; import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand; import com.onarandombox.MultiverseCore.commandtools.context.MVConfigValue; import com.onarandombox.MultiverseCore.config.MVCoreConfig; +import com.onarandombox.MultiverseCore.exceptions.MultiverseException; import jakarta.inject.Inject; import org.jetbrains.annotations.NotNull; import org.jvnet.hk2.annotations.Service; @@ -34,7 +35,7 @@ public class ConfigCommand extends MultiverseCommand { @CommandCompletion("@mvconfigs") @Syntax(" [new-value]") @Description("") //TODO - public void onConfigCommand(BukkitCommandIssuer issuer, + public void onConfigCommand(MVCommandIssuer issuer, @Syntax("") @Description("") //TODO @@ -53,18 +54,26 @@ public class ConfigCommand extends MultiverseCommand { updateConfigValue(issuer, name, value.getValue()); } - private void showConfigValue(BukkitCommandIssuer issuer, String name) { + private void showConfigValue(MVCommandIssuer issuer, String name) { config.getProperty(name) .onSuccess(value -> issuer.sendMessage(name + "is currently set to " + value)) .onFailure(e -> issuer.sendMessage("Unable to get " + name + ": " + e.getMessage())); } - private void updateConfigValue(BukkitCommandIssuer issuer, String name, Object value) { + private void updateConfigValue(MVCommandIssuer issuer, String name, Object value) { config.setProperty(name, value) .onSuccess(ignore -> { config.save(); issuer.sendMessage("Successfully set " + name + " to " + value); }) - .onFailure(e -> issuer.sendMessage("Unable to set " + name + " to " + value + ": " + e.getMessage())); + .onFailure(e -> { + issuer.sendMessage("Unable to set " + name + " to " + value + "."); + if (e instanceof MultiverseException) { + var message = ((MultiverseException) e).getMVMessage(); + if (message != null) { + issuer.sendError(message); + } + } + }); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java index a3d60a55..f5742fb5 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/handle/FileConfigHandle.java @@ -7,8 +7,10 @@ import java.util.logging.Logger; import com.dumptruckman.minecraft.util.Logging; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; +import com.onarandombox.MultiverseCore.configuration.node.ConfigNodeNotFoundException; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.configuration.node.ValueNode; +import com.onarandombox.MultiverseCore.exceptions.MultiverseException; import io.vavr.control.Try; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.Plugin; @@ -127,7 +129,7 @@ abstract class FileConfigHandle { */ public Try get(@Nullable String name) { return nodes.findNode(name, ValueNode.class) - .toTry(() -> new Exception("Node not found")) + .toTry(() -> new ConfigNodeNotFoundException(name)) .map(node -> get((ValueNode) node)); } @@ -150,7 +152,7 @@ abstract class FileConfigHandle { */ public Try set(@Nullable String name, Object value) { return nodes.findNode(name, ValueNode.class) - .toTry(() -> new Exception("Node not found")) + .toTry(() -> new ConfigNodeNotFoundException(name)) .flatMap(node -> set(node, value)); } @@ -164,7 +166,7 @@ abstract class FileConfigHandle { */ public Try set(@NotNull ValueNode node, T value) { if (!node.validate(value)) { - return Try.failure(new Exception("Validation failed")); + return Try.failure(new MultiverseException("Validation failed", null)); // TODO replace validation } T oldValue = get(node); config.set(node.getPath(), value); diff --git a/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNodeNotFoundException.java b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNodeNotFoundException.java new file mode 100644 index 00000000..3917a17e --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/configuration/node/ConfigNodeNotFoundException.java @@ -0,0 +1,14 @@ +package com.onarandombox.MultiverseCore.configuration.node; + +import com.onarandombox.MultiverseCore.exceptions.MultiverseException; +import org.jetbrains.annotations.Nullable; + +import static com.onarandombox.MultiverseCore.utils.MVCorei18n.CONFIG_NODE_NOTFOUND; +import static com.onarandombox.MultiverseCore.utils.message.MessageReplacement.replace; + +public class ConfigNodeNotFoundException extends MultiverseException { + + public ConfigNodeNotFoundException(@Nullable String nodeName) { + super(CONFIG_NODE_NOTFOUND.bundle("Config node not found: {node}", replace("{node}").with(nodeName)), null); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java b/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java index 1e5cbe35..388b619d 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java +++ b/src/main/java/com/onarandombox/MultiverseCore/utils/MVCorei18n.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; public enum MVCorei18n implements MessageKeyProvider { // config status CONFIG_SAVE_FAILED, + CONFIG_NODE_NOTFOUND, // check command CHECK_CHECKING, diff --git a/src/main/resources/multiverse-core_en.properties b/src/main/resources/multiverse-core_en.properties index 0cd452ea..31ed2ea7 100644 --- a/src/main/resources/multiverse-core_en.properties +++ b/src/main/resources/multiverse-core_en.properties @@ -1,5 +1,6 @@ # configuration mv-core.config.save.failed=Unable to save Multiverse-Core config.yml. Your changes will be temporary! +mv-core.config.node.notfound=Node not found in config: {node} # /mv check mv-core.check.description=Checks if a player can teleport to a destination. @@ -113,4 +114,3 @@ mv-core.unload.success=&aUnloaded world '{world}'! # /mv usage mv-core.usage.description=Show Multiverse-Core command usage. -