diff --git a/paper-api/.gitignore b/paper-api/.gitignore new file mode 100644 index 0000000000..1590e71a07 --- /dev/null +++ b/paper-api/.gitignore @@ -0,0 +1,5 @@ + +/build +/nbproject +/build.xml +/manifest.mf \ No newline at end of file diff --git a/paper-api/src/org/bukkit/Server.java b/paper-api/src/org/bukkit/Server.java index f6ab34ec2c..2c2fae84e0 100644 --- a/paper-api/src/org/bukkit/Server.java +++ b/paper-api/src/org/bukkit/Server.java @@ -1,6 +1,8 @@ package org.bukkit; +import org.bukkit.plugin.PluginManager; + /** * Represents a server implementation */ @@ -25,4 +27,11 @@ public interface Server { * @return An array of Players that are currently online */ public Player[] getOnlinePlayers(); + + /** + * Gets the PluginManager for interfacing with plugins + * + * @return PluginManager for this Server instance + */ + public PluginManager getPluginManager(); } diff --git a/paper-api/src/org/bukkit/plugin/InvalidDescriptionException.java b/paper-api/src/org/bukkit/plugin/InvalidDescriptionException.java index aee3e3973f..2d586a14fa 100644 --- a/paper-api/src/org/bukkit/plugin/InvalidDescriptionException.java +++ b/paper-api/src/org/bukkit/plugin/InvalidDescriptionException.java @@ -5,30 +5,31 @@ package org.bukkit.plugin; * Thrown when attempting to load an invalid PluginDescriptionFile */ public class InvalidDescriptionException extends Exception { - private final Exception innerException; + private final Throwable cause; /** * Constructs a new InvalidDescriptionException based on the given Exception * - * @param exception Exception that triggered this Exception + * @param throwable Exception that triggered this Exception */ - public InvalidDescriptionException(Exception exception) { - innerException = exception; + public InvalidDescriptionException(Throwable throwable) { + cause = throwable; } /** * Constructs a new InvalidDescriptionException */ public InvalidDescriptionException() { - innerException = null; + cause = null; } /** - * If applicable, returns the Exception that triggered this InvalidDescriptionException + * If applicable, returns the Exception that triggered this Exception * * @return Inner exception, or null if one does not exist */ - public Exception getInnerException() { - return innerException; + @Override + public Throwable getCause() { + return cause; } } diff --git a/paper-api/src/org/bukkit/plugin/InvalidPluginException.java b/paper-api/src/org/bukkit/plugin/InvalidPluginException.java new file mode 100644 index 0000000000..9ab904c153 --- /dev/null +++ b/paper-api/src/org/bukkit/plugin/InvalidPluginException.java @@ -0,0 +1,35 @@ + +package org.bukkit.plugin; + +/** + * Thrown when attempting to load an invalid Plugin file + */ +public class InvalidPluginException extends Exception { + private final Throwable cause; + + /** + * Constructs a new InvalidPluginException based on the given Exception + * + * @param throwable Exception that triggered this Exception + */ + public InvalidPluginException(Throwable throwable) { + cause = throwable; + } + + /** + * Constructs a new InvalidPluginException + */ + public InvalidPluginException() { + cause = null; + } + + /** + * 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; + } +} diff --git a/paper-api/src/org/bukkit/plugin/Plugin.java b/paper-api/src/org/bukkit/plugin/Plugin.java index ba781ce261..a097945107 100644 --- a/paper-api/src/org/bukkit/plugin/Plugin.java +++ b/paper-api/src/org/bukkit/plugin/Plugin.java @@ -4,63 +4,49 @@ package org.bukkit.plugin; import org.bukkit.Server; /** - * Represents a plugin + * Represents a Plugin */ -public abstract class Plugin { - private boolean isEnabled = false; - private final PluginLoader loader; - private final Server server; - +public interface Plugin { /** - * Constructs a new plugin instance + * Returns the plugin.yaml file containing the details for this plugin * - * @param pluginLoader PluginLoader that is responsible for this plugin - * @param instance Server instance that is running this plugin + * @return Contents of the plugin.yaml file */ - protected Plugin(PluginLoader pluginLoader, Server instance) { - loader = pluginLoader; - server = instance; - } + public PluginDescriptionFile getDescription(); /** * Gets the associated PluginLoader responsible for this plugin * * @return PluginLoader that controls this plugin */ - protected final PluginLoader getPluginLoader() { - return loader; - } + public PluginLoader getPluginLoader(); /** * Returns the Server instance currently running this plugin * * @return Server running this plugin */ - public final Server getServer() { - return server; - } + public Server getServer(); /** * Returns a value indicating whether or not this plugin is currently enabled - * + * * @return true if this plugin is enabled, otherwise false */ - public final boolean isEnabled() { - return isEnabled; - } - - /** - * Called when this plugin is enabled - */ - protected abstract void onEnable(); + public boolean isEnabled(); /** * Called when this plugin is disabled */ - protected abstract void onDisable(); + public void onDisable(); + + /** + * Called when this plugin is enabled + */ + public void onEnable(); /** * Called when this plugin is first initialized */ - protected abstract void onInitialize(); + public void onInitialize(); } diff --git a/paper-api/src/org/bukkit/plugin/PluginDescriptionFile.java b/paper-api/src/org/bukkit/plugin/PluginDescriptionFile.java index 52632e1178..9387d253a8 100644 --- a/paper-api/src/org/bukkit/plugin/PluginDescriptionFile.java +++ b/paper-api/src/org/bukkit/plugin/PluginDescriptionFile.java @@ -53,6 +53,24 @@ public final class PluginDescriptionFile { yaml.dump(saveMap(), writer); } + /** + * Returns the name of a plugin + * + * @return String name + */ + public String getName() { + return name; + } + + /** + * Returns the main class for a plugin + * + * @return Java classpath + */ + public String getMain() { + return main; + } + private void loadMap(Map map) throws ClassCastException { name = (String)map.get("name"); main = (String)map.get("main"); diff --git a/paper-api/src/org/bukkit/plugin/PluginLoader.java b/paper-api/src/org/bukkit/plugin/PluginLoader.java index f7913d20dd..01112122e4 100644 --- a/paper-api/src/org/bukkit/plugin/PluginLoader.java +++ b/paper-api/src/org/bukkit/plugin/PluginLoader.java @@ -18,6 +18,7 @@ public interface PluginLoader { * @return Plugin if it exists, otherwise null */ public Plugin getPlugin(String name); + /** * Checks if the given plugin is enabled or not * @@ -42,8 +43,9 @@ public interface PluginLoader { * @param file File to attempt to load * @return Plugin that was contained in the specified file, or null if * unsuccessful + * @throws InvalidPluginException Thrown when the specified file is not a plugin */ - public Plugin loadPlugin(File file); + public Plugin loadPlugin(File file) throws InvalidPluginException; /** * Returns a list of all filename filters expected by this PluginLoader diff --git a/paper-api/src/org/bukkit/plugin/PluginManager.java b/paper-api/src/org/bukkit/plugin/PluginManager.java index de710414cf..d1d15c67ad 100644 --- a/paper-api/src/org/bukkit/plugin/PluginManager.java +++ b/paper-api/src/org/bukkit/plugin/PluginManager.java @@ -7,6 +7,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import org.bukkit.Server; import java.util.regex.Pattern; @@ -17,6 +19,7 @@ import java.util.regex.Pattern; public final class PluginManager { private final Server server; private final HashMap fileAssociations = new HashMap(); + private final List plugins = new ArrayList(); public PluginManager(Server instance) { server = instance; @@ -63,7 +66,13 @@ public final class PluginManager { File[] files = directory.listFiles(); for (File file : files) { - Plugin plugin = loadPlugin(file); + Plugin plugin = null; + + try { + plugin = loadPlugin(file); + } catch (InvalidPluginException ex) { + Logger.getLogger(PluginManager.class.getName()).log(Level.SEVERE, "Could not load " + file.getPath() + " in " + directory.getPath(), ex); + } if (plugin != null) { result.add(plugin); @@ -80,8 +89,9 @@ public final class PluginManager { * * @param file File containing the plugin to load * @return The Plugin loaded, or null if it was invalid + * @throws InvalidPluginException Thrown when the specified file is not a valid plugin */ - public Plugin loadPlugin(File file) { + public Plugin loadPlugin(File file) throws InvalidPluginException { Set filters = fileAssociations.keySet(); Plugin result = null; @@ -95,6 +105,11 @@ public final class PluginManager { } } + if (result != null) { + plugins.add(result); + result.onInitialize(); + } + return result; } } diff --git a/paper-api/src/org/bukkit/plugin/java/JavaPlugin.java b/paper-api/src/org/bukkit/plugin/java/JavaPlugin.java new file mode 100644 index 0000000000..1b8dd2f59b --- /dev/null +++ b/paper-api/src/org/bukkit/plugin/java/JavaPlugin.java @@ -0,0 +1,91 @@ + +package org.bukkit.plugin.java; + +import java.io.File; +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; + +/** + * Represents a Java plugin + */ +public abstract class JavaPlugin implements Plugin { + private boolean isEnabled = false; + private final PluginLoader loader; + private final Server server; + private final File file; + private final PluginDescriptionFile description; + private final ClassLoader classLoader; + + /** + * Constructs a new Java plugin instance + * + * @param pluginLoader PluginLoader that is responsible for this plugin + * @param instance Server instance that is running this plugin + * @param desc PluginDescriptionFile containing metadata on this plugin + * @param plugin File containing this plugin + * @param cLoader ClassLoader which holds this plugin + */ + protected JavaPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File plugin, ClassLoader cLoader) { + loader = pluginLoader; + server = instance; + file = plugin; + description = desc; + classLoader = cLoader; + } + + /** + * Gets the associated PluginLoader responsible for this plugin + * + * @return PluginLoader that controls this plugin + */ + public final PluginLoader getPluginLoader() { + return loader; + } + + /** + * Returns the Server instance currently running this plugin + * + * @return Server running this plugin + */ + public final Server getServer() { + return server; + } + + /** + * Returns a value indicating whether or not this plugin is currently enabled + * + * @return true if this plugin is enabled, otherwise false + */ + public final boolean isEnabled() { + return isEnabled; + } + + /** + * Returns the file which contains this plugin + * + * @return File containing this plugin + */ + protected File getFile() { + return file; + } + + /** + * Returns the plugin.yaml file containing the details for this plugin + * + * @return Contents of the plugin.yaml file + */ + public PluginDescriptionFile getDescription() { + return description; + } + + /** + * Returns the ClassLoader which holds this plugin + * + * @return ClassLoader holding this plugin + */ + protected ClassLoader getClassLoader() { + return classLoader; + } +} diff --git a/paper-api/src/org/bukkit/plugin/java/JavaPluginLoader.java b/paper-api/src/org/bukkit/plugin/java/JavaPluginLoader.java index 58d498edbd..b5ca9d9af9 100644 --- a/paper-api/src/org/bukkit/plugin/java/JavaPluginLoader.java +++ b/paper-api/src/org/bukkit/plugin/java/JavaPluginLoader.java @@ -2,10 +2,19 @@ package org.bukkit.plugin.java; import java.io.File; +import java.io.FileNotFoundException; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.logging.Level; +import java.util.logging.Logger; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginLoader; import java.util.regex.Pattern; import org.bukkit.Server; +import org.bukkit.plugin.InvalidPluginException; +import org.bukkit.plugin.PluginDescriptionFile; /** * Represents a Java plugin loader, allowing plugins in the form of .jars @@ -32,8 +41,26 @@ public final class JavaPluginLoader implements PluginLoader { throw new UnsupportedOperationException("Not supported yet."); } - public Plugin loadPlugin(File file) { - throw new UnsupportedOperationException("Not supported yet."); + public Plugin loadPlugin(File file) throws InvalidPluginException { + JavaPlugin result = null; + PluginDescriptionFile description = new PluginDescriptionFile("Sample Plugin", "org.bukkit.plugin.sample.main"); + + if (!file.exists()) { + throw new InvalidPluginException(new FileNotFoundException(String.format("%s does not exist", file.getPath()))); + } + + try { + ClassLoader loader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, getClass().getClassLoader()); + Class jarClass = Class.forName(description.getMain()); + Class plugin = jarClass.asSubclass(JavaPlugin.class); + Constructor constructor = plugin.getConstructor(PluginLoader.class, Server.class, PluginDescriptionFile.class, File.class, ClassLoader.class); + + result = constructor.newInstance(this, server, description, file, loader); + } catch (Exception ex) { + throw new InvalidPluginException(ex); + } + + return (Plugin)result; } public Pattern[] getPluginFileFilters() {