mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-18 14:47:47 +01:00
* #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:
parent
7864bb06ac
commit
329657bd5f
@ -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) {
|
||||
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());
|
||||
|
36
src/main/java/fr/xephi/authme/util/ExceptionUtils.java
Normal file
36
src/main/java/fr/xephi/authme/util/ExceptionUtils.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package fr.xephi.authme.service.yaml;
|
||||
|
||||
import ch.jalu.configme.resource.YamlFileResource;
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import org.junit.Test;
|
||||
import org.yaml.snakeyaml.parser.ParserException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Test for {@link YamlFileResourceProvider}.
|
||||
*/
|
||||
public class YamlFileResourceProviderTest {
|
||||
|
||||
@Test
|
||||
public void shouldLoadValidFile() {
|
||||
// given
|
||||
File yamlFile = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "service/yaml/validYaml.yml");
|
||||
|
||||
// when
|
||||
YamlFileResource resource = YamlFileResourceProvider.loadFromFile(yamlFile);
|
||||
|
||||
// then
|
||||
assertThat(resource.getString("test.jkl"), equalTo("Test test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowForInvalidFile() {
|
||||
// given
|
||||
File yamlFile = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "service/yaml/invalidYaml.yml");
|
||||
|
||||
// when
|
||||
try {
|
||||
YamlFileResourceProvider.loadFromFile(yamlFile);
|
||||
|
||||
// then
|
||||
fail("Expected exception to be thrown");
|
||||
} catch (YamlParseException e) {
|
||||
assertThat(e.getFile(), equalTo(yamlFile.getPath()));
|
||||
assertThat(e.getCause(), instanceOf(ParserException.class));
|
||||
}
|
||||
}
|
||||
}
|
54
src/test/java/fr/xephi/authme/util/ExceptionUtilsTest.java
Normal file
54
src/test/java/fr/xephi/authme/util/ExceptionUtilsTest.java
Normal file
@ -0,0 +1,54 @@
|
||||
package fr.xephi.authme.util;
|
||||
|
||||
import fr.xephi.authme.ReflectionTestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link ExceptionUtils}.
|
||||
*/
|
||||
public class ExceptionUtilsTest {
|
||||
|
||||
@Test
|
||||
public void shouldFindWantedThrowable() {
|
||||
// given
|
||||
ConcurrentModificationException initialCme = new ConcurrentModificationException();
|
||||
Throwable th = new Throwable(initialCme);
|
||||
ConcurrentModificationException cme = new ConcurrentModificationException(th);
|
||||
IllegalStateException ise = new IllegalStateException(cme);
|
||||
UnsupportedOperationException uoe = new UnsupportedOperationException(ise);
|
||||
ReflectiveOperationException roe = new ReflectiveOperationException(uoe);
|
||||
|
||||
// when
|
||||
IllegalStateException resultIse = ExceptionUtils.findThrowableInCause(IllegalStateException.class, roe);
|
||||
ConcurrentModificationException resultCme = ExceptionUtils.findThrowableInCause(ConcurrentModificationException.class, cme);
|
||||
StackOverflowError resultSoe = ExceptionUtils.findThrowableInCause(StackOverflowError.class, cme);
|
||||
|
||||
// then
|
||||
assertThat(resultIse, sameInstance(ise));
|
||||
assertThat(resultCme, sameInstance(cme));
|
||||
assertThat(resultSoe, nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleCircularCausesGracefully() {
|
||||
// given
|
||||
IllegalStateException ise = new IllegalStateException();
|
||||
UnsupportedOperationException uoe = new UnsupportedOperationException(ise);
|
||||
ReflectiveOperationException roe = new ReflectiveOperationException(uoe);
|
||||
ReflectionTestUtils.setField(Throwable.class, ise, "cause", roe);
|
||||
|
||||
// when
|
||||
NullPointerException resultNpe = ExceptionUtils.findThrowableInCause(NullPointerException.class, uoe);
|
||||
UnsupportedOperationException resultUoe = ExceptionUtils.findThrowableInCause(UnsupportedOperationException.class, uoe);
|
||||
|
||||
// then
|
||||
assertThat(resultNpe, nullValue());
|
||||
assertThat(resultUoe, sameInstance(uoe));
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
# File with invalid YAML
|
||||
test:
|
||||
abc: 'test'
|
||||
def: 'Going to forget a quote here
|
||||
jkl: 'Test test'
|
@ -0,0 +1,4 @@
|
||||
test:
|
||||
abc: 'test'
|
||||
def: 'All quotes are good here'
|
||||
jkl: 'Test test'
|
Loading…
Reference in New Issue
Block a user