diff --git a/src/main/java/org/bukkit/fillr/Getter.java b/src/main/java/org/bukkit/fillr/Getter.java index 8a054189..55d65ded 100644 --- a/src/main/java/org/bukkit/fillr/Getter.java +++ b/src/main/java/org/bukkit/fillr/Getter.java @@ -8,6 +8,7 @@ import org.bukkit.*; import org.bukkit.command.CommandSender; import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.InvalidPluginException; +import org.bukkit.plugin.UnknownDependencyException; public class Getter { private Server server; @@ -40,6 +41,8 @@ public class Getter { File plugin = new File(DIRECTORY, name + ".jar"); try { server.getPluginManager().loadPlugin(plugin); + } catch (UnknownDependencyException ex) { + server.getLogger().log(Level.SEVERE, null, ex); } catch (InvalidPluginException ex) { server.getLogger().log(Level.SEVERE, null, ex); } catch (InvalidDescriptionException ex) { diff --git a/src/main/java/org/bukkit/fillr/Updater.java b/src/main/java/org/bukkit/fillr/Updater.java index 5479fbd5..e4ce9189 100644 --- a/src/main/java/org/bukkit/fillr/Updater.java +++ b/src/main/java/org/bukkit/fillr/Updater.java @@ -98,6 +98,8 @@ public class Updater { File plugin = new File(DIRECTORY, name + ".jar"); try { server.getPluginManager().loadPlugin(plugin); + } catch (UnknownDependencyException ex) { + server.getLogger().log(Level.SEVERE, null, ex); } catch (InvalidPluginException ex) { server.getLogger().log(Level.SEVERE, null, ex); } catch (InvalidDescriptionException ex) { diff --git a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java index 46aee5a3..c0ed5952 100644 --- a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +++ b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java @@ -7,6 +7,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -18,6 +19,7 @@ public final class PluginDescriptionFile { private static final Yaml yaml = new Yaml(new SafeConstructor()); private String name = null; private String main = null; + private ArrayList depend = null; private String version = null; private Object commands = null; private String description = null; @@ -99,6 +101,10 @@ public final class PluginDescriptionFile { return commands; } + public Object getDepend() { + return depend; + } + /** * Gets the description of this plugin * @@ -149,6 +155,14 @@ public final class PluginDescriptionFile { } } + if (map.containsKey("depend")) { + try { + depend = (ArrayList)map.get("depend"); + } catch (ClassCastException ex) { + throw new InvalidDescriptionException(ex, "depend is of wrong type"); + } + } + if (map.containsKey("website")) { try { website = (String)map.get("website"); @@ -191,6 +205,7 @@ public final class PluginDescriptionFile { map.put("version", version); if (commands != null) map.put("command", commands); + if (depend != null) map.put("depend", depend); if (website != null) map.put("website", website); if (description != null) map.put("description", description); diff --git a/src/main/java/org/bukkit/plugin/PluginLoader.java b/src/main/java/org/bukkit/plugin/PluginLoader.java index eaf6c066..245c850f 100644 --- a/src/main/java/org/bukkit/plugin/PluginLoader.java +++ b/src/main/java/org/bukkit/plugin/PluginLoader.java @@ -20,7 +20,7 @@ public interface PluginLoader { * unsuccessful * @throws InvalidPluginException Thrown when the specified file is not a plugin */ - public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException; + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException; /** * Returns a list of all filename filters expected by this PluginLoader diff --git a/src/main/java/org/bukkit/plugin/PluginManager.java b/src/main/java/org/bukkit/plugin/PluginManager.java index e89351a0..18e8916e 100644 --- a/src/main/java/org/bukkit/plugin/PluginManager.java +++ b/src/main/java/org/bukkit/plugin/PluginManager.java @@ -65,7 +65,7 @@ public interface PluginManager { * @throws InvalidPluginException Thrown when the specified file is not a valid plugin * @throws InvalidDescriptionException Thrown when the specified file contains an invalid description */ - public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException; + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException; /** * Loads the plugins contained within the specified directory diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java index 693e2eb1..4bb73957 100644 --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java @@ -12,6 +12,9 @@ import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -88,19 +91,45 @@ public final class SimplePluginManager implements PluginManager { List result = new ArrayList(); File[] files = directory.listFiles(); - for (File file : files) { - Plugin plugin = null; + boolean allFailed = false; + boolean finalPass = false; - try { - plugin = loadPlugin(file); - } catch (InvalidPluginException ex) { - server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath() + ": " + ex.getMessage(), ex); - } catch (InvalidDescriptionException ex) { - server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath() + ": " + ex.getMessage(), ex); + LinkedList filesList = new LinkedList(Arrays.asList(files)); + + while(!allFailed || finalPass) { + allFailed = true; + Iterator itr = filesList.iterator(); + while(itr.hasNext()) { + File file = itr.next(); + Plugin plugin = null; + + try { + plugin = loadPlugin(file); + itr.remove(); + } catch (UnknownDependencyException ex) { + if(finalPass) { + server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath() + ": " + ex.getMessage(), ex); + itr.remove(); + } else { + plugin = null; + } + } catch (InvalidPluginException ex) { + server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath() + ": " + ex.getMessage(), ex); + itr.remove(); + } catch (InvalidDescriptionException ex) { + server.getLogger().log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath() + ": " + ex.getMessage(), ex); + itr.remove(); + } + + if (plugin != null) { + result.add(plugin); + allFailed = false; + } } - - if (plugin != null) { - result.add(plugin); + if(finalPass) { + break; + } else if(allFailed) { + finalPass = true; } } @@ -117,7 +146,7 @@ public final class SimplePluginManager implements PluginManager { * @throws InvalidPluginException Thrown when the specified file is not a valid plugin * @throws InvalidDescriptionException Thrown when the specified file contains an invalid description */ - public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException { + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { Set filters = fileAssociations.keySet(); Plugin result = null; diff --git a/src/main/java/org/bukkit/plugin/UnknownDependencyException.java b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java new file mode 100644 index 00000000..dc5da651 --- /dev/null +++ b/src/main/java/org/bukkit/plugin/UnknownDependencyException.java @@ -0,0 +1,63 @@ + +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid Plugin file + */ +public class UnknownDependencyException extends Exception { + + private static final long serialVersionUID = 5721389371901775894L; + private final Throwable cause; + private final String message; + + /** + * Constructs a new UnknownDependencyException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public UnknownDependencyException(Throwable throwable) { + this(throwable, "Unknown dependency"); + } + + /** + * Constructs a new UnknownDependencyException with the given message + * + * @param message Brief message explaining the cause of the exception + */ + public UnknownDependencyException(final String message) { + this(null, message); + } + + /** + * Constructs a new UnknownDependencyException based on the given Exception + * + * @param message Brief message explaining the cause of the exception + * @param throwable Exception that triggered this Exception + */ + public UnknownDependencyException(final Throwable throwable, final String message) { + this.cause = null; + this.message = message; + } + + /** + * Constructs a new UnknownDependencyException + */ + public UnknownDependencyException() { + this(null, "Unknown dependency"); + } + + /** + * If applicable, returns the Exception that triggered this Exception + * + * @return Inner exception, or null if one does not exist + */ + @Override + public Throwable getCause() { + return cause; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java index 18fdfa90..2ab3e09f 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java @@ -9,6 +9,9 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.Arrays; +import java.util.Map; +import java.util.ArrayList; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; @@ -36,12 +39,13 @@ public final class JavaPluginLoader implements PluginLoader { Pattern.compile("\\.jar$"), }; private final Map> classes = new HashMap>(); + private final Map files = new HashMap(); public JavaPluginLoader(Server instance) { server = instance; } - public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException { + public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { JavaPlugin result = null; PluginDescriptionFile description = null; @@ -67,8 +71,37 @@ public final class JavaPluginLoader implements PluginLoader { File dataFolder = getDataFolder(file); + ArrayList depend; try { - ClassLoader loader = new PluginClassLoader(this, new URL[]{file.toURI().toURL()}, getClass().getClassLoader()); + depend = (ArrayList)description.getDepend(); + if(depend == null) { + depend = new ArrayList(); + } + } catch (ClassCastException ex) { + throw new InvalidPluginException(ex); + } + + ArrayList dependFiles = new ArrayList(); + + for(String pluginName : depend) { + if(files == null) { + throw new UnknownDependencyException(pluginName); + } + File current = files.get(pluginName); + if(current == null) { + throw new UnknownDependencyException(pluginName); + } + dependFiles.add(current); + } + + try { + URL[] urls = new URL[dependFiles.size() + 1]; + urls[0] = file.toURI().toURL(); + int cnt = 1; + for(File f : dependFiles) { + urls[cnt++] = f.toURI().toURL(); + } + ClassLoader loader = new PluginClassLoader(this, urls, getClass().getClassLoader()); Class jarClass = Class.forName(description.getMain(), true, loader); Class plugin = jarClass.asSubclass(JavaPlugin.class); @@ -80,6 +113,8 @@ public final class JavaPluginLoader implements PluginLoader { throw new InvalidPluginException(ex); } + files.put(description.getName(), file); + return (Plugin)result; } @@ -112,7 +147,9 @@ public final class JavaPluginLoader implements PluginLoader { } public void setClass(final String name, final Class clazz) { - classes.put(name, clazz); + if(!classes.containsKey(name)) { + classes.put(name, clazz); + } } public EventExecutor createExecutor( Event.Type type, Listener listener ) { @@ -429,6 +466,8 @@ public final class JavaPluginLoader implements PluginLoader { server.getPluginManager().callEvent(new PluginEvent(Event.Type.PLUGIN_DISABLE, plugin)); + files.remove(jPlugin.getDescription().getName()); + if (cloader instanceof PluginClassLoader) { PluginClassLoader loader = (PluginClassLoader)cloader; Set names = loader.getClasses(); diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java index d17e0f4f..bc6cb0a2 100644 --- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java @@ -24,17 +24,25 @@ public class PluginClassLoader extends URLClassLoader { Class result = classes.get(name); if (result == null) { - result = loader.getClassByName(name); + ClassNotFoundException ex = null; - if (result == null) { + try { result = super.findClass(name); - - if (result != null) { - loader.setClass(name, result); - } + } catch (ClassNotFoundException e) { + ex = e; } - classes.put(name, result); + if (result != null) { + loader.setClass(name, result); + } else { + result = loader.getClassByName(name); + } + + if (result != null ) { + classes.put(name, result); + } else { + throw ex; + } } return result;