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
This commit is contained in:
allinkdev 2023-08-11 20:01:19 +01:00 committed by GitHub
parent 086e5ca72f
commit 8e5c52d0e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 175 additions and 55 deletions

View File

@ -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 <T> The type of the objects in the list.
* @param clazz The class of the type.
* @return The List object.
*/
<T> List<T> getList(String path);
<T> @Unmodifiable List<T> getList(String path, Class<T> 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<String> getStringList(String path);
@Unmodifiable List<String> 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.
* <p>
* 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 <T> 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> T get(String path);
<T> Optional<T> get(String path, Class<T> 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 <T> The type of the value.
* @param clazz The class of the type.
* @return The value at the given path.
*/
<T> T getOrDefault(String path, T fallback);
<T> T getOrDefault(String path, Class<T> clazz, T fallback);
}

View File

@ -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<File, FileConfiguration> 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 <T> List<T> getList(String path, Class<T> clazz)
{
return this.contextProvider.getList(this.getStringList(path), clazz);
}
@Override
public List<String> 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 <T> void set(String path, T value)
{
this.fileConfiguration.set(path, value);
}
@Override
public <T> Optional<T> get(String path, Class<T> clazz)
{
return Optional.ofNullable(this.contextProvider.fromString(path, clazz));
}
@Override
public <T> T getOrDefault(String path, Class<T> clazz, T fallback)
{
return this.get(path, clazz).orElse(fallback);
}
}

View File

@ -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
{
}