diff --git a/bFundamentals/pom.xml b/bFundamentals/pom.xml index 6a2eedf..6256a98 100644 --- a/bFundamentals/pom.xml +++ b/bFundamentals/pom.xml @@ -32,6 +32,11 @@ jNBT 1.1 + + org.reflections + reflections + 0.9.9-RC1 + @@ -50,7 +55,9 @@ commons-*:* - org.jnbt:jNBT + org.jnbt:jNBT + org.javassist:javassist + org.reflections:reflections org.apache.httpcomponents:* diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/BukkitConfigurationManager.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/BukkitConfigurationManager.java index f4bd670..8570b89 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/BukkitConfigurationManager.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/BukkitConfigurationManager.java @@ -40,6 +40,7 @@ public class BukkitConfigurationManager implements ConfigManager { protected String m_logPrefix = null; protected DatabaseSettings m_databaseSettings = null; protected String m_crashPass; + protected File m_moduleDir; /* (non-Javadoc) * @see uk.codingbadgers.bFundamentals.ConfigManager#loadConfiguration(java.io.File) @@ -48,10 +49,14 @@ public class BukkitConfigurationManager implements ConfigManager { public void loadConfiguration(File configFile) throws IOException { FileConfiguration config = YamlConfiguration.loadConfiguration(configFile); + config.options().header("bFundamentals configuration"); + config.addDefault("general.language", "UK"); config.addDefault("general.debug", false); config.addDefault("general.crash.password", "Password"); + config.addDefault("module.loading.dir", "${plugindir}/modules"); + config.addDefault("module.update.enabled", false); config.addDefault("module.update.download", false); config.addDefault("module.update.apply", false); @@ -66,7 +71,8 @@ public void loadConfiguration(File configFile) throws IOException { config.addDefault("database.password", ""); config.addDefault("database.port", 3306); config.addDefault("database.updateRate", 5); - + + config.options().copyHeader(true); config.options().copyDefaults(true); config.save(configFile); @@ -74,6 +80,8 @@ public void loadConfiguration(File configFile) throws IOException { m_debug = config.getBoolean("general.debug"); m_crashPass = config.getString("general.crash.password", "Password"); + m_moduleDir = parseDirectory(config.getString("module.loading.dir")); + m_autoUpdate = config.getBoolean("module.update.enabled"); m_autoDownload = config.getBoolean("module.update.download"); m_autoApply = config.getBoolean("module.update.apply"); @@ -92,68 +100,55 @@ public void loadConfiguration(File configFile) throws IOException { } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#getDatabaseSettings() - */ + private File parseDirectory(String string) { + string = string.replace("${plugindir}", bFundamentals.getInstance().getDataFolder().getAbsolutePath()); + string = string.replace("${basedir}", new File(".").getAbsolutePath()); + return new File(string); + } + @Override public DatabaseSettings getDatabaseSettings() { return m_databaseSettings; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#getLanguage() - */ @Override public String getLanguage() { return m_language; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#isDebugEnabled() - */ @Override public boolean isDebugEnabled() { return m_debug; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#isAutoUpdateEnabled() - */ @Override public boolean isAutoUpdateEnabled() { return m_autoUpdate; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#isAutoDownloadEnabled() - */ @Override public boolean isAutoDownloadEnabled() { return m_autoDownload; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#isAutoInstallEnabled() - */ @Override public boolean isAutoInstallEnabled() { return m_autoApply; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#getLogPrefix() - */ @Override public String getLogPrefix() { return m_logPrefix; } - /* (non-Javadoc) - * @see uk.codingbadgers.bFundamentals.ConfigManager#getCrashPassword() - */ @Override public String getCrashPassword() { return m_crashPass; } + @Override + public File getModuleDirectory() { + return m_moduleDir; + } + } diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/ConfigManager.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/ConfigManager.java index 8aab7af..ff3a110 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/ConfigManager.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/ConfigManager.java @@ -86,4 +86,11 @@ public interface ConfigManager { */ public abstract String getCrashPassword(); + /** + * Gets the current module directory. + * + * @return the module directory + */ + public abstract File getModuleDirectory(); + } \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/bFundamentals.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/bFundamentals.java index 6910c8b..d579721 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/bFundamentals.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/bFundamentals.java @@ -48,7 +48,7 @@ import ru.tehkode.permissions.bukkit.PermissionsEx; import uk.codingbadgers.bFundamentals.module.Module; -import uk.codingbadgers.bFundamentals.module.ModuleLoader; +import uk.codingbadgers.bFundamentals.module.loader.ModuleLoader; import uk.codingbadgers.bFundamentals.player.FundamentalPlayer; import uk.codingbadgers.bFundamentals.player.FundamentalPlayerArray; import uk.thecodingbadgers.bDatabaseManager.bDatabaseManager; diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/commands/ModuleCommand.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/commands/ModuleCommand.java index e4ec623..c5bc2d1 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/commands/ModuleCommand.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/commands/ModuleCommand.java @@ -23,6 +23,7 @@ import java.util.logging.Level; import org.apache.commons.lang.Validate; +import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandException; import org.bukkit.command.CommandSender; @@ -32,6 +33,7 @@ import com.google.common.collect.ImmutableList.Builder; import uk.codingbadgers.bFundamentals.bFundamentals; +import uk.codingbadgers.bFundamentals.error.ExceptionHandler; import uk.codingbadgers.bFundamentals.module.Module; /** @@ -225,30 +227,36 @@ public void addChildCommand(ModuleChildCommand command) { */ @Override public final boolean execute(CommandSender sender, String label, String[] args) { - if (args.length >= 1) { - for (ModuleChildCommand child : m_children) { - if (child.getLabel().equalsIgnoreCase(args[0])) { - m_module.log(Level.INFO, child.getLabel()); - // cut first argument (sub command) out of command then handle as child command - args = Arrays.copyOfRange(args, 1, args.length); - return child.execute(sender, label, args); + try { + if (args.length >= 1) { + for (ModuleChildCommand child : m_children) { + if (child.getLabel().equalsIgnoreCase(args[0])) { + m_module.log(Level.INFO, child.getLabel()); + // cut first argument (sub command) out of command then handle as child command + args = Arrays.copyOfRange(args, 1, args.length); + return child.execute(sender, label, args); + } } } + + // for backwards compatibility call old method first, will pass to new if left as default + if (onCommand(sender, label, args)) { + return true; + } + + // call command method in module if still not handled + if (m_module.onCommand(sender, label, args)) { + return true; + } + + // if not handled for any reason, send usage + Module.sendMessage(m_module.getName(), sender, getUsage()); + return false; + } catch (Exception ex) { + ExceptionHandler.handleException(ex); + sender.sendMessage(ChatColor.RED + "Sorry there was a error executing your command."); + return false; } - - // for backwards compatibility call old method first, will pass to new if left as default - if (onCommand(sender, label, args)) { - return true; - } - - // call command method in module if still not handled - if (m_module.onCommand(sender, label, args)) { - return true; - } - - // if not handled for any reason, send usage - Module.sendMessage(m_module.getName(), sender, getUsage()); - return false; } /** diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/error/ExceptionHandler.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/error/ExceptionHandler.java index 554d337..2b8b342 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/error/ExceptionHandler.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/error/ExceptionHandler.java @@ -18,7 +18,14 @@ package uk.codingbadgers.bFundamentals.error; import java.lang.Thread.UncaughtExceptionHandler; +import java.util.logging.Level; +import uk.codingbadgers.bFundamentals.bFundamentals; + +/** + * The Class ExceptionHandler, handles exceptions generated by bFundamentals + * and any sub modules. + */ public class ExceptionHandler implements UncaughtExceptionHandler { private static final ExceptionHandler instance; @@ -28,12 +35,21 @@ public class ExceptionHandler implements UncaughtExceptionHandler { Thread.setDefaultUncaughtExceptionHandler(instance); } + /** + * Handle an exception. + * + * @param e the exception caught + * @return true, if successful + */ public static boolean handleException(Throwable e) { - e.printStackTrace(); + bFundamentals.getInstance().getLogger().log(Level.WARNING, null, e); ReportExceptionRunnable run = new ReportExceptionRunnable(e); return run.run(); } + /* (non-Javadoc) + * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable) + */ @Override public void uncaughtException(Thread t, Throwable e) { handleException(e); diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/Module.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/Module.java index d3b293b..5ff0b0f 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/Module.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/Module.java @@ -26,21 +26,30 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.io.FileInputStream; import java.io.InputStreamReader; +import java.net.URL; import java.util.HashMap; +import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import net.milkbowl.vault.chat.Chat; +import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import uk.codingbadgers.bFundamentals.bFundamentals; @@ -48,52 +57,65 @@ import uk.codingbadgers.bFundamentals.commands.ModuleCommandHandler; import uk.codingbadgers.bFundamentals.config.ConfigFactory; import uk.codingbadgers.bFundamentals.config.ConfigFile; -import uk.codingbadgers.bFundamentals.module.loader.Loadable; +import uk.codingbadgers.bFundamentals.module.events.ModuleDisableEvent; +import uk.codingbadgers.bFundamentals.module.events.ModuleEnableEvent; +import uk.codingbadgers.bFundamentals.module.loader.ClassFinder; +import uk.codingbadgers.bFundamentals.module.loader.ModuleClassLoader; import uk.codingbadgers.bFundamentals.update.UpdateThread; import uk.codingbadgers.bFundamentals.update.Updater; import uk.thecodingbadgers.bDatabaseManager.Database.BukkitDatabase; /** * The base Module class any module should extend this, it also provides helper - * methods for the module. + * methods for the module, modules should be annotated with {@link ModuleInfo} + * to save the information of the module. */ -public abstract class Module extends Loadable implements Listener { +public abstract class Module implements Listener { - protected static BukkitDatabase m_database = null; + protected final BukkitDatabase m_database; protected final bFundamentals m_plugin; - protected File m_configFile = null; + protected File m_configFile; protected FileConfiguration m_config; - private static Permission m_permissions = null; + private boolean m_debug = false; private boolean loadedLanguageFile; private boolean m_enabled; + private File m_file; + private JarFile m_jar; + private File m_dataFolder; + private ModuleLogger m_log; + private UpdateThread m_updater; + private ModuleDescription m_description; private List> m_configFiles; private List m_listeners = new ArrayList(); - private ModuleLogger m_log; private Map m_languageMap = new HashMap(); - private UpdateThread m_updater; + private ModuleClassLoader m_loader; /** * Instantiates a new module with default settings. */ public Module() { - super(); m_plugin = bFundamentals.getInstance(); m_database = bFundamentals.getBukkitDatabase(); m_debug = bFundamentals.getConfigurationManager().isDebugEnabled(); - m_permissions = bFundamentals.getPermissions(); } - public void init() { + /** + * Initialise this module + */ + public final void init() { m_log = new ModuleLogger(this); } - protected void setUpdater(Updater updater) { + protected final void setUpdater(Updater updater) { m_updater = new UpdateThread(updater); log(Level.INFO, "Set new updater to " + m_updater.getUpdater().getUpdater()); } - public void update() { + /** + * If enabled, check if this module needs a update + */ + public final void update() { if (m_updater == null) { log(Level.INFO, "Updater is null, cannot check for updates"); return; @@ -202,6 +224,31 @@ protected void loadLanguageFile() { } + /** + * Gets the language value for the current loaded language, case + * insensitive, all keys are forced to be in lower case. + * + * @param key + * the language key + * @return the language value, if available, the key with hyphens removed + * and in lower case otherwise + */ + public String getLanguageValue(String key) { + Validate.notNull(key, "Language key cannot be null"); + + if (!loadedLanguageFile) { + log(Level.SEVERE, "Cannot get language value before loading language file"); + } + + String value = m_languageMap.get(key.toLowerCase()); + + if (value == null) { + value = key.toLowerCase().replace("-", " "); + } + + return value; + } + /** * Log a message console via this modules logger. * @@ -230,6 +277,10 @@ public Logger getLogger() { * the bukkit event listener */ public final void register(Listener listener) { + if (m_listeners.contains(listener)) { + return; + } + m_plugin.getServer().getPluginManager().registerEvents(listener, m_plugin); m_listeners.add(listener); } @@ -239,23 +290,41 @@ public final void register(Listener listener) { * * @return the vault permissions instance */ - public Permission getPermissions() { - return m_permissions; + public final Permission getPermissions() { + return bFundamentals.getPermissions(); + } + + /** + * Gets the vault chat instance. + * + * @return the vault chat instance + */ + public final Chat getChat() { + return bFundamentals.getChat(); } + /** + * Gets the vault economy instance. + * + * @return the vault economy instance + */ + public final Economy getEconomy() { + return bFundamentals.getEconomy(); + } + /** * The enable method for this module, called on enabling the module via * {@link #setEnabled(boolean)} this is used to register commands, events * and any other things that should be registered on enabling the module. */ - public abstract void onEnable(); + public void onEnable() {} /** * The disable method for this module, called on disabling the module via * {@link #setEnabled(boolean)} this is used to clean up after the module when * it is disabled. */ - public abstract void onDisable(); + public void onDisable() {} /** * The load method for this module, called on loading the module via the @@ -272,21 +341,46 @@ public void onLoad() {} * * @param enabled if you want to enable or disable the module */ - public void setEnabled(boolean enabled) { + public final void setEnabled(boolean enabled) { if (enabled) { if (m_enabled) { return; } - + + ModuleEnableEvent event = new ModuleEnableEvent(bFundamentals.getInstance(), this); + Bukkit.getServer().getPluginManager().callEvent(event); + onEnable(); m_enabled = true; + + try { + Set> listeners = ClassFinder.findListeners(m_loader, new URL[] {m_file.toURI().toURL()}); + debugConsole("Loading " + listeners.size() + " listeners"); + + for (Class clazz : listeners) { + try { + debugConsole("Loading Listener (" + clazz.getName() + ")"); + register(clazz.newInstance()); + } catch (Exception ex) { + log(Level.WARNING, clazz.getName() + " does not have atleast one public no argument constructor."); + } + } + } catch (Exception ex) { + } + } else { if (!m_enabled) { return; } - + + ModuleDisableEvent event = new ModuleDisableEvent(bFundamentals.getInstance(), this); + Bukkit.getServer().getPluginManager().callEvent(event); + onDisable(); ModuleCommandHandler.deregisterCommand(this); + for (Listener listener : getListeners()) { + HandlerList.unregisterAll(listener); + } m_enabled = false; } } @@ -296,7 +390,7 @@ public void setEnabled(boolean enabled) { * * @return if the module is enabled */ - public boolean isEnabled() { + public final boolean isEnabled() { return m_enabled; } @@ -318,45 +412,6 @@ public boolean onCommand(CommandSender sender, String label, String[] args) { return false; } - /** - * Gets the version of this module loaded from the path.yml file. - * - * @return the module version - */ - public String getVersion() { - return getDesciption().getVersion(); - } - - /** - * Checks if a player has a specific permission. - * - * @param player - * the player to check - * @param node - * the permission node - * @return true, if the player has the permission - */ - public static boolean hasPermission(final Player player, final String node) { - if (m_permissions.has(player, node)) { - return true; - } - return false; - } - - /** - * Send message to a player formated in the default style. - * - * @param name - * the name of the module - * @param player - * the player to send to - * @param message - * the message - */ - public static void sendMessage(String name, CommandSender player, String message) { - player.sendMessage(ChatColor.DARK_PURPLE + "[" + name + "] " + ChatColor.RESET + message); - } - /** * Register a command to this module. * @@ -377,38 +432,13 @@ public List getCommands() { return ModuleCommandHandler.getCommands(this); } - /** - * Gets the language value for the current loaded language, case - * insensitive, all keys are forced to be in lower case. - * - * @param key - * the language key - * @return the language value, if available, the key with hyphens removed - * and in lower case otherwise - */ - public String getLanguageValue(String key) { - Validate.notNull(key, "Language key cannot be null"); - - if (!loadedLanguageFile) { - log(Level.SEVERE, "Cannot get language value before loading language file"); - } - - String value = m_languageMap.get(key.toLowerCase()); - - if (value == null) { - value = key.toLowerCase().replace("-", " "); - } - - return value; - } - /** * Get all the listeners registered to this module, for cleaning up on * disable * * @return a list of all listeners */ - public List getListeners() { + public final List getListeners() { return m_listeners; } @@ -417,7 +447,7 @@ public List getListeners() { * * @return if debug is enabled */ - public boolean isDebug() { + public final boolean isDebug() { return m_debug; } @@ -427,7 +457,7 @@ public boolean isDebug() { * @param debug * whether debug is on or not */ - public void setDebug(boolean debug) { + public final void setDebug(boolean debug) { m_debug = debug; } @@ -437,7 +467,7 @@ public void setDebug(boolean debug) { * @param message * the message to output */ - public void debugConsole(String message) { + public final void debugConsole(String message) { if (!m_debug) return; @@ -450,10 +480,9 @@ public void debugConsole(String message) { * file should be {@code static} and have a {@link Element} * annotation associated with it. * - * @param clazz - * the config class + * @param clazz the config class */ - public void registerConfig(Class clazz) { + public final void registerConfig(Class clazz) { if (m_configFiles == null) { m_configFiles = new ArrayList>(); } @@ -467,4 +496,238 @@ public void registerConfig(Class clazz) { } m_configFiles.add(clazz); } + + /* Start Loading specific methods */ + + /** + * Set the datafolder. + * + * @param dataFolder the data folder + */ + public final void setDatafolder(File dataFolder) { + if (m_dataFolder != null) { + throw new IllegalStateException("Data folder already set"); + } + dataFolder.mkdirs(); + this.m_dataFolder = dataFolder; + } + + /** + * Set the file for this loadable. + * + * @param file the file + */ + public final void setFile(File file) { + if (m_file != null) { + throw new IllegalStateException("File already set"); + } + this.m_file = file; + } + + /** + * Set the jar file. + * + * @param jar the jar + */ + public final void setJarFile(JarFile jar) { + if (m_jar != null) { + throw new IllegalStateException("Jar file already set"); + } + this.m_jar = jar; + } + + /** + * Set the {@link ModuleDescription} for this module. + * + * @param ldf the loadable description file + */ + public final void setDesciption(ModuleDescription ldf) { + if (m_description != null) { + throw new IllegalStateException("Description already set"); + } + this.m_description = ldf; + } + + /** + * Sets the {@link ModuleClassLoader} for this module + * + * @param loader the current class loader for this module + */ + public final void setClassLoader(ModuleClassLoader loader) { + if (m_loader != null) { + throw new IllegalStateException("Class loader already set"); + } + this.m_loader = loader; + } + + /* End Loading specific methods */ + + /** + * Gets the config. + * + * @return The config + */ + public final FileConfiguration getConfig() { + if (m_config == null) { + reloadConfig(); + } + + return m_config; + } + + /** + * Gets the data folder of this. + * + * @return The directory of this + */ + public final File getDataFolder() { + return m_dataFolder; + } + + /** + * Gets the file of the loadable. + * + * @return the jar file as a {@link File} + */ + public final File getFile() { + return m_file; + } + + /** + * Gets the name of the Loadable. + * + * @return The name + */ + public final ModuleClassLoader getClassLoader() { + return m_loader; + } + + /** + * Gets the name of the Loadable. + * + * @return The name + */ + public final String getName() { + return getDescription().getName(); + } + + /** + * Gets the version of this module loaded from the path.yml file. + * + * @return the module version + */ + public final String getVersion() { + return getDescription().getVersion(); + } + + /** + * Gets an embedded resource in this plugin. + * + * @param name File name of the resource + * @return InputStream of the file if found, otherwise null + */ + public final InputStream getResource(String name) { + ZipEntry entry = m_jar.getEntry(name); + + if (entry == null) + return null; + + try { + return m_jar.getInputStream(entry); + } catch (IOException e) { + return null; + } + } + + /** + * Reloads the config. + */ + public final void reloadConfig() { + if (m_configFile == null) { + m_configFile = new File(getDataFolder(), "config.yml"); + } + + m_config = YamlConfiguration.loadConfiguration(m_configFile); + + InputStream defConfigStream = getResource("config.yml"); + + if (defConfigStream != null) { + YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); + m_config.setDefaults(defConfig); + } + } + + /** + * Saves the config. + * + * @return if the config was saved successfully + */ + public final boolean saveConfig() { + if (m_config == null || m_configFile == null) { + return false; + } + + try { + m_config.save(m_configFile); + } catch (IOException e) { + return false; + } + return true; + } + + /** + * Gets the description. + * + * @return the description + */ + public final ModuleDescription getDescription() { + return this.m_description; + } + + /** + * Checks if a player has a specific permission. + * + * @param player + * the player to check + * @param node + * the permission node + * @return true, if the player has the permission + */ + public static boolean hasPermission(final Player player, final String node) { + if (bFundamentals.getPermissions().has(player, node)) { + return true; + } + return false; + } + + /** + * Checks if a player has a specific permission. + * + * @param player + * the player to check + * @param node + * the permission node + * @return true, if the player has the permission + */ + public static boolean hasPermission(final CommandSender player, final String node) { + if (bFundamentals.getPermissions().has(player, node)) { + return true; + } + return false; + } + + /** + * Send message to a player formated in the default style. + * + * @param name + * the name of the module + * @param player + * the player to send to + * @param message + * the message + */ + public static void sendMessage(String name, CommandSender player, String message) { + player.sendMessage(ChatColor.DARK_PURPLE + "[" + name + "] " + ChatColor.RESET + message); + } + } \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleDescription.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleDescription.java new file mode 100644 index 0000000..5ba1022 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleDescription.java @@ -0,0 +1,138 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.bukkit.configuration.file.YamlConfiguration; + +import uk.codingbadgers.bFundamentals.module.annotation.ModuleInfo; +import uk.codingbadgers.bFundamentals.utils.CollectionUtils; + +/** + * The Class LoadableDescriptionFile, represents the data stored in the about a + * module, either by a path.yml file of a {@link Module} or a {@link ModuleInfo} + * annotation. + * + * @author James Fitzpatrick + */ +public class ModuleDescription { + + private final String name; + private final String version; + private final String description; + private final String mainClass; + private final List authors; + private final Collection dependencies; + + /** + * Instantiates a new module description from the data in a path.yml file. + * + * @param istream + * the input stream that this file is loaded from + */ + public ModuleDescription(InputStream istream) { + YamlConfiguration ldf = YamlConfiguration.loadConfiguration(istream); + + name = ldf.getString("name", "Unknown Module"); + version = ldf.getString("version", "0.0"); + description = ldf.getString("description", ""); + mainClass = ldf.getString("main-class"); + authors = CollectionUtils.toImmutableList(ldf.getStringList("authors")); + dependencies = Collections.unmodifiableCollection(ldf.getStringList("dependencies")); + } + + /** + * Instantiates a new module description from the data in a + * {@link ModuleInfo} annotation. + * + * @param info + * the {@link ModuleInfo} annotation + * @param mainclass + * the mainclass loaded + */ + public ModuleDescription(ModuleInfo info, String mainclass) { + this.name = info.value(); + this.version = info.version(); + this.mainClass = mainclass; + this.description = info.description(); + this.authors = CollectionUtils.toImmutableList(Arrays.asList(info.authors())); + this.dependencies = Collections.unmodifiableCollection(new ArrayList()); + } + + /** + * Gets the name of this module. + * + * @return the name of this module + */ + public String getName() { + return name; + } + + /** + * Gets the version of this module. + * + * @return the version of this module + */ + public String getVersion() { + return version; + } + + /** + * Gets the description for this module. + * + * @return the description of this module + */ + public String getDescription() { + return description; + } + + /** + * Gets the main class of this module. + * + * @return the fully qualified name of the main class of this module + * @deprecated Main classes should not have to be defined anymore + */ + public String getMainClass() { + return mainClass; + } + + /** + * Gets the authors of this module. + * + * @return a immutable list of the authors of this module + */ + public List getAuthors() { + return authors; + } + + /** + * Gets the module dependencies of this loadable, this module will load + * after all of the dependencies have module. + * + * @return a unmodifiable collection of the dependencies + */ + public Collection getDependencies() { + return dependencies; + } +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoader.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoader.java deleted file mode 100644 index 58f2526..0000000 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoader.java +++ /dev/null @@ -1,217 +0,0 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.logging.Level; - -import org.bukkit.Bukkit; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; - -import uk.codingbadgers.bFundamentals.bFundamentals; -import uk.codingbadgers.bFundamentals.error.ExceptionHandler; -import uk.codingbadgers.bFundamentals.module.loader.Loader; - -/** - * The ModuleLoader. - */ -public class ModuleLoader { - - /** The List of modules. */ - private final List m_modules; - private Loader m_loader; - - /** - * Instantiates a new module loader. - */ - public ModuleLoader() { - m_modules = new LinkedList(); - if (getModuleDir().mkdir()) - bFundamentals.log(Level.INFO, "Creating Module Directory..."); - } - - /** - * Gets the directory of the modules. - * - * @return the module dir - */ - public File getModuleDir() { - return new File(bFundamentals.getInstance().getDataFolder(), "modules"); - } - - /** - * Loads all the modules in the base modules directory. - */ - public void load() { - m_loader = new Loader(bFundamentals.getInstance(), getModuleDir()); - m_modules.addAll(m_loader.sort(m_loader.load())); - - for (Module module : m_modules) { - try { - module.onLoad(); - Bukkit.getHelpMap().addTopic(new ModuleHelpTopic(module)); - module.log(Level.INFO, module.getName() + " v:" + module.getVersion() + " has been loaded successfuly"); - } catch (Throwable ex) { - ExceptionHandler.handleException(ex); - } - } - - bFundamentals.log(Level.INFO, "Loaded " + m_modules.size() + " modules."); - } - - /** - * Loads a module with a given name - * - * @param fileName the files name - */ - public void load(String fileName) { - File module = new File(getModuleDir() + File.separator + fileName + ".jar"); - load(module); - } - - /** - * Loads a module with a jar file - * - * @param file the jar file for this module - */ - public void load(File file) { - if (m_loader == null) - m_loader = new Loader(bFundamentals.getInstance(), getModuleDir()); - - if (getModule(file) != null) - throw new IllegalArgumentException("Module " + file.getName() + " is already loaded"); - - m_modules.clear(); - m_modules.addAll(m_loader.sort(m_loader.load(file))); - - Module module = getModule(file); - module.onLoad(); - module.log(Level.INFO, module.getName() + " v:" + module.getVersion() + " has been loaded successfuly"); - } - - /** - * Unloads the modules. - */ - public void unload() { - disable(); - m_modules.clear(); - } - - /** - * Unload a specific module. - * - * @param module the module - */ - public void unload(Module module) { - try { - module.setEnabled(false); - for (Listener listener : module.getListeners()) { - HandlerList.unregisterAll(listener); - } - m_modules.remove(module); - } catch (Throwable ex) { - ExceptionHandler.handleException(ex); - } - } - - /** - * Run on enable in all modules. - */ - public void enable() { - for (Module module : m_modules) { - try { - module.setEnabled(true); - } catch (Throwable ex) { - ExceptionHandler.handleException(ex); - } - } - } - - /** - * run on disable in all modules. - */ - public void disable() { - List modules = new ArrayList(m_modules); - for (Module module : modules) { - try { - unload(module); - } catch (Throwable ex) { - ExceptionHandler.handleException(ex); - } - } - } - - /** - * Gets the modules. - * - * @return the modules - */ - public List getModules() { - return m_modules; - } - - - /** - * Update all the loaded modules if an updater is set - */ - public void update() { - for (Module module : m_modules) { - module.update(); - } - } - - /** - * Gets the module from its name. - * - * @param string the string - * @return the module - */ - public Module getModule(String string) { - Iterator itr = m_modules.iterator(); - while(itr.hasNext()) { - Module module = itr.next(); - if (module.getName().equalsIgnoreCase(string)) { - return module; - } - } - return null; - } - - /** - * Gets the module from its file. - * - * @param file the file - * @return the module - */ - public Module getModule(File file) { - Iterator itr = m_modules.iterator(); - while(itr.hasNext()) { - Module module = itr.next(); - if (module.getFile().getPath().equalsIgnoreCase(file.getPath())) { - return module; - } - } - return null; - } - -} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/annotation/ModuleInfo.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/annotation/ModuleInfo.java new file mode 100644 index 0000000..a971033 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/annotation/ModuleInfo.java @@ -0,0 +1,62 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The Annotation ModuleInfo, defines the module information for a class. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ModuleInfo { + + /** + * The module's name. + * + * @return the module's name + */ + String value(); + + /** + * The module's version. + * + * @return the module's version + */ + String version() default "1.0"; + + /** + * The module's authors. + * + * @return the module's authors + */ + String[] authors() default {"Unkown"}; + + /** + * The module's description. + * + * @return the module's description + */ + String description() default ""; + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleDisableEvent.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleDisableEvent.java new file mode 100644 index 0000000..c3dc664 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleDisableEvent.java @@ -0,0 +1,40 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.events; + +import org.bukkit.plugin.Plugin; + +import uk.codingbadgers.bFundamentals.module.Module; + +/** + * The ModuleDisableEvent, called when a module is disabled via + * {@link Module#setEnabled(boolean)}. + */ +public class ModuleDisableEvent extends ModuleEvent { + + /** + * Instantiates a new module disable event. + * + * @param plugin the plugin + * @param loadable the loadable + */ + public ModuleDisableEvent(Plugin plugin, Module loadable) { + super(plugin, loadable); + } + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoadEvent.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEnableEvent.java similarity index 62% rename from bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoadEvent.java rename to bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEnableEvent.java index 3241072..0d95f63 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/ModuleLoadEvent.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEnableEvent.java @@ -1,32 +1,40 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module; - -import java.util.jar.JarFile; - -import org.bukkit.plugin.Plugin; - -import uk.codingbadgers.bFundamentals.module.loader.LoadEvent; - -public class ModuleLoadEvent extends LoadEvent { - - public ModuleLoadEvent(Plugin plugin, Module loadable, JarFile jarFile) { - super(plugin, loadable, jarFile); - } - -} +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.events; + +import org.bukkit.plugin.Plugin; + +import uk.codingbadgers.bFundamentals.module.Module; + +/** + * The ModuleEnableEvent, called when a module is enabled via + * {@link Module#setEnabled(boolean)}. + */ +public class ModuleEnableEvent extends ModuleEvent { + + /** + * Instantiates a new module enable event. + * + * @param plugin the plugin + * @param loadable the loadable + */ + public ModuleEnableEvent(Plugin plugin, Module loadable) { + super(plugin, loadable); + } + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEvent.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEvent.java new file mode 100644 index 0000000..ded11e7 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleEvent.java @@ -0,0 +1,82 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.events; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.Plugin; + +import uk.codingbadgers.bFundamentals.module.Module; + +/** + * A module event, represents an event that . + */ +public abstract class ModuleEvent extends Event { + + private static final HandlerList handlers = new HandlerList(); + + /* (non-Javadoc) + * @see org.bukkit.event.Event#getHandlers() + */ + @Override + public HandlerList getHandlers() { + return handlers; + } + + /** + * Gets the handler list. + * + * @return the handler list + */ + public static HandlerList getHandlerList() { + return handlers; + } + + private final Plugin plugin; + private final Module loadable; + + /** + * Instantiates a new module event. + * + * @param plugin the plugin + * @param loadable the module involved in the event + */ + public ModuleEvent(Plugin plugin, Module loadable) { + this.plugin = plugin; + this.loadable = loadable; + } + + /** + * Gets the module involved in the event. + * + * @return the module + */ + public Module getModule() { + return loadable; + } + + /** + * Gets the plugin. + * + * @return the plugin + */ + public Plugin getPlugin() { + return plugin; + } + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleLoadEvent.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleLoadEvent.java new file mode 100644 index 0000000..ead4cde --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/events/ModuleLoadEvent.java @@ -0,0 +1,75 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.events; + +import java.util.jar.JarFile; + +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.Plugin; + +import uk.codingbadgers.bFundamentals.module.Module; + +/** + * The ModuleLoadEvent, called when a module is loaded via + * {@link ModuleLoader#loadModule(java.io.File)}. + */ +public class ModuleLoadEvent extends ModuleEvent { + + private static final HandlerList handlers = new HandlerList(); + + + /* (non-Javadoc) + * @see uk.codingbadgers.bFundamentals.module.events.ModuleEvent#getHandlers() + */ + @Override + public HandlerList getHandlers() { + return handlers; + } + + /** + * Gets the handler list. + * + * @return the handler list + */ + public static HandlerList getHandlerList() { + return handlers; + } + + private final JarFile jarFile; + + /** + * Instantiates a new module load event. + * + * @param plugin the plugin + * @param loadable the loadable + * @param jarFile the jar file + */ + public ModuleLoadEvent(Plugin plugin, Module loadable, JarFile jarFile) { + super(plugin, loadable); + this.jarFile = jarFile; + } + + /** + * Gets the jar file. + * + * @return the jar file + */ + public JarFile getJarFile() { + return jarFile; + } +} \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ClassFinder.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ClassFinder.java new file mode 100644 index 0000000..1f12b2a --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ClassFinder.java @@ -0,0 +1,60 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.loader; + +import java.net.URL; +import java.util.Set; + +import org.bukkit.event.Listener; +import org.reflections.Reflections; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; + +import uk.codingbadgers.bFundamentals.module.Module; + +/** + * The Class ClassFinder, used to find specific types of classes quickly for + * module auto loading and registration. + */ +public class ClassFinder { + + /** + * Find all the module classes in a class loader. + * + * @param loader the loader + * @param url the urls to check + * @return all classes that extend {@link Module} in that loader + */ + public static Set> findModules(ModuleClassLoader loader, URL[] url) { + Reflections reflect = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forClassLoader(loader)).addClassLoader(loader)); + return reflect.getSubTypesOf(Module.class); + } + + /** + * Find all the listener classes in a class loader. + * + * @param loader the loader + * @param url the urls to check + * @return all classes that implement {@link Listener} in that loader + */ + public static Set> findListeners(ModuleClassLoader loader, URL[] url) { + Reflections reflect = new Reflections(new ConfigurationBuilder().addUrls(url).addClassLoader(loader).addClassLoader(ClassFinder.class.getClassLoader())); + return reflect.getSubTypesOf(Listener.class); + } + +} \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/FileExtensionFilter.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/FileExtensionFilter.java index 28e577e..e3368bd 100644 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/FileExtensionFilter.java +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/FileExtensionFilter.java @@ -1,34 +1,45 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module.loader; - -import java.io.File; -import java.io.FileFilter; - -public final class FileExtensionFilter implements FileFilter { - - private final String extension; - - public FileExtensionFilter(String extension) { - this.extension = extension; - } - - public boolean accept(File file) { - return file.getName().endsWith(extension); - } +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.loader; + +import java.io.File; +import java.io.FileFilter; + +/** + * The Class FileExtensionFilter. + */ +public final class FileExtensionFilter implements FileFilter { + + private final String extension; + + /** + * Instantiates a new file extension filter. + * + * @param extension the extension to test for + */ + public FileExtensionFilter(String extension) { + this.extension = extension; + } + + /* (non-Javadoc) + * @see java.io.FileFilter#accept(java.io.File) + */ + public boolean accept(File file) { + return file.getName().endsWith(extension); + } } \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadEvent.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadEvent.java deleted file mode 100644 index d5bd35a..0000000 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadEvent.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module.loader; - -import java.util.jar.JarFile; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.plugin.Plugin; - -/* Copyright (C) 2012 Nodin Chan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * LoadEvent - Called when a Loadable has been loaded - * - * @author NodinChan - * @param the loadable type - */ -public class LoadEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); - - private final Plugin plugin; - - private final T loadable; - - private final JarFile jarFile; - - public LoadEvent(Plugin plugin, T loadable, JarFile jarFile) { - this.plugin = plugin; - this.loadable = loadable; - this.jarFile = jarFile; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - /** - * Gets the JAR file of the loaded loadable - * - * @return The JAR file - */ - public JarFile getJarFile() { - return jarFile; - } - - /** - * Gets the loaded Loadable - * - * @return The Loadable - */ - public T getLoadable() { - return loadable; - } - - /** - * Gets the plugin calling this event - * - * @return The plugin calling the event - */ - public Plugin getPlugin() { - return plugin; - } -} \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loadable.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loadable.java deleted file mode 100644 index b4b60d1..0000000 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loadable.java +++ /dev/null @@ -1,308 +0,0 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module.loader; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -/* Copyright (C) 2012 Nodin Chan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Loadable - Base for loadable classes. - * - * @author NodinChan - */ -public class Loadable implements Cloneable { - - private String name; - private File configFile; - private FileConfiguration config; - private LoadableDescriptionFile description; - private JarFile jar; - private File dataFolder; - private File file; - - /** - * Instantiates a new loadable. - * - * @param name the name - * @deprecated use a {@link LoadableDescriptionFile} instead - */ - public Loadable(String name) { - this.name = name; - } - - /** - * Instantiates a new loadable. - */ - public Loadable() { - } - - /* (non-Javadoc) - * @see java.lang.Object#clone() - */ - @Override - public Loadable clone() { - Loadable loadable = new Loadable(name); - loadable.config = YamlConfiguration.loadConfiguration(configFile); - loadable.configFile = configFile; - loadable.dataFolder = dataFolder; - loadable.file = file; - loadable.jar = jar; - loadable.description = description; - return loadable; - } - - /** - * Set the datafolder. - * - * @param dataFolder the data folder - * @return the file - */ - public File setDatafolder(File dataFolder) { - dataFolder.mkdirs(); - return this.dataFolder = dataFolder; - } - - /** - * Set the file for this loadable. - * - * @param file the file - * @return the file - */ - public File setFile(File file) { - return this.file = file; - } - - /** - * Set the jar file. - * - * @param jar the jar - * @return the jar file - */ - public JarFile setJarFile(JarFile jar) { - return this.jar = jar; - } - - /** - * Set the {@link LoadableDescriptionFile} for this module. - * - * @param ldf the loadable description file - * @return the loadable description file - */ - public LoadableDescriptionFile setDesciption(LoadableDescriptionFile ldf) { - this.description = ldf; - this.name = description.getName(); - return description; - } - - /** - * Initialises the loadable, called on loading the module. - */ - public void init() {} - - /** - * Gets the config. - * - * @return The config - */ - public FileConfiguration getConfig() { - if (config == null) - reloadConfig(); - - return config; - } - - /** - * Gets the data folder of this. - * - * @return The directory of this - */ - public File getDataFolder() { - return dataFolder; - } - - /** - * Gets the file of the loadable. - * - * @return the jar file as a {@link File} - */ - public File getFile() { - return file; - } - - /** - * Gets the name of the Loadable. - * - * @return The name - */ - public final String getName() { - return getDesciption().getName(); - } - - /** - * Gets an embedded resource in this plugin. - * - * @param name File name of the resource - * @return InputStream of the file if found, otherwise null - */ - public InputStream getResource(String name) { - ZipEntry entry = jar.getEntry(name); - - if (entry == null) - return null; - - try { - return jar.getInputStream(entry); - } catch (IOException e) { - return null; - } - } - - /** - * Reloads the config. - */ - public void reloadConfig() { - if (configFile == null) - configFile = new File(getDataFolder(), "config.yml"); - - config = YamlConfiguration.loadConfiguration(configFile); - - InputStream defConfigStream = getResource("config.yml"); - - if (defConfigStream != null) { - YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); - config.setDefaults(defConfig); - } - } - - /** - * Saves the config. - */ - public void saveConfig() { - if (config == null || configFile == null) - return; - - try { - config.save(configFile); - } catch (IOException e) { - } - } - - /** - * Called when the Loadable is unloaded. - */ - public void unload() { - } - - /** - * Gets the desciption. - * - * @return the desciption - */ - public LoadableDescriptionFile getDesciption() { - return this.description; - } - - /** - * The Class LoadResult. - */ - public static final class LoadResult { - - /** The result. */ - private final Result result; - - /** The reason. */ - private final String reason; - - /** - * Instantiates a new load result. - */ - public LoadResult() { - this(Result.SUCCESS, ""); - } - - /** - * Instantiates a new load result. - * - * @param failReason the fail reason - */ - public LoadResult(String failReason) { - this(Result.FAILURE, failReason); - } - - /** - * Instantiates a new load result. - * - * @param result the result - * @param reason the reason - */ - public LoadResult(Result result, String reason) { - this.result = result; - this.reason = reason; - } - - /** - * Gets the reason. - * - * @return the reason - */ - public String getReason() { - return reason; - } - - /** - * Gets the result. - * - * @return the result - */ - public Result getResult() { - return result; - } - - /** - * The Result for loading. - */ - public enum Result { - - /** If the loadable didn't load successfully. */ - FAILURE, - /** If the loadable loaded successfully. */ - SUCCESS - } - } -} \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadableDescriptionFile.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadableDescriptionFile.java deleted file mode 100644 index debfb46..0000000 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/LoadableDescriptionFile.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module.loader; - -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.bukkit.configuration.file.YamlConfiguration; - -import com.google.common.collect.ImmutableList; - -/** - * The Class LoadableDescriptionFile, represents the data stored in the - * path.yml file of a {@link Loadable}. - * - * @author James Fitzpatrick - */ -public class LoadableDescriptionFile { - - private final String name; - private final String version; - private final String description; - private final String mainClass; - private final List authors; - private final Collection dependencies; - - /** - * Instantiates a new loadable description file. - * - * @param istream the input stream that this file is loaded from - */ - @SuppressWarnings("deprecation") - public LoadableDescriptionFile(InputStream istream) { - YamlConfiguration ldf = YamlConfiguration.loadConfiguration(istream); - - name = ldf.getString("name", "Unknown Module"); - version = ldf.getString("version", "0.0"); - description = ldf.getString("description", ""); - mainClass = ldf.getString("main-class"); - authors = ImmutableList.of(ldf.getStringList("authors").toArray(new String[0])); - dependencies = Collections.unmodifiableCollection(ldf.getStringList("dependencies")); - } - - /** - * Gets the name of this loadable. - * - * @return the name of this loadable - */ - public String getName() { - return name; - } - - /** - * Gets the version of this loadable. - * - * @return the version of this loadable - */ - public String getVersion() { - return version; - } - - /** - * Gets the description for this loadable. - * - * @return the description of this loadable - */ - public String getDescription() { - return description; - } - - /** - * Gets the main class of this loadable. - * - * @return the fully qualified name of the main class of this loadable - */ - public String getMainClass() { - return mainClass; - } - - /** - * Gets the authors of this loadable. - * - * @return a immutable list of the authors of this loadable - */ - public List getAuthors() { - return authors; - } - - /** - * Gets the module dependencies of this loadable, this module will load after - * all of the dependencies have loaded. - * - * @return a unmodifiable collection of the dependencies - */ - public Collection getDependencies() { - return dependencies; - } -} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loader.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loader.java deleted file mode 100644 index d5d2652..0000000 --- a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/Loader.java +++ /dev/null @@ -1,258 +0,0 @@ -/** - * bFundamentals 1.2-SNAPSHOT - * Copyright (C) 2013 CodingBadgers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package uk.codingbadgers.bFundamentals.module.loader; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.PluginClassLoader; - -import uk.codingbadgers.bFundamentals.error.ExceptionHandler; -import uk.codingbadgers.bFundamentals.module.Module; -import uk.codingbadgers.bFundamentals.module.ModuleLoadEvent; - -/* Copyright (C) 2012 Nodin Chan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Loader - Loader base for loading Loadables. - * - * @author NodinChan - */ -public class Loader { - - private final Plugin plugin; - private final List files; - private final List loadables; - private ClassLoader loader; - - /** - * Instantiates a new loader. - * - * @param plugin - * the plugin - * @param dir - * the directory to load modules from - */ - public Loader(Plugin plugin, File dir) { - this.plugin = plugin; - this.files = Arrays.asList(dir.listFiles(new FileExtensionFilter(".jar"))); - this.loadables = new ArrayList(); - - generateClassLoader(); - } - - private void generateClassLoader() { - this.loadables.clear(); - - List urls = new ArrayList(); - - for (File file : files) { - try { - urls.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - } - - this.loader = PluginClassLoader.newInstance(urls.toArray(new URL[0]), plugin.getClass().getClassLoader()); - } - - /** - * Gets the Logger. - * - * @return The Logger - */ - public Logger getLogger() { - return plugin.getLogger(); - } - - /** - * Loads the all loadables in the directory specified. - * - * @return List of loaded loadables - */ - public final List load() { - for (File file : files) { - load(file); - } - return loadables; - } - - /** - * Load file into the loader. - * - * @param file - * the file - * @return the list - * @TODO support module dependencies - */ - public List load(File file) { - try { - JarFile jarFile = new JarFile(file); - String mainClass = null; - LoadableDescriptionFile ldf = null; - - if (jarFile.getEntry("path.yml") != null) { - JarEntry element = jarFile.getJarEntry("path.yml"); - ldf = new LoadableDescriptionFile(jarFile.getInputStream(element)); - mainClass = ldf.getMainClass(); - } - - if (mainClass != null) { - Class clazz = Class.forName(mainClass, true, loader); - - if (clazz != null) { - Class loadableClass = clazz.asSubclass(Module.class); - Constructor constructor = loadableClass.getConstructor(); - Module loadable = constructor.newInstance(); - - if (loadables.contains(loadable)) { - getLogger().log(Level.WARNING, "The loadable " + file.getName() + " is already loaded, make sure to disable the module first"); - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load"); - jarFile.close(); - return loadables; - } - - loadable.setFile(file); - loadable.setDesciption(ldf); - loadable.setJarFile(jarFile); - loadable.setDatafolder(new File(file.getParentFile(), loadable.getName())); - loadable.init(); - - loadables.add(loadable); - - ModuleLoadEvent event = new ModuleLoadEvent(plugin, loadable, jarFile); - plugin.getServer().getPluginManager().callEvent(event); - - } else { - jarFile.close(); - throw new ClassNotFoundException("Class " + mainClass + " could not be found."); - } - - } else { - jarFile.close(); - throw new ClassNotFoundException("Could not find main class in the path.yml."); - } - - } catch (ClassCastException e) { - e.printStackTrace(); - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " is in the wrong directory."); - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load."); - } catch (ClassNotFoundException e) { - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load."); - getLogger().log(Level.WARNING, "Invalid path.yml."); - getLogger().log(Level.WARNING, e.getMessage()); - } catch (NoClassDefFoundError e) { - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load."); - getLogger().log(Level.WARNING, "The class " + e.getMessage() + " cannot be found."); - getLogger().log(Level.WARNING, "Is this module missing a required dependency?"); - } catch (Throwable e) { - ExceptionHandler.handleException(e); - getLogger().log(Level.WARNING, "Unknown cause."); - getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load."); - } - return loadables; - } - - /** - * Reloads the Loader. - * - * @return the list of modules loaded - */ - public List reload() { - unload(); - generateClassLoader(); - return load(); - } - - /** - * Sorts a list of Loadables by name in alphabetical order. - * - * @param loadables - * The list of Loadables to sort - * @return The sorted list of Loadables - */ - public List sort(List loadables) { - List sortedLoadables = new ArrayList(); - List names = new ArrayList(); - - for (Loadable t : loadables) { - names.add(t.getName()); - } - - Collections.sort(names); - - for (String name : names) { - for (Module t : loadables) { - if (t.getName().equals(name)) { - sortedLoadables.add(t); - } - } - } - - return sortedLoadables; - } - - /** - * Sorts a map of Loadables by name in alphabetical order. - * - * @param loadables - * The map of Loadables to sort - * @return The sorted map of Loadables - */ - public Map sort(Map loadables) { - Map sortedLoadables = new HashMap(); - List names = new ArrayList(loadables.keySet()); - - Collections.sort(names); - - for (String name : names) { - sortedLoadables.put(name, loadables.get(name)); - } - - return sortedLoadables; - } - - /** - * Unloads the Loader. - */ - public void unload() { - loadables.clear(); - } -} \ No newline at end of file diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleClassLoader.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleClassLoader.java new file mode 100644 index 0000000..4261c65 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleClassLoader.java @@ -0,0 +1,108 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.loader; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.Validate; + + +/** + * The ModuleClassLoader, used to load classes for modules. + */ +public class ModuleClassLoader extends URLClassLoader { + private final ModuleLoader loader; + private final Map> classes = new HashMap>(); + + /** + * Instantiates a new module class loader. + * + * @param moduleLoader the module loader + * @param urls the urls of the module + * @param parent the parent + */ + public ModuleClassLoader(final ModuleLoader moduleLoader, final URL[] urls, final ClassLoader parent) { + super(urls, parent); + Validate.notNull(moduleLoader, "Loader cannot be null"); + this.loader = moduleLoader; + } + + @Override + public void addURL(URL url) { + super.addURL(url); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + return findClass(name, true); + } + + /** + * Find a class. + * + * @param name the name of the class in the format for {@link Class#forName(String)} + * @param checkGlobal whether or not to check the global cache + * @return the class loaded + * @throws ClassNotFoundException the class not found exception + */ + public Class findClass(String name, boolean checkGlobal) throws ClassNotFoundException { + if (name.startsWith("org.bukkit.") || name.startsWith("net.minecraft.")) { + throw new ClassNotFoundException(name); + } + + System.out.println("Finding class " + name); + + Class result = classes.get(name); + + if (result == null) { + if (checkGlobal) { + result = loader.getClassByName(name); + } + + if (result == null) { + result = super.findClass(name); + + if (result != null) { + loader.setClass(name, result); + } + } + + classes.put(name, result); + } + + if (result == null) { + throw new ClassNotFoundException(name); + } + + return result; + } + + /** + * Gets the cache of all the classes loaded by this loader. + * + * @return the cache + */ + public Set getClasses() { + return classes.keySet(); + } + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleLoader.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleLoader.java new file mode 100644 index 0000000..d5fecec --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/module/loader/ModuleLoader.java @@ -0,0 +1,419 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.module.loader; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.ConfigurationSerialization; + +import uk.codingbadgers.bFundamentals.bFundamentals; +import uk.codingbadgers.bFundamentals.error.ExceptionHandler; +import uk.codingbadgers.bFundamentals.module.Module; +import uk.codingbadgers.bFundamentals.module.ModuleDescription; +import uk.codingbadgers.bFundamentals.module.ModuleHelpTopic; +import uk.codingbadgers.bFundamentals.module.annotation.ModuleInfo; +import uk.codingbadgers.bFundamentals.module.events.ModuleLoadEvent; + +/** + * The ModuleLoader, used to load bFundamentals {@link Module}'s at runtime, + * it will automatically find any classes that extend {@link Module} in jars + * in the module directory and load them in. + */ +public class ModuleLoader { + + private Map loaders = new HashMap(); + private Map> classes = new HashMap>(); + private List m_modules; + + /** + * Instantiates a new module loader. + */ + public ModuleLoader() { + m_modules = new LinkedList(); + if (bFundamentals.getConfigurationManager().getModuleDirectory().mkdir()) { + bFundamentals.log(Level.INFO, "Creating Module Directory..."); + } + } + + /** + * Gets the directory of the modules. + * + * @return the module dir + * @deprecated {@link uk.codingbadgers.bFundamentals.ConfigManager#getModuleDirectory()} + */ + public File getModuleDir() { + return bFundamentals.getConfigurationManager().getModuleDirectory(); + } + + /** + * Loads all the modules in the base modules directory. + */ + public void load() { + + List files = Arrays.asList(bFundamentals.getConfigurationManager().getModuleDirectory().listFiles(new FileExtensionFilter(".jar"))); + for (File file : files) { + loadModule(file); + } + + sort(); + + for (Module module : m_modules) { + try { + module.onLoad(); + module.log(Level.INFO, module.getName() + " v:" + module.getVersion() + " has been loaded successfuly"); + } catch (Exception ex) { + ExceptionHandler.handleException(ex); + } + } + + bFundamentals.log(Level.INFO, "Loaded " + m_modules.size() + " modules."); + } + + /** + * Load a module into the server. + * + * @param file the module's jar file + * @return the module instance + */ + public Module loadModule(File file) { + Module result = null; + + try { + URL[] urls = new URL[] { file.toURI().toURL() }; + + ModuleClassLoader loader = new ModuleClassLoader(this, urls, getClass().getClassLoader()); + + JarFile jarFile = new JarFile(file); + ModuleDescription moduledescription = null; + Set> modules = new HashSet>(); + + modules.addAll(ClassFinder.findModules(loader, urls)); + + // Old system descriptive system, left for backwards compatibility + if (jarFile.getEntry("path.yml") != null) { + JarEntry element = jarFile.getJarEntry("path.yml"); + moduledescription = new ModuleDescription(jarFile.getInputStream(element)); + } + + if (modules.size() == 0) { + jarFile.close(); + throw new ClassNotFoundException("Could not find a main class in jar " + file.getName() + "."); + } + + if (bFundamentals.getConfigurationManager().isDebugEnabled()) { + getLogger().log(Level.INFO, "Loading " + modules.size() + " modules for jar " + file.getName()); + } + + for (Class clazz : modules) { + + if (bFundamentals.getConfigurationManager().isDebugEnabled()) { + getLogger().log(Level.INFO, "Loading clazz " + clazz.getName()); + } + + ModuleDescription description = moduledescription; + + if (clazz.isAnnotationPresent(ModuleInfo.class)) { + ModuleInfo info = clazz.getAnnotation(ModuleInfo.class); + description = new ModuleDescription(info, clazz.getName()); + } + + if (description == null) { + throw new IOException("Description not found for module " + file.getName() + "."); + } + + result = clazz.newInstance(); + + if (m_modules.contains(result)) { + getLogger().log(Level.WARNING, "The loadable " + file.getName() + " is already loaded, make sure to disable the module first"); + getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load"); + jarFile.close(); + return null; + } + + result.setFile(file); + result.setDesciption(description); + result.setJarFile(jarFile); + result.setDatafolder(new File(bFundamentals.getConfigurationManager().getModuleDirectory(), result.getName())); + result.setClassLoader(loader); + result.init(); + + ModuleLoadEvent event = new ModuleLoadEvent(bFundamentals.getInstance(), result, jarFile); + Bukkit.getServer().getPluginManager().callEvent(event); + + m_modules.add(result); + loaders.put(result.getName(), loader); + } + + } catch (Throwable e) { + if (e instanceof Error && !(e instanceof NoClassDefFoundError)) { + getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load because of a serious error"); + getLogger().log(Level.WARNING, e.getClass().getName()); + } else { + getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " failed to load."); + } + + if (e instanceof ClassCastException) { + getLogger().log(Level.WARNING, "The JAR file " + file.getName() + " is in the wrong directory."); + } else if (e instanceof ClassNotFoundException || e instanceof NoClassDefFoundError) { + getLogger().log(Level.WARNING, "Could not find class " + e.getMessage()); + getLogger().log(Level.WARNING, "Are you missing a required dependecy?"); + } else if (e instanceof RuntimeException) { + getLogger().log(Level.WARNING, "Unknown cause", e); + } else { + getLogger().log(Level.WARNING, "Unknown cause."); + getLogger().log(Level.WARNING, e.getMessage()); + ExceptionHandler.handleException(e); + } + } + + return result; + } + + private Logger getLogger() { + return bFundamentals.getInstance().getLogger(); + } + + /** + * Loads a module with a given name. + * + * @param fileName the files name + */ + public void load(String fileName) { + File module = new File(bFundamentals.getConfigurationManager().getModuleDirectory() + File.separator + fileName + ".jar"); + load(module); + } + + /** + * Loads a module with a jar file. + * + * @param file the jar file for this module + */ + public void load(File file) { + if (getModule(file) != null) { + throw new IllegalArgumentException("Module " + file.getName() + " is already loaded"); + } + + Module result = loadModule(file); + + if (result == null) { + return; + } + + m_modules.add(result); + + result.onLoad(); + result.log(Level.INFO, result.getName() + " v:" + result.getVersion() + " has been loaded successfuly"); + } + + /** + * Unloads the modules. + */ + public void unload() { + disable(); + m_modules.clear(); + } + + /** + * Unload a specific module. + * + * @param module + * the module + */ + public void unload(Module module) { + try { + module.setEnabled(false); + m_modules.remove(module); + } catch (Exception ex) { + ExceptionHandler.handleException(ex); + } + } + + /** + * Run on enable in all modules. + */ + public void enable() { + for (Module module : m_modules) { + try { + module.setEnabled(true); + Bukkit.getHelpMap().addTopic(new ModuleHelpTopic(module)); + } catch (Exception ex) { + ExceptionHandler.handleException(ex); + } + } + } + + /** + * run on disable in all modules. + */ + public void disable() { + List modules = new ArrayList(m_modules); + for (Module module : modules) { + try { + unload(module); + } catch (Exception ex) { + ExceptionHandler.handleException(ex); + } + } + } + + /** + * Gets the modules. + * + * @return the modules + */ + public List getModules() { + return m_modules; + } + + /** + * Update all the loaded modules if an updater is set. + */ + public void update() { + if (!bFundamentals.getConfigurationManager().isAutoUpdateEnabled()) { + return; + } + + for (Module module : m_modules) { + module.update(); + } + } + + /** + * Gets the module from its name. + * + * @param string + * the string + * @return the module + */ + public Module getModule(String string) { + Iterator itr = m_modules.iterator(); + while (itr.hasNext()) { + Module module = itr.next(); + if (module.getName().equalsIgnoreCase(string)) { + return module; + } + } + return null; + } + + /** + * Gets the module from its file. + * + * @param file + * the file + * @return the module + */ + public Module getModule(File file) { + Iterator itr = m_modules.iterator(); + while (itr.hasNext()) { + Module module = itr.next(); + if (module.getFile().getPath().equalsIgnoreCase(file.getPath())) { + return module; + } + } + return null; + } + + /** + * Gets a class by its name from any of the module class loads. + * + * @param name the full class name, in the format for {@link Class#forName(String)} + * @return the class specified by its name + * @throws ClassNotFoundException if the specific class cannot be found + */ + Class getClassByName(String name) throws ClassNotFoundException { + Class cachedClass = classes.get(name); + + if (cachedClass != null) { + return cachedClass; + } else { + for (String current : loaders.keySet()) { + ModuleClassLoader loader = loaders.get(current); + try { + cachedClass = loader.findClass(name, false); + } catch (ClassNotFoundException cnfe) { + } + + if (cachedClass != null) { + return cachedClass; + } + } + } + throw new ClassNotFoundException(name); + } + + /** + * Sets a class for a specific name in the internal cache. + * + * @param name the name + * @param clazz the class + */ + void setClass(String name, Class clazz) { + if (!classes.containsKey(name)) { + classes.put(name, clazz); + + if (ConfigurationSerializable.class.isAssignableFrom(clazz)) { + Class serializable = clazz.asSubclass(ConfigurationSerializable.class); + ConfigurationSerialization.registerClass(serializable); + } + } + } + + /** + * Sort the modules by name in the module list. + */ + void sort() { + List sortedLoadables = new ArrayList(); + List names = new ArrayList(); + + for (Module t : m_modules) { + names.add(t.getName()); + } + + Collections.sort(names); + + for (String name : names) { + for (Module t : m_modules) { + if (t.getName().equals(name)) { + sortedLoadables.add(t); + } + } + } + + m_modules = sortedLoadables; + } + +} diff --git a/bFundamentals/src/uk/codingbadgers/bFundamentals/utils/CollectionUtils.java b/bFundamentals/src/uk/codingbadgers/bFundamentals/utils/CollectionUtils.java new file mode 100644 index 0000000..507dba3 --- /dev/null +++ b/bFundamentals/src/uk/codingbadgers/bFundamentals/utils/CollectionUtils.java @@ -0,0 +1,41 @@ +/** + * bFundamentals 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package uk.codingbadgers.bFundamentals.utils; + +import java.util.List; + +import com.google.common.collect.ImmutableList.Builder; + +/** + * The Utility class for using google collections. + */ +public class CollectionUtils { + + /** + * Create a immutable copy of a list. + * + * @param the generic type of the list + * @param list the list to create a copy of + * @return a immutable copy of the list + */ + public static List toImmutableList(List list) { + Builder builder = new Builder(); + builder.addAll(list); + return builder.build(); + } +} diff --git a/bFundamentals/test/uk/thecodingbadgers/bFundamentals/TestConfigManager.java b/bFundamentals/test/uk/thecodingbadgers/bFundamentals/TestConfigManager.java index e6f87cb..903d1ec 100644 --- a/bFundamentals/test/uk/thecodingbadgers/bFundamentals/TestConfigManager.java +++ b/bFundamentals/test/uk/thecodingbadgers/bFundamentals/TestConfigManager.java @@ -65,6 +65,11 @@ public String getLogPrefix() { throw new UnsupportedOperationException(); } + @Override + public File getModuleDirectory() { + throw new UnsupportedOperationException(); + } + @Override public String getCrashPassword() { return "PASSWORD"; diff --git a/bGui/src/uk/codingbadgers/bgui/click/ServerHandler.java b/bGui/src/uk/codingbadgers/bgui/click/ServerHandler.java index e963c85..67330b2 100644 --- a/bGui/src/uk/codingbadgers/bgui/click/ServerHandler.java +++ b/bGui/src/uk/codingbadgers/bgui/click/ServerHandler.java @@ -1,3 +1,20 @@ +/** + * bGui 1.2-SNAPSHOT + * Copyright (C) 2013 CodingBadgers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package uk.codingbadgers.bgui.click; import java.io.ByteArrayOutputStream;