From 02079f1f5ceede785b537073807bc4c67b68dbd0 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 27 Apr 2016 22:49:20 +0200 Subject: [PATCH] #432 Create custom dependency injector --- pom.xml | 7 + src/main/java/fr/xephi/authme/AntiBot.java | 2 + src/main/java/fr/xephi/authme/AuthMe.java | 154 ++++------ .../java/fr/xephi/authme/DataManager.java | 40 ++- src/main/java/fr/xephi/authme/api/API.java | 19 +- src/main/java/fr/xephi/authme/api/NewAPI.java | 3 + .../xephi/authme/command/CommandHandler.java | 9 +- .../xephi/authme/command/CommandMapper.java | 5 +- .../xephi/authme/command/CommandService.java | 58 ++-- .../authme/command/help/HelpProvider.java | 8 +- .../fr/xephi/authme/hooks/PluginHooks.java | 14 +- .../AuthMeServiceInitializer.java | 286 ++++++++++++++++++ .../authme/initialization/BaseCommands.java | 14 + .../initialization/ConstructorInjection.java | 77 +++++ .../authme/initialization/DataFolder.java | 14 + .../authme/initialization/FieldInjection.java | 112 +++++++ .../authme/initialization/Injection.java | 36 +++ .../{ => initialization}/MetricsStarter.java | 4 +- .../authme/listener/AuthMePlayerListener.java | 40 +-- .../authme/listener/AuthMeServerListener.java | 21 +- .../AuthMeTabCompletePacketAdapter.java | 3 + .../listener/AuthMeTablistPacketAdapter.java | 2 + .../authme/{ => mail}/ImageGenerator.java | 7 +- .../fr/xephi/authme/mail/SendMailSSL.java | 1 - .../authme/permission/PermissionsManager.java | 55 ++-- .../fr/xephi/authme/process/Management.java | 30 +- .../xephi/authme/process/ProcessService.java | 42 ++- .../authme/process/join/AsynchronousJoin.java | 7 +- .../authme/security/PasswordSecurity.java | 2 + .../fr/xephi/authme/settings/SpawnLoader.java | 5 +- .../fr/xephi/authme/util/BukkitService.java | 2 + src/main/java/fr/xephi/authme/util/Utils.java | 3 +- .../xephi/authme/util/ValidationService.java | 2 + .../authme/command/CommandServiceTest.java | 9 +- .../authme/command/help/HelpProviderTest.java | 6 +- .../AuthMeServiceInitializerTest.java | 194 ++++++++++++ .../initialization/samples/AlphaService.java | 20 ++ .../samples/BadFieldInjection.java | 16 + .../initialization/samples/BetaManager.java | 20 ++ .../samples/CircularClasses.java | 30 ++ .../samples/ClassWithAbstractDependency.java | 32 ++ .../samples/ClassWithAnnotations.java | 29 ++ .../initialization/samples/Duration.java | 14 + .../FieldInjectionWithAnnotations.java | 40 +++ .../initialization/samples/GammaService.java | 20 ++ .../initialization/samples/InvalidClass.java | 14 + .../samples/InvalidPostConstruct.java | 19 ++ .../samples/PostConstructTestClass.java | 37 +++ .../initialization/samples/ProvidedClass.java | 18 ++ .../authme/initialization/samples/Size.java | 14 + .../authme/process/ProcessServiceTest.java | 9 +- 51 files changed, 1347 insertions(+), 278 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java create mode 100644 src/main/java/fr/xephi/authme/initialization/BaseCommands.java create mode 100644 src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java create mode 100644 src/main/java/fr/xephi/authme/initialization/DataFolder.java create mode 100644 src/main/java/fr/xephi/authme/initialization/FieldInjection.java create mode 100644 src/main/java/fr/xephi/authme/initialization/Injection.java rename src/main/java/fr/xephi/authme/{ => initialization}/MetricsStarter.java (93%) rename src/main/java/fr/xephi/authme/{ => mail}/ImageGenerator.java (88%) create mode 100644 src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/Duration.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/GammaService.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java create mode 100644 src/test/java/fr/xephi/authme/initialization/samples/Size.java diff --git a/pom.xml b/pom.xml index ec273c536..a93987381 100644 --- a/pom.xml +++ b/pom.xml @@ -405,6 +405,13 @@ true + + + javax.inject + javax.inject + 1 + + com.maxmind.geoip diff --git a/src/main/java/fr/xephi/authme/AntiBot.java b/src/main/java/fr/xephi/authme/AntiBot.java index 75a2a3b59..fcdb2206d 100644 --- a/src/main/java/fr/xephi/authme/AntiBot.java +++ b/src/main/java/fr/xephi/authme/AntiBot.java @@ -9,6 +9,7 @@ import fr.xephi.authme.settings.properties.ProtectionSettings; import fr.xephi.authme.util.BukkitService; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -27,6 +28,7 @@ public class AntiBot { private final List antibotPlayers = new ArrayList<>(); private AntiBotStatus antiBotStatus = AntiBotStatus.DISABLED; + @Inject public AntiBot(NewSetting settings, Messages messages, PermissionsManager permissionsManager, BukkitService bukkitService) { this.settings = settings; diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 08a1945c1..812e88e9f 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -7,12 +7,8 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; -import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.command.CommandInitializer; -import fr.xephi.authme.command.CommandMapper; -import fr.xephi.authme.command.CommandService; -import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.datasource.CacheDataSource; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSourceType; @@ -21,8 +17,11 @@ import fr.xephi.authme.datasource.MySQL; import fr.xephi.authme.datasource.SQLite; import fr.xephi.authme.hooks.BungeeCordMessage; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.AuthMeServiceInitializer; +import fr.xephi.authme.initialization.BaseCommands; +import fr.xephi.authme.initialization.DataFolder; +import fr.xephi.authme.initialization.MetricsStarter; import fr.xephi.authme.listener.AuthMeBlockListener; -import fr.xephi.authme.listener.AuthMeEntityListener; import fr.xephi.authme.listener.AuthMeInventoryPacketAdapter; import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener16; @@ -38,7 +37,6 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Management; -import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.SHA256; import fr.xephi.authme.settings.NewSetting; @@ -61,7 +59,6 @@ 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 fr.xephi.authme.util.ValidationService; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -71,6 +68,7 @@ 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; @@ -80,14 +78,12 @@ import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; 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 static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; /** * The AuthMe main class. @@ -103,7 +99,6 @@ public class AuthMe extends JavaPlugin { // Private Instances private static AuthMe plugin; - private static Server server; /* * Maps and stuff */ @@ -138,7 +133,6 @@ public class AuthMe extends JavaPlugin { private DataSource database; private PluginHooks pluginHooks; private SpawnLoader spawnLoader; - private AntiBot antiBot; private boolean autoPurging; private BukkitService bukkitService; @@ -215,17 +209,15 @@ public class AuthMe extends JavaPlugin { @Override public void onEnable() { // Set various instances - server = getServer(); plugin = this; ConsoleLogger.setLogger(getLogger()); - setPluginInfos(); // Load settings and custom configurations, if it fails, stop the server due to security reasons. newSettings = createNewSetting(); if (newSettings == null) { ConsoleLogger.showError("Could not load configuration. Aborting."); - server.shutdown(); + getServer().shutdown(); return; } ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING), @@ -233,7 +225,7 @@ public class AuthMe extends JavaPlugin { // Old settings manager if (!loadSettings()) { - server.shutdown(); + getServer().shutdown(); setEnabled(false); return; } @@ -249,23 +241,40 @@ public class AuthMe extends JavaPlugin { stopOrUnload(); return; } - - bukkitService = new BukkitService(this); - pluginHooks = new PluginHooks(server.getPluginManager()); - MigrationService.changePlainTextToSha256(newSettings, database, new SHA256()); - passwordSecurity = new PasswordSecurity(getDataSource(), newSettings, Bukkit.getPluginManager()); - // Initialize spawn loader - spawnLoader = new SpawnLoader(getDataFolder(), newSettings, pluginHooks); - permsMan = initializePermissionsManager(); - antiBot = new AntiBot(newSettings, messages, permsMan, bukkitService); - ValidationService validationService = new ValidationService(newSettings, database, permsMan); - commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings, - pluginHooks, spawnLoader, antiBot, validationService, bukkitService); + + AuthMeServiceInitializer initializer = new AuthMeServiceInitializer("fr.xephi.authme"); + // Register elements of the Bukkit / JavaPlugin environment + initializer.register(AuthMe.class, this); + initializer.register(Server.class, getServer()); + initializer.register(PluginManager.class, getServer().getPluginManager()); + initializer.register(BukkitScheduler.class, getServer().getScheduler()); + initializer.provide(DataFolder.class, getDataFolder()); + + // Register elements we instantiate manually + initializer.register(newSettings); + initializer.register(messages); + initializer.register(DataSource.class, database); + initializer.provide(BaseCommands.class, CommandInitializer.buildCommands()); + + // Some statically injected things + initializer.register(PlayerCache.class, PlayerCache.getInstance()); + initializer.register(LimboCache.class, LimboCache.getInstance()); + + permsMan = initializer.get(PermissionsManager.class); + bukkitService = initializer.get(BukkitService.class); + pluginHooks = initializer.get(PluginHooks.class); + passwordSecurity = initializer.get(PasswordSecurity.class); + spawnLoader = initializer.get(SpawnLoader.class); + commandHandler = initializer.get(CommandHandler.class); + api = initializer.get(NewAPI.class); + management = initializer.get(Management.class); + dataManager = initializer.get(DataManager.class); + initializer.get(API.class); // Set up Metrics - MetricsStarter.setupMetrics(plugin, newSettings); + MetricsStarter.setupMetrics(this, newSettings); // Set console filter setupConsoleFilter(); @@ -282,22 +291,12 @@ public class AuthMe extends JavaPlugin { // End of Hooks // Do a backup on start - new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.START); + new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.START); // Setup the inventory backup playerBackup = new JsonCache(); - // Set the DataManager - dataManager = new DataManager(this, pluginHooks, bukkitService); - - // Set up the new API - setupApi(); - - // Set up the management - ProcessService processService = new ProcessService(newSettings, messages, this, database, - passwordSecurity, pluginHooks, spawnLoader, validationService, bukkitService); - management = new Management(this, processService, database, PlayerCache.getInstance()); // Set up the BungeeCord hook setupBungeeCordHook(newSettings); @@ -306,7 +305,7 @@ public class AuthMe extends JavaPlugin { reloadSupportHook(); // Register event listeners - registerEventListeners(messages, database, management, pluginHooks, spawnLoader, antiBot); + registerEventListeners(initializer); // Start Email recall task if needed scheduleRecallEmailTask(); @@ -370,29 +369,27 @@ public class AuthMe extends JavaPlugin { /** * Register all event listeners. */ - private void registerEventListeners(Messages messages, DataSource dataSource, Management management, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot) { + private void registerEventListeners(AuthMeServiceInitializer initializer) { // Get the plugin manager instance - PluginManager pluginManager = server.getPluginManager(); + PluginManager pluginManager = getServer().getPluginManager(); // Register event listeners - pluginManager.registerEvents(new AuthMePlayerListener( - this, newSettings, messages, dataSource, antiBot, management, bukkitService), this); - pluginManager.registerEvents(new AuthMeBlockListener(), this); - pluginManager.registerEvents(new AuthMeEntityListener(), this); - pluginManager.registerEvents(new AuthMeServerListener(this, messages, pluginHooks, spawnLoader), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMeBlockListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener.class), this); + pluginManager.registerEvents(initializer.get(AuthMeServerListener.class), this); // Try to register 1.6 player listeners try { Class.forName("org.bukkit.event.player.PlayerEditBookEvent"); - pluginManager.registerEvents(new AuthMePlayerListener16(), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener16.class), this); } catch (ClassNotFoundException ignore) { } // Try to register 1.8 player listeners try { Class.forName("org.bukkit.event.player.PlayerInteractAtEntityEvent"); - pluginManager.registerEvents(new AuthMePlayerListener18(), this); + pluginManager.registerEvents(initializer.get(AuthMePlayerListener18.class), this); } catch (ClassNotFoundException ignore) { } } @@ -426,30 +423,6 @@ public class AuthMe extends JavaPlugin { } } - private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, - PasswordSecurity passwordSecurity, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, - ValidationService validationService, BukkitService bukkitService) { - HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); - Set baseCommands = CommandInitializer.buildCommands(); - CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); - CommandService commandService = new CommandService(this, mapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); - return new CommandHandler(commandService); - } - - /** - * Set up the API. This sets up the new and the old API. - */ - @SuppressWarnings("deprecation") - private void setupApi() { - // Set up the API - api = new NewAPI(this); - - // Set up the deprecated API - new API(this); - } - /** * Load the plugin's settings. * @@ -462,7 +435,7 @@ public class AuthMe extends JavaPlugin { } catch (Exception e) { ConsoleLogger.logException("Can't load the configuration file... Something went wrong. " + "To avoid security issues the server will shut down!", e); - server.shutdown(); + getServer().shutdown(); } return false; } @@ -507,14 +480,15 @@ public class AuthMe extends JavaPlugin { // Do backup on stop if enabled if (newSettings != null) { - new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); + new PerformBackup(this, newSettings).doBackup(PerformBackup.BackupCause.STOP); } + final AuthMe pluginInstance = this; new Thread(new Runnable() { @Override public void run() { List pendingTasks = new ArrayList<>(); for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) { - if (pendingTask.getOwner().equals(plugin) && !pendingTask.isSync()) { + if (pendingTask.getOwner().equals(pluginInstance) && !pendingTask.isSync()) { pendingTasks.add(pendingTask.getTaskId()); } } @@ -553,9 +527,9 @@ public class AuthMe extends JavaPlugin { public void stopOrUnload() { if (Settings.isStopEnabled) { ConsoleLogger.showError("THE SERVER IS GOING TO SHUT DOWN AS DEFINED IN THE CONFIGURATION!"); - server.shutdown(); + getServer().shutdown(); } else { - server.getPluginManager().disablePlugin(AuthMe.getInstance()); + getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); } } @@ -598,7 +572,7 @@ public class AuthMe extends JavaPlugin { database = dataSource; if (DataSourceType.SQLITE == dataSourceType) { - server.getScheduler().runTaskAsynchronously(this, new Runnable() { + getServer().getScheduler().runTaskAsynchronously(this, new Runnable() { @Override public void run() { int accounts = database.getAccountsRegistered(); @@ -611,15 +585,6 @@ public class AuthMe extends JavaPlugin { } } - /** - * Set up the permissions manager. - */ - private PermissionsManager initializePermissionsManager() { - PermissionsManager manager = new PermissionsManager(Bukkit.getServer(), getLogger()); - manager.setup(); - return manager; - } - // Set the console filter to remove the passwords private void setLog4JFilter() { Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @@ -636,7 +601,7 @@ public class AuthMe extends JavaPlugin { // Check the presence of the ProtocolLib plugin public void checkProtocolLib() { - if (!server.getPluginManager().isPluginEnabled("ProtocolLib")) { + if (!getServer().getPluginManager().isPluginEnabled("ProtocolLib")) { if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); Settings.protectInventoryBeforeLogInEnabled = false; @@ -671,7 +636,7 @@ public class AuthMe extends JavaPlugin { // Save Player Data private void savePlayer(Player player) { - if (Utils.isNPC(player) || Utils.isUnrestricted(player)) { + if (safeIsNpc(player) || Utils.isUnrestricted(player)) { return; } String name = player.getName().toLowerCase(); @@ -699,6 +664,10 @@ public class AuthMe extends JavaPlugin { PlayerCache.getInstance().removePlayer(name); } + private boolean safeIsNpc(Player player) { + return pluginHooks != null && pluginHooks.isNpc(player) || player.hasMetadata("NPC"); + } + // Select the player to kick when a vip player joins the server when full public Player generateKickPlayer(Collection collection) { for (Player player : collection) { @@ -715,7 +684,7 @@ public class AuthMe extends JavaPlugin { return; } autoPurging = true; - server.getScheduler().runTaskAsynchronously(this, new Runnable() { + getServer().getScheduler().runTaskAsynchronously(this, new Runnable() { @Override public void run() { ConsoleLogger.info("AutoPurging the Database..."); @@ -772,6 +741,7 @@ public class AuthMe extends JavaPlugin { public String replaceAllInfo(String message, Player player) { String playersOnline = Integer.toString(bukkitService.getOnlinePlayers().size()); String ipAddress = Utils.getPlayerIp(player); + Server server = getServer(); return message .replace("&", "\u00a7") .replace("{PLAYER}", player.getName()) diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 061683fa0..f5751d429 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -2,32 +2,37 @@ package fr.xephi.authme; import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.PurgeSettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import javax.inject.Inject; import java.io.File; import java.util.ArrayList; import java.util.List; +import static fr.xephi.authme.util.StringUtils.makePath; + /** */ public class DataManager { - private final AuthMe plugin; - private final PluginHooks pluginHooks; - private final BukkitService bukkitService; + @Inject + private Server server; + @Inject + private PluginHooks pluginHooks; + @Inject + private BukkitService bukkitService; + @Inject + private NewSetting settings; + @Inject + private PermissionsManager permissionsManager; - /* - * Constructor. - */ - public DataManager(AuthMe plugin, PluginHooks pluginHooks, BukkitService bukkitService) { - this.plugin = plugin; - this.pluginHooks = pluginHooks; - this.bukkitService = bukkitService; - } + DataManager() { } private List getOfflinePlayers(List names) { List result = new ArrayList<>(); @@ -98,9 +103,8 @@ public class DataManager { public synchronized void purgeDat(List cleared) { int i = 0; - File dataFolder = new File(plugin.getServer().getWorldContainer() - + File.separator + plugin.getSettings().getProperty(PurgeSettings.DEFAULT_WORLD) - + File.separator + "players"); + File dataFolder = new File(server.getWorldContainer(), + makePath(settings.getProperty(PurgeSettings.DEFAULT_WORLD), "players")); List offlinePlayers = getOfflinePlayers(cleared); for (OfflinePlayer player : offlinePlayers) { File playerFile = new File(dataFolder, Utils.getUUIDorName(player) + ".dat"); @@ -142,14 +146,8 @@ public class DataManager { // TODO: What is this method for? Is it correct? // TODO: Make it work with OfflinePlayers group data. public synchronized void purgePermissions(List cleared) { - // Get the permissions manager, and make sure it's valid - PermissionsManager permsMan = plugin.getPermissionsManager(); - if (permsMan == null) { - ConsoleLogger.showError("Unable to access permissions manager instance!"); - return; - } for (String name : cleared) { - permsMan.removeAllGroups(bukkitService.getPlayerExact(name)); + permissionsManager.removeAllGroups(bukkitService.getPlayerExact(name)); } ConsoleLogger.info("AutoPurge: Removed permissions from " + cleared.size() + " player(s)."); } diff --git a/src/main/java/fr/xephi/authme/api/API.java b/src/main/java/fr/xephi/authme/api/API.java index 58960f9d6..26f5ea8f7 100644 --- a/src/main/java/fr/xephi/authme/api/API.java +++ b/src/main/java/fr/xephi/authme/api/API.java @@ -3,6 +3,8 @@ package fr.xephi.authme.api; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.process.Management; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.util.Utils; @@ -12,6 +14,8 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import javax.inject.Inject; + /** * Deprecated API of AuthMe. Please use {@link NewAPI} instead. */ @@ -20,7 +24,9 @@ public class API { public static final String newline = System.getProperty("line.separator"); public static AuthMe instance; + private static DataSource dataSource; private static PasswordSecurity passwordSecurity; + private static Management management; /** * Constructor for the deprecated API. @@ -28,9 +34,12 @@ public class API { * @param instance AuthMe */ @Deprecated - public API(AuthMe instance) { + @Inject + API(AuthMe instance, DataSource dataSource, PasswordSecurity passwordSecurity, Management management) { API.instance = instance; - passwordSecurity = instance.getPasswordSecurity(); + API.dataSource = dataSource; + API.passwordSecurity = passwordSecurity; + API.management = management; } /** @@ -109,7 +118,7 @@ public class API { @Deprecated public static boolean isRegistered(String playerName) { String player = playerName.toLowerCase(); - return instance.getDataSource().isAuthAvailable(player); + return dataSource.isAuthAvailable(player); } /** @@ -144,7 +153,7 @@ public class API { .lastLogin(0) .realName(playerName) .build(); - return instance.getDataSource().saveAuth(auth); + return dataSource.saveAuth(auth); } /** @@ -154,7 +163,7 @@ public class API { */ @Deprecated public static void forceLogin(Player player) { - instance.getManagement().performLogin(player, "dontneed", true); + management.performLogin(player, "dontneed", true); } @Deprecated diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 0f5437623..d3a0b7d8c 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -12,6 +12,8 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.util.Utils; +import javax.inject.Inject; + /** * The current API of AuthMe. Recommended method of retrieving the API object: * @@ -28,6 +30,7 @@ public class NewAPI { * * @param plugin The AuthMe plugin instance */ + @Inject public NewAPI(AuthMe plugin) { this.plugin = plugin; } diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java index 37c1a2a16..5f7b32af5 100644 --- a/src/main/java/fr/xephi/authme/command/CommandHandler.java +++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java @@ -1,14 +1,14 @@ package fr.xephi.authme.command; -import java.util.ArrayList; -import java.util.List; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.help.HelpProvider; +import fr.xephi.authme.util.StringUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; -import fr.xephi.authme.util.StringUtils; +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; /** * The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription} @@ -29,6 +29,7 @@ public class CommandHandler { * * @param commandService The CommandService instance */ + @Inject public CommandHandler(CommandService commandService) { this.commandService = commandService; } diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java index e43ee4bb1..18473b281 100644 --- a/src/main/java/fr/xephi/authme/command/CommandMapper.java +++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java @@ -1,11 +1,13 @@ package fr.xephi.authme.command; import fr.xephi.authme.command.executable.HelpCommand; +import fr.xephi.authme.initialization.BaseCommands; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -28,7 +30,8 @@ public class CommandMapper { private final Set baseCommands; private final PermissionsManager permissionsManager; - public CommandMapper(Set baseCommands, PermissionsManager permissionsManager) { + @Inject + public CommandMapper(@BaseCommands Set baseCommands, PermissionsManager permissionsManager) { this.baseCommands = baseCommands; this.permissionsManager = permissionsManager; } diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 5c5abfcc4..d42629449 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -19,6 +19,7 @@ import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.util.Collection; import java.util.List; @@ -28,39 +29,30 @@ import java.util.List; */ public class CommandService { - private final AuthMe authMe; - private final Messages messages; - private final HelpProvider helpProvider; - private final CommandMapper commandMapper; - private final PasswordSecurity passwordSecurity; - private final PermissionsManager permissionsManager; - private final NewSetting settings; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - private final AntiBot antiBot; - private final ValidationService validationService; - private final BukkitService bukkitService; - - /* - * Constructor. - */ - public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, - PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings, - PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot, - ValidationService validationService, BukkitService bukkitService) { - this.authMe = authMe; - this.messages = messages; - this.helpProvider = helpProvider; - this.commandMapper = commandMapper; - this.passwordSecurity = passwordSecurity; - this.permissionsManager = permissionsManager; - this.settings = settings; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - this.antiBot = antiBot; - this.validationService = validationService; - this.bukkitService = bukkitService; - } + @Inject + private AuthMe authMe; + @Inject + private Messages messages; + @Inject + private HelpProvider helpProvider; + @Inject + private CommandMapper commandMapper; + @Inject + private PasswordSecurity passwordSecurity; + @Inject + private PermissionsManager permissionsManager; + @Inject + private NewSetting settings; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; + @Inject + private AntiBot antiBot; + @Inject + private ValidationService validationService; + @Inject + private BukkitService bukkitService; /** * Send a message to a player. diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java index 7bc06f03d..c5a3ec5f8 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -10,10 +10,13 @@ import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.permission.DefaultPermission; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.util.CollectionUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -45,9 +48,10 @@ public class HelpProvider { private final PermissionsManager permissionsManager; private final String helpHeader; - public HelpProvider(PermissionsManager permissionsManager, String helpHeader) { + @Inject + public HelpProvider(PermissionsManager permissionsManager, NewSetting settings) { this.permissionsManager = permissionsManager; - this.helpHeader = helpHeader; + this.helpHeader = settings.getProperty(PluginSettings.HELP_HEADER); } public List printHelp(CommandSender sender, FoundCommandResult result, int options) { diff --git a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java index 3a54709ad..76f8e0347 100644 --- a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java +++ b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; +import javax.inject.Inject; import java.io.File; /** @@ -28,6 +29,7 @@ public class PluginHooks { * * @param pluginManager The server's plugin manager */ + @Inject public PluginHooks(PluginManager pluginManager) { this.pluginManager = pluginManager; tryHookToCombatPlus(); @@ -75,13 +77,23 @@ public class PluginHooks { return null; } + /** + * Checks whether the player is an NPC. + * + * @param player The player to process + * @return True if player is NPC, false otherwise + */ + public boolean isNpc(Player player) { + return player.hasMetadata("NPC") || isNpcInCombatTagPlus(player); + } + /** * Query the CombatTagPlus plugin whether the given player is an NPC. * * @param player The player to verify * @return True if the player is an NPC according to CombatTagPlus, false if not or if the plugin is unavailable */ - public boolean isNpcInCombatTagPlus(Player player) { + private boolean isNpcInCombatTagPlus(Player player) { return combatTagPlus != null && combatTagPlus.getNpcPlayerHelper().isNpc(player); } diff --git a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java new file mode 100644 index 000000000..b751b32ed --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java @@ -0,0 +1,286 @@ +package fr.xephi.authme.initialization; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; + +import javax.annotation.PostConstruct; +import javax.inject.Provider; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Dependency injector of AuthMe: initializes and injects services and tasks. + *

+ * Only constructor and field injection are supported, indicated with the JSR330 + * {@link javax.inject.Inject @Inject} annotation. + *

+ * {@link PostConstruct @PostConstruct} methods are recognized and invoked upon + * instantiation. Note that the parent classes are not scanned for such methods. + */ +public class AuthMeServiceInitializer { + + private final Set ALLOWED_PACKAGES; + private final Map, Object> objects; + + /** + * Constructor. + * + * @param allowedPackages list of allowed packages. Only classes whose package + * starts with any of the given entries will be instantiated + */ + public AuthMeServiceInitializer(String... allowedPackages) { + ALLOWED_PACKAGES = ImmutableSet.copyOf(allowedPackages); + objects = new HashMap<>(); + } + + /** + * Retrieves or instantiates an object of the given type. + * + * @param clazz the class to retrieve the value for + * @param the class' type + * @return object of the class' type + */ + public T get(Class clazz) { + return get(clazz, new HashSet>()); + } + + /** + * Registers an instantiation by its type. + * + * @param object the object to register + * @throws IllegalStateException if an object of the same type has already been registered + */ + public void register(Object object) { + if (object instanceof Type) { + throw new IllegalStateException("You tried to register a Type object: '" + object + + "'. This likely indicates an error. Please use register(Class, T) if really desired."); + } + storeObject(object); + } + + /** + * Register an object with a custom class (supertype). Use this for example to specify a + * concrete implementation of an interface or an abstract class. + * + * @param clazz the class to register the object for + * @param object the object + * @param the class' type + */ + public void register(Class clazz, T object) { + if (objects.containsKey(clazz)) { + throw new IllegalStateException("There is already an object present for " + clazz); + } + Preconditions.checkNotNull(object); + objects.put(clazz, object); + } + + /** + * Associate an annotation with a value. + * + * @param annotation the annotation + * @param value the value + */ + public void provide(Class annotation, Object value) { + if (objects.containsKey(annotation)) { + throw new IllegalStateException("Annotation @" + annotation.getClass().getSimpleName() + + " already registered"); + } + Preconditions.checkNotNull(value); + objects.put(annotation, value); + } + + /** + * Returns an instance of the given class or the value associated with an annotation, + * by retrieving it or by instantiating it if not yet present. + * + * @param clazz the class to retrieve a value for + * @param traversedClasses the list of traversed classes + * @param the class' type + * @return instance or associated value (for annotations) + */ + private T get(Class clazz, Set> traversedClasses) { + if (Annotation.class.isAssignableFrom(clazz)) { + throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!"); + } else if (objects.containsKey(clazz)) { + return getObject(clazz); + } + + // First time we come across clazz, need to instantiate it. Add the clazz to the list of traversed + // classes in a new list, so each path we need to take has its own Set. + validatePackage(clazz); + validateInstantiable(clazz); + + traversedClasses = new HashSet<>(traversedClasses); + traversedClasses.add(clazz); + System.out.println(Strings.repeat(" ", traversedClasses.size() * 2) + "- Instantiating " + clazz); + return instantiate(clazz, traversedClasses); + } + + /** + * Instantiates the given class by locating an @Inject constructor and retrieving + * or instantiating its parameters. + * + * @param clazz the class to instantiate + * @param traversedClasses collection of classes already traversed + * @param the class' type + * @return the instantiated object + */ + private T instantiate(Class clazz, Set> traversedClasses) { + Injection injection = firstNotNull(ConstructorInjection.provide(clazz), FieldInjection.provide(clazz)); + if (injection == null) { + throw new IllegalStateException("Did not find injection method for " + clazz + ". Make sure you have " + + "a constructor with @Inject or fields with @Inject. Fields with @Inject require " + + "the default constructor"); + } + + validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses); + Object[] dependencies = resolveDependencies(injection, traversedClasses); + T object = injection.instantiateWith(dependencies); + storeObject(object); + executePostConstructMethods(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. + * + * @param injection the injection parameters + * @param traversedClasses collection of traversed classes + * @return array with the parameters to use in the constructor + */ + private Object[] resolveDependencies(Injection injection, Set> traversedClasses) { + Class[] dependencies = injection.getDependencies(); + Class[] annotations = injection.getDependencyAnnotations(); + Object[] values = new Object[dependencies.length]; + for (int i = 0; i < dependencies.length; ++i) { + if (annotations[i] != null) { + Object value = objects.get(annotations[i]); + if (value == null) { + throw new IllegalStateException("Value for field with @" + annotations[i].getSimpleName() + + " must be registered beforehand"); + } + values[i] = value; + } else { + values[i] = get(dependencies[i], traversedClasses); + } + } + return values; + } + + + /** + * Internal method to retrieve an object from the objects map for non-annotation classes. + * In such cases, the type of the entry always corresponds to the key, i.e. the entry of key + * {@code Class} is guaranteed to be of type {@code T}. + *

+ * To retrieve values identified with an annotation, use {@code objects.get(clazz)} directly. + * We do not know or control the type of the value of keys of annotation classes. + * + * @param clazz the class to retrieve the implementation of + * @param the type + * @return the implementation + */ + private T getObject(Class clazz) { + Object o = objects.get(clazz); + if (o == null) { + throw new NullPointerException("No instance of " + clazz + " available"); + } + return clazz.cast(o); + } + + /** + * Stores the given object with its class as key. Throws an exception if the key already has + * a value associated to it. + * + * @param object the object to store + */ + private void storeObject(Object object) { + if (objects.containsKey(object.getClass())) { + throw new IllegalStateException("There is already an object present for " + object.getClass()); + } + Preconditions.checkNotNull(object); + objects.put(object.getClass(), object); + } + + /** + * Validates that none of the dependencies' types are present in the given collection + * of traversed classes. This prevents circular dependencies. + * + * @param dependencies the dependencies of the class + * @param traversedClasses the collection of traversed classes + */ + private static void validateInjectionHasNoCircularDependencies(Class[] dependencies, + Set> traversedClasses) { + for (Class clazz : dependencies) { + if (traversedClasses.contains(clazz)) { + throw new IllegalStateException("Found cyclic dependency - already traversed '" + clazz + + "' (full traversal list: " + traversedClasses + ")"); + } + } + } + + /** + * Validates the package of a parameter type to ensure that it is part of the allowed packages. + * This ensures that we don't try to instantiate things that are beyond our reach in case some + * external parameter type has not been registered. + * + * @param clazz the class to validate + */ + private void validatePackage(Class clazz) { + if (clazz.getPackage() == null) { + throw new IllegalStateException("Primitive types must be provided explicitly (or use an annotation)."); + } + String packageName = clazz.getPackage().getName(); + for (String allowedPackage : ALLOWED_PACKAGES) { + if (packageName.startsWith(allowedPackage)) { + return; + } + } + throw new IllegalStateException("Class " + clazz + " with package " + packageName + " is outside of the " + + "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.getParameterCount() == 0) { + try { + method.setAccessible(true); + method.invoke(object); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + } else { + throw new IllegalStateException("@PostConstruct methods must have an empty parameter list. " + + "Found parameters in " + method + " belonging to " + object.getClass()); + } + } + } + } + + private static void validateInstantiable(Class clazz) { + if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated"); + } + } + + @SafeVarargs + private static Injection firstNotNull(Provider>... providers) { + for (Provider> provider : providers) { + Injection object = provider.get(); + if (object != null) { + return object; + } + } + return null; + } +} diff --git a/src/main/java/fr/xephi/authme/initialization/BaseCommands.java b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java new file mode 100644 index 000000000..156cb947c --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to denote the collection of AuthMe commands. + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface BaseCommands { +} diff --git a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java new file mode 100644 index 000000000..f77ae58cd --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java @@ -0,0 +1,77 @@ +package fr.xephi.authme.initialization; + +import javax.inject.Inject; +import javax.inject.Provider; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * Functionality for constructor injection. + */ +class ConstructorInjection implements Injection { + + private final Constructor constructor; + + private ConstructorInjection(Constructor constructor) { + this.constructor = constructor; + } + + @Override + public Class[] getDependencies() { + return constructor.getParameterTypes(); + } + + @Override + public Class[] getDependencyAnnotations() { + Annotation[][] parameterAnnotations = constructor.getParameterAnnotations(); + Class[] annotations = new Class[parameterAnnotations.length]; + for (int i = 0; i < parameterAnnotations.length; ++i) { + annotations[i] = parameterAnnotations[i].length > 0 + ? parameterAnnotations[i][0].annotationType() + : null; + } + return annotations; + } + + @Override + public T instantiateWith(Object... values) { + try { + return constructor.newInstance(values); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + } + + public static Provider> provide(final Class clazz) { + return new Provider>() { + @Override + public ConstructorInjection get() { + Constructor constructor = getInjectionConstructor(clazz); + return constructor == null ? null : new ConstructorInjection<>(constructor); + } + }; + } + + + /** + * Gets the first found constructor annotated with {@link Inject} of the given class + * and marks it as accessible. + * + * @param clazz the class to process + * @param the class' type + * @return injection constructor for the class + */ + @SuppressWarnings("unchecked") + private static Constructor getInjectionConstructor(Class clazz) { + Constructor[] constructors = clazz.getDeclaredConstructors(); + for (Constructor constructor : constructors) { + if (constructor.isAnnotationPresent(Inject.class)) { + constructor.setAccessible(true); + return (Constructor) constructor; + } + } + return null; + } + +} diff --git a/src/main/java/fr/xephi/authme/initialization/DataFolder.java b/src/main/java/fr/xephi/authme/initialization/DataFolder.java new file mode 100644 index 000000000..33b879977 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/DataFolder.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for specifying the plugin's data folder. + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface DataFolder { +} diff --git a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java new file mode 100644 index 000000000..aafb0bde3 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java @@ -0,0 +1,112 @@ +package fr.xephi.authme.initialization; + +import com.google.common.base.Preconditions; + +import javax.inject.Inject; +import javax.inject.Provider; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Functionality for field injection. + */ +class FieldInjection implements Injection { + + private final Field[] fields; + private final Constructor defaultConstructor; + + private FieldInjection(Constructor defaultConstructor, Collection fields) { + this.fields = fields.toArray(new Field[fields.size()]); + this.defaultConstructor = defaultConstructor; + } + + @Override + public Class[] getDependencies() { + Class[] types = new Class[fields.length]; + for (int i = 0; i < fields.length; ++i) { + types[i] = fields[i].getType(); + } + return types; + } + + @Override + public Class[] getDependencyAnnotations() { + Class[] annotations = new Class[fields.length]; + for (int i = 0; i < fields.length; ++i) { + annotations[i] = getFirstNonInjectAnnotation(fields[i]); + } + return annotations; + } + + @Override + public T instantiateWith(Object... values) { + Preconditions.checkArgument(values.length == fields.length, + "The number of values must be equal to the number of fields"); + + T instance; + try { + instance = defaultConstructor.newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + + for (int i = 0; i < fields.length; ++i) { + try { + fields[i].set(instance, values[i]); + } catch (IllegalAccessException e) { + throw new UnsupportedOperationException(e); + } + } + return instance; + } + + private static Class getFirstNonInjectAnnotation(Field field) { + for (Annotation annotation : field.getAnnotations()) { + if (annotation.annotationType() != Inject.class) { + return annotation.annotationType(); + } + } + return null; + } + + public static Provider> provide(final Class clazz) { + return new Provider>() { + @Override + public FieldInjection get() { + Constructor constructor = getDefaultConstructor(clazz); + if (constructor == null) { + return null; + } + List fields = getInjectionFields(clazz); + return fields == null ? null : new FieldInjection<>(constructor, fields); + } + }; + } + + private static List getInjectionFields(Class clazz) { + List fields = new ArrayList<>(); + for (Field field : clazz.getDeclaredFields()) { + if (field.isAnnotationPresent(Inject.class)) { + field.setAccessible(true); + fields.add(field); + } + } + return fields; + } + + private static Constructor getDefaultConstructor(Class clazz) { + try { + Constructor defaultConstructor = clazz.getDeclaredConstructor(); + defaultConstructor.setAccessible(true); + return (Constructor) defaultConstructor; + } catch (NoSuchMethodException ignore) { + // no default constructor available + } + return null; + } +} diff --git a/src/main/java/fr/xephi/authme/initialization/Injection.java b/src/main/java/fr/xephi/authme/initialization/Injection.java new file mode 100644 index 000000000..6e85b4ce5 --- /dev/null +++ b/src/main/java/fr/xephi/authme/initialization/Injection.java @@ -0,0 +1,36 @@ +package fr.xephi.authme.initialization; + +/** + * Common interface for all injection methods. + * + * @param the type of the concerned object + */ +interface Injection { + + /** + * Returns the dependencies that must be provided to instantiate the given item. + * + * @return list of dependencies + * @see #instantiateWith + */ + Class[] getDependencies(); + + /** + * Returns the annotation on each dependency if available. The indices of this + * array correspond to the ones of {@link #getDependencies()}. If no annotation + * is available, {@code null} is stored. If multiple annotations are present, only + * one is stored (no guarantee on which one). + * + * @return annotation for each dependency + */ + Class[] getDependencyAnnotations(); + + /** + * Creates a new instance with the given values as dependencies. The given values + * must correspond to {@link #getDependencies()} in size, order and type. + * + * @param values the values to set for the dependencies + * @return resulting object + */ + T instantiateWith(Object... values); +} diff --git a/src/main/java/fr/xephi/authme/MetricsStarter.java b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java similarity index 93% rename from src/main/java/fr/xephi/authme/MetricsStarter.java rename to src/main/java/fr/xephi/authme/initialization/MetricsStarter.java index eac9ebaf4..4a163f98a 100644 --- a/src/main/java/fr/xephi/authme/MetricsStarter.java +++ b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java @@ -1,5 +1,7 @@ -package fr.xephi.authme; +package fr.xephi.authme.initialization; +import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.PluginSettings; diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index a17eacd58..97383c538 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -18,6 +18,7 @@ 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.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; @@ -53,6 +54,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerShearEntityEvent; +import javax.inject.Inject; import java.util.concurrent.ConcurrentHashMap; import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent; @@ -67,24 +69,22 @@ public class AuthMePlayerListener implements Listener { public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>(); public static final ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>(); - private final AuthMe plugin; - private final NewSetting settings; - private final Messages m; - private final DataSource dataSource; - private final AntiBot antiBot; - private final Management management; - private final BukkitService bukkitService; - - public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource, - AntiBot antiBot, Management management, BukkitService bukkitService) { - this.plugin = plugin; - this.settings = settings; - this.m = messages; - this.dataSource = dataSource; - this.antiBot = antiBot; - this.management = management; - this.bukkitService = bukkitService; - } + @Inject + private AuthMe plugin; + @Inject + private NewSetting settings; + @Inject + private Messages m; + @Inject + private DataSource dataSource; + @Inject + private AntiBot antiBot; + @Inject + private Management management; + @Inject + private BukkitService bukkitService; + @Inject + private SpawnLoader spawnLoader; private void handleChat(AsyncPlayerChatEvent event) { if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) { @@ -201,7 +201,7 @@ public class AuthMePlayerListener implements Listener { return; } - Location spawn = plugin.getSpawnLocation(player); + Location spawn = spawnLoader.getSpawnLocation(player); if (spawn != null && spawn.getWorld() != null) { if (!player.getWorld().equals(spawn.getWorld())) { player.teleport(spawn); @@ -517,7 +517,7 @@ public class AuthMePlayerListener implements Listener { Player player = event.getPlayer(); String name = player.getName().toLowerCase(); - Location spawn = plugin.getSpawnLocation(player); + Location spawn = spawnLoader.getSpawnLocation(player); if (Settings.isSaveQuitLocationEnabled && dataSource.isAuthAvailable(name)) { PlayerAuth auth = PlayerAuth.builder() .name(name) diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java index ec8326b56..54df067ec 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java @@ -15,21 +15,20 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.ServerListPingEvent; +import javax.inject.Inject; + /** */ public class AuthMeServerListener implements Listener { - private final AuthMe plugin; - private final Messages messages; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - - public AuthMeServerListener(AuthMe plugin, Messages messages, PluginHooks pluginHooks, SpawnLoader spawnLoader) { - this.plugin = plugin; - this.messages = messages; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - } + @Inject + private AuthMe plugin; + @Inject + private Messages messages; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; @EventHandler(priority = EventPriority.HIGHEST) public void onServerPing(ServerListPingEvent event) { diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java index d82669858..ae6c47bcb 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java @@ -11,8 +11,11 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; +import javax.inject.Inject; + public class AuthMeTabCompletePacketAdapter extends PacketAdapter { + @Inject public AuthMeTabCompletePacketAdapter(AuthMe plugin) { super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE); } diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java index a23ce5c18..d13668d50 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java @@ -19,6 +19,7 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.util.BukkitService; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.logging.Level; @@ -27,6 +28,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter { private final BukkitService bukkitService; + @Inject public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) { super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO); this.bukkitService = bukkitService; diff --git a/src/main/java/fr/xephi/authme/ImageGenerator.java b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java similarity index 88% rename from src/main/java/fr/xephi/authme/ImageGenerator.java rename to src/main/java/fr/xephi/authme/mail/ImageGenerator.java index e529efabd..77d989015 100644 --- a/src/main/java/fr/xephi/authme/ImageGenerator.java +++ b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java @@ -1,6 +1,9 @@ -package fr.xephi.authme; +package fr.xephi.authme.mail; -import java.awt.*; +import java.awt.Color; +import java.awt.Font; +import java.awt.GradientPaint; +import java.awt.Graphics2D; import java.awt.image.BufferedImage; /** diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index c80001c34..d83326026 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -2,7 +2,6 @@ package fr.xephi.authme.mail; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.ImageGenerator; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.EmailSettings; diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index ee27f82cc..7dfcd40c4 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -2,6 +2,7 @@ package fr.xephi.authme.permission; import de.bananaco.bpermissions.api.ApiLayer; import de.bananaco.bpermissions.api.CalculableType; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.util.CollectionUtils; import net.milkbowl.vault.permission.Permission; @@ -20,11 +21,12 @@ import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; import ru.tehkode.permissions.PermissionUser; import ru.tehkode.permissions.bukkit.PermissionsEx; +import javax.annotation.PostConstruct; +import javax.inject.Inject; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.logging.Logger; /** *

@@ -48,10 +50,7 @@ public class PermissionsManager implements PermissionsService { * Server instance. */ private final Server server; - /** - * Logger instance. - */ - private Logger log; + private final PluginManager pluginManager; /** * Type of permissions system that is currently used. * Null if no permissions system is hooked and/or used. @@ -70,11 +69,11 @@ public class PermissionsManager implements PermissionsService { * Constructor. * * @param server Server instance - * @param log Logger */ - public PermissionsManager(Server server, Logger log) { + @Inject + public PermissionsManager(Server server, PluginManager pluginManager) { this.server = server; - this.log = log; + this.pluginManager = pluginManager; } /** @@ -100,39 +99,37 @@ public class PermissionsManager implements PermissionsService { * * @return The detected permissions system. */ + @PostConstruct public PermissionsSystemType setup() { // Force-unhook from current hooked permissions systems unhook(); - // Define the plugin manager - final PluginManager pluginManager = this.server.getPluginManager(); - // Reset used permissions system type flag permsType = null; // Loop through all the available permissions system types - for(PermissionsSystemType type : PermissionsSystemType.values()) { + for (PermissionsSystemType type : PermissionsSystemType.values()) { // Try to find and hook the current plugin if available, print an error if failed try { // Try to find the plugin for the current permissions system Plugin plugin = pluginManager.getPlugin(type.getPluginName()); // Make sure a plugin with this name was found - if(plugin == null) + if (plugin == null) continue; // Make sure the plugin is enabled before hooking - if(!plugin.isEnabled()) { - this.log.info("Not hooking into " + type.getName() + " because it's disabled!"); + if (!plugin.isEnabled()) { + ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!"); continue; } // Use the proper method to hook this plugin - switch(type) { + switch (type) { case PERMISSIONS_EX: // Get the permissions manager for PermissionsEx and make sure it isn't null - if(PermissionsEx.getPermissionManager() == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + if (PermissionsEx.getPermissionManager() == null) { + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } @@ -146,8 +143,8 @@ public class PermissionsManager implements PermissionsService { case Z_PERMISSIONS: // Set the zPermissions service and make sure it's valid zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class); - if(zPermissionsService == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + if (zPermissionsService == null) { + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } @@ -157,14 +154,14 @@ public class PermissionsManager implements PermissionsService { // Get the permissions provider service RegisteredServiceProvider permissionProvider = this.server.getServicesManager().getRegistration(Permission.class); if (permissionProvider == null) { - this.log.info("Failed to hook into " + type.getName() + "!"); + ConsoleLogger.info("Failed to hook into " + type.getName() + "!"); continue; } // Get the Vault provider and make sure it's valid vaultPerms = permissionProvider.getProvider(); - if(vaultPerms == null) { - this.log.info("Not using " + type.getName() + " because it's disabled!"); + if (vaultPerms == null) { + ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!"); continue; } @@ -177,19 +174,19 @@ public class PermissionsManager implements PermissionsService { this.permsType = type; // Show a success message - this.log.info("Hooked into " + type.getName() + "!"); + ConsoleLogger.info("Hooked into " + type.getName() + "!"); // Return the used permissions system type return type; } catch (Exception ex) { // An error occurred, show a warning message - this.log.info("Error while hooking into " + type.getName() + "!"); + ConsoleLogger.logException("Error while hooking into " + type.getName(), ex); } } // No recognized permissions system found, show a message and return - this.log.info("No supported permissions system found! Permissions are disabled!"); + ConsoleLogger.info("No supported permissions system found! Permissions are disabled!"); return null; } @@ -201,7 +198,7 @@ public class PermissionsManager implements PermissionsService { this.permsType = null; // Print a status message to the console - this.log.info("Unhooked from Permissions!"); + ConsoleLogger.info("Unhooked from Permissions!"); } /** @@ -232,7 +229,7 @@ public class PermissionsManager implements PermissionsService { if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") || pluginName.equals("bPermissions") || pluginName.equals("GroupManager") || pluginName.equals("zPermissions") || pluginName.equals("Vault")) { - this.log.info(pluginName + " plugin enabled, dynamically updating permissions hooks!"); + ConsoleLogger.info(pluginName + " plugin enabled, dynamically updating permissions hooks!"); setup(); } } @@ -251,7 +248,7 @@ public class PermissionsManager implements PermissionsService { if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") || pluginName.equals("bPermissions") || pluginName.equals("GroupManager") || pluginName.equals("zPermissions") || pluginName.equals("Vault")) { - this.log.info(pluginName + " plugin disabled, updating hooks!"); + ConsoleLogger.info(pluginName + " plugin disabled, updating hooks!"); setup(); } } diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 4b279c9a1..04a0f414b 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -3,6 +3,7 @@ package fr.xephi.authme.process; import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.process.email.AsyncAddEmail; import fr.xephi.authme.process.email.AsyncChangeEmail; import fr.xephi.authme.process.join.AsynchronousJoin; @@ -14,23 +15,26 @@ import fr.xephi.authme.process.unregister.AsynchronousUnregister; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; +import javax.inject.Inject; + /** */ public class Management { - private final AuthMe plugin; - private final BukkitScheduler sched; - private final ProcessService processService; - private final DataSource dataSource; - private final PlayerCache playerCache; + @Inject + private AuthMe plugin; + @Inject + private BukkitScheduler sched; + @Inject + private ProcessService processService; + @Inject + private DataSource dataSource; + @Inject + private PlayerCache playerCache; + @Inject + private PluginHooks pluginHooks; - public Management(AuthMe plugin, ProcessService processService, DataSource dataSource, PlayerCache playerCache) { - this.plugin = plugin; - this.sched = this.plugin.getServer().getScheduler(); - this.processService = processService; - this.dataSource = dataSource; - this.playerCache = playerCache; - } + Management() { } public void performLogin(final Player player, final String password, final boolean forceLogin) { runTask(new AsynchronousLogin(player, password, forceLogin, plugin, dataSource, processService)); @@ -49,7 +53,7 @@ public class Management { } public void performJoin(final Player player) { - runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, processService)); + runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, pluginHooks, processService)); } public void performQuit(final Player player, final boolean isKick) { diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java index 653be1565..a338cad42 100644 --- a/src/main/java/fr/xephi/authme/process/ProcessService.java +++ b/src/main/java/fr/xephi/authme/process/ProcessService.java @@ -17,6 +17,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.scheduler.BukkitTask; +import javax.inject.Inject; import java.util.Collection; /** @@ -24,29 +25,24 @@ import java.util.Collection; */ public class ProcessService { - private final NewSetting settings; - private final Messages messages; - private final AuthMe authMe; - private final DataSource dataSource; - private final PasswordSecurity passwordSecurity; - private final PluginHooks pluginHooks; - private final SpawnLoader spawnLoader; - private final ValidationService validationService; - private final BukkitService bukkitService; - - public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource, - PasswordSecurity passwordSecurity, PluginHooks pluginHooks, SpawnLoader spawnLoader, - ValidationService validationService, BukkitService bukkitService) { - this.settings = settings; - this.messages = messages; - this.authMe = authMe; - this.dataSource = dataSource; - this.passwordSecurity = passwordSecurity; - this.pluginHooks = pluginHooks; - this.spawnLoader = spawnLoader; - this.validationService = validationService; - this.bukkitService = bukkitService; - } + @Inject + private NewSetting settings; + @Inject + private Messages messages; + @Inject + private AuthMe authMe; + @Inject + private DataSource dataSource; + @Inject + private PasswordSecurity passwordSecurity; + @Inject + private PluginHooks pluginHooks; + @Inject + private SpawnLoader spawnLoader; + @Inject + private ValidationService validationService; + @Inject + private BukkitService bukkitService; /** * Retrieve a property's value. diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index 37b0dfbd3..c9ab7159a 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -9,6 +9,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.FirstSpawnTeleportEvent; import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.events.SpawnTeleportEvent; +import fr.xephi.authme.hooks.PluginHooks; import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.PlayerStatePermission; @@ -45,18 +46,20 @@ public class AsynchronousJoin implements Process { private final String name; private final ProcessService service; private final PlayerCache playerCache; + private final PluginHooks pluginHooks; private final boolean disableCollisions = MethodUtils .getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null; public AsynchronousJoin(Player player, AuthMe plugin, DataSource database, PlayerCache playerCache, - ProcessService service) { + PluginHooks pluginHooks, ProcessService service) { this.player = player; this.plugin = plugin; this.database = database; this.name = player.getName().toLowerCase(); this.service = service; this.playerCache = playerCache; + this.pluginHooks = pluginHooks; } @Override @@ -190,7 +193,7 @@ public class AsynchronousJoin implements Process { player.setWalkSpeed(0.0f); } player.setNoDamageTicks(registrationTimeout); - if (plugin.getPluginHooks().isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { + if (pluginHooks.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) { player.performCommand("motd"); } if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) { diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java index 94a8abeb4..458c99699 100644 --- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java +++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java @@ -8,6 +8,7 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.plugin.PluginManager; +import javax.inject.Inject; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -22,6 +23,7 @@ public class PasswordSecurity { private final DataSource dataSource; private final PluginManager pluginManager; + @Inject public PasswordSecurity(DataSource dataSource, NewSetting settings, PluginManager pluginManager) { this.settings = settings; this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index 59693a98c..a046d813d 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -4,6 +4,7 @@ import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.hooks.PluginHooks; +import fr.xephi.authme.initialization.DataFolder; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.util.FileUtils; import fr.xephi.authme.util.StringUtils; @@ -14,6 +15,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import javax.inject.Inject; import java.io.File; import java.io.IOException; @@ -40,7 +42,8 @@ public class SpawnLoader { * @param settings The setting instance * @param pluginHooks The plugin hooks instance */ - public SpawnLoader(File pluginFolder, NewSetting settings, PluginHooks pluginHooks) { + @Inject + public SpawnLoader(@DataFolder File pluginFolder, NewSetting settings, PluginHooks pluginHooks) { File spawnFile = new File(pluginFolder, "spawn.yml"); // TODO ljacqu 20160312: Check if resource could be copied and handle the case if not FileUtils.copyFileFromResource(spawnFile, "spawn.yml"); diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java index ea405d807..592caa228 100644 --- a/src/main/java/fr/xephi/authme/util/BukkitService.java +++ b/src/main/java/fr/xephi/authme/util/BukkitService.java @@ -7,6 +7,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; +import javax.inject.Inject; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; @@ -28,6 +29,7 @@ public class BukkitService { private final boolean getOnlinePlayersIsCollection; private Method getOnlinePlayers; + @Inject public BukkitService(AuthMe authMe) { this.authMe = authMe; getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField(); diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 5850645bd..5d8c08eea 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -165,8 +165,9 @@ public final class Utils { }); } + @Deprecated public static boolean isNPC(Player player) { - return player.hasMetadata("NPC") || plugin.getPluginHooks().isNpcInCombatTagPlus(player); + return plugin.getPluginHooks().isNpc(player); } public static void teleportToSpawn(Player player) { diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java index 7f8b78b7a..815f493f3 100644 --- a/src/main/java/fr/xephi/authme/util/ValidationService.java +++ b/src/main/java/fr/xephi/authme/util/ValidationService.java @@ -10,6 +10,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; +import javax.inject.Inject; import java.util.Collection; import java.util.List; @@ -22,6 +23,7 @@ public class ValidationService { private final DataSource dataSource; private final PermissionsManager permissionsManager; + @Inject public ValidationService(NewSetting settings, DataSource dataSource, PermissionsManager permissionsManager) { this.settings = settings; this.dataSource = dataSource; diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 89a35571f..a1ff5e22f 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -18,10 +18,10 @@ import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -41,6 +41,7 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class CommandServiceTest { + @InjectMocks private CommandService commandService; @Mock private AuthMe authMe; @@ -67,12 +68,6 @@ public class CommandServiceTest { @Mock private BukkitService bukkitService; - @Before - public void setUpService() { - commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity, - permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService); - } - @Test public void shouldSendMessage() { // given diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index 3ec47a4f4..e7d85f146 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -6,6 +6,8 @@ import fr.xephi.authme.command.FoundResultStatus; import fr.xephi.authme.command.TestCommandsUtil; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.PluginSettings; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.junit.Before; @@ -52,7 +54,9 @@ public class HelpProviderTest { @Before public void setUpHelpProvider() { permissionsManager = mock(PermissionsManager.class); - helpProvider = new HelpProvider(permissionsManager, HELP_HEADER); + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(PluginSettings.HELP_HEADER)).willReturn(HELP_HEADER); + helpProvider = new HelpProvider(permissionsManager, settings); sender = mock(CommandSender.class); } diff --git a/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java new file mode 100644 index 000000000..613222919 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java @@ -0,0 +1,194 @@ +package fr.xephi.authme.initialization; + +import fr.xephi.authme.initialization.samples.BadFieldInjection; +import fr.xephi.authme.initialization.samples.BetaManager; +import fr.xephi.authme.initialization.samples.CircularClasses; +import fr.xephi.authme.initialization.samples.ClassWithAbstractDependency; +import fr.xephi.authme.initialization.samples.ClassWithAnnotations; +import fr.xephi.authme.initialization.samples.Duration; +import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations; +import fr.xephi.authme.initialization.samples.InvalidClass; +import fr.xephi.authme.initialization.samples.InvalidPostConstruct; +import fr.xephi.authme.initialization.samples.PostConstructTestClass; +import fr.xephi.authme.initialization.samples.ProvidedClass; +import fr.xephi.authme.initialization.samples.Size; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * Test for {@link AuthMeServiceInitializer}. + */ +public class AuthMeServiceInitializerTest { + + private static final String ALLOWED_PACKAGE = "fr.xephi.authme.initialization"; + + private AuthMeServiceInitializer initializer; + + @Before + public void setInitializer() { + initializer = new AuthMeServiceInitializer(ALLOWED_PACKAGE); + initializer.register(new ProvidedClass("")); + } + + @Test + public void shouldInitializeElements() { + // given / when + BetaManager betaManager = initializer.get(BetaManager.class); + + // then + assertThat(betaManager, not(nullValue())); + for (Object o : betaManager.getDependencies()) { + assertThat(o, not(nullValue())); + } + } + + @Test(expected = IllegalStateException.class) + public void shouldThrowForInvalidPackage() { + // given / when / then + initializer.get(InvalidClass.class); + } + + @Test + public void shouldPassValueByAnnotation() { + // given + int size = 12; + long duration = -15482L; + initializer.provide(Size.class, size); + initializer.provide(Duration.class, duration); + + // when + ClassWithAnnotations object = initializer.get(ClassWithAnnotations.class); + + // then + assertThat(object, not(nullValue())); + assertThat(object.getSize(), equalTo(size)); + assertThat(object.getDuration(), equalTo(duration)); + // some sample check to make sure we only have one instance of GammaService + assertThat(object.getGammaService(), equalTo(initializer.get(BetaManager.class).getDependencies()[1])); + } + + @Test(expected = RuntimeException.class) + public void shouldRecognizeCircularReferences() { + // given / when / then + initializer.get(CircularClasses.Circular3.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForUnregisteredAnnotation() { + // given + initializer.provide(Size.class, 4523); + + // when / then + initializer.get(ClassWithAnnotations.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForFieldInjectionWithNoDefaultConstructor() { + // given / when / then + initializer.get(BadFieldInjection.class); + } + + @Test + public void shouldInjectFieldsWithAnnotationsProperly() { + // given + initializer.provide(Size.class, 2809375); + initializer.provide(Duration.class, 13095L); + + // when + FieldInjectionWithAnnotations result = initializer.get(FieldInjectionWithAnnotations.class); + + // then + assertThat(result.getSize(), equalTo(2809375)); + assertThat(result.getDuration(), equalTo(13095L)); + assertThat(result.getBetaManager(), not(nullValue())); + assertThat(result.getClassWithAnnotations(), not(nullValue())); + assertThat(result.getClassWithAnnotations().getGammaService(), + equalTo(result.getBetaManager().getDependencies()[1])); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForAnnotationAsKey() { + // given / when / then + initializer.get(Size.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForSecondRegistration() { + // given / when / then + initializer.register(new ProvidedClass("")); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForSecondAnnotationRegistration() { + // given + initializer.provide(Size.class, 12); + + // when / then + initializer.provide(Size.class, -8); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForNullValueAssociatedToAnnotation() { + // given / when / then + initializer.provide(Duration.class, null); + } + + @Test(expected = NullPointerException.class) + public void shouldThrowForRegisterWithNull() { + // given / when / then + initializer.register(String.class, null); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForRegisterOfType() { + // given / when / then + // this most likely means that the second argument was forgotten, so throw an error and force + // the API user to use the explicit register(Class.class, String.class) if really, really desired + // (Though for such generic types, an annotation would be a lot better) + initializer.register(String.class); + } + + @Test + public void shouldExecutePostConstructMethod() { + // given + initializer.provide(Size.class, 15123); + + // when + PostConstructTestClass testClass = initializer.get(PostConstructTestClass.class); + + // then + assertThat(testClass.werePostConstructsCalled(), equalTo(true)); + assertThat(testClass.getBetaManager(), not(nullValue())); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForInvalidPostConstructMethod() { + // given / when / then + initializer.get(InvalidPostConstruct.class); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowForAbstractNonRegisteredDependency() { + // given / when / then + initializer.get(ClassWithAbstractDependency.class); + } + + @Test + public void shouldInstantiateWithImplementationOfAbstractDependency() { + // given + ClassWithAbstractDependency.ConcreteDependency concrete = new ClassWithAbstractDependency.ConcreteDependency(); + initializer.register(ClassWithAbstractDependency.AbstractDependency.class, concrete); + + // when + ClassWithAbstractDependency cwad = initializer.get(ClassWithAbstractDependency.class); + + // then + assertThat(cwad.getAbstractDependency() == concrete, equalTo(true)); + assertThat(cwad.getAlphaService(), not(nullValue())); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java new file mode 100644 index 000000000..2a93a43c3 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class with dependency to ProvidedClass. + */ +public class AlphaService { + + private ProvidedClass providedClass; + + @Inject + AlphaService(ProvidedClass providedClass) { + this.providedClass = providedClass; + } + + public ProvidedClass getProvidedClass() { + return providedClass; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java new file mode 100644 index 000000000..9dc415485 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java @@ -0,0 +1,16 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample class with invalid field injection (requires default constructor). + */ +public class BadFieldInjection { + + @Inject + private AlphaService alphaService; + + public BadFieldInjection(BetaManager betaManager) { + throw new IllegalStateException("Should never be called"); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java new file mode 100644 index 000000000..8c2fe923f --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - depends on Provided, alpha and gamma. + */ +public class BetaManager { + + @Inject + private ProvidedClass providedClass; + @Inject + private GammaService gammaService; + @Inject + private AlphaService alphaService; + + public Object[] getDependencies() { + return new Object[]{providedClass, gammaService, alphaService}; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java new file mode 100644 index 000000000..e9a1460ea --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java @@ -0,0 +1,30 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Classes with circular dependencies. + */ +public class CircularClasses { + + public static final class Circular1 { + @Inject + public Circular1(AlphaService alphaService, Circular3 circular3) { + // -- + } + } + + public static final class Circular2 { + @Inject + public Circular2(Circular1 circular1) { + // -- + } + } + + public static final class Circular3 { + @Inject + public Circular3(Circular2 circular2, BetaManager betaManager) { + // -- + } + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java new file mode 100644 index 000000000..25b651b32 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java @@ -0,0 +1,32 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Test with an abstract class declared as dependency. + */ +public class ClassWithAbstractDependency { + + private final AlphaService alphaService; + private final AbstractDependency abstractDependency; + + @Inject + public ClassWithAbstractDependency(AlphaService as, AbstractDependency ad) { + this.alphaService = as; + this.abstractDependency = ad; + } + + public AlphaService getAlphaService() { + return alphaService; + } + + public AbstractDependency getAbstractDependency() { + return abstractDependency; + } + + public static abstract class AbstractDependency { + } + + public static final class ConcreteDependency extends AbstractDependency { + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java new file mode 100644 index 000000000..61dca71b8 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java @@ -0,0 +1,29 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +public class ClassWithAnnotations { + + private int size; + private GammaService gammaService; + private long duration; + + @Inject + ClassWithAnnotations(@Size int size, GammaService gammaService, @Duration long duration) { + this.size = size; + this.gammaService = gammaService; + this.duration = duration; + } + + public int getSize() { + return size; + } + + public GammaService getGammaService() { + return gammaService; + } + + public long getDuration() { + return duration; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Duration.java b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java new file mode 100644 index 000000000..e61c6d28b --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sample annotation. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Duration { +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java new file mode 100644 index 000000000..65bdf537d --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java @@ -0,0 +1,40 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - field injection, including custom annotations. + */ +public class FieldInjectionWithAnnotations { + + @Inject + private BetaManager betaManager; + @Inject + @Size + private int size; + @Duration + @Inject + private long duration; + @Inject + protected ClassWithAnnotations classWithAnnotations; + + FieldInjectionWithAnnotations() { + } + + public BetaManager getBetaManager() { + return betaManager; + } + + public int getSize() { + return size; + } + + public long getDuration() { + return duration; + } + + public ClassWithAnnotations getClassWithAnnotations() { + return classWithAnnotations; + } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java new file mode 100644 index 000000000..8ee970321 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java @@ -0,0 +1,20 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class dependent on alpha and provided. + */ +public class GammaService { + + private AlphaService alphaService; + + @Inject + GammaService(AlphaService alphaService) { + this.alphaService = alphaService; + } + + public AlphaService getAlphaService() { + return alphaService; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java new file mode 100644 index 000000000..b896af9d6 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - invalid class, since Integer parameter type is outside of the allowed package and not annotated. + */ +public class InvalidClass { + + @Inject + public InvalidClass(AlphaService alphaService, Integer i) { + throw new IllegalStateException("Should never be called"); + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java new file mode 100644 index 000000000..85c7f4c4f --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java @@ -0,0 +1,19 @@ +package fr.xephi.authme.initialization.samples; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +/** + * Class with invalid @PostConstruct method. + */ +public class InvalidPostConstruct { + + @Inject + private AlphaService alphaService; + @Inject + private ProvidedClass providedClass; + + @PostConstruct + public void invalidPostConstr(BetaManager betaManager) { + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java new file mode 100644 index 000000000..a4e570324 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java @@ -0,0 +1,37 @@ +package fr.xephi.authme.initialization.samples; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +/** + * Sample class for testing the execution of the @PostConstruct method. + */ +public class PostConstructTestClass { + + @Inject + @Size + private int size; + @Inject + private BetaManager betaManager; + private boolean wasPostConstructCalled = false; + private boolean wasSecondPostConstructCalled = false; + + @PostConstruct + protected void setFieldToTrue() { + wasPostConstructCalled = true; + } + + @PostConstruct + public int otherPostConstructMethod() { + wasSecondPostConstructCalled = true; + return 42; + } + + public boolean werePostConstructsCalled() { + return wasPostConstructCalled && wasSecondPostConstructCalled; + } + + public BetaManager getBetaManager() { + return betaManager; + } +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java new file mode 100644 index 000000000..7ce81bd30 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java @@ -0,0 +1,18 @@ +package fr.xephi.authme.initialization.samples; + +import javax.inject.Inject; + +/** + * Sample - class that is always provided to the initializer beforehand. + */ +public class ProvidedClass { + + @Inject + public ProvidedClass() { + throw new IllegalStateException("Should never be called (tests always provide this class)"); + } + + public ProvidedClass(String manualConstructor) { + } + +} diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Size.java b/src/test/java/fr/xephi/authme/initialization/samples/Size.java new file mode 100644 index 000000000..320a7b7c5 --- /dev/null +++ b/src/test/java/fr/xephi/authme/initialization/samples/Size.java @@ -0,0 +1,14 @@ +package fr.xephi.authme.initialization.samples; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Sample annotation. + */ +@Target({ElementType.PARAMETER, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Size { +} diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java index ab935d029..f641b1f01 100644 --- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java +++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java @@ -13,9 +13,9 @@ import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.BukkitService; import fr.xephi.authme.util.ValidationService; import org.bukkit.command.CommandSender; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class ProcessServiceTest { + @InjectMocks private ProcessService processService; @Mock private ValidationService validationService; @@ -51,12 +52,6 @@ public class ProcessServiceTest { @Mock private BukkitService bukkitService; - @Before - public void setUpService() { - processService = new ProcessService(settings, messages, authMe, dataSource, passwordSecurity, - pluginHooks, spawnLoader, validationService, bukkitService); - } - @Test public void shouldGetProperty() { // given