And people think dependancy loading is easy. Close #381

This commit is contained in:
md_5 2013-06-05 18:24:33 +10:00
parent 33d315b719
commit b1e3f6a75b
4 changed files with 65 additions and 67 deletions

View File

@ -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 );
}
}

View File

@ -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;
}

View File

@ -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 );

View File

@ -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();