From 8e5c52d0e8ba60f943b1740252d91e702be914a0 Mon Sep 17 00:00:00 2001 From: allinkdev <44676012+allinkdev@users.noreply.github.com> Date: Fri, 11 Aug 2023 20:01:19 +0100 Subject: [PATCH] Implement configuration system (#12) * Return primitives in configuration interface where possible This should save some unnecessary performance and memory overhead caused by the storage of object wrappers of the primitive types and the unboxing of those object wrappers into the wrapped primitive types when we try to do some primitive-exclusive operation. I doubt that we'll be using the additional sugar methods that these wrappers provide most of the time, and if we need to we can just box the returned primitives. * Mark returned lists in Configuration interface as Unmodifiable I can't think of a use-case where we would want to modify the returned list from the Configuration interface we're accessing; however in case those situations do in-fact exist, I've made the decision to mark the return values of those methods as Unmodifiable so that there are no confusions in the future when the returned list throws an UnsupportedOperationException * Provide class parameter in Configuration#getList Otherwise, it's impossible to actually check if the on-disk configuration values are actually of the same type as/a subclass of what the plugin is expecting in the implementation. * State that Configuration#getList will return an empty list if it fails I don't think it would go particularly well if we were to return a list of Objects when we have a parameterized method. Additionally, how would components of the plugin respond to being given a list of Objects instead of whatever type they were expecting? This should be a better fail-safe solution compared to what we were previously going to do. * Return an optional in Configuration#get if something went wrong * Add class parameter to Configuration#get * Update JavaDoc of Configuration#getList to reflect new parameter * Remove final modifier from parameter * Add class parameter to Configuration#getOrDefault * Fix misspelled JavaDoc tag * Partially implement a wrapper over FileConfiguration that implements our Configuration * Fix codestyle violation * Add copyright header & change package * Add code for WrappedBukkitConfiguration#getList and WrappedBukkitConfiguration#get --- .../fns/patchwork/config/Configuration.java | 58 +++---- .../config/WrappedBukkitConfiguration.java | 143 ++++++++++++++++++ .../fns/patchwork/config/YamlWrapper.java | 29 ---- 3 files changed, 175 insertions(+), 55 deletions(-) create mode 100644 Patchwork/src/main/java/fns/patchwork/config/WrappedBukkitConfiguration.java delete mode 100644 Patchwork/src/main/java/fns/patchwork/config/YamlWrapper.java diff --git a/Patchwork/src/main/java/fns/patchwork/config/Configuration.java b/Patchwork/src/main/java/fns/patchwork/config/Configuration.java index 4000725..4bcb347 100644 --- a/Patchwork/src/main/java/fns/patchwork/config/Configuration.java +++ b/Patchwork/src/main/java/fns/patchwork/config/Configuration.java @@ -25,9 +25,13 @@ package fns.patchwork.config; import fns.patchwork.api.Context; import fns.patchwork.provider.ContextProvider; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; + import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Optional; /** * Represents a configuration file of any type. @@ -67,23 +71,24 @@ public interface Configuration String getString(String path); /** - * Gets a Boolean object from the associated path. + * Gets a boolean primitive from the associated path. * - * @param path The path to get the Boolean from. - * @return The Boolean object. + * @param path The path to get the boolean from. + * @return The boolean primitive. */ - Boolean getBoolean(String path); + boolean getBoolean(String path); /** * Gets a List object from the associated path. This method will use {@link Context}s and the - * {@link ContextProvider} to get the object types in the list. If the objects cannot be inferred, the method will - * return a list of generic {@link Object}s. + * {@link ContextProvider} to get the object types in the list. If the stored objects cannot be deciphered, + * the method will return an empty list. * * @param path The path to get the List from. * @param The type of the objects in the list. + * @param clazz The class of the type. * @return The List object. */ - List getList(String path); + @Unmodifiable List getList(String path, Class clazz); /** * Gets a List object from the associated path. The List that is returned will be the String values which are stored @@ -92,31 +97,31 @@ public interface Configuration * @param path The path to get the List from. * @return The List object. */ - List getStringList(String path); + @Unmodifiable List getStringList(String path); /** - * Gets an Integer from the associated path. + * Gets an int from the associated path. * - * @param path The path to get the Integer from. - * @return The Integer object. + * @param path The path to get the int from. + * @return The int primitive. */ - Integer getInt(String path); + int getInt(String path); /** - * Gets a Long from the associated path. + * Gets a long from the associated path. * - * @param path The path to get the Long from. - * @return The Long object. + * @param path The path to get the long from. + * @return The long primitive. */ - Long getLong(String path); + long getLong(String path); /** - * Gets a Double from the associated path. + * Gets a double from the associated path. * - * @param path The path to get the Double from. - * @return The Double object. + * @param path The path to get the double from. + * @return The double primitive. */ - Double getDouble(String path); + double getDouble(String path); /** * Sets the value at the given path to the given value. @@ -130,14 +135,14 @@ public interface Configuration /** * Gets the value at the given path as the given type. *

- * This method will use {@link Context}s and the {@link ContextProvider} to get the object type. If the object type - * cannot be inferred, the method will return a generic {@link Object}. + * This method will use {@link Context}s and the {@link ContextProvider} to get the object type. * - * @param path The path to get the value from. + * @param path The path to get the value from * @param The type of the value. - * @return The value at the given path. + * @param clazz The class of the type. + * @return An optional containing the value at the given path if it is present or the type could not be inferred. */ - T get(String path); + Optional get(String path, Class clazz); /** * Gets the value at the given path as the given type. @@ -148,7 +153,8 @@ public interface Configuration * @param path The path to get the value from. * @param fallback The fallback value to return if the value at the given path is null. * @param The type of the value. + * @param clazz The class of the type. * @return The value at the given path. */ - T getOrDefault(String path, T fallback); + T getOrDefault(String path, Class clazz, T fallback); } \ No newline at end of file diff --git a/Patchwork/src/main/java/fns/patchwork/config/WrappedBukkitConfiguration.java b/Patchwork/src/main/java/fns/patchwork/config/WrappedBukkitConfiguration.java new file mode 100644 index 0000000..25b1b06 --- /dev/null +++ b/Patchwork/src/main/java/fns/patchwork/config/WrappedBukkitConfiguration.java @@ -0,0 +1,143 @@ +/* + * This file is part of Freedom-Network-Suite - https://github.com/AtlasMediaGroup/Freedom-Network-Suite + * Copyright (C) 2023 Total Freedom Server Network and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package fns.patchwork.config; + +import fns.patchwork.provider.ContextProvider; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public final class WrappedBukkitConfiguration implements Configuration +{ + private final ContextProvider contextProvider = new ContextProvider(); + private final FileConfiguration fileConfiguration; + private final File file; + + public WrappedBukkitConfiguration(Function configurationCreator, File file) + { + this.fileConfiguration = configurationCreator.apply(file); + this.file = file; + } + + public WrappedBukkitConfiguration(FileConfiguration fileConfiguration, File file) + { + this.fileConfiguration = fileConfiguration; + this.file = file; + } + + @Override + public void save() throws IOException + { + this.fileConfiguration.save(this.file); + } + + @Override + public void load() throws IOException + { + try + { + this.fileConfiguration.load(this.file); + } catch (InvalidConfigurationException e) + { + throw new IOException("Invalid configuration file on disk", e); + } + } + + @Override + public String getFileName() + { + return this.file.getName(); + } + + @Override + public File getConfigurationFile() + { + return this.file; + } + + @Override + public String getString(String path) + { + return this.fileConfiguration.getString(path); + } + + @Override + public boolean getBoolean(String path) + { + return this.fileConfiguration.getBoolean(path); + } + + @Override + public List getList(String path, Class clazz) + { + return this.contextProvider.getList(this.getStringList(path), clazz); + } + + @Override + public List getStringList(String path) + { + return this.fileConfiguration.getStringList(path); + } + + @Override + public int getInt(String path) + { + return this.fileConfiguration.getInt(path); + } + + @Override + public long getLong(String path) + { + return this.fileConfiguration.getLong(path); + } + + @Override + public double getDouble(String path) + { + return this.fileConfiguration.getDouble(path); + } + + @Override + public void set(String path, T value) + { + this.fileConfiguration.set(path, value); + } + + @Override + public Optional get(String path, Class clazz) + { + return Optional.ofNullable(this.contextProvider.fromString(path, clazz)); + } + + @Override + public T getOrDefault(String path, Class clazz, T fallback) + { + return this.get(path, clazz).orElse(fallback); + } +} diff --git a/Patchwork/src/main/java/fns/patchwork/config/YamlWrapper.java b/Patchwork/src/main/java/fns/patchwork/config/YamlWrapper.java deleted file mode 100644 index dc4cea8..0000000 --- a/Patchwork/src/main/java/fns/patchwork/config/YamlWrapper.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of Freedom-Network-Suite - https://github.com/AtlasMediaGroup/Freedom-Network-Suite - * Copyright (C) 2023 Total Freedom Server Network and contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package fns.patchwork.config; - -public final class YamlWrapper -{ - -}