#704 Implement reloading via injector

- Create interfaces Reloadable and SettingsDependent to recognize reloadable classes
- Iterate through instances in injector to reload
This commit is contained in:
ljacqu 2016-05-12 19:51:10 +02:00
parent 4bad04b160
commit e04f7dc711
19 changed files with 240 additions and 50 deletions

View File

@ -321,23 +321,6 @@ public class AuthMe extends JavaPlugin {
runAutoPurge(); runAutoPurge();
} }
/**
* Reload certain components.
*
* @throws Exception if an error occurs
*/
public void reload() throws Exception {
newSettings.reload();
// We do not change database type for consistency issues, but we'll output a note in the logs
if (!newSettings.getProperty(DatabaseSettings.BACKEND).equals(database.getType())) {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
}
database.reload();
messages.reload(newSettings.getMessagesFile());
passwordSecurity.reload();
spawnLoader.initialize(newSettings);
}
/** /**
* Set up the mail API, if enabled. * Set up the mail API, if enabled.
*/ */

View File

@ -4,7 +4,11 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.inject.Inject; import javax.inject.Inject;
@ -18,10 +22,25 @@ public class ReloadCommand implements ExecutableCommand {
@Inject @Inject
private AuthMe plugin; private AuthMe plugin;
@Inject
private AuthMeServiceInitializer initializer;
@Inject
private NewSetting settings;
@Inject
private DataSource dataSource;
@Override @Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) { public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) {
try { try {
plugin.reload(); settings.reload();
// We do not change database type for consistency issues, but we'll output a note in the logs
if (!settings.getProperty(DatabaseSettings.BACKEND).equals(dataSource.getType())) {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
sender.sendMessage("Note: cannot change database type during /authme reload");
}
initializer.performReloadOnServices();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) { } catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting"); sender.sendMessage("Error occurred during reload of AuthMe: aborting");

View File

@ -7,6 +7,7 @@ import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandPermissions; import fr.xephi.authme.command.CommandPermissions;
import fr.xephi.authme.command.CommandUtils; import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.permission.DefaultPermission; import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
@ -26,7 +27,7 @@ import static java.util.Collections.singletonList;
/** /**
* Help syntax generator for AuthMe commands. * Help syntax generator for AuthMe commands.
*/ */
public class HelpProvider { public class HelpProvider implements SettingsDependent {
// --- Bit flags --- // --- Bit flags ---
/** Set to <i>not</i> show the command. */ /** Set to <i>not</i> show the command. */
@ -46,12 +47,12 @@ public class HelpProvider {
public static final int ALL_OPTIONS = ~HIDE_COMMAND; public static final int ALL_OPTIONS = ~HIDE_COMMAND;
private final PermissionsManager permissionsManager; private final PermissionsManager permissionsManager;
private final String helpHeader; private String helpHeader;
@Inject @Inject
public HelpProvider(PermissionsManager permissionsManager, NewSetting settings) { public HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
this.permissionsManager = permissionsManager; this.permissionsManager = permissionsManager;
this.helpHeader = settings.getProperty(PluginSettings.HELP_HEADER); loadSettings(settings);
} }
public List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) { public List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
@ -88,6 +89,11 @@ public class HelpProvider {
return lines; return lines;
} }
@Override
public void loadSettings(NewSetting settings) {
helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
}
private static void printDetailedDescription(CommandDescription command, List<String> lines) { private static void printDetailedDescription(CommandDescription command, List<String> lines) {
lines.add(ChatColor.GOLD + "Short description: " + ChatColor.WHITE + command.getDescription()); lines.add(ChatColor.GOLD + "Short description: " + ChatColor.WHITE + command.getDescription());
lines.add(ChatColor.GOLD + "Detailed description:"); lines.add(ChatColor.GOLD + "Detailed description:");

View File

@ -1,6 +1,7 @@
package fr.xephi.authme.datasource; package fr.xephi.authme.datasource;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.List; import java.util.List;
@ -8,7 +9,7 @@ import java.util.List;
/** /**
* Interface for manipulating {@link PlayerAuth} objects from a data source. * Interface for manipulating {@link PlayerAuth} objects from a data source.
*/ */
public interface DataSource { public interface DataSource extends Reloadable {
/** /**
* Return whether there is a record for the given username. * Return whether there is a record for the given username.
@ -204,6 +205,7 @@ public interface DataSource {
/** /**
* Reload the data source. * Reload the data source.
*/ */
@Override
void reload(); void reload();
} }

View File

@ -2,6 +2,7 @@ package fr.xephi.authme.initialization;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import fr.xephi.authme.settings.NewSetting;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Provider; import javax.inject.Provider;
@ -122,6 +123,26 @@ public class AuthMeServiceInitializer {
return object; return object;
} }
/**
* Performs a reload on all applicable instances which are registered.
* Requires that the {@link NewSetting settings} instance be registered.
* <p>
* Note that the order in which these classes are reloaded is not guaranteed.
*/
public void performReloadOnServices() {
NewSetting settings = (NewSetting) objects.get(NewSetting.class);
if (settings == null) {
throw new IllegalStateException("Settings instance is null");
}
for (Object object : objects.values()) {
if (object instanceof Reloadable) {
((Reloadable) object).reload();
} else if (object instanceof SettingsDependent) {
((SettingsDependent) object).loadSettings(settings);
}
}
}
/** /**
* Instantiates the given class by locating an @Inject constructor and retrieving * Instantiates the given class by locating an @Inject constructor and retrieving
* or instantiating its parameters. * or instantiating its parameters.

View File

@ -0,0 +1,13 @@
package fr.xephi.authme.initialization;
/**
* Interface for reloadable entities.
*/
public interface Reloadable {
/**
* Performs the reload action.
*/
void reload();
}

View File

@ -0,0 +1,16 @@
package fr.xephi.authme.initialization;
import fr.xephi.authme.settings.NewSetting;
/**
* Interface for classes that keep a local copy of certain settings.
*/
public interface SettingsDependent {
/**
* Loads the needed settings.
*
* @param settings the settings instance
*/
void loadSettings(NewSetting settings);
}

View File

@ -1,6 +1,8 @@
package fr.xephi.authme.output; package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -14,7 +16,7 @@ import java.io.InputStreamReader;
/** /**
* Class for retrieving and sending translatable messages to players. * Class for retrieving and sending translatable messages to players.
*/ */
public class Messages { public class Messages implements SettingsDependent {
private FileConfiguration configuration; private FileConfiguration configuration;
private String fileName; private String fileName;
@ -114,13 +116,9 @@ public class Messages {
return message; return message;
} }
/** @Override
* Reset the messages manager to retrieve messages from the given file instead of the current one. public void loadSettings(NewSetting settings) {
* initializeFile(settings.getMessagesFile());
* @param messagesFile The new file to load messages from
*/
public void reload(File messagesFile) {
initializeFile(messagesFile);
} }
private void initializeFile(File messageFile) { private void initializeFile(File messageFile) {

View File

@ -3,6 +3,7 @@ package fr.xephi.authme.security;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.PasswordEncryptionEvent; import fr.xephi.authme.events.PasswordEncryptionEvent;
import fr.xephi.authme.initialization.AuthMeServiceInitializer; import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.security.crypts.EncryptionMethod; import fr.xephi.authme.security.crypts.EncryptionMethod;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.NewSetting;
@ -15,7 +16,7 @@ import javax.inject.Inject;
/** /**
* Manager class for password-related operations. * Manager class for password-related operations.
*/ */
public class PasswordSecurity { public class PasswordSecurity implements Reloadable {
@Inject @Inject
private NewSetting settings; private NewSetting settings;
@ -36,6 +37,7 @@ public class PasswordSecurity {
* Load or reload the configuration. * Load or reload the configuration.
*/ */
@PostConstruct @PostConstruct
@Override
public void reload() { public void reload() {
this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH); this.supportOldAlgorithm = settings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH);

View File

@ -1,6 +1,7 @@
package fr.xephi.authme.security.crypts; package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.security.crypts.description.HasSalt; import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation; import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType; import fr.xephi.authme.security.crypts.description.SaltType;
@ -13,13 +14,13 @@ import javax.inject.Inject;
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8 @Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting @HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting
public class BCRYPT implements EncryptionMethod { public class BCRYPT implements EncryptionMethod, SettingsDependent {
private final int bCryptLog2Rounds; private int bCryptLog2Rounds;
@Inject @Inject
public BCRYPT(NewSetting settings) { public BCRYPT(NewSetting settings) {
this.bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND); loadSettings(settings);
} }
@Override @Override
@ -52,4 +53,9 @@ public class BCRYPT implements EncryptionMethod {
public boolean hasSeparateSalt() { public boolean hasSeparateSalt() {
return false; return false;
} }
@Override
public void loadSettings(NewSetting settings) {
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
}
} }

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.security.crypts; package fr.xephi.authme.security.crypts;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.security.RandomString; import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt; import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation; import fr.xephi.authme.security.crypts.description.Recommendation;
@ -14,13 +15,13 @@ import static fr.xephi.authme.security.HashUtils.md5;
@Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8) @Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8)
@HasSalt(value = SaltType.TEXT) // length defined by the doubleMd5SaltLength setting @HasSalt(value = SaltType.TEXT) // length defined by the doubleMd5SaltLength setting
public class SALTED2MD5 extends SeparateSaltMethod { public class SALTED2MD5 extends SeparateSaltMethod implements SettingsDependent {
private final int saltLength; private int saltLength;
@Inject @Inject
public SALTED2MD5(NewSetting settings) { public SALTED2MD5(NewSetting settings) {
saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH); loadSettings(settings);
} }
@Override @Override
@ -33,4 +34,9 @@ public class SALTED2MD5 extends SeparateSaltMethod {
return RandomString.generateHex(saltLength); return RandomString.generateHex(saltLength);
} }
@Override
public void loadSettings(NewSetting settings) {
saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH);
}
} }

View File

@ -4,6 +4,7 @@ import fr.xephi.authme.security.HashUtils;
public class SMF extends UsernameSaltMethod { public class SMF extends UsernameSaltMethod {
@Override
public HashedPassword computeHash(String password, String name) { public HashedPassword computeHash(String password, String name) {
return new HashedPassword(HashUtils.sha1(name.toLowerCase() + password)); return new HashedPassword(HashUtils.sha1(name.toLowerCase() + password));
} }

View File

@ -5,6 +5,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
@ -27,7 +28,7 @@ import java.io.IOException;
* should be taken from. In AuthMe, we can distinguish between the regular spawn and a "first spawn", * should be taken from. In AuthMe, we can distinguish between the regular spawn and a "first spawn",
* to which players will be teleported who have joined for the first time. * to which players will be teleported who have joined for the first time.
*/ */
public class SpawnLoader { public class SpawnLoader implements SettingsDependent {
private final File authMeConfigurationFile; private final File authMeConfigurationFile;
private final PluginHooks pluginHooks; private final PluginHooks pluginHooks;
@ -49,7 +50,7 @@ public class SpawnLoader {
FileUtils.copyFileFromResource(spawnFile, "spawn.yml"); FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
this.authMeConfigurationFile = new File(pluginFolder, "spawn.yml"); this.authMeConfigurationFile = new File(pluginFolder, "spawn.yml");
this.pluginHooks = pluginHooks; this.pluginHooks = pluginHooks;
initialize(settings); loadSettings(settings);
} }
/** /**
@ -57,7 +58,8 @@ public class SpawnLoader {
* *
* @param settings The settings instance * @param settings The settings instance
*/ */
public void initialize(NewSetting settings) { @Override
public void loadSettings(NewSetting settings) {
spawnPriority = settings.getProperty(RestrictionSettings.SPAWN_PRIORITY).split(","); spawnPriority = settings.getProperty(RestrictionSettings.SPAWN_PRIORITY).split(",");
authMeConfiguration = YamlConfiguration.loadConfiguration(authMeConfigurationFile); authMeConfiguration = YamlConfiguration.loadConfiguration(authMeConfigurationFile);
loadEssentialsSpawn(); loadEssentialsSpawn();

View File

@ -3,7 +3,12 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.TestHelper; import fr.xephi.authme.TestHelper;
import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -14,6 +19,9 @@ import org.mockito.runners.MockitoJUnitRunner;
import java.util.Collections; import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.matches; import static org.mockito.Matchers.matches;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -32,7 +40,13 @@ public class ReloadCommandTest {
private AuthMe authMe; private AuthMe authMe;
@Mock @Mock
private CommandService service; private AuthMeServiceInitializer initializer;
@Mock
private NewSetting settings;
@Mock
private DataSource dataSource;
@BeforeClass @BeforeClass
public static void setUpLogger() { public static void setUpLogger() {
@ -40,30 +54,55 @@ public class ReloadCommandTest {
} }
@Test @Test
public void shouldReload() throws Exception { public void shouldReload() {
// given // given
CommandSender sender = mock(CommandSender.class); CommandSender sender = mock(CommandSender.class);
CommandService service = mock(CommandService.class);
given(settings.getProperty(DatabaseSettings.BACKEND)).willReturn(DataSourceType.MYSQL);
given(dataSource.getType()).willReturn(DataSourceType.MYSQL);
// when // when
command.executeCommand(sender, Collections.<String>emptyList(), service); command.executeCommand(sender, Collections.<String>emptyList(), service);
// then // then
verify(authMe).reload(); verify(settings).reload();
verify(initializer).performReloadOnServices();
verify(service).send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); verify(service).send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} }
@Test @Test
public void shouldHandleReloadError() throws Exception { public void shouldHandleReloadError() {
// given // given
doThrow(IllegalStateException.class).when(authMe).reload();
CommandSender sender = mock(CommandSender.class); CommandSender sender = mock(CommandSender.class);
CommandService service = mock(CommandService.class);
doThrow(IllegalStateException.class).when(initializer).performReloadOnServices();
given(settings.getProperty(DatabaseSettings.BACKEND)).willReturn(DataSourceType.MYSQL);
given(dataSource.getType()).willReturn(DataSourceType.MYSQL);
// when // when
command.executeCommand(sender, Collections.<String>emptyList(), service); command.executeCommand(sender, Collections.<String>emptyList(), service);
// then // then
verify(authMe).reload(); verify(settings).reload();
verify(initializer).performReloadOnServices();
verify(sender).sendMessage(matches("Error occurred.*")); verify(sender).sendMessage(matches("Error occurred.*"));
verify(authMe).stopOrUnload(); verify(authMe).stopOrUnload();
} }
@Test
public void shouldIssueWarningForChangedDatasourceSetting() {
// given
CommandSender sender = mock(CommandSender.class);
CommandService service = mock(CommandService.class);
given(settings.getProperty(DatabaseSettings.BACKEND)).willReturn(DataSourceType.MYSQL);
given(dataSource.getType()).willReturn(DataSourceType.SQLITE);
// when
command.executeCommand(sender, Collections.<String>emptyList(), service);
// then
verify(settings).reload();
verify(initializer).performReloadOnServices();
verify(sender).sendMessage(argThat(containsString("cannot change database type")));
}
} }

View File

@ -8,6 +8,7 @@ import fr.xephi.authme.initialization.samples.ClassWithAbstractDependency;
import fr.xephi.authme.initialization.samples.ClassWithAnnotations; import fr.xephi.authme.initialization.samples.ClassWithAnnotations;
import fr.xephi.authme.initialization.samples.Duration; import fr.xephi.authme.initialization.samples.Duration;
import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations; import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations;
import fr.xephi.authme.initialization.samples.GammaService;
import fr.xephi.authme.initialization.samples.InstantiationFallbackClasses; import fr.xephi.authme.initialization.samples.InstantiationFallbackClasses;
import fr.xephi.authme.initialization.samples.InvalidClass; import fr.xephi.authme.initialization.samples.InvalidClass;
import fr.xephi.authme.initialization.samples.InvalidPostConstruct; import fr.xephi.authme.initialization.samples.InvalidPostConstruct;
@ -15,6 +16,7 @@ import fr.xephi.authme.initialization.samples.InvalidStaticFieldInjection;
import fr.xephi.authme.initialization.samples.PostConstructTestClass; import fr.xephi.authme.initialization.samples.PostConstructTestClass;
import fr.xephi.authme.initialization.samples.ProvidedClass; import fr.xephi.authme.initialization.samples.ProvidedClass;
import fr.xephi.authme.initialization.samples.Size; import fr.xephi.authme.initialization.samples.Size;
import fr.xephi.authme.settings.NewSetting;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -23,6 +25,7 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Test for {@link AuthMeServiceInitializer}. * Test for {@link AuthMeServiceInitializer}.
@ -244,4 +247,34 @@ public class AuthMeServiceInitializerTest {
assertThat(result.getFallbackDependency(), not(nullValue())); assertThat(result.getFallbackDependency(), not(nullValue()));
} }
@Test
public void shouldPerformReloadOnApplicableInstances() {
// given
initializer.provide(Size.class, 12);
initializer.provide(Duration.class, -113L);
initializer.register(NewSetting.class, mock(NewSetting.class));
GammaService gammaService = initializer.get(GammaService.class);
PostConstructTestClass postConstructTestClass = initializer.get(PostConstructTestClass.class);
ProvidedClass providedClass = initializer.get(ProvidedClass.class);
initializer.get(ClassWithAnnotations.class);
// Assert that no class was somehow reloaded at initialization
assertThat(gammaService.getWasReloaded() || postConstructTestClass.getWasReloaded()
|| providedClass.getWasReloaded(), equalTo(false));
// when
initializer.performReloadOnServices();
// then
assertThat(gammaService.getWasReloaded(), equalTo(true));
assertThat(postConstructTestClass.getWasReloaded(), equalTo(true));
assertThat(providedClass.getWasReloaded(), equalTo(true));
}
@Test(expected = RuntimeException.class)
public void shouldThrowForNullSetting() {
// given / when / then
initializer.performReloadOnServices();
}
} }

View File

@ -1,13 +1,16 @@
package fr.xephi.authme.initialization.samples; package fr.xephi.authme.initialization.samples;
import fr.xephi.authme.initialization.Reloadable;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
* Sample - class dependent on alpha service. * Sample - class dependent on alpha service.
*/ */
public class GammaService { public class GammaService implements Reloadable {
private AlphaService alphaService; private AlphaService alphaService;
private boolean wasReloaded;
@Inject @Inject
public GammaService(AlphaService alphaService) { public GammaService(AlphaService alphaService) {
@ -17,4 +20,13 @@ public class GammaService {
public AlphaService getAlphaService() { public AlphaService getAlphaService() {
return alphaService; return alphaService;
} }
@Override
public void reload() {
wasReloaded = true;
}
public boolean getWasReloaded() {
return wasReloaded;
}
} }

View File

@ -1,12 +1,15 @@
package fr.xephi.authme.initialization.samples; package fr.xephi.authme.initialization.samples;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.settings.NewSetting;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
* Sample class for testing the execution of @PostConstruct methods. * Sample class for testing the execution of @PostConstruct methods.
*/ */
public class PostConstructTestClass { public class PostConstructTestClass implements SettingsDependent {
@Inject @Inject
@Size @Size
@ -15,6 +18,7 @@ public class PostConstructTestClass {
private BetaManager betaManager; private BetaManager betaManager;
private boolean wasPostConstructCalled = false; private boolean wasPostConstructCalled = false;
private boolean wasSecondPostConstructCalled = false; private boolean wasSecondPostConstructCalled = false;
private boolean wasReloaded = false;
@PostConstruct @PostConstruct
protected void setFieldToTrue() { protected void setFieldToTrue() {
@ -34,4 +38,15 @@ public class PostConstructTestClass {
public BetaManager getBetaManager() { public BetaManager getBetaManager() {
return betaManager; return betaManager;
} }
@Override
public void loadSettings(NewSetting settings) {
if (settings != null) {
wasReloaded = true;
}
}
public boolean getWasReloaded() {
return wasReloaded;
}
} }

View File

@ -1,11 +1,15 @@
package fr.xephi.authme.initialization.samples; package fr.xephi.authme.initialization.samples;
import fr.xephi.authme.initialization.Reloadable;
import javax.inject.Inject; import javax.inject.Inject;
/** /**
* Sample - class that is always provided to the initializer beforehand. * Sample - class that is always provided to the initializer beforehand.
*/ */
public class ProvidedClass { public class ProvidedClass implements Reloadable {
private boolean wasReloaded = false;
@Inject @Inject
public ProvidedClass() { public ProvidedClass() {
@ -15,4 +19,12 @@ public class ProvidedClass {
public ProvidedClass(String manualConstructor) { public ProvidedClass(String manualConstructor) {
} }
@Override
public void reload() {
wasReloaded = true;
}
public boolean getWasReloaded() {
return wasReloaded;
}
} }

View File

@ -2,6 +2,7 @@ package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.TestHelper; import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.NewSetting;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.Before; import org.junit.Before;
@ -19,6 +20,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat; import static org.junit.Assume.assumeThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -247,9 +249,11 @@ public class MessagesIntegrationTest {
MessageKey key = MessageKey.WRONG_PASSWORD; MessageKey key = MessageKey.WRONG_PASSWORD;
// assumption: message comes back as defined in messages_test.yml // assumption: message comes back as defined in messages_test.yml
assumeThat(messages.retrieveSingle(key), equalTo("§cWrong password!")); assumeThat(messages.retrieveSingle(key), equalTo("§cWrong password!"));
NewSetting settings = mock(NewSetting.class);
given(settings.getMessagesFile()).willReturn(TestHelper.getJarFile("/messages_test2.yml"));
// when // when
messages.reload(TestHelper.getJarFile("/messages_test2.yml")); messages.loadSettings(settings);
// then // then
assertThat(messages.retrieveSingle(key), equalTo("test2 - wrong password")); assertThat(messages.retrieveSingle(key), equalTo("test2 - wrong password"));