And people think dependancy loading is easy. Close #381
This commit is contained in:
parent
33d315b719
commit
b1e3f6a75b
@ -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 );
|
||||
}
|
||||
}
|
||||
|
@ -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<String> depends = new HashSet<>();
|
||||
/**
|
||||
* File we were loaded from.
|
||||
*/
|
||||
private File file = null;
|
||||
}
|
||||
|
@ -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<String, Plugin> plugins = new HashMap<>();
|
||||
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
||||
private final Map<String, Command> commandMap = new HashMap<>();
|
||||
private Map<String, PluginDescription> 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<Plugin, Boolean> pluginStatuses = new HashMap<>();
|
||||
for ( Map.Entry<String, Plugin> entry : plugins.entrySet() )
|
||||
Map<PluginDescription, Boolean> pluginStatuses = new HashMap<>();
|
||||
for ( Map.Entry<String, PluginDescription> entry : toLoad.entrySet() )
|
||||
{
|
||||
Plugin plugin = entry.getValue();
|
||||
if ( !this.enablePlugin( pluginStatuses, new Stack<Plugin>(), plugin ) )
|
||||
PluginDescription plugin = entry.getValue();
|
||||
if ( !enablePlugin( pluginStatuses, new Stack<PluginDescription>(), 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<Plugin, Boolean> pluginStatuses, Stack<Plugin> dependStack, Plugin plugin)
|
||||
private boolean enablePlugin(Map<PluginDescription, Boolean> pluginStatuses, Stack<PluginDescription> 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 );
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user