diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java index 0b47a2e6..caa7f5e7 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java @@ -76,11 +76,11 @@ public class Plugin * @param description the description that describes this plugin * @param jarfile this plugins jar or container */ - final void init(ProxyServer proxy, PluginDescription description, File file) + final void init(ProxyServer proxy, PluginDescription description) { this.proxy = proxy; this.description = description; - this.file = file; + this.file = description.getFile(); this.logger = new PluginLogger( this ); } } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java index 4ecab7cc..4a7135aa 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.plugin; +import java.io.File; import java.util.HashSet; import java.util.Set; import lombok.AllArgsConstructor; @@ -35,4 +36,8 @@ public class PluginDescription * Plugin hard dependencies. */ private Set depends = new HashSet<>(); + /** + * File we were loaded from. + */ + private File file = null; } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index 19d00346..08a4891f 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -10,6 +10,7 @@ import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Stack; import java.util.jar.JarEntry; @@ -38,8 +39,9 @@ public class PluginManager /*========================================================================*/ private final Yaml yaml = new Yaml(); private final EventBus eventBus; - private final Map plugins = new HashMap<>(); + private final Map plugins = new LinkedHashMap<>(); private final Map commandMap = new HashMap<>(); + private Map toLoad = new HashMap<>(); @SuppressWarnings("unchecked") public PluginManager(ProxyServer proxy) @@ -130,23 +132,37 @@ public class PluginManager return plugins.get( name ); } - /** - * Enable all plugins by calling the {@link Plugin#onEnable()} method. - */ - public void enablePlugins() + public void loadAndEnablePlugins() { - Map pluginStatuses = new HashMap<>(); - for ( Map.Entry entry : plugins.entrySet() ) + Map pluginStatuses = new HashMap<>(); + for ( Map.Entry entry : toLoad.entrySet() ) { - Plugin plugin = entry.getValue(); - if ( !this.enablePlugin( pluginStatuses, new Stack(), plugin ) ) + PluginDescription plugin = entry.getValue(); + if ( !enablePlugin( pluginStatuses, new Stack(), plugin ) ) { ProxyServer.getInstance().getLogger().warning( "Failed to enable " + entry.getKey() ); } } + toLoad.clear(); + toLoad = null; + + for ( Plugin plugin : plugins.values() ) + { + try + { + plugin.onEnable(); + ProxyServer.getInstance().getLogger().log( Level.INFO, "Enabled plugin {0} version {1} by {2}", new Object[] + { + plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getAuthor() + } ); + } catch ( Throwable t ) + { + ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t ); + } + } } - private boolean enablePlugin(Map pluginStatuses, Stack dependStack, Plugin plugin) + private boolean enablePlugin(Map pluginStatuses, Stack dependStack, PluginDescription plugin) { if ( pluginStatuses.containsKey( plugin ) ) { @@ -157,9 +173,9 @@ public class PluginManager boolean status = true; // try to load dependencies first - for ( String dependName : plugin.getDescription().getDepends() ) + for ( String dependName : plugin.getDepends() ) { - Plugin depend = this.plugins.get( dependName ); + PluginDescription depend = toLoad.get( dependName ); Boolean dependStatus = depend != null ? pluginStatuses.get( depend ) : Boolean.FALSE; if ( dependStatus == null ) @@ -167,11 +183,11 @@ public class PluginManager if ( dependStack.contains( depend ) ) { StringBuilder dependencyGraph = new StringBuilder(); - for ( Plugin element : dependStack ) + for ( PluginDescription element : dependStack ) { - dependencyGraph.append( element.getDescription().getName() ).append( " -> " ); + dependencyGraph.append( element.getName() ).append( " -> " ); } - dependencyGraph.append( plugin.getDescription().getName() ).append( " -> " ).append( dependName ); + dependencyGraph.append( plugin.getName() ).append( " -> " ).append( dependName ); ProxyServer.getInstance().getLogger().log( Level.WARNING, "Circular dependency detected: " + dependencyGraph ); status = false; } else @@ -186,7 +202,7 @@ public class PluginManager { ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[] { - depend.getDescription().getName(), plugin.getDescription().getName() + depend.getName(), plugin.getName() } ); status = false; } @@ -202,15 +218,23 @@ public class PluginManager { try { - plugin.onEnable(); - ProxyServer.getInstance().getLogger().log( Level.INFO, "Enabled plugin {0} version {1} by {2}", new Object[] + URLClassLoader loader = new PluginClassloader( new URL[] { - plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getAuthor() + plugin.getFile().toURI().toURL() + } ); + Class main = loader.loadClass( plugin.getMain() ); + Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance(); + + clazz.init( proxy, plugin ); + plugins.put( plugin.getName(), clazz ); + clazz.onLoad(); + ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[] + { + plugin.getName(), plugin.getVersion(), plugin.getAuthor() } ); } catch ( Throwable t ) { - ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t ); - status = false; + proxy.getLogger().log( Level.WARNING, "Error enabling plugin " + plugin.getName(), t ); } } @@ -218,51 +242,12 @@ public class PluginManager return status; } - /** - * Load a plugin from the specified file. This file must be in jar format. - * This will not enable plugins, {@link #enablePlugins()} must be called. - * - * @param file the file to load from - * @throws Exception Any exceptions encountered when loading a plugin from - * this file. - */ - public void loadPlugin(File file) throws Exception - { - Preconditions.checkNotNull( file, "file" ); - Preconditions.checkArgument( file.isFile(), "Must load from file" ); - - try ( JarFile jar = new JarFile( file ) ) - { - JarEntry pdf = jar.getJarEntry( "plugin.yml" ); - Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" ); - - try ( InputStream in = jar.getInputStream( pdf ) ) - { - PluginDescription desc = yaml.loadAs( in, PluginDescription.class ); - URLClassLoader loader = new PluginClassloader( new URL[] - { - file.toURI().toURL() - } ); - Class main = loader.loadClass( desc.getMain() ); - Plugin plugin = (Plugin) main.getDeclaredConstructor().newInstance(); - - plugin.init( proxy, desc, file ); - plugins.put( desc.getName(), plugin ); - plugin.onLoad(); - ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[] - { - desc.getName(), desc.getVersion(), desc.getAuthor() - } ); - } - } - } - /** * Load all plugins from the specified folder. * * @param folder the folder to search for plugins in */ - public void loadPlugins(File folder) + public void detectPlugins(File folder) { Preconditions.checkNotNull( folder, "folder" ); Preconditions.checkArgument( folder.isDirectory(), "Must load from a directory" ); @@ -271,9 +256,17 @@ public class PluginManager { if ( file.isFile() && file.getName().endsWith( ".jar" ) ) { - try + try ( JarFile jar = new JarFile( file ) ) { - loadPlugin( file ); + JarEntry pdf = jar.getJarEntry( "plugin.yml" ); + Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" ); + + try ( InputStream in = jar.getInputStream( pdf ) ) + { + PluginDescription desc = yaml.loadAs( in, PluginDescription.class ); + desc.setFile( file ); + toLoad.put( desc.getName(), desc ); + } } catch ( Exception ex ) { ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load plugin from file " + file, ex ); diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 8ddef0b0..971a979c 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -195,7 +195,7 @@ public class BungeeCord extends ProxyServer public void start() throws Exception { pluginsFolder.mkdir(); - pluginManager.loadPlugins( pluginsFolder ); + pluginManager.detectPlugins( pluginsFolder ); config.load(); if ( reconnectHandler == null ) { @@ -203,7 +203,7 @@ public class BungeeCord extends ProxyServer } isRunning = true; - pluginManager.enablePlugins(); + pluginManager.loadAndEnablePlugins(); startListeners();