Merge branch 'master' of https://github.com/AuthMe-Team/AuthMeReloaded into 707-process-as-service

Conflicts:
	src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
	src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
This commit is contained in:
ljacqu
2016-05-20 19:48:26 +02:00
29 changed files with 489 additions and 386 deletions
+16 -19
View File
@@ -44,16 +44,10 @@ import fr.xephi.authme.settings.SettingsMigrationService;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.EmailSettings;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.PurgeSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.task.PurgeTask;
@@ -64,6 +58,17 @@ import fr.xephi.authme.util.GeoLiteAPI;
import fr.xephi.authme.util.MigrationService;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.io.File;
import java.sql.SQLException;
@@ -76,17 +81,9 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
import static fr.xephi.authme.settings.properties.EmailSettings.RECALL_PLAYERS;
/**
* The AuthMe main class.
@@ -223,8 +220,8 @@ public class AuthMe extends JavaPlugin {
getServer().shutdown();
return;
}
ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING),
new File(getDataFolder(), "authme.log"));
ConsoleLogger.setLogFile(new File(getDataFolder(), "authme.log"));
ConsoleLogger.setLoggingOptions(newSettings);
// Old settings manager
if (!loadSettings()) {
@@ -1,6 +1,7 @@
package fr.xephi.authme;
import com.google.common.base.Throwables;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.StringUtils;
@@ -21,22 +22,26 @@ public final class ConsoleLogger {
private static final String NEW_LINE = System.getProperty("line.separator");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private static Logger logger;
private static boolean enableDebug = false;
private static boolean useLogging = false;
private static File logFile;
private ConsoleLogger() {
// Service class
}
public static void setLogger(Logger logger) {
ConsoleLogger.logger = logger;
}
public static void setLoggingOptions(boolean useLogging, File logFile) {
ConsoleLogger.useLogging = useLogging;
public static void setLogFile(File logFile) {
ConsoleLogger.logFile = logFile;
}
public static void setLoggingOptions(NewSetting settings) {
ConsoleLogger.useLogging = settings.getProperty(SecuritySettings.USE_LOGGING);
ConsoleLogger.enableDebug = !settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE);
}
/**
* Print an info message.
*
@@ -50,7 +55,7 @@ public final class ConsoleLogger {
}
public static void debug(String message) {
if (!AuthMe.getInstance().getSettings().getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) {
if (enableDebug) {
logger.fine(message);
if (useLogging) {
writeLog("Debug: " + message);
@@ -4,9 +4,7 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.task.PurgeTask;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -26,12 +24,6 @@ public class PurgeCommand implements ExecutableCommand {
@Inject
private DataSource dataSource;
@Inject
private PluginHooks pluginHooks;
@Inject
private BukkitService bukkitService;
@Inject
private AuthMe plugin;
@@ -40,6 +40,7 @@ public class ReloadCommand implements ExecutableCommand {
ConsoleLogger.info("Note: cannot change database type during /authme reload");
sender.sendMessage("Note: cannot change database type during /authme reload");
}
ConsoleLogger.setLoggingOptions(settings);
initializer.performReloadOnServices();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) {
@@ -144,8 +144,8 @@ public class AuthMeServiceInitializer {
}
/**
* Instantiates the given class by locating an @Inject constructor and retrieving
* or instantiating its parameters.
* Instantiates the given class by locating its @Inject elements and retrieving
* or instantiating the required instances.
*
* @param clazz the class to instantiate
* @param traversedClasses collection of classes already traversed
@@ -164,13 +164,13 @@ public class AuthMeServiceInitializer {
validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
Object[] dependencies = resolveDependencies(injection, traversedClasses);
T object = injection.instantiateWith(dependencies);
executePostConstructMethods(object);
executePostConstructMethod(object);
return object;
}
/**
* Resolves the dependencies for the given constructor, i.e. returns a collection that satisfy
* the constructor's parameter types by retrieving elements or instantiating them where necessary.
* Resolves the dependencies for the given class instantiation, i.e. returns a collection that satisfy
* the class' dependencies by retrieving elements or instantiating them where necessary.
*
* @param injection the injection parameters
* @param traversedClasses collection of traversed classes
@@ -247,21 +247,20 @@ public class AuthMeServiceInitializer {
+ "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
}
private static void executePostConstructMethods(Object object) {
for (Method method : object.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
if (method.getParameterTypes().length == 0 && !Modifier.isStatic(method.getModifiers())) {
try {
method.setAccessible(true);
method.invoke(object);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new UnsupportedOperationException(e);
}
} else {
throw new IllegalStateException(String.format("@PostConstruct methods may not be static or have "
+ " any parameters. Method '%s' of class '%s' is either static or has parameters",
method.getName(), object.getClass().getSimpleName()));
}
/**
* Executes an object's method annotated with {@link PostConstruct} if present.
* Throws an exception if there are multiple such methods, or if the method is static.
*
* @param object the object to execute the post construct method for
*/
private static void executePostConstructMethod(Object object) {
Method postConstructMethod = getAndValidatePostConstructMethod(object.getClass());
if (postConstructMethod != null) {
try {
postConstructMethod.setAccessible(true);
postConstructMethod.invoke(object);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new UnsupportedOperationException("Error executing @PostConstruct method", e);
}
}
}
@@ -272,6 +271,32 @@ public class AuthMeServiceInitializer {
}
}
/**
* Validate and locate the given class' post construct method. Returns {@code null} if none present.
*
* @param clazz the class to search
* @return post construct method, or null
*/
private static Method getAndValidatePostConstructMethod(Class<?> clazz) {
Method postConstructMethod = null;
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
if (postConstructMethod != null) {
throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz);
} else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. "
+ "Invalid method in " + clazz);
} else if (method.getReturnType() != void.class) {
throw new IllegalStateException("@PostConstruct method must have return type void. "
+ "Offending class: " + clazz);
} else {
postConstructMethod = method;
}
}
}
return postConstructMethod;
}
@SafeVarargs
private static <T> Injection<T> firstNotNull(Provider<? extends Injection<T>>... providers) {
for (Provider<? extends Injection<T>> provider : providers) {
@@ -1,5 +1,6 @@
package fr.xephi.authme.initialization;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Provider;
import java.lang.reflect.AccessibleObject;
@@ -8,7 +9,7 @@ import java.lang.reflect.InvocationTargetException;
/**
* Fallback instantiation method for classes with an accessible no-args constructor
* and no no {@link Inject} annotations whatsoever.
* and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}.
*/
public class InstantiationFallback<T> implements Injection<T> {
@@ -54,9 +55,9 @@ public class InstantiationFallback<T> implements Injection<T> {
Constructor<T> noArgsConstructor = getNoArgsConstructor(clazz);
// Return fallback only if we have no args constructor and no @Inject annotation anywhere
if (noArgsConstructor != null
&& !isInjectAnnotationPresent(clazz.getDeclaredConstructors())
&& !isInjectAnnotationPresent(clazz.getDeclaredFields())
&& !isInjectAnnotationPresent(clazz.getDeclaredMethods())) {
&& !isInjectionAnnotationPresent(clazz.getDeclaredConstructors())
&& !isInjectionAnnotationPresent(clazz.getDeclaredFields())
&& !isInjectionAnnotationPresent(clazz.getDeclaredMethods())) {
return new InstantiationFallback<>(noArgsConstructor);
}
return null;
@@ -73,9 +74,9 @@ public class InstantiationFallback<T> implements Injection<T> {
}
}
private static <A extends AccessibleObject> boolean isInjectAnnotationPresent(A[] accessibles) {
private static <A extends AccessibleObject> boolean isInjectionAnnotationPresent(A[] accessibles) {
for (A accessible : accessibles) {
if (accessible.isAnnotationPresent(Inject.class)) {
if (accessible.isAnnotationPresent(Inject.class) || accessible.isAnnotationPresent(PostConstruct.class)) {
return true;
}
}
@@ -17,7 +17,6 @@ import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.ProtectionSettings;
@@ -57,6 +56,7 @@ import org.bukkit.event.player.PlayerShearEntityEvent;
import javax.inject.Inject;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS;
@@ -354,14 +354,16 @@ public class AuthMePlayerListener implements Listener {
return;
}
if (name.length() > Settings.getMaxNickLength || name.length() < Settings.getMinNickLength) {
if (name.length() > settings.getProperty(RestrictionSettings.MAX_NICKNAME_LENGTH) || name.length() < settings.getProperty(RestrictionSettings.MIN_NICKNAME_LENGTH)) {
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_LENGTH));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return;
}
if (!Settings.nickPattern.matcher(player.getName()).matches() || name.equalsIgnoreCase("Player")) {
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CHARACTERS).replace("REG_EX", Settings.getNickRegex));
String nickRegEx = settings.getProperty(RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS);
Pattern nickPattern = Pattern.compile(nickRegEx);
if (nickPattern.matcher(player.getName()).matches() || name.equalsIgnoreCase("Player")) {
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CHARACTERS).replace("REG_EX", nickRegEx));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
return;
}
@@ -505,14 +507,16 @@ public class AuthMePlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) {
if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
if (!shouldCancelEvent(event)) {
return;
}
Player player = event.getPlayer();
String name = player.getName().toLowerCase();
Location spawn = spawnLoader.getSpawnLocation(player);
if (Settings.isSaveQuitLocationEnabled && dataSource.isAuthAvailable(name)) {
if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION) && dataSource.isAuthAvailable(name)) {
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
@@ -1,6 +1,9 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -16,11 +19,20 @@ public class AuthMePlayerListener19 implements Listener {
@Inject
private SpawnLoader spawnLoader;
AuthMePlayerListener19() { }
@Inject
private NewSetting settings;
/* WTF was that? We need to check all the settings before moving the player to the spawn!
*
* TODO: fixme please!
*
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerSpawn(PlayerSpawnLocationEvent event) {
if(settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
event.setSpawnLocation(spawnLoader.getSpawnLocation(event.getPlayer()));
}
*/
}
@@ -96,11 +96,9 @@ public class PermissionsManager implements PermissionsService {
/**
* Setup and hook into the permissions systems.
*
* @return The detected permissions system.
*/
@PostConstruct
public PermissionsSystemType setup() {
public void setup() {
// Force-unhook from current hooked permissions systems
unhook();
@@ -177,7 +175,7 @@ public class PermissionsManager implements PermissionsService {
ConsoleLogger.info("Hooked into " + type.getName() + "!");
// Return the used permissions system type
return type;
return;
} catch (Exception ex) {
// An error occurred, show a warning message
@@ -187,7 +185,6 @@ public class PermissionsManager implements PermissionsService {
// No recognized permissions system found, show a message and return
ConsoleLogger.info("No supported permissions system found! Permissions are disabled!");
return null;
}
/**
@@ -230,9 +230,9 @@ public class AsynchronousJoin implements AsynchronousProcess {
: MessageKey.REGISTER_MESSAGE;
}
if (msgInterval > 0 && limboCache.getLimboPlayer(name) != null) {
BukkitTask msgTask = service.runTask(new MessageTask(service.getBukkitService(), plugin.getMessages(),
name, msg, msgInterval));
LimboPlayer limboPlayer = limboCache.getLimboPlayer(name);
BukkitTask msgTask = service.runTaskLater(new MessageTask(service.getBukkitService(), plugin.getMessages(),
name, msg, msgInterval), 20L);
LimboPlayer limboPlayer = limboCache.getLimboPlayer(name);
if (limboPlayer != null) {
limboPlayer.setMessageTask(msgTask);
}
@@ -1,7 +1,6 @@
package fr.xephi.authme.security.crypts;
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.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
@@ -14,13 +13,13 @@ import javax.inject.Inject;
@Recommendation(Usage.RECOMMENDED) // provided the salt length is >= 8
@HasSalt(value = SaltType.TEXT) // length depends on the bcryptLog2Rounds setting
public class BCRYPT implements EncryptionMethod, SettingsDependent {
public class BCRYPT implements EncryptionMethod {
private int bCryptLog2Rounds;
private final int bCryptLog2Rounds;
@Inject
public BCRYPT(NewSetting settings) {
loadSettings(settings);
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
}
@Override
@@ -54,8 +53,4 @@ public class BCRYPT implements EncryptionMethod, SettingsDependent {
return false;
}
@Override
public void loadSettings(NewSetting settings) {
bCryptLog2Rounds = settings.getProperty(HooksSettings.BCRYPT_LOG2_ROUND);
}
}
@@ -1,6 +1,5 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.initialization.SettingsDependent;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
@@ -15,13 +14,13 @@ import static fr.xephi.authme.security.HashUtils.md5;
@Recommendation(Usage.ACCEPTABLE) // presuming that length is something sensible (>= 8)
@HasSalt(value = SaltType.TEXT) // length defined by the doubleMd5SaltLength setting
public class SALTED2MD5 extends SeparateSaltMethod implements SettingsDependent {
public class SALTED2MD5 extends SeparateSaltMethod {
private int saltLength;
private final int saltLength;
@Inject
public SALTED2MD5(NewSetting settings) {
loadSettings(settings);
saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH);
}
@Override
@@ -34,9 +33,5 @@ public class SALTED2MD5 extends SeparateSaltMethod implements SettingsDependent
return RandomString.generateHex(saltLength);
}
@Override
public void loadSettings(NewSetting settings) {
saltLength = settings.getProperty(SecuritySettings.DOUBLE_MD5_SALT_LENGTH);
}
}
@@ -9,7 +9,9 @@ import fr.xephi.authme.initialization.AuthMeServiceInitializer;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.CommandSender;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,6 +55,13 @@ public class ReloadCommandTest {
TestHelper.setupLogger();
}
@Before
public void setDefaultSettings() {
// Mock properties retrieved by ConsoleLogger
given(settings.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)).willReturn(false);
given(settings.getProperty(SecuritySettings.USE_LOGGING)).willReturn(false);
}
@Test
public void shouldReload() {
// given
@@ -204,10 +204,11 @@ public abstract class AbstractResourceClosingTest {
}
/**
* Return a list with some test elements that correspond to the given list type's generic type.
* Return a collection of the required type with some test elements that correspond to the
* collection's generic type.
*
* @param type The list type to process and build a test list for
* @return Test list with sample elements of the correct type
* @param type The collection type to process and build a test collection for
* @return Test collection with sample elements of the correct type
*/
private static Collection<?> getTypedCollection(Type type) {
if (type instanceof ParameterizedType) {
@@ -18,8 +18,11 @@ import fr.xephi.authme.initialization.samples.ProvidedClass;
import fr.xephi.authme.initialization.samples.Size;
import fr.xephi.authme.settings.NewSetting;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
@@ -36,6 +39,11 @@ public class AuthMeServiceInitializerTest {
private AuthMeServiceInitializer initializer;
// As we test many cases that throw exceptions, we use JUnit's ExpectedException Rule
// to make sure that we receive the exception we expect
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void setInitializer() {
initializer = new AuthMeServiceInitializer(ALLOWED_PACKAGE);
@@ -54,15 +62,17 @@ public class AuthMeServiceInitializerTest {
}
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForInvalidPackage() {
// given / when / then
expectRuntimeExceptionWith("outside of the allowed packages");
initializer.get(InvalidClass.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForUnregisteredPrimitiveType() {
// given / when / then
expectRuntimeExceptionWith("Primitive types must be provided");
initializer.get(int.class);
}
@@ -85,24 +95,27 @@ public class AuthMeServiceInitializerTest {
assertThat(object.getGammaService(), equalTo(initializer.get(BetaManager.class).getDependencies()[1]));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldRecognizeCircularReferences() {
// given / when / then
expectRuntimeExceptionWith("Found cyclic dependency");
initializer.get(CircularClasses.Circular3.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForUnregisteredAnnotation() {
// given
initializer.provide(Size.class, 4523);
// when / then
expectRuntimeExceptionWith("must be registered beforehand");
initializer.get(ClassWithAnnotations.class);
}
@Test(expected = RuntimeException.class)
public void shouldThrowForFieldInjectionWithNoDefaultConstructor() {
@Test
public void shouldThrowForFieldInjectionWithoutNoArgsConstructor() {
// given / when / then
expectRuntimeExceptionWith("Did not find injection method");
initializer.get(BadFieldInjection.class);
}
@@ -124,36 +137,41 @@ public class AuthMeServiceInitializerTest {
equalTo(result.getBetaManager().getDependencies()[1]));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForAnnotationAsKey() {
// given / when / then
expectRuntimeExceptionWith("Cannot retrieve annotated elements in this way");
initializer.get(Size.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForSecondRegistration() {
// given / when / then
expectRuntimeExceptionWith("There is already an object present");
initializer.register(ProvidedClass.class, new ProvidedClass(""));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForSecondAnnotationRegistration() {
// given
initializer.provide(Size.class, 12);
// when / then
expectRuntimeExceptionWith("already registered");
initializer.provide(Size.class, -8);
}
@Test(expected = NullPointerException.class)
@Test
public void shouldThrowForNullValueAssociatedToAnnotation() {
// given / when / then
expectedException.expect(NullPointerException.class);
initializer.provide(Duration.class, null);
}
@Test(expected = NullPointerException.class)
@Test
public void shouldThrowForRegisterWithNull() {
// given / when / then
expectedException.expect(NullPointerException.class);
initializer.register(String.class, null);
}
@@ -166,31 +184,49 @@ public class AuthMeServiceInitializerTest {
PostConstructTestClass testClass = initializer.get(PostConstructTestClass.class);
// then
assertThat(testClass.werePostConstructsCalled(), equalTo(true));
assertThat(testClass.wasPostConstructCalled(), equalTo(true));
assertThat(testClass.getBetaManager(), not(nullValue()));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForInvalidPostConstructMethod() {
// given / when / then
expectRuntimeExceptionWith("@PostConstruct method may not be static or have any parameters");
initializer.get(InvalidPostConstruct.WithParams.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForStaticPostConstructMethod() {
// given / when / then
expectRuntimeExceptionWith("@PostConstruct method may not be static or have any parameters");
initializer.get(InvalidPostConstruct.Static.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldForwardExceptionFromPostConstruct() {
// given / when / then
expectRuntimeExceptionWith("Error executing @PostConstruct method");
initializer.get(InvalidPostConstruct.ThrowsException.class);
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForMultiplePostConstructMethods() {
// given / when / then
expectRuntimeExceptionWith("Multiple methods with @PostConstruct");
initializer.get(InvalidPostConstruct.MultiplePostConstructs.class);
}
@Test
public void shouldThrowForPostConstructNotReturningVoid() {
// given / when / then
expectRuntimeExceptionWith("@PostConstruct method must have return type void");
initializer.get(InvalidPostConstruct.NotVoidReturnType.class);
}
@Test
public void shouldThrowForAbstractNonRegisteredDependency() {
// given / when / then
expectRuntimeExceptionWith("cannot be instantiated");
initializer.get(ClassWithAbstractDependency.class);
}
@@ -208,12 +244,13 @@ public class AuthMeServiceInitializerTest {
assertThat(cwad.getAlphaService(), not(nullValue()));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForAlreadyRegisteredClass() {
// given
initializer.register(BetaManager.class, new BetaManager());
// when / then
expectRuntimeExceptionWith("There is already an object present");
initializer.register(BetaManager.class, new BetaManager());
}
@@ -229,9 +266,10 @@ public class AuthMeServiceInitializerTest {
assertThat(singletonScoped, not(sameInstance(requestScoped)));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForStaticFieldInjection() {
// given / when / then
expectRuntimeExceptionWith("is static but annotated with @Inject");
initializer.newInstance(InvalidStaticFieldInjection.class);
}
@@ -271,10 +309,16 @@ public class AuthMeServiceInitializerTest {
assertThat(providedClass.getWasReloaded(), equalTo(true));
}
@Test(expected = RuntimeException.class)
@Test
public void shouldThrowForNullSetting() {
// given / when / then
expectRuntimeExceptionWith("Settings instance is null");
initializer.performReloadOnServices();
}
private void expectRuntimeExceptionWith(String message) {
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(containsString(message));
}
}
@@ -115,11 +115,9 @@ public class FieldInjectionTest {
}
private static class ThrowingConstructor {
@SuppressWarnings("unused")
@Inject
private ProvidedClass providedClass;
@SuppressWarnings("unused")
public ThrowingConstructor() {
throw new UnsupportedOperationException("Exception in constructor");
}
@@ -65,4 +65,14 @@ public class InstantiationFallbackTest {
assertThat(instantiation, nullValue());
}
@Test
public void shouldReturnNullForClassWithPostConstruct() {
// given / when
Injection<InstantiationFallbackClasses.ClassWithPostConstruct> instantiation =
InstantiationFallback.provide(InstantiationFallbackClasses.ClassWithPostConstruct.class).get();
// then
assertThat(instantiation, nullValue());
}
}
@@ -1,9 +1,10 @@
package fr.xephi.authme.initialization.samples;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
/**
* Sample class - triggers instantiation fallback.
* Sample class - tests various situations for the instantiation fallback.
*/
public abstract class InstantiationFallbackClasses {
@@ -42,4 +43,12 @@ public abstract class InstantiationFallbackClasses {
}
}
// Class with @PostConstruct method should never be instantiated by instantiation fallback
public static final class ClassWithPostConstruct {
@PostConstruct
public void postConstructMethod() {
// --
}
}
}
@@ -9,10 +9,8 @@ import javax.inject.Inject;
public abstract class InvalidPostConstruct {
public static final class WithParams {
@SuppressWarnings("unused")
@Inject
private AlphaService alphaService;
@SuppressWarnings("unused")
@Inject
private ProvidedClass providedClass;
@@ -36,9 +34,36 @@ public abstract class InvalidPostConstruct {
}
public static final class ThrowsException {
@Inject
private ProvidedClass providedClass;
@PostConstruct
public void throwingPostConstruct() {
throw new IllegalStateException("Exception in post construct");
}
}
public static final class NotVoidReturnType {
@Inject
private ProvidedClass providedClass;
@PostConstruct
public int returnsInt() {
return 42;
}
}
public static final class MultiplePostConstructs {
@Inject
private ProvidedClass providedClass;
@PostConstruct
public void postConstruct1() {
// --
}
@PostConstruct
public void postConstruct2() {
// --
}
}
}
@@ -17,22 +17,15 @@ public class PostConstructTestClass implements SettingsDependent {
@Inject
private BetaManager betaManager;
private boolean wasPostConstructCalled = false;
private boolean wasSecondPostConstructCalled = false;
private boolean wasReloaded = false;
@PostConstruct
protected void setFieldToTrue() {
public void postConstructMethod() {
wasPostConstructCalled = true;
}
@PostConstruct
public int otherPostConstructMethod() {
wasSecondPostConstructCalled = true;
return 42;
}
public boolean werePostConstructsCalled() {
return wasPostConstructCalled && wasSecondPostConstructCalled;
public boolean wasPostConstructCalled() {
return wasPostConstructCalled;
}
public BetaManager getBetaManager() {
+37 -11
View File
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
import tools.commands.CommandPageCreater;
import tools.hashmethods.HashAlgorithmsDescriptionTask;
import tools.permissions.PermissionsListWriter;
import tools.utils.AutoToolTask;
import tools.utils.ToolTask;
import java.util.Scanner;
@@ -12,9 +13,9 @@ import java.util.Set;
/**
* Task that runs all tasks which update files in the docs folder.
*/
public class UpdateDocsTask implements ToolTask {
public class UpdateDocsTask implements AutoToolTask {
private final Set<Class<? extends ToolTask>> TASKS = ImmutableSet.<Class<? extends ToolTask>>of(
private static final Set<Class<? extends ToolTask>> TASKS = ImmutableSet.<Class<? extends ToolTask>>of(
CommandPageCreater.class, HashAlgorithmsDescriptionTask.class, PermissionsListWriter.class);
@Override
@@ -23,17 +24,25 @@ public class UpdateDocsTask implements ToolTask {
}
@Override
public void execute(Scanner scanner) {
for (Class<? extends ToolTask> taskClass : TASKS) {
try {
ToolTask task = instantiateTask(taskClass);
System.out.println("\nRunning " + task.getTaskName() + "\n-------------------");
public void execute(final Scanner scanner) {
executeTasks(new TaskRunner() {
@Override
public void execute(ToolTask task) {
task.execute(scanner);
} catch (UnsupportedOperationException e) {
System.err.println("Error running task of class '" + taskClass + "'");
e.printStackTrace();
}
}
});
}
@Override
public void executeDefault() {
executeTasks(new TaskRunner() {
@Override
public void execute(ToolTask task) {
if (task instanceof AutoToolTask) {
((AutoToolTask) task).executeDefault();
}
}
});
}
private static ToolTask instantiateTask(Class<? extends ToolTask> clazz) {
@@ -43,4 +52,21 @@ public class UpdateDocsTask implements ToolTask {
throw new UnsupportedOperationException(e);
}
}
private static void executeTasks(TaskRunner runner) {
for (Class<? extends ToolTask> taskClass : TASKS) {
try {
ToolTask task = instantiateTask(taskClass);
System.out.println("\nRunning " + task.getTaskName() + "\n-------------------");
runner.execute(task);
} catch (UnsupportedOperationException e) {
System.err.println("Error running task of class '" + taskClass + "'");
e.printStackTrace();
}
}
}
private interface TaskRunner {
void execute(ToolTask task);
}
}