Use Try<Void> for config loading and saving

This commit is contained in:
Ben Woo 2023-09-08 19:43:04 +08:00
parent f1ee2ee227
commit 0513865f43
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
15 changed files with 123 additions and 100 deletions

View File

@ -358,7 +358,8 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
*/ */
@Override @Override
public boolean saveAllConfigs() { public boolean saveAllConfigs() {
return configProvider.get().save() // TODO: Make this all Try<Void>
return configProvider.get().save().isSuccess()
&& worldManagerProvider.get().saveWorldsConfig() && worldManagerProvider.get().saveWorldsConfig()
&& anchorManagerProvider.get().saveAnchors(); && anchorManagerProvider.get().saveAnchors();
} }

View File

@ -12,7 +12,7 @@ public interface MVConfig {
* Loads the config from disk. * Loads the config from disk.
* @return True if the config was loaded successfully. * @return True if the config was loaded successfully.
*/ */
boolean load(); Try<Void> load();
/** /**
* Whether the config has been loaded. * Whether the config has been loaded.
@ -23,7 +23,7 @@ public interface MVConfig {
/** /**
* Saves the config to disk. * Saves the config to disk.
*/ */
boolean save(); Try<Void> save();
/** /**
* Gets the nodes for the config. * Gets the nodes for the config.

View File

@ -50,7 +50,8 @@ public class ReloadCommand extends MultiverseCommand {
public void onReloadCommand(@NotNull BukkitCommandIssuer issuer) { public void onReloadCommand(@NotNull BukkitCommandIssuer issuer) {
issuer.sendInfo(MVCorei18n.RELOAD_RELOADING); issuer.sendInfo(MVCorei18n.RELOAD_RELOADING);
try { try {
this.config.load(); // TODO: Make this all Try<Void>
this.config.load().getOrElseThrow(e -> new RuntimeException("Failed to load config", e));
this.worldManager.initAllWorlds(); this.worldManager.initAllWorlds();
this.anchorManager.loadAnchors(); this.anchorManager.loadAnchors();
} catch (Exception e) { } catch (Exception e) {

View File

@ -89,7 +89,7 @@ public class MVCoreConfig implements MVConfig {
} }
@Override @Override
public boolean load() { public Try<Void> load() {
migrateFromOldConfigFile(); migrateFromOldConfigFile();
return configHandle.load(); return configHandle.load();
} }
@ -100,9 +100,8 @@ public class MVCoreConfig implements MVConfig {
} }
@Override @Override
public boolean save() { public Try<Void> save() {
configHandle.save(); return configHandle.save();
return true;
} }
@Override @Override

View File

@ -1,5 +1,6 @@
package com.onarandombox.MultiverseCore.configuration.handle; package com.onarandombox.MultiverseCore.configuration.handle;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -9,6 +10,7 @@ import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.CommentedNode; import com.onarandombox.MultiverseCore.configuration.node.CommentedNode;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode; import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration; import io.github.townyadvanced.commentedconfiguration.CommentedConfiguration;
import io.vavr.control.Try;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -35,9 +37,12 @@ public class CommentedYamlConfigHandle extends FileConfigHandle<CommentedConfigu
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected boolean loadConfigObject() { protected void loadConfigObject() throws IOException {
config = new CommentedConfiguration(configPath, logger); config = new CommentedConfiguration(configPath, logger);
return config.load(); if (!config.load()) {
throw new IOException("Failed to load commented config file " + configPath
+ ". See console for details.");
}
} }
/** /**
@ -71,9 +76,9 @@ public class CommentedYamlConfigHandle extends FileConfigHandle<CommentedConfigu
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean save() { public Try<Void> save() {
config.save(); // TODO: There is no way to check if the save was successful.
return true; return Try.run(() -> config.save());
} }
public static class Builder extends FileConfigHandle.Builder<CommentedConfiguration, Builder> { public static class Builder extends FileConfigHandle.Builder<CommentedConfiguration, Builder> {

View File

@ -2,6 +2,7 @@ package com.onarandombox.MultiverseCore.configuration.handle;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import io.vavr.control.Try;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -16,7 +17,7 @@ public class ConfigurationSectionHandle extends GenericConfigHandle<Configuratio
return new Builder<>(configurationSection); return new Builder<>(configurationSection);
} }
public ConfigurationSectionHandle(@NotNull ConfigurationSection configurationSection, protected ConfigurationSectionHandle(@NotNull ConfigurationSection configurationSection,
@Nullable Logger logger, @Nullable Logger logger,
@Nullable NodeGroup nodes, @Nullable NodeGroup nodes,
@Nullable ConfigMigrator migrator) { @Nullable ConfigMigrator migrator) {
@ -24,6 +25,17 @@ public class ConfigurationSectionHandle extends GenericConfigHandle<Configuratio
this.config = configurationSection; this.config = configurationSection;
} }
/**
* Loads the configuration with a new configuration section.
*
* @param section The configuration section.
* @return Whether the configuration was loaded or its given error.
*/
public Try<Void> load(@NotNull ConfigurationSection section) {
this.config = section;
return load();
}
/** /**
* Builder for {@link ConfigurationSectionHandle}. * Builder for {@link ConfigurationSectionHandle}.
* *

View File

@ -5,12 +5,11 @@ import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import io.vavr.control.Try;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -33,49 +32,43 @@ abstract class FileConfigHandle<C extends FileConfiguration> extends GenericConf
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean load() { public Try<Void> load() {
boolean newFileCreated; boolean isNewFile = !configFile.exists();
try { return createConfigFile()
newFileCreated = createConfigFile(); .andThenTry(this::loadConfigObject)
} catch (IOException e) { .andThenTry(() -> {
Logging.severe("Failed to create config file: %s", configFile.getName()); if (!isNewFile) {
Logging.severe(e.getMessage()); migrateConfig();
return false; }
} setUpNodes();
if (!loadConfigObject()) { });
Logging.severe("Failed to load config file: %s", configFile.getName());
return false;
}
if (!newFileCreated) {
migrateConfig();
}
setUpNodes();
return true;
} }
/** /**
* Create a new config file if file does not exist * Create a new config file if file does not exist.
* *
* @return True if file exist or created successfully, otherwise false. * @return Whether the file was created or its given error.
*/ */
protected boolean createConfigFile() throws IOException { protected Try<Void> createConfigFile() {
if (configFile.exists()) { return Try.run(() -> {
return false; if (configFile.exists()) {
} return;
return configFile.createNewFile(); }
if (!configFile.createNewFile()) {
throw new IOException("Failed to create config file: " + configFile.getName());
}
});
} }
/** /**
* Loads the configuration object. * Loads the configuration object.
*
* @return True if the configuration was loaded successfully, false otherwise.
*/ */
protected abstract boolean loadConfigObject(); protected abstract void loadConfigObject() throws IOException, InvalidConfigurationException;
/** /**
* Saves the configuration. * Saves the configuration.
*/ */
public abstract boolean save(); public abstract Try<Void> save();
/** /**
* Checks if the configuration is loaded. * Checks if the configuration is loaded.

View File

@ -3,9 +3,7 @@ package com.onarandombox.MultiverseCore.configuration.handle;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.ConfigNodeNotFoundException; import com.onarandombox.MultiverseCore.configuration.node.ConfigNodeNotFoundException;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.NodeSerializer;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode; import com.onarandombox.MultiverseCore.configuration.node.ValueNode;
import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -24,7 +22,7 @@ public abstract class GenericConfigHandle<C extends ConfigurationSection> {
protected C config; protected C config;
public GenericConfigHandle(@Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) { protected GenericConfigHandle(@Nullable Logger logger, @Nullable NodeGroup nodes, @Nullable ConfigMigrator migrator) {
this.logger = logger; this.logger = logger;
this.nodes = nodes; this.nodes = nodes;
this.migrator = migrator; this.migrator = migrator;
@ -33,12 +31,13 @@ public abstract class GenericConfigHandle<C extends ConfigurationSection> {
/** /**
* Loads the configuration. * Loads the configuration.
* *
* @return True if the configuration was loaded successfully, false otherwise. * @return Whether the configuration was loaded or its given error.
*/ */
public boolean load() { public Try<Void> load() {
migrateConfig(); return Try.run(() -> {
setUpNodes(); migrateConfig();
return true; setUpNodes();
});
} }
/** /**

View File

@ -6,7 +6,7 @@ import java.util.logging.Logger;
import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator; import com.onarandombox.MultiverseCore.configuration.migration.ConfigMigrator;
import com.onarandombox.MultiverseCore.configuration.node.NodeGroup; import com.onarandombox.MultiverseCore.configuration.node.NodeGroup;
import com.onarandombox.MultiverseCore.configuration.node.ValueNode; import io.vavr.control.Try;
import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -35,27 +35,17 @@ public class YamlConfigHandle extends FileConfigHandle<YamlConfiguration> {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected boolean loadConfigObject() { protected void loadConfigObject() throws IOException, InvalidConfigurationException {
config = new YamlConfiguration(); config = new YamlConfiguration();
try { config.load(configFile);
config.load(configFile);
} catch (IOException | InvalidConfigurationException e) {
return false;
}
return true;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean save() { public Try<Void> save() {
try { return Try.run(() -> config.save(configFile));
config.save(configFile);
} catch (IOException e) {
return false;
}
return true;
} }
/** /**

View File

@ -95,7 +95,9 @@ public class WorldManager {
* Loads all worlds from the worlds config. * Loads all worlds from the worlds config.
*/ */
public void initAllWorlds() { public void initAllWorlds() {
populateWorldFromConfig(); if (!populateWorldFromConfig()) {
return;
}
loadDefaultWorlds(); loadDefaultWorlds();
autoLoadOfflineWorlds(); autoLoadOfflineWorlds();
saveWorldsConfig(); saveWorldsConfig();
@ -104,8 +106,13 @@ public class WorldManager {
/** /**
* Generate offline worlds from the worlds config. * Generate offline worlds from the worlds config.
*/ */
private void populateWorldFromConfig() { private boolean populateWorldFromConfig() {
worldsConfigManager.load(); Try<Void> load = worldsConfigManager.load();
if (load.isFailure()) {
Logging.severe("Failed to load worlds config: " + load.getCause().getMessage());
load.getCause().printStackTrace();
return false;
}
worldsConfigManager.getAllWorldConfigs().forEach(worldConfig -> { worldsConfigManager.getAllWorldConfigs().forEach(worldConfig -> {
getMVWorld(worldConfig.getWorldName()) getMVWorld(worldConfig.getWorldName())
.peek(mvWorld -> mvWorld.setWorldConfig(worldConfig)); .peek(mvWorld -> mvWorld.setWorldConfig(worldConfig));
@ -116,6 +123,7 @@ public class WorldManager {
offlineWorldsMap.put(offlineWorld.getName(), offlineWorld); offlineWorldsMap.put(offlineWorld.getName(), offlineWorld);
}); });
}); });
return true;
} }
/** /**
@ -785,6 +793,11 @@ public class WorldManager {
* @return true if it had successfully saved the file. * @return true if it had successfully saved the file.
*/ */
public boolean saveWorldsConfig() { public boolean saveWorldsConfig() {
return worldsConfigManager.save(); return worldsConfigManager.save()
.onFailure(failure -> {
Logging.severe("Failed to save worlds config: %s", failure);
failure.printStackTrace();
})
.isSuccess();
} }
} }

View File

@ -35,7 +35,7 @@ public class WorldConfig {
load(); load();
} }
public boolean load() { public Try<Void> load() {
return configHandle.load(); return configHandle.load();
} }

View File

@ -1,6 +1,7 @@
package com.onarandombox.MultiverseCore.worldnew.config; package com.onarandombox.MultiverseCore.worldnew.config;
import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.MultiverseCore;
import io.vavr.control.Try;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
@ -8,7 +9,6 @@ import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service; import org.jvnet.hk2.annotations.Service;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -23,32 +23,36 @@ public class WorldsConfigManager {
private YamlConfiguration worldsConfig; private YamlConfiguration worldsConfig;
@Inject @Inject
public WorldsConfigManager(@NotNull MultiverseCore core) { WorldsConfigManager(@NotNull MultiverseCore core) {
worldConfigMap = new HashMap<>(); worldConfigMap = new HashMap<>();
worldConfigFile = core.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile(); worldConfigFile = core.getDataFolder().toPath().resolve(CONFIG_FILENAME).toFile();
load();
} }
public void load() { public Try<Void> load() {
worldsConfig = YamlConfiguration.loadConfiguration(worldConfigFile);
worldConfigMap.clear(); worldConfigMap.clear();
for (String worldName : getAllWorldsInConfig()) {
worldConfigMap.put(worldName, new WorldConfig(worldName, getWorldConfigSection(worldName))); return Try.run(() -> {
} if (!worldConfigFile.exists()) {
worldConfigFile.createNewFile();
}
worldsConfig = new YamlConfiguration();
worldsConfig.load(worldConfigFile);
}).andThenTry(() -> {
for (String worldName : getAllWorldsInConfig()) {
worldConfigMap.put(worldName, new WorldConfig(worldName, getWorldConfigSection(worldName)));
}
}).onFailure(e -> {
worldsConfig = null;
worldConfigMap.clear();
});
} }
public boolean isLoaded() { public boolean isLoaded() {
return worldsConfig != null; return worldsConfig != null;
} }
public boolean save() { public Try<Void> save() {
try { return Try.run(() -> worldsConfig.save(worldConfigFile));
worldsConfig.save(worldConfigFile);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
} }
public Set<String> getAllWorldsInConfig() { public Set<String> getAllWorldsInConfig() {

View File

@ -26,8 +26,8 @@ class ConfigTest : TestWithMockBukkit() {
assertNotNull(defaultConfig) assertNotNull(defaultConfig)
File(Path.of(multiverseCore.dataFolder.absolutePath, "config.yml").absolutePathString()).writeText(defaultConfig) File(Path.of(multiverseCore.dataFolder.absolutePath, "config.yml").absolutePathString()).writeText(defaultConfig)
assertTrue(config.load()) assertTrue(config.load().isSuccess)
assertTrue(config.save()) assertTrue(config.save().isSuccess)
} }
@Test @Test
@ -40,8 +40,8 @@ class ConfigTest : TestWithMockBukkit() {
val oldConfig = getResourceAsText("/old_config.yml") val oldConfig = getResourceAsText("/old_config.yml")
assertNotNull(oldConfig) assertNotNull(oldConfig)
multiverseCore.dataFolder.toPath().resolve("config.yml").toFile().writeText(oldConfig) multiverseCore.dataFolder.toPath().resolve("config.yml").toFile().writeText(oldConfig)
assertTrue(config.load()) assertTrue(config.load().isSuccess)
assertTrue(config.save()) assertTrue(config.save().isSuccess)
assertEquals(true, config.enforceAccess) assertEquals(true, config.enforceAccess)
assertEquals(false, config.isEnablePrefixChat) assertEquals(false, config.isEnablePrefixChat)

View File

@ -22,8 +22,10 @@ class WorldConfigMangerTest : TestWithMockBukkit() {
assertNotNull(defaultConfig) assertNotNull(defaultConfig)
File(Path.of(multiverseCore.dataFolder.absolutePath, "worlds2.yml").absolutePathString()).writeText(defaultConfig) File(Path.of(multiverseCore.dataFolder.absolutePath, "worlds2.yml").absolutePathString()).writeText(defaultConfig)
worldConfigManager = worldConfigManager = multiverseCore.getService(WorldsConfigManager::class.java).takeIf { it != null } ?: run {
WorldsConfigManager(multiverseCore) throw IllegalStateException("WorldsConfigManager is not available as a service") }
assertTrue(worldConfigManager.load().isSuccess)
} }
@Test @Test

View File

@ -3,6 +3,7 @@ package org.mvplugins.multiverse.core.world
import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig
import com.onarandombox.MultiverseCore.worldnew.config.WorldsConfigManager import com.onarandombox.MultiverseCore.worldnew.config.WorldsConfigManager
import org.bukkit.Location import org.bukkit.Location
import org.junit.jupiter.api.Assertions
import org.mvplugins.multiverse.core.TestWithMockBukkit import org.mvplugins.multiverse.core.TestWithMockBukkit
import java.io.File import java.io.File
import java.nio.file.Path import java.nio.file.Path
@ -15,7 +16,7 @@ import kotlin.test.assertTrue
class WorldConfigTest : TestWithMockBukkit() { class WorldConfigTest : TestWithMockBukkit() {
private lateinit var worldConfigFile : WorldsConfigManager private lateinit var worldConfigManager : WorldsConfigManager
private lateinit var worldConfig : WorldConfig private lateinit var worldConfig : WorldConfig
@BeforeTest @BeforeTest
@ -24,9 +25,12 @@ class WorldConfigTest : TestWithMockBukkit() {
assertNotNull(defaultConfig) assertNotNull(defaultConfig)
File(Path.of(multiverseCore.dataFolder.absolutePath, "worlds2.yml").absolutePathString()).writeText(defaultConfig) File(Path.of(multiverseCore.dataFolder.absolutePath, "worlds2.yml").absolutePathString()).writeText(defaultConfig)
worldConfigFile = worldConfigManager = multiverseCore.getService(WorldsConfigManager::class.java).takeIf { it != null } ?: run {
WorldsConfigManager(multiverseCore) throw IllegalStateException("WorldsConfigManager is not available as a service") }
worldConfig = worldConfigFile.getWorldConfig("world")
assertTrue(worldConfigManager.load().isSuccess)
worldConfig = worldConfigManager.getWorldConfig("world")
assertNotNull(worldConfig);
} }
@Test @Test