From 58bdf388bfd0dab86497876e7364aa2315585474 Mon Sep 17 00:00:00 2001 From: filoghost Date: Thu, 9 Jul 2020 23:35:40 +0200 Subject: [PATCH] Large configuration refactoring --- .../chestcommands/ChestCommands.java | 18 +- .../chestcommands/config/ConfigLoader.java | 126 -------------- .../chestcommands/config/ConfigManager.java | 117 ++++++------- .../config/ConfigValueException.java | 9 - .../{files => }/CustomPlaceholders.java | 10 +- .../config/{files => }/Lang.java | 8 +- .../config/{files => }/Settings.java | 12 +- .../chestcommands/config/SpecialConfig.java | 128 -------------- .../config/framework/BaseConfigManager.java | 51 ++++++ .../config/{ => framework}/Config.java | 20 ++- .../config/framework/ConfigLoader.java | 143 ++++++++++++++++ .../config/{ => framework}/ConfigSection.java | 15 +- .../framework/exception/ConfigException.java | 13 ++ .../exception/ConfigLoadException.java | 9 + .../exception/ConfigSaveException.java | 9 + .../exception/ConfigSyntaxException.java | 11 ++ .../exception/ConfigValueException.java | 9 + .../config/framework/mapped/ConfigMapper.java | 157 ++++++++++++++++++ .../framework/mapped/IncludeStatic.java | 26 +++ .../config/framework/mapped/MappedConfig.java | 33 ++++ .../framework/mapped/MappedConfigLoader.java | 78 +++++++++ .../config/framework/mapped/MappedField.java | 88 ++++++++++ .../mapped/converter/BooleanConverter.java | 38 +++++ .../framework/mapped/converter/Converter.java | 29 ++++ .../mapped/converter/DoubleConverter.java | 38 +++++ .../mapped/converter/IntegerConverter.java | 38 +++++ .../mapped/converter/ListConverter.java | 51 ++++++ .../mapped/converter/StringConverter.java | 38 +++++ .../framework/mapped/modifier/ChatColors.java | 26 +++ .../mapped/modifier/ChatColorsModifier.java | 36 ++++ .../mapped/modifier/ValueModifier.java | 38 +++++ .../chestcommands/legacy/Upgrade.java | 27 ++- .../legacy/UpgradesExecutor.java | 38 +++-- .../legacy/upgrades/MenuUpgrade.java | 22 +-- .../legacy/upgrades/PlaceholdersUpgrade.java | 26 +-- .../legacy/upgrades/SettingsUpgrade.java | 23 +-- .../chestcommands/parsing/ErrorFormat.java | 13 +- .../parsing/icon/IconSettings.java | 4 +- .../parsing/menu/MenuParser.java | 20 +-- .../chestcommands/util/Preconditions.java | 4 +- 40 files changed, 1135 insertions(+), 464 deletions(-) delete mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigLoader.java delete mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigValueException.java rename Plugin/src/main/java/me/filoghost/chestcommands/config/{files => }/CustomPlaceholders.java (83%) rename Plugin/src/main/java/me/filoghost/chestcommands/config/{files => }/Lang.java (85%) rename Plugin/src/main/java/me/filoghost/chestcommands/config/{files => }/Settings.java (70%) delete mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/SpecialConfig.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/BaseConfigManager.java rename Plugin/src/main/java/me/filoghost/chestcommands/config/{ => framework}/Config.java (73%) create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigLoader.java rename Plugin/src/main/java/me/filoghost/chestcommands/config/{ => framework}/ConfigSection.java (91%) create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigException.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigLoadException.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSaveException.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSyntaxException.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigValueException.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/ConfigMapper.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/IncludeStatic.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfig.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfigLoader.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedField.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/BooleanConverter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/Converter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/DoubleConverter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/IntegerConverter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/ListConverter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/StringConverter.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColors.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColorsModifier.java create mode 100644 Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ValueModifier.java diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java b/Plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java index 5e1bc40..4fc019f 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/ChestCommands.java @@ -17,12 +17,11 @@ package me.filoghost.chestcommands; import me.filoghost.chestcommands.api.internal.BackendAPI; import me.filoghost.chestcommands.command.CommandHandler; import me.filoghost.chestcommands.command.framework.CommandFramework; -import me.filoghost.chestcommands.config.ConfigLoader; +import me.filoghost.chestcommands.config.framework.ConfigLoader; import me.filoghost.chestcommands.config.ConfigManager; -import me.filoghost.chestcommands.config.files.CustomPlaceholders; -import me.filoghost.chestcommands.config.files.Lang; -import me.filoghost.chestcommands.parsing.menu.LoadedMenu; -import me.filoghost.chestcommands.config.files.Settings; +import me.filoghost.chestcommands.config.CustomPlaceholders; +import me.filoghost.chestcommands.config.Lang; +import me.filoghost.chestcommands.config.Settings; import me.filoghost.chestcommands.hook.BarAPIHook; import me.filoghost.chestcommands.hook.BungeeCordHook; import me.filoghost.chestcommands.hook.PlaceholderAPIHook; @@ -34,10 +33,11 @@ import me.filoghost.chestcommands.listener.InventoryListener; import me.filoghost.chestcommands.listener.JoinListener; import me.filoghost.chestcommands.listener.SignListener; import me.filoghost.chestcommands.menu.MenuManager; +import me.filoghost.chestcommands.parsing.menu.LoadedMenu; import me.filoghost.chestcommands.task.RefreshMenusTask; +import me.filoghost.chestcommands.util.Log; import me.filoghost.chestcommands.util.Utils; import me.filoghost.chestcommands.util.collection.ErrorCollector; -import me.filoghost.chestcommands.util.Log; import me.filoghost.updatechecker.UpdateChecker; import org.bstats.bukkit.MetricsLite; import org.bukkit.Bukkit; @@ -152,9 +152,9 @@ public class ChestCommands extends JavaPlugin { public ErrorCollector load() { ErrorCollector errors = new ErrorCollector(); menuManager.clear(); - boolean isFreshInstall = !Files.isDirectory(configManager.getBaseDataPath()); + boolean isFreshInstall = !Files.isDirectory(configManager.getRootDataFolder()); try { - Files.createDirectories(configManager.getBaseDataPath()); + Files.createDirectories(configManager.getRootDataFolder()); } catch (IOException e) { errors.addError("Plugin failed to load, couldn't create data folder."); return errors; @@ -172,7 +172,7 @@ public class ChestCommands extends JavaPlugin { // Create the menu folder with the example menu if (!Files.isDirectory(configManager.getMenusFolder())) { - ConfigLoader exampleMenuLoader = new ConfigLoader(configManager.getMenusFolder().resolve("example.yml")); + ConfigLoader exampleMenuLoader = configManager.getConfigLoader(configManager.getMenusFolder().resolve("example.yml")); configManager.tryCreateDefault(exampleMenuLoader); } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigLoader.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigLoader.java deleted file mode 100644 index 7c8cd2b..0000000 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigLoader.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package me.filoghost.chestcommands.config; - -import me.filoghost.chestcommands.util.Preconditions; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -public class ConfigLoader { - - private final Path path; - - public ConfigLoader(Path path) { - this.path = path; - } - - public Path getPath() { - return path; - } - - public void createDefault(Path baseDataPath) throws IOException { - if (!path.startsWith(baseDataPath)) { - throw new IOException("Config file " + path + " must be inside " + baseDataPath); - } - - if (Files.exists(path)) { - return; - } - - if (path.getParent() != null) { - Files.createDirectories(path.getParent()); - } - - Path absoluteDataPath = baseDataPath.toAbsolutePath(); - Path absoluteConfigPath = path.toAbsolutePath(); - - if (absoluteConfigPath.startsWith(absoluteDataPath)) { - Path relativeConfigPath = absoluteDataPath.relativize(absoluteConfigPath); - String internalJarPath = toInternalJarPath(relativeConfigPath); - - try (InputStream defaultFile = getResource(internalJarPath)) { - if (defaultFile != null) { - Files.copy(defaultFile, path); - return; - } - } - } - - Files.createFile(path); - } - - private String toInternalJarPath(Path path) { - return StreamSupport.stream(path.spliterator(), false) - .map(Path::toString) - .collect(Collectors.joining("/", "/", "")); - } - - - private InputStream getResource(String internalJarPath) throws IOException { - Preconditions.notNull(internalJarPath, "internalJarPath"); - - URL resourceURL = getClass().getResource(internalJarPath); - if (resourceURL == null) { - return null; - } - - URLConnection connection = resourceURL.openConnection(); - connection.setUseCaches(false); - return connection.getInputStream(); - } - - - public Config load() throws IOException, InvalidConfigurationException { - YamlConfiguration yaml = new YamlConfiguration(); - - try (BufferedReader reader = Files.newBufferedReader(path)) { - yaml.load(reader); - } - - return new Config(yaml, path); - } - - public Config loadEmpty() { - return new Config(new YamlConfiguration(), path); - } - - public void save(Config config) throws IOException { - if (path.getParent() != null) { - Files.createDirectories(path.getParent()); - } - - String data = config.saveToString(); - - try (BufferedWriter writer = Files.newBufferedWriter(path)) { - writer.write(data); - } - } - - public String getFileName() { - return path.getFileName().toString(); - } - -} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigManager.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigManager.java index 5b70d7b..fe0339e 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigManager.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigManager.java @@ -14,14 +14,17 @@ */ package me.filoghost.chestcommands.config; -import me.filoghost.chestcommands.config.files.CustomPlaceholders; -import me.filoghost.chestcommands.config.files.Lang; +import me.filoghost.chestcommands.config.framework.BaseConfigManager; +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigLoader; +import me.filoghost.chestcommands.config.framework.exception.ConfigException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSyntaxException; +import me.filoghost.chestcommands.config.framework.mapped.MappedConfigLoader; import me.filoghost.chestcommands.parsing.menu.LoadedMenu; -import me.filoghost.chestcommands.config.files.Settings; import me.filoghost.chestcommands.parsing.menu.MenuParser; -import me.filoghost.chestcommands.util.collection.ErrorCollector; import me.filoghost.chestcommands.util.Log; -import org.bukkit.configuration.InvalidConfigurationException; +import me.filoghost.chestcommands.util.Preconditions; +import me.filoghost.chestcommands.util.collection.ErrorCollector; import java.io.IOException; import java.nio.file.FileVisitOption; @@ -33,55 +36,46 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -public class ConfigManager { +public class ConfigManager extends BaseConfigManager { - private final Path baseDataPath; - private final ConfigLoader settingsConfigLoader; + private final MappedConfigLoader settingsConfigLoader; private final ConfigLoader placeholdersConfigLoader; - private final ConfigLoader langConfigLoader; + private final MappedConfigLoader langConfigLoader; - public ConfigManager(Path baseDataPath) { - this.baseDataPath = baseDataPath; - settingsConfigLoader = new ConfigLoader(baseDataPath.resolve("config.yml")); - placeholdersConfigLoader = new ConfigLoader(baseDataPath.resolve("custom-placeholders.yml")); - langConfigLoader = new ConfigLoader(baseDataPath.resolve("lang.yml")); + public ConfigManager(Path rootDataFolder) { + super(rootDataFolder); + + settingsConfigLoader = getMappedConfigLoader("config.yml", Settings::new); + placeholdersConfigLoader = getConfigLoader("custom-placeholders.yml"); + langConfigLoader = getMappedConfigLoader("lang.yml", Lang::new); } public Settings tryLoadSettings() { - Settings settings = new Settings(); - try { - settingsConfigLoader.createDefault(baseDataPath); - settings.load(settingsConfigLoader); - } catch (Throwable t) { - logConfigLoadException(settingsConfigLoader, t); + return settingsConfigLoader.init(); + } catch (ConfigException e) { + logConfigInitException(settingsConfigLoader.getFileName(), e); + return new Settings(); } - - return settings; } public Lang tryLoadLang() { - Lang lang = new Lang(); - try { - langConfigLoader.createDefault(baseDataPath); - lang.load(langConfigLoader); - } catch (Throwable t) { - logConfigLoadException(langConfigLoader, t); + return langConfigLoader.init(); + } catch (ConfigException e) { + logConfigInitException(langConfigLoader.getFileName(), e); + return new Lang(); } - - return lang; } public CustomPlaceholders tryLoadCustomPlaceholders(ErrorCollector errorCollector) { CustomPlaceholders placeholders = new CustomPlaceholders(); try { - placeholdersConfigLoader.createDefault(baseDataPath); - Config placeholdersConfig = placeholdersConfigLoader.load(); + Config placeholdersConfig = placeholdersConfigLoader.init(); placeholders.load(placeholdersConfig, errorCollector); - } catch (Throwable t) { - logConfigLoadException(placeholdersConfigLoader, t); + } catch (ConfigException t) { + logConfigInitException(placeholdersConfigLoader.getFileName(), t); } return placeholders; @@ -89,20 +83,22 @@ public class ConfigManager { public void tryCreateDefault(ConfigLoader configLoader) { try { - configLoader.createDefault(baseDataPath); - } catch (Throwable t) { - logConfigLoadException(configLoader, t); + configLoader.createDefault(); + } catch (ConfigException e) { + logConfigInitException(configLoader.getFileName(), e); } } public Path getMenusFolder() { - return baseDataPath.resolve("menu"); + return rootDataFolder.resolve("menu"); } /** * Returns a list of YML menu files. */ public List getMenuPaths() throws IOException { + Preconditions.checkState(Files.isDirectory(getMenusFolder()), "menus folder doesn't exist"); + try (Stream paths = Files.walk(getMenusFolder(), FileVisitOption.FOLLOW_LINKS)) { return paths.filter(Files::isRegularFile) .filter(this::isYmlPath) @@ -110,39 +106,15 @@ public class ConfigManager { } } - - private boolean isYmlPath(Path path) { - return path.getFileName().toString().toLowerCase().endsWith(".yml"); - } - - private void logConfigLoadException(ConfigLoader configLoader, Throwable t) { - t.printStackTrace(); - - if (t instanceof IOException) { - Log.warning("Error while reading the file \"" + configLoader.getFileName() + "\". Default values will be used."); - } else if (t instanceof InvalidConfigurationException) { - Log.warning("Invalid YAML syntax in the file \"" + configLoader.getFileName() + "\", please look at the error above. Default values will be used."); + private void logConfigInitException(String fileName, ConfigException e) { + if (e instanceof ConfigSyntaxException) { + Log.warning("Invalid YAML syntax in config file \"" + fileName + "\": " + e.getMessage()); } else { - Log.warning("Unhandled error while parsing the file \"" + configLoader.getFileName() + "\". Please inform the developer."); + e.printStackTrace(); + Log.warning("Error while reading config file \"" + fileName + "\": " + e.getMessage()); } } - public Path getBaseDataPath() { - return baseDataPath; - } - - public ConfigLoader getSettingsConfigLoader() { - return settingsConfigLoader; - } - - public ConfigLoader getPlaceholdersConfigLoader() { - return placeholdersConfigLoader; - } - - public ConfigLoader getLangConfigLoader() { - return langConfigLoader; - } - public List tryLoadMenus(ErrorCollector errorCollector) { List loadedMenus = new ArrayList<>(); List menuPaths; @@ -155,16 +127,21 @@ public class ConfigManager { } for (Path menuFile : menuPaths) { - ConfigLoader menuConfigLoader = new ConfigLoader(menuFile); + ConfigLoader menuConfigLoader = new ConfigLoader(rootDataFolder, menuFile); try { Config menuConfig = menuConfigLoader.load(); loadedMenus.add(MenuParser.loadMenu(menuConfig, errorCollector)); - } catch (Throwable t) { - logConfigLoadException(menuConfigLoader, t); + } catch (ConfigException e) { + logConfigInitException(menuConfigLoader.getFileName(), e); } } return loadedMenus; } + + private boolean isYmlPath(Path path) { + return path.getFileName().toString().toLowerCase().endsWith(".yml"); + } + } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigValueException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigValueException.java deleted file mode 100644 index 61aa8b1..0000000 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigValueException.java +++ /dev/null @@ -1,9 +0,0 @@ -package me.filoghost.chestcommands.config; - -public class ConfigValueException extends Exception { - - public ConfigValueException(String message) { - super(message); - } - -} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/CustomPlaceholders.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/CustomPlaceholders.java similarity index 83% rename from Plugin/src/main/java/me/filoghost/chestcommands/config/files/CustomPlaceholders.java rename to Plugin/src/main/java/me/filoghost/chestcommands/config/CustomPlaceholders.java index 5164727..b8b4beb 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/CustomPlaceholders.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/CustomPlaceholders.java @@ -12,12 +12,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package me.filoghost.chestcommands.config.files; +package me.filoghost.chestcommands.config; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.util.collection.ErrorCollector; +import me.filoghost.chestcommands.config.framework.Config; import me.filoghost.chestcommands.util.Colors; import me.filoghost.chestcommands.util.collection.CollectionUtils; +import me.filoghost.chestcommands.util.collection.ErrorCollector; import java.util.HashMap; import java.util.List; @@ -36,12 +36,12 @@ public class CustomPlaceholders { String replacement = Colors.addColors(config.getString(key)); if (placeholder.length() == 0) { - errorCollector.addError("Error in " + config.getFileName() + ": placeholder cannot be empty (skipped)."); + errorCollector.addError("Error in " + config.getSourceFileName() + ": placeholder cannot be empty (skipped)."); continue; } if (placeholder.length() > 100) { - errorCollector.addError("Error in " + config.getFileName() + ": placeholder cannot be longer than 100 character (" + placeholder + ")."); + errorCollector.addError("Error in " + config.getSourceFileName() + ": placeholder cannot be longer than 100 character (" + placeholder + ")."); continue; } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/Lang.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/Lang.java similarity index 85% rename from Plugin/src/main/java/me/filoghost/chestcommands/config/files/Lang.java rename to Plugin/src/main/java/me/filoghost/chestcommands/config/Lang.java index 53dc987..7108241 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/Lang.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/Lang.java @@ -12,11 +12,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package me.filoghost.chestcommands.config.files; +package me.filoghost.chestcommands.config; -import me.filoghost.chestcommands.config.SpecialConfig; +import me.filoghost.chestcommands.config.framework.mapped.MappedConfig; +import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColors; -public class Lang extends SpecialConfig { +@ChatColors +public class Lang extends MappedConfig { public String no_open_permission = "&cYou don't have permission &e{permission} &cto use this menu."; public String default_no_icon_permission = "&cYou don't have permission for this icon."; diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/Settings.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/Settings.java similarity index 70% rename from Plugin/src/main/java/me/filoghost/chestcommands/config/files/Settings.java rename to Plugin/src/main/java/me/filoghost/chestcommands/config/Settings.java index a8bd20c..d308eb4 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/files/Settings.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/Settings.java @@ -12,11 +12,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package me.filoghost.chestcommands.config.files; +package me.filoghost.chestcommands.config; -import me.filoghost.chestcommands.config.SpecialConfig; +import me.filoghost.chestcommands.config.framework.mapped.MappedConfig; +import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColors; -public class Settings extends SpecialConfig { +@ChatColors +public class Settings extends MappedConfig { public String default_color__name = "&f"; public String default_color__lore = "&7"; @@ -25,8 +27,8 @@ public class Settings extends SpecialConfig { public Settings() { setHeader( - "ChestCommands main configuration file.\n" + - "Documentation: https://filoghost.me/docs/chest-commands\n"); + "ChestCommands main configuration file.", + "Documentation: https://filoghost.me/docs/chest-commands"); } } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/SpecialConfig.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/SpecialConfig.java deleted file mode 100644 index d6a285f..0000000 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/SpecialConfig.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package me.filoghost.chestcommands.config; - -import me.filoghost.chestcommands.util.Colors; -import me.filoghost.chestcommands.util.Log; -import org.bukkit.configuration.InvalidConfigurationException; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -/** - * A special configuration wrapper that reads the values using reflection. - * It will also save default values if not set. - */ -public abstract class SpecialConfig { - - private transient String header; - private transient Map defaultValuesMap; - - public void setHeader(String header) { - this.header = header; - } - - public void load(ConfigLoader loader) throws IOException, IllegalAccessException, InvalidConfigurationException { - Config config = loader.load(); - - // Check if the configuration was initialized - if (defaultValuesMap == null) { - defaultValuesMap = new HashMap<>(); - - // Put the values in the default values map - for (Field field : getClass().getDeclaredFields()) { - if (skipField(field)) continue; - - field.setAccessible(true); - String configKey = getConfigNode(field); - - try { - Object defaultValue = field.get(this); - if (defaultValue != null) { - defaultValuesMap.put(configKey, defaultValue); - } else { - Log.warning("The field " + field.getName() + " was not provided with a default value, please inform the developer."); - } - - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - - boolean needsSave = false; - - // Save default values not set - for (Entry entry : defaultValuesMap.entrySet()) { - if (!config.isSet(entry.getKey())) { - needsSave = true; - config.set(entry.getKey(), entry.getValue()); - } - } - - if (needsSave) { - config.setHeader(header); - loader.save(config); - } - - // Now read change the fields - for (Field field : getClass().getDeclaredFields()) { - if (skipField(field)) { - continue; - } - - field.setAccessible(true); - String configNode = getConfigNode(field); - - if (config.isSet(configNode)) { - Class type = field.getType(); - - if (type == boolean.class || type == Boolean.class) { - field.set(this, config.getBoolean(configNode)); - - } else if (type == int.class || type == Integer.class) { - field.set(this, config.getInt(configNode)); - - } else if (type == double.class || type == Double.class) { - field.set(this, config.getDouble(configNode)); - - } else if (type == String.class) { - field.set(this, Colors.addColors(config.getString(configNode))); // Always add colors - - } else { - Log.warning("Unknown field type: " + field.getType().getName() + " (" + field.getName() + "). Please inform the developer."); - } - - } else { - field.set(this, defaultValuesMap.get(configNode)); - } - } - } - - - private boolean skipField(Field field) { - int modifiers = field.getModifiers(); - return Modifier.isTransient(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers); - } - - private String getConfigNode(Field field) { - return field.getName().replace("__", ".").replace("_", "-"); - } - -} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/BaseConfigManager.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/BaseConfigManager.java new file mode 100644 index 0000000..00efc64 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/BaseConfigManager.java @@ -0,0 +1,51 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework; + +import me.filoghost.chestcommands.config.framework.mapped.MappedConfig; +import me.filoghost.chestcommands.config.framework.mapped.MappedConfigLoader; + +import java.nio.file.Path; +import java.util.function.Supplier; + +public class BaseConfigManager { + + protected final Path rootDataFolder; + + public BaseConfigManager(Path rootDataFolder) { + this.rootDataFolder = rootDataFolder; + } + + public Path getRootDataFolder() { + return rootDataFolder; + } + + public ConfigLoader getConfigLoader(String fileName) { + return getConfigLoader(rootDataFolder.resolve(fileName)); + } + + public ConfigLoader getConfigLoader(Path configPath) { + return new ConfigLoader(rootDataFolder, configPath); + } + + public MappedConfigLoader getMappedConfigLoader(String fileName, Supplier mappedObjectConstructor) { + return getMappedConfigLoader(rootDataFolder.resolve(fileName), mappedObjectConstructor); + } + + public MappedConfigLoader getMappedConfigLoader(Path configPath, Supplier mappedObjectConstructor) { + return new MappedConfigLoader<>(rootDataFolder, configPath, mappedObjectConstructor); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/Config.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/Config.java similarity index 73% rename from Plugin/src/main/java/me/filoghost/chestcommands/config/Config.java rename to Plugin/src/main/java/me/filoghost/chestcommands/config/framework/Config.java index b8d43f7..8460851 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/Config.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/Config.java @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package me.filoghost.chestcommands.config; +package me.filoghost.chestcommands.config.framework; import org.bukkit.configuration.file.YamlConfiguration; @@ -21,16 +21,20 @@ import java.nio.file.Path; public class Config extends ConfigSection { private final YamlConfiguration yaml; - private final Path filePath; + private final Path sourceFilePath; - public Config(YamlConfiguration yaml, Path filePath) { - super(yaml); - this.yaml = yaml; - this.filePath = filePath; + public Config(Path sourceFilePath) { + this(new YamlConfiguration(), sourceFilePath); } - public String getFileName() { - return filePath.getFileName().toString(); + public Config(YamlConfiguration yaml, Path sourceFilePath) { + super(yaml); + this.yaml = yaml; + this.sourceFilePath = sourceFilePath; + } + + public String getSourceFileName() { + return sourceFilePath.getFileName().toString(); } public String saveToString() { diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigLoader.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigLoader.java new file mode 100644 index 0000000..66006a2 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigLoader.java @@ -0,0 +1,143 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework; + +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSyntaxException; +import me.filoghost.chestcommands.util.Preconditions; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class ConfigLoader { + + private final Path rootDataFolder; + private final Path configPath; + + public ConfigLoader(Path rootDataFolder, Path configPath) { + Preconditions.checkArgument(configPath.startsWith(rootDataFolder), "config file " + configPath + " cannot be outside " + rootDataFolder); + + this.rootDataFolder = rootDataFolder; + this.configPath = configPath; + } + + public Config init() throws ConfigSaveException, ConfigLoadException { + createDefault(); + return load(); + } + + public void createDefault() throws ConfigSaveException { + if (fileExists()) { + return; + } + + createParentDirectory(); + + Path relativeConfigPath = rootDataFolder.relativize(configPath); + String internalJarPath = toInternalJarPath(relativeConfigPath); + + try (InputStream defaultFile = getInternalResource(internalJarPath)) { + if (defaultFile != null) { + Files.copy(defaultFile, configPath); + } else { + Files.createFile(configPath); + } + } catch (IOException e) { + throw new ConfigSaveException("couldn't create default config file " + configPath, e); + } + } + + private String toInternalJarPath(Path path) { + return StreamSupport.stream(path.spliterator(), false) + .map(Path::toString) + .collect(Collectors.joining("/", "/", "")); + } + + + private InputStream getInternalResource(String internalJarPath) throws IOException { + Preconditions.notNull(internalJarPath, "internalJarPath"); + + URL resourceURL = getClass().getResource(internalJarPath); + if (resourceURL == null) { + return null; + } + + URLConnection connection = resourceURL.openConnection(); + connection.setUseCaches(false); + return connection.getInputStream(); + } + + public boolean fileExists() { + return (Files.isRegularFile(configPath)); + } + + public Config load() throws ConfigLoadException { + Preconditions.checkState(fileExists(), configPath.getFileName() + " doesn't exist or is not a regular file"); + + YamlConfiguration yaml = new YamlConfiguration(); + + try (BufferedReader reader = Files.newBufferedReader(configPath)) { + yaml.load(reader); + } catch (IOException e) { + throw new ConfigLoadException("couldn't read config file " + configPath, e); + } catch (InvalidConfigurationException e) { + throw new ConfigSyntaxException(e.getMessage(), e); + } + + return new Config(yaml, configPath); + } + + public void save(Config config) throws ConfigSaveException { + createParentDirectory(); + + String data = config.saveToString(); + + try (BufferedWriter writer = Files.newBufferedWriter(configPath)) { + writer.write(data); + } catch (IOException e) { + throw new ConfigSaveException("couldn't write config data to " + configPath, e); + } + } + + private void createParentDirectory() throws ConfigSaveException { + if (configPath.getParent() != null) { + try { + Files.createDirectories(configPath.getParent()); + } catch (IOException e) { + throw new ConfigSaveException("couldn't create directory " + configPath.getParent(), e); + } + } + } + + public Path getConfigPath() { + return configPath; + } + + public String getFileName() { + return configPath.getFileName().toString(); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigSection.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigSection.java similarity index 91% rename from Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigSection.java rename to Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigSection.java index 1e6fe77..70e5ab0 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/config/ConfigSection.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/ConfigSection.java @@ -1,5 +1,6 @@ -package me.filoghost.chestcommands.config; +package me.filoghost.chestcommands.config.framework; +import me.filoghost.chestcommands.config.framework.exception.ConfigValueException; import org.bukkit.configuration.ConfigurationSection; import java.util.ArrayList; @@ -75,10 +76,6 @@ public class ConfigSection { return yamlSection.getKeys(deep); } - public boolean contains(String path) { - return yamlSection.contains(path); - } - public boolean isSet(String path) { return yamlSection.isSet(path); } @@ -91,10 +88,6 @@ public class ConfigSection { return yamlSection.getString(path); } - public String getString(String path, String def) { - return yamlSection.getString(path, def); - } - public int getInt(String path) { return yamlSection.getInt(path); } @@ -107,10 +100,6 @@ public class ConfigSection { return yamlSection.getDouble(path); } - public long getLong(String path) { - return yamlSection.getLong(path); - } - public List getStringList(String path) { return yamlSection.getStringList(path); } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigException.java new file mode 100644 index 0000000..5dd6b05 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigException.java @@ -0,0 +1,13 @@ +package me.filoghost.chestcommands.config.framework.exception; + +public class ConfigException extends Exception { + + public ConfigException(String message) { + super(message); + } + + public ConfigException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigLoadException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigLoadException.java new file mode 100644 index 0000000..c145072 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigLoadException.java @@ -0,0 +1,9 @@ +package me.filoghost.chestcommands.config.framework.exception; + +public class ConfigLoadException extends ConfigException { + + public ConfigLoadException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSaveException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSaveException.java new file mode 100644 index 0000000..de64ce1 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSaveException.java @@ -0,0 +1,9 @@ +package me.filoghost.chestcommands.config.framework.exception; + +public class ConfigSaveException extends ConfigException { + + public ConfigSaveException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSyntaxException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSyntaxException.java new file mode 100644 index 0000000..5f868c0 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigSyntaxException.java @@ -0,0 +1,11 @@ +package me.filoghost.chestcommands.config.framework.exception; + +import org.bukkit.configuration.InvalidConfigurationException; + +public class ConfigSyntaxException extends ConfigLoadException { + + public ConfigSyntaxException(String message, InvalidConfigurationException cause) { + super(message, cause); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigValueException.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigValueException.java new file mode 100644 index 0000000..2a484b6 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/exception/ConfigValueException.java @@ -0,0 +1,9 @@ +package me.filoghost.chestcommands.config.framework.exception; + +public class ConfigValueException extends ConfigException { + + public ConfigValueException(String message) { + super(message); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/ConfigMapper.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/ConfigMapper.java new file mode 100644 index 0000000..686f35a --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/ConfigMapper.java @@ -0,0 +1,157 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped; + +import com.google.common.collect.ImmutableList; +import me.filoghost.chestcommands.config.framework.ConfigSection; +import me.filoghost.chestcommands.config.framework.mapped.converter.BooleanConverter; +import me.filoghost.chestcommands.config.framework.mapped.converter.Converter; +import me.filoghost.chestcommands.config.framework.mapped.converter.DoubleConverter; +import me.filoghost.chestcommands.config.framework.mapped.converter.IntegerConverter; +import me.filoghost.chestcommands.config.framework.mapped.converter.ListConverter; +import me.filoghost.chestcommands.config.framework.mapped.converter.StringConverter; +import me.filoghost.chestcommands.config.framework.mapped.modifier.ChatColorsModifier; +import me.filoghost.chestcommands.config.framework.mapped.modifier.ValueModifier; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +public class ConfigMapper { + + private static final List CONVERTERS = ImmutableList.of( + new DoubleConverter(), + new IntegerConverter(), + new BooleanConverter(), + new StringConverter(), + new ListConverter() + ); + + private static final List> VALUE_MODIFIERS = ImmutableList.of( + new ChatColorsModifier() + ); + + private final MappedConfig mappedObject; + private final ConfigSection config; + private final List mappedFields; + + public ConfigMapper(MappedConfig mappedObject, ConfigSection config) throws ReflectiveOperationException { + this.mappedObject = mappedObject; + this.config = config; + this.mappedFields = getMappableFields(mappedObject.getClass()); + } + + private List getMappableFields(Class type) throws ReflectiveOperationException { + Field[] declaredFields; + + try { + declaredFields = type.getDeclaredFields(); + } catch (Throwable t) { + throw new ReflectiveOperationException(t); + } + + return Arrays.stream(declaredFields) + .filter(this::isMappable) + .map(MappedField::new) + .collect(Collectors.toList()); + } + + public Map getFieldValues() throws ReflectiveOperationException { + Map mappedFieldValues = new HashMap<>(); + + for (MappedField mappedField : mappedFields) { + Object defaultValue = mappedField.getFromObject(mappedObject); + + if (defaultValue == null) { + throw new IllegalArgumentException("mapped field \"" + mappedField.getFieldName() + "\" cannot be null by default"); + } + + mappedFieldValues.put(mappedField, defaultValue); + } + + return mappedFieldValues; + } + + public boolean addMissingConfigValues(Map defaultValues) { + boolean modified = false; + + // Add missing values from defaults + for (Entry entry : defaultValues.entrySet()) { + MappedField mappedField = entry.getKey(); + Object defaultValue = entry.getValue(); + + if (!config.isSet(mappedField.getConfigPath())) { + modified = true; + Converter converter = findConverter(mappedField.getFieldType()); + converter.setConfigValue(config, mappedField.getConfigPath(), defaultValue); + } + } + + return modified; + } + + public void injectObjectFields() throws ReflectiveOperationException { + for (MappedField mappedField : mappedFields) { + injectObjectField(mappedField); + } + } + + private void injectObjectField(MappedField mappedField) throws ReflectiveOperationException { + Type[] genericTypes = mappedField.getGenericTypes(); + Converter converter = findConverter(mappedField.getFieldType()); + + Object fieldValue = converter.getFieldValue(config, mappedField.getConfigPath(), genericTypes); + + for (Annotation annotation : mappedField.getAnnotations()) { + fieldValue = applyValueModifiers(fieldValue, annotation); + } + + mappedField.setToObject(mappedObject, fieldValue); + } + + private Object applyValueModifiers(Object fieldValue, Annotation annotation) { + for (ValueModifier modifier : VALUE_MODIFIERS) { + if (modifier.isApplicable(annotation, fieldValue)) { + fieldValue = modifier.transform(annotation, fieldValue); + } + } + return fieldValue; + } + + private Converter findConverter(Class type) { + return CONVERTERS.stream() + .filter(converter -> converter.matches(type)) + .findFirst() + .orElseThrow(() -> new IllegalStateException("cannot find converter for type " + type)); + } + + private boolean isMappable(Field field) { + int modifiers = field.getModifiers(); + boolean includeStatic = field.isAnnotationPresent(IncludeStatic.class) + || field.getDeclaringClass().isAnnotationPresent(IncludeStatic.class); + + return (!Modifier.isStatic(modifiers) || includeStatic) + || !Modifier.isTransient(modifiers) + || !Modifier.isFinal(modifiers); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/IncludeStatic.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/IncludeStatic.java new file mode 100644 index 0000000..c90b557 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/IncludeStatic.java @@ -0,0 +1,26 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.TYPE}) +public @interface IncludeStatic { + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfig.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfig.java new file mode 100644 index 0000000..e97b425 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfig.java @@ -0,0 +1,33 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped; + +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; + +public class MappedConfig { + + private String header; + + protected void setHeader(String... header) { + this.header = String.join("\n", header) + "\n"; + } + + public String getHeader() { + return header; + } + + public void postLoad() throws ConfigLoadException {} + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfigLoader.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfigLoader.java new file mode 100644 index 0000000..fd3208f --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedConfigLoader.java @@ -0,0 +1,78 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped; + +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigLoader; +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; + +import java.nio.file.Path; +import java.util.Map; +import java.util.function.Supplier; + +public class MappedConfigLoader { + + private final ConfigLoader configLoader; + private final Supplier mappedObjectConstructor; + private Map defaultValues; + + public MappedConfigLoader(Path rootDataFolder, Path configPath, Supplier mappedObjectConstructor) { + this.configLoader = new ConfigLoader(rootDataFolder, configPath); + this.mappedObjectConstructor = mappedObjectConstructor; + } + + public T init() throws ConfigLoadException, ConfigSaveException { + Config config = configLoader.init(); + T mappedObject = mappedObjectConstructor.get(); + + ConfigMapper mapper; + try { + mapper = new ConfigMapper(mappedObject, config); + } catch (ReflectiveOperationException e) { + throw new ConfigLoadException("couldn't initialize config mapper for class " + mappedObject.getClass(), e); + } + + // Extract default values from fields + if (defaultValues == null) { + try { + defaultValues = mapper.getFieldValues(); + } catch (ReflectiveOperationException e) { + throw new ConfigLoadException("couldn't read field values in class " + mappedObject.getClass(), e); + } + } + + // Add missing values and save if necessary + boolean modified = mapper.addMissingConfigValues(defaultValues); + if (modified) { + config.setHeader(mappedObject.getHeader()); + configLoader.save(config); + } + + // Update the mapped object with the contents from the config + try { + mapper.injectObjectFields(); + } catch (ReflectiveOperationException e) { + throw new ConfigLoadException("couldn't inject fields values in class " + mappedObject.getClass(), e); + } + mappedObject.postLoad(); + return mappedObject; + } + + public String getFileName() { + return configLoader.getFileName(); + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedField.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedField.java new file mode 100644 index 0000000..d9370dc --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/MappedField.java @@ -0,0 +1,88 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class MappedField { + + private final Field field; + private final String configPath; + + public MappedField(Field field) { + this.field = field; + + this.configPath = field.getName() + .replace("__", ".") + .replace("_", "-"); + } + + public Object getFromObject(MappedConfig mappedObject) throws ReflectiveOperationException { + try { + field.setAccessible(true); + return field.get(mappedObject); + } catch (Throwable t) { + throw new ReflectiveOperationException(t); + } + } + + public void setToObject(MappedConfig mappedObject, Object fieldValue) throws ReflectiveOperationException { + try { + field.setAccessible(true); + field.set(mappedObject, fieldValue); + } catch (Throwable t) { + throw new ReflectiveOperationException(t); + } + } + + public Type[] getGenericTypes() throws ReflectiveOperationException { + try { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + return ((ParameterizedType) genericType).getActualTypeArguments(); + } else { + return null; + } + } catch (Throwable t) { + throw new ReflectiveOperationException(t); + } + } + + public List getAnnotations() { + return Stream.concat( + Arrays.stream(field.getDeclaredAnnotations()), + Arrays.stream(field.getDeclaringClass().getDeclaredAnnotations())) + .collect(Collectors.toList()); + } + + public String getFieldName() { + return field.getName(); + } + + public Class getFieldType() { + return field.getType(); + } + + public String getConfigPath() { + return configPath; + } +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/BooleanConverter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/BooleanConverter.java new file mode 100644 index 0000000..2960496 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/BooleanConverter.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; + +import java.lang.reflect.Type; + +public class BooleanConverter implements Converter { + + @Override + public void setConfigValue(ConfigSection config, String path, Object value) { + config.set(path, value); + } + + @Override + public Boolean getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) { + return config.getBoolean(path); + } + + @Override + public boolean matches(Class type) { + return type == Boolean.class || type == boolean.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/Converter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/Converter.java new file mode 100644 index 0000000..df0e921 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/Converter.java @@ -0,0 +1,29 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; + +import java.lang.reflect.Type; + +public interface Converter { + + void setConfigValue(ConfigSection config, String path, Object value); + + Object getFieldValue(ConfigSection config, String path, Type[] genericTypes); + + boolean matches(Class type); + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/DoubleConverter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/DoubleConverter.java new file mode 100644 index 0000000..e6c9ffc --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/DoubleConverter.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; + +import java.lang.reflect.Type; + +public class DoubleConverter implements Converter { + + @Override + public void setConfigValue(ConfigSection config, String path, Object value) { + config.set(path, value); + } + + @Override + public Double getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) { + return config.getDouble(path); + } + + @Override + public boolean matches(Class type) { + return type == Double.class || type == double.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/IntegerConverter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/IntegerConverter.java new file mode 100644 index 0000000..47ac621 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/IntegerConverter.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; + +import java.lang.reflect.Type; + +public class IntegerConverter implements Converter { + + @Override + public void setConfigValue(ConfigSection config, String path, Object value) { + config.set(path, value); + } + + @Override + public Integer getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) { + return config.getInt(path); + } + + @Override + public boolean matches(Class type) { + return type == Integer.class || type == int.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/ListConverter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/ListConverter.java new file mode 100644 index 0000000..99ca844 --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/ListConverter.java @@ -0,0 +1,51 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; +import me.filoghost.chestcommands.util.Preconditions; + +import java.lang.reflect.Type; +import java.util.List; + +public class ListConverter implements Converter { + + @Override + public void setConfigValue(ConfigSection config, String path, Object value) { + config.set(path, value); + } + + @Override + public List getFieldValue(ConfigSection config, String path, Type[] genericTypes) { + Preconditions.notNull(genericTypes, "genericTypes"); + Preconditions.checkArgument(genericTypes.length == 1, "genericTypes length must be 1"); + + Type listType = genericTypes[0]; + + if (listType == Integer.class) { + return config.getIntegerList(path); + } else if (listType == String.class) { + return config.getStringList(path); + } else { + throw new IllegalArgumentException("unsupported list type: " + listType); + } + } + + @Override + public boolean matches(Class type) { + return type == List.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/StringConverter.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/StringConverter.java new file mode 100644 index 0000000..422dcbd --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/converter/StringConverter.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.converter; + +import me.filoghost.chestcommands.config.framework.ConfigSection; + +import java.lang.reflect.Type; + +public class StringConverter implements Converter { + + @Override + public void setConfigValue(ConfigSection config, String path, Object value) { + config.set(path, value); + } + + @Override + public String getFieldValue(ConfigSection config, String path, Type[] parameterizedTypes) { + return config.getString(path); + } + + @Override + public boolean matches(Class type) { + return type == String.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColors.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColors.java new file mode 100644 index 0000000..7a8034e --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColors.java @@ -0,0 +1,26 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.modifier; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.TYPE}) +public @interface ChatColors { + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColorsModifier.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColorsModifier.java new file mode 100644 index 0000000..18f65cd --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ChatColorsModifier.java @@ -0,0 +1,36 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.modifier; + +import me.filoghost.chestcommands.util.Colors; + +public class ChatColorsModifier implements ValueModifier { + + @Override + public String transformChecked(ChatColors annotation, String value) { + return Colors.addColors(value); + } + + @Override + public Class getAnnotationType() { + return ChatColors.class; + } + + @Override + public Class getValueType() { + return String.class; + } + +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ValueModifier.java b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ValueModifier.java new file mode 100644 index 0000000..1925f7a --- /dev/null +++ b/Plugin/src/main/java/me/filoghost/chestcommands/config/framework/mapped/modifier/ValueModifier.java @@ -0,0 +1,38 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package me.filoghost.chestcommands.config.framework.mapped.modifier; + +import me.filoghost.chestcommands.util.Preconditions; + +import java.lang.annotation.Annotation; + +public interface ValueModifier { + + V transformChecked(A annotation, V value); + + Class getAnnotationType(); + + Class getValueType(); + + default boolean isApplicable(Annotation annotation, Object value) { + return getAnnotationType().isInstance(annotation) && getValueType().isInstance(value); + } + + default Object transform(Annotation annotation, Object fieldValue) { + Preconditions.checkArgument(isApplicable(annotation, fieldValue), "modifier doesn't match given types"); + + return transformChecked(getAnnotationType().cast(annotation), getValueType().cast(fieldValue)); + } +} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/Upgrade.java b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/Upgrade.java index dad391f..ee45a69 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/Upgrade.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/Upgrade.java @@ -14,10 +14,9 @@ */ package me.filoghost.chestcommands.legacy; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.config.ConfigLoader; +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; import me.filoghost.chestcommands.util.Preconditions; -import org.bukkit.configuration.InvalidConfigurationException; import java.io.IOException; import java.nio.file.Files; @@ -40,7 +39,11 @@ public abstract class Upgrade { Preconditions.checkState(!hasRun, "Upgrade can only be run once"); hasRun = true; - computeChanges(); + try { + computeChanges(); + } catch (ConfigLoadException e) { + throw new UpgradeException("couldn't load file to upgrade \"" + getOriginalFile().getFileName() + "\"", e); + } if (modified) { try { @@ -51,7 +54,7 @@ public abstract class Upgrade { try { saveChanges(); - } catch (IOException e) { + } catch (ConfigSaveException e) { throw new UpgradeException("couldn't save upgraded file \"" + getUpgradedFile().getFileName() + "\"", e); } } @@ -59,16 +62,6 @@ public abstract class Upgrade { return modified; } - protected Config loadConfig(ConfigLoader configLoader) throws UpgradeException { - try { - return configLoader.load(); - } catch (IOException e) { - throw new UpgradeException("couldn't read configuration file \"" + configLoader.getFileName() + "\"", e); - } catch (InvalidConfigurationException e) { - throw new UpgradeException("couldn't parse YAML syntax of file \"" + configLoader.getFileName() + "\"", e); - } - } - private void createBackupFile(Path path) throws IOException { String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd-HH.mm")); String backupName = path.getFileName() + "_" + date + ".backup"; @@ -80,8 +73,8 @@ public abstract class Upgrade { public abstract Path getUpgradedFile(); - protected abstract void computeChanges() throws UpgradeException; + protected abstract void computeChanges() throws ConfigLoadException; - protected abstract void saveChanges() throws IOException; + protected abstract void saveChanges() throws ConfigSaveException; } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/UpgradesExecutor.java b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/UpgradesExecutor.java index f49d0fa..f2a54bd 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/UpgradesExecutor.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/UpgradesExecutor.java @@ -15,7 +15,7 @@ package me.filoghost.chestcommands.legacy; import me.filoghost.chestcommands.config.ConfigManager; -import me.filoghost.chestcommands.config.ConfigLoader; +import me.filoghost.chestcommands.config.framework.ConfigLoader; import me.filoghost.chestcommands.legacy.UpgradesDoneRegistry.UpgradeID; import me.filoghost.chestcommands.legacy.upgrades.MenuUpgrade; import me.filoghost.chestcommands.legacy.upgrades.PlaceholdersUpgrade; @@ -42,7 +42,7 @@ public class UpgradesExecutor { public void run(boolean isFreshInstall) throws UpgradeExecutorException { this.failedUpgrades = new ArrayList<>(); - Path upgradesDoneFile = configManager.getBaseDataPath().resolve(".upgrades-done"); + Path upgradesDoneFile = configManager.getRootDataFolder().resolve(".upgrades-done"); try { upgradesDoneRegistry = new UpgradesDoneRegistry(upgradesDoneFile); @@ -56,18 +56,23 @@ public class UpgradesExecutor { upgradesDoneRegistry.setAllDone(); } else { - String legacyCommandSeparator = readLegacyCommandSeparator(); + String legacyCommandSeparator; + if (!upgradesDoneRegistry.isDone(UpgradeID.V4_MENUS)) { + legacyCommandSeparator = readLegacyCommandSeparator(); + } else { + legacyCommandSeparator = null; + } - SettingsUpgrade settingsUpgrade = new SettingsUpgrade(configManager.getSettingsConfigLoader()); + SettingsUpgrade settingsUpgrade = new SettingsUpgrade(configManager); runIfNecessary(UpgradeID.V4_CONFIG, settingsUpgrade); - PlaceholdersUpgrade placeholdersUpgrade = new PlaceholdersUpgrade(configManager.getPlaceholdersConfigLoader(), configManager.getBaseDataPath()); + PlaceholdersUpgrade placeholdersUpgrade = new PlaceholdersUpgrade(configManager); runIfNecessary(UpgradeID.V4_PLACEHOLDERS, placeholdersUpgrade); try { List menuUpgrades = CollectionUtils.transform( configManager.getMenuPaths(), - menuPath -> new MenuUpgrade(new ConfigLoader(menuPath), legacyCommandSeparator)); + menuPath -> new MenuUpgrade(configManager.getConfigLoader(menuPath), legacyCommandSeparator)); runIfNecessary(UpgradeID.V4_MENUS, menuUpgrades); } catch (IOException e) { failedUpgrades.add(configManager.getMenusFolder()); @@ -91,18 +96,18 @@ public class UpgradesExecutor { } private String readLegacyCommandSeparator() { - String legacyCommandSeparator; - ConfigLoader settingsConfigLoader = configManager.getSettingsConfigLoader(); + ConfigLoader settingsConfigLoader = configManager.getConfigLoader("config.yml"); - try { - legacyCommandSeparator = settingsConfigLoader.load().getString("multiple-commands-separator", ";"); - } catch (Exception e) { - legacyCommandSeparator = ";"; - Log.severe("Failed to load " + settingsConfigLoader.getFileName() - + ", assuming default command separator \"" + legacyCommandSeparator + "\"."); + if (!settingsConfigLoader.fileExists()) { + return null; } - return legacyCommandSeparator; + try { + return settingsConfigLoader.load().getString("multiple-commands-separator"); + } catch (Throwable t) { + Log.severe("Failed to load " + settingsConfigLoader.getFileName() + ", assuming default command separator \";\"."); + return null; + } } @@ -143,8 +148,7 @@ public class UpgradesExecutor { private void logUpgradeException(Upgrade upgrade, UpgradeException upgradeException) { Log.severe( - "Error while trying to automatically upgrade " - + upgrade.getOriginalFile() + ": " + upgradeException.getMessage(), + "Error while trying to automatically upgrade " + upgrade.getOriginalFile() + ": " + upgradeException.getMessage(), upgradeException.getCause()); } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/MenuUpgrade.java b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/MenuUpgrade.java index 14e3f97..e37f38d 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/MenuUpgrade.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/MenuUpgrade.java @@ -14,16 +14,16 @@ */ package me.filoghost.chestcommands.legacy.upgrades; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.config.ConfigLoader; -import me.filoghost.chestcommands.config.ConfigSection; +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigLoader; +import me.filoghost.chestcommands.config.framework.ConfigSection; +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; import me.filoghost.chestcommands.legacy.Upgrade; -import me.filoghost.chestcommands.legacy.UpgradeException; -import me.filoghost.chestcommands.parsing.menu.MenuSettingsNode; import me.filoghost.chestcommands.parsing.icon.IconSettingsNode; +import me.filoghost.chestcommands.parsing.menu.MenuSettingsNode; import me.filoghost.chestcommands.util.Strings; -import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -43,17 +43,17 @@ public class MenuUpgrade extends Upgrade { @Override public Path getOriginalFile() { - return menuConfigLoader.getPath(); + return menuConfigLoader.getConfigPath(); } @Override public Path getUpgradedFile() { - return menuConfigLoader.getPath(); + return menuConfigLoader.getConfigPath(); } @Override - protected void computeChanges() throws UpgradeException { - Config menuConfig = loadConfig(menuConfigLoader); + protected void computeChanges() throws ConfigLoadException { + Config menuConfig = menuConfigLoader.load(); menuConfig.setHeader(null); for (String key : menuConfig.getKeys(true)) { @@ -74,7 +74,7 @@ public class MenuUpgrade extends Upgrade { } @Override - protected void saveChanges() throws IOException { + protected void saveChanges() throws ConfigSaveException { menuConfigLoader.save(updatedConfig); } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/PlaceholdersUpgrade.java b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/PlaceholdersUpgrade.java index 1d5abbc..9f0142e 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/PlaceholdersUpgrade.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/PlaceholdersUpgrade.java @@ -14,10 +14,12 @@ */ package me.filoghost.chestcommands.legacy.upgrades; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.config.ConfigLoader; +import me.filoghost.chestcommands.config.ConfigManager; +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigLoader; +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; import me.filoghost.chestcommands.legacy.Upgrade; -import me.filoghost.chestcommands.legacy.UpgradeException; import me.filoghost.chestcommands.util.Strings; import org.apache.commons.lang.StringEscapeUtils; @@ -28,13 +30,13 @@ import java.util.List; public class PlaceholdersUpgrade extends Upgrade { - private final ConfigLoader newPlaceholdersConfigLoader; private final Path oldPlaceholdersFile; + private final ConfigLoader newPlaceholdersConfigLoader; private Config updatedConfig; - public PlaceholdersUpgrade(ConfigLoader placeholdersConfigLoader, Path dataPath) { - this.newPlaceholdersConfigLoader = placeholdersConfigLoader; - this.oldPlaceholdersFile = dataPath.resolve("placeholders.yml"); + public PlaceholdersUpgrade(ConfigManager configManager) { + this.oldPlaceholdersFile = configManager.getRootDataFolder().resolve("placeholders.yml"); + this.newPlaceholdersConfigLoader = configManager.getConfigLoader("custom-placeholders.yml"); } @Override @@ -44,22 +46,22 @@ public class PlaceholdersUpgrade extends Upgrade { @Override public Path getUpgradedFile() { - return newPlaceholdersConfigLoader.getPath(); + return newPlaceholdersConfigLoader.getConfigPath(); } @Override - protected void computeChanges() throws UpgradeException { + protected void computeChanges() throws ConfigLoadException { if (!Files.isRegularFile(oldPlaceholdersFile)) { return; } // Do NOT load the new placeholder configuration from disk, as it should only contain placeholders imported from the old file - Config newPlaceholdersConfig = newPlaceholdersConfigLoader.loadEmpty(); + Config newPlaceholdersConfig = new Config(newPlaceholdersConfigLoader.getConfigPath()); List lines; try { lines = Files.readAllLines(oldPlaceholdersFile); } catch (IOException e) { - throw new UpgradeException("couldn't read file \"" + oldPlaceholdersFile.getFileName() + "\"", e); + throw new ConfigLoadException("couldn't read file \"" + oldPlaceholdersFile.getFileName() + "\"", e); } for (String line : lines) { @@ -85,7 +87,7 @@ public class PlaceholdersUpgrade extends Upgrade { } @Override - protected void saveChanges() throws IOException { + protected void saveChanges() throws ConfigSaveException { try { Files.deleteIfExists(oldPlaceholdersFile); } catch (IOException ignored) {} diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/SettingsUpgrade.java b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/SettingsUpgrade.java index b70596a..c3dc2bf 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/SettingsUpgrade.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/legacy/upgrades/SettingsUpgrade.java @@ -14,12 +14,13 @@ */ package me.filoghost.chestcommands.legacy.upgrades; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.config.ConfigLoader; +import me.filoghost.chestcommands.config.ConfigManager; +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigLoader; +import me.filoghost.chestcommands.config.framework.exception.ConfigLoadException; +import me.filoghost.chestcommands.config.framework.exception.ConfigSaveException; import me.filoghost.chestcommands.legacy.Upgrade; -import me.filoghost.chestcommands.legacy.UpgradeException; -import java.io.IOException; import java.nio.file.Path; public class SettingsUpgrade extends Upgrade { @@ -27,23 +28,23 @@ public class SettingsUpgrade extends Upgrade { private final ConfigLoader settingsConfigLoader; private Config updatedConfig; - public SettingsUpgrade(ConfigLoader settingsConfigLoader) { - this.settingsConfigLoader = settingsConfigLoader; + public SettingsUpgrade(ConfigManager configManager) { + this.settingsConfigLoader = configManager.getConfigLoader("config.yml"); } @Override public Path getOriginalFile() { - return settingsConfigLoader.getPath(); + return settingsConfigLoader.getConfigPath(); } @Override public Path getUpgradedFile() { - return settingsConfigLoader.getPath(); + return settingsConfigLoader.getConfigPath(); } @Override - protected void computeChanges() throws UpgradeException { - Config settingsConfig = loadConfig(settingsConfigLoader); + protected void computeChanges() throws ConfigLoadException { + Config settingsConfig = settingsConfigLoader.load(); removeNode(settingsConfig, "use-only-commands-without-args"); removeNode(settingsConfig, "use-console-colors"); @@ -61,7 +62,7 @@ public class SettingsUpgrade extends Upgrade { @Override - protected void saveChanges() throws IOException { + protected void saveChanges() throws ConfigSaveException { settingsConfigLoader.save(updatedConfig); } } diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/ErrorFormat.java b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/ErrorFormat.java index ccdfac8..7e3c86c 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/ErrorFormat.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/ErrorFormat.java @@ -1,19 +1,20 @@ package me.filoghost.chestcommands.parsing; +import me.filoghost.chestcommands.config.framework.Config; import me.filoghost.chestcommands.parsing.icon.IconSettings; public class ErrorFormat { - public static String invalidMenuSetting(String menuName, String invalidSetting, String errorMessage) { - return menuError(menuName, "has an invalid menu setting \"" + invalidSetting + "\": " + errorMessage); + public static String invalidMenuSetting(Config menuConfig, String invalidSetting, String errorMessage) { + return menuError(menuConfig, "has an invalid menu setting \"" + invalidSetting + "\": " + errorMessage); } - public static String missingMenuSetting(String menuName, String missingSetting) { - return menuError(menuName, "is missing the menu setting \"" + missingSetting + "\""); + public static String missingMenuSetting(Config menuConfig, String missingSetting) { + return menuError(menuConfig, "is missing the menu setting \"" + missingSetting + "\""); } - private static String menuError(String menuName, String errorMessage) { - return "The menu \"" + menuName + "\" " + errorMessage + "."; + private static String menuError(Config menuConfig, String errorMessage) { + return "The menu \"" + menuConfig.getSourceFileName() + "\" " + errorMessage + "."; } public static String invalidAttribute(IconSettings iconSettings, String attributeName, String errorMessage) { diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/icon/IconSettings.java b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/icon/IconSettings.java index de7ef59..2d41e82 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/icon/IconSettings.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/icon/IconSettings.java @@ -14,8 +14,8 @@ */ package me.filoghost.chestcommands.parsing.icon; -import me.filoghost.chestcommands.config.ConfigSection; -import me.filoghost.chestcommands.config.ConfigValueException; +import me.filoghost.chestcommands.config.framework.ConfigSection; +import me.filoghost.chestcommands.config.framework.exception.ConfigValueException; import me.filoghost.chestcommands.icon.InternalConfigurableIcon; import me.filoghost.chestcommands.parsing.ParseException; import me.filoghost.chestcommands.parsing.icon.attributes.ActionsAttribute; diff --git a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java index c868437..7a25b4b 100644 --- a/Plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java +++ b/Plugin/src/main/java/me/filoghost/chestcommands/parsing/menu/MenuParser.java @@ -15,11 +15,11 @@ package me.filoghost.chestcommands.parsing.menu; import me.filoghost.chestcommands.action.Action; -import me.filoghost.chestcommands.config.Config; -import me.filoghost.chestcommands.config.ConfigSection; -import me.filoghost.chestcommands.config.ConfigValueException; -import me.filoghost.chestcommands.menu.InternalIconMenu; +import me.filoghost.chestcommands.config.framework.Config; +import me.filoghost.chestcommands.config.framework.ConfigSection; +import me.filoghost.chestcommands.config.framework.exception.ConfigValueException; import me.filoghost.chestcommands.icon.InternalConfigurableIcon; +import me.filoghost.chestcommands.menu.InternalIconMenu; import me.filoghost.chestcommands.parsing.ActionParser; import me.filoghost.chestcommands.parsing.ErrorFormat; import me.filoghost.chestcommands.parsing.ItemStackParser; @@ -41,7 +41,7 @@ public class MenuParser { MenuSettings menuSettings = loadMenuSettings(menuConfig, errorCollector); List iconSettingsList = loadIconSettingsList(menuConfig, errorCollector); - InternalIconMenu iconMenu = new InternalIconMenu(menuSettings.getTitle(), menuSettings.getRows(), menuConfig.getFileName()); + InternalIconMenu iconMenu = new InternalIconMenu(menuSettings.getTitle(), menuSettings.getRows(), menuConfig.getSourceFileName()); for (IconSettings iconSettings : iconSettingsList) { try { @@ -54,7 +54,7 @@ public class MenuParser { iconMenu.setRefreshTicks(menuSettings.getRefreshTicks()); iconMenu.setOpenActions(menuSettings.getOpenActions()); - return new LoadedMenu(iconMenu, menuConfig.getFileName(), menuSettings.getCommands(), menuSettings.getOpenTrigger()); + return new LoadedMenu(iconMenu, menuConfig.getSourceFileName(), menuSettings.getCommands(), menuSettings.getOpenTrigger()); } @@ -105,7 +105,7 @@ public class MenuParser { } } catch (ConfigValueException e) { title = ChatColor.DARK_RED + "No name set"; - errorCollector.addError(ErrorFormat.missingMenuSetting(config.getFileName(), MenuSettingsNode.NAME)); + errorCollector.addError(ErrorFormat.missingMenuSetting(config, MenuSettingsNode.NAME)); } int rows; @@ -116,7 +116,7 @@ public class MenuParser { } } catch (ConfigValueException e) { rows = 6; // Defaults to 6 rows - errorCollector.addError(ErrorFormat.missingMenuSetting(config.getFileName(), MenuSettingsNode.ROWS)); + errorCollector.addError(ErrorFormat.missingMenuSetting(config, MenuSettingsNode.ROWS)); } MenuSettings menuSettings = new MenuSettings(title, rows); @@ -157,7 +157,7 @@ public class MenuParser { menuSettings.setOpenTrigger(openTrigger); } catch (ParseException e) { - errorCollector.addError(ErrorFormat.invalidMenuSetting(config.getFileName(), MenuSettingsNode.OPEN_ITEM_MATERIAL, e.getMessage())); + errorCollector.addError(ErrorFormat.invalidMenuSetting(config, MenuSettingsNode.OPEN_ITEM_MATERIAL, e.getMessage())); } } } @@ -183,7 +183,7 @@ public class MenuParser { } ConfigSection iconSection = config.getConfigSection(iconSectionName); - IconSettings iconSettings = new IconSettings(config.getFileName(), iconSectionName); + IconSettings iconSettings = new IconSettings(config.getSourceFileName(), iconSectionName); iconSettings.loadFrom(iconSection, errorCollector); iconSettingsList.add(iconSettings); } diff --git a/Utils/src/main/java/me/filoghost/chestcommands/util/Preconditions.java b/Utils/src/main/java/me/filoghost/chestcommands/util/Preconditions.java index 473c164..ead530c 100644 --- a/Utils/src/main/java/me/filoghost/chestcommands/util/Preconditions.java +++ b/Utils/src/main/java/me/filoghost/chestcommands/util/Preconditions.java @@ -14,10 +14,10 @@ */ package me.filoghost.chestcommands.util; -import java.util.Collection; - import org.bukkit.Material; +import java.util.Collection; + public final class Preconditions { private Preconditions() {}