#1497 Show specific message for invalid YAML files (#1506)

* #1497 Throw dedicated exception for invalid YAML files and handle it on startup
- Wrap SnakeYAML exceptions when loading config.yml and commands.yml on startup into own exception type
- Handle exception type on startup with specific error message

* #1497 Fix inaccurate JavaDoc comment
This commit is contained in:
ljacqu
2018-02-23 23:31:22 +01:00
committed by GitHub
parent 7864bb06ac
commit 329657bd5f
10 changed files with 216 additions and 5 deletions
+9 -1
View File
@@ -26,11 +26,13 @@ import fr.xephi.authme.service.BackupService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.service.bungeecord.BungeeReceiver;
import fr.xephi.authme.service.yaml.YamlParseException;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SettingsWarner;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.CleanupTask;
import fr.xephi.authme.task.purge.PurgeService;
import fr.xephi.authme.util.ExceptionUtils;
import org.apache.commons.lang.SystemUtils;
import org.bukkit.Server;
import org.bukkit.command.Command;
@@ -133,7 +135,13 @@ public class AuthMe extends JavaPlugin {
try {
initialize();
} catch (Throwable th) {
ConsoleLogger.logException("Aborting initialization of AuthMe:", th);
YamlParseException yamlParseException = ExceptionUtils.findThrowableInCause(YamlParseException.class, th);
if (yamlParseException == null) {
ConsoleLogger.logException("Aborting initialization of AuthMe:", th);
} else {
ConsoleLogger.logException("File '" + yamlParseException.getFile() + "' contains invalid YAML. "
+ "Please run its contents through http://yamllint.com", yamlParseException);
}
stopOrUnload();
return;
}
@@ -2,7 +2,7 @@ package fr.xephi.authme.initialization;
import ch.jalu.configme.configurationdata.ConfigurationData;
import ch.jalu.configme.resource.PropertyResource;
import ch.jalu.configme.resource.YamlFileResource;
import fr.xephi.authme.service.yaml.YamlFileResourceProvider;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SettingsMigrationService;
import fr.xephi.authme.settings.properties.AuthMeSettingsRetriever;
@@ -37,7 +37,7 @@ public class SettingsProvider implements Provider<Settings> {
if (!configFile.exists()) {
FileUtils.create(configFile);
}
PropertyResource resource = new YamlFileResource(configFile);
PropertyResource resource = YamlFileResourceProvider.loadFromFile(configFile);
ConfigurationData configurationData = AuthMeSettingsRetriever.buildConfigurationData();
return new Settings(dataFolder, resource, migrationService, configurationData);
}
@@ -0,0 +1,30 @@
package fr.xephi.authme.service.yaml;
import ch.jalu.configme.resource.YamlFileResource;
import org.yaml.snakeyaml.parser.ParserException;
import java.io.File;
/**
* Creates {@link YamlFileResource} objects.
*/
public final class YamlFileResourceProvider {
private YamlFileResourceProvider() {
}
/**
* Creates a {@link YamlFileResource} instance for the given file. Wraps SnakeYAML's parse exception
* into an AuthMe exception.
*
* @param file the file to load
* @return the generated resource
*/
public static YamlFileResource loadFromFile(File file) {
try {
return new YamlFileResource(file);
} catch (ParserException e) {
throw new YamlParseException(file.getPath(), e);
}
}
}
@@ -0,0 +1,26 @@
package fr.xephi.authme.service.yaml;
import org.yaml.snakeyaml.parser.ParserException;
/**
* Exception when a YAML file could not be parsed.
*/
public class YamlParseException extends RuntimeException {
private final String file;
/**
* Constructor.
*
* @param file the file a parsing exception occurred with
* @param snakeYamlException the caught exception from SnakeYAML
*/
public YamlParseException(String file, ParserException snakeYamlException) {
super(snakeYamlException);
this.file = file;
}
public String getFile() {
return file;
}
}
@@ -1,11 +1,11 @@
package fr.xephi.authme.settings.commandconfig;
import ch.jalu.configme.SettingsManager;
import ch.jalu.configme.resource.YamlFileResource;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.GeoIpService;
import fr.xephi.authme.service.yaml.YamlFileResourceProvider;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.lazytags.Tag;
@@ -149,7 +149,7 @@ public class CommandManager implements Reloadable {
FileUtils.copyFileFromResource(file, "commands.yml");
SettingsManager settingsManager = new SettingsManager(
new YamlFileResource(file), commandMigrationService, CommandSettingsHolder.class);
YamlFileResourceProvider.loadFromFile(file), commandMigrationService, CommandSettingsHolder.class);
CommandConfig commandConfig = settingsManager.getProperty(CommandSettingsHolder.COMMANDS);
onJoinCommands = newReplacer(commandConfig.getOnJoin());
onLoginCommands = newOnLoginCmdReplacer(commandConfig.getOnLogin());
@@ -0,0 +1,36 @@
package fr.xephi.authme.util;
import com.google.common.collect.Sets;
import java.util.Set;
/**
* Utilities for exceptions.
*/
public final class ExceptionUtils {
private ExceptionUtils() {
}
/**
* Returns the first throwable of the given {@code wantedThrowableType} by visiting the provided
* throwable and its causes recursively.
*
* @param wantedThrowableType the throwable type to find
* @param throwable the throwable to start with
* @param <T> the desired throwable subtype
* @return the first throwable found of the given type, or null if none found
*/
public static <T extends Throwable> T findThrowableInCause(Class<T> wantedThrowableType, Throwable throwable) {
Set<Throwable> visitedObjects = Sets.newIdentityHashSet();
Throwable currentThrowable = throwable;
while (currentThrowable != null && !visitedObjects.contains(currentThrowable)) {
if (wantedThrowableType.isInstance(currentThrowable)) {
return wantedThrowableType.cast(currentThrowable);
}
visitedObjects.add(currentThrowable);
currentThrowable = currentThrowable.getCause();
}
return null;
}
}