From 40c59f2f7eabe1e624533bd1e9e7bc7e80278832 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Thu, 28 Dec 2017 14:50:02 +0100 Subject: [PATCH] AddonsAPI - Polishing the API Renamed all the classes --- .../bskyblock/api/addons/Addon.java | 167 ++++++++++++++++++ .../api/addons/AddonClassLoader.java | 67 +++++++ .../api/addons/AddonDescription.java | 111 ++++++++++++ .../bskyblock/api/addons/AddonInterface.java | 7 + .../bskyblock/api/addons/AddonState.java | 49 +++++ .../api/addons/event/AddonDisableEvent.java | 25 +++ .../api/addons/event/AddonEnableEvent.java | 25 +++ .../api/addons/event/AddonLoadEvent.java | 25 +++ .../api/addons/event/PremadeEvent.java | 19 ++ .../api/addons/exception/AddonException.java | 14 ++ .../InvalidAddonFormatException.java | 30 ++++ .../InvalidAddonInheritException.java | 14 ++ 12 files changed, 553 insertions(+) create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/Addon.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/AddonClassLoader.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/AddonDescription.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/AddonInterface.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/AddonState.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/event/AddonDisableEvent.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/event/AddonEnableEvent.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/event/AddonLoadEvent.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/event/PremadeEvent.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/exception/AddonException.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonFormatException.java create mode 100644 src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonInheritException.java diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/Addon.java b/src/main/java/us/tastybento/bskyblock/api/addons/Addon.java new file mode 100644 index 000000000..73abb5138 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/Addon.java @@ -0,0 +1,167 @@ +package us.tastybento.bskyblock.api.addons; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Logger; + +import org.bukkit.Server; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; + +import us.tastybento.bskyblock.BSkyBlock; + +/** + * Add-on class for BSkyBlock. Extend this to create an add-on. + * The operation and methods are very similar to Bukkit's JavaPlugin. + * + * @author Tastybento, ComminQ + */ +public abstract class Addon implements AddonInterface { + + private static final String ADDON_CONFIG_FILENAME = "config.yml"; + private boolean enabled; + private AddonDescription description; + private FileConfiguration config; + private File dataFolder; + private File file; + + public Addon() { + this.enabled = false; + } + + public JavaPlugin getBSkyBlock(){ + return BSkyBlock.getInstance(); + } + + public FileConfiguration getConfig() { + config = loadYamlFile(ADDON_CONFIG_FILENAME); + return config; + } + + public File getDataFolder() { + return dataFolder; + } + + public AddonDescription getDescription() { + return description; + } + + /** + * @return the file + */ + public File getFile() { + return file; + } + + public Logger getLogger() { + return getBSkyBlock().getLogger(); + } + + public Server getServer() { + return getBSkyBlock().getServer(); + } + + public boolean isEnabled() { + return enabled; + } + + private FileConfiguration loadYamlFile(String file) { + File yamlFile = new File(dataFolder, file); + + YamlConfiguration config = null; + if (yamlFile.exists()) { + try { + config = new YamlConfiguration(); + config.load(yamlFile); + } catch (Exception e) { + e.printStackTrace(); + } + } + return config; + } + + public void registerListener(Listener listener){ + BSkyBlock.getInstance().getServer().getPluginManager().registerEvents(listener, BSkyBlock.getInstance()); + } + + public void saveDefaultConfig() { + saveResource(ADDON_CONFIG_FILENAME, true); + config = loadYamlFile(ADDON_CONFIG_FILENAME); + } + + /** + * Saves a resource contained in this add-on's jar file. + * @param resourcePath + * @param replace + */ + public void saveResource(String resourcePath, boolean replace) { + if (resourcePath == null || resourcePath.equals("")) { + throw new IllegalArgumentException("ResourcePath cannot be null or empty"); + } + + resourcePath = resourcePath.replace('\\', '/'); + InputStream in = null; + try { + JarFile jar = new JarFile(file); + JarEntry config = jar.getJarEntry(resourcePath); + if (config != null) { + in = jar.getInputStream(config); + } + if (in == null) { + jar.close(); + throw new IllegalArgumentException("The embedded resource '" + resourcePath + "' cannot be found in " + jar.getName()); + } + File outFile = new File(dataFolder, resourcePath); + int lastIndex = resourcePath.lastIndexOf('/'); + File outDir = new File(dataFolder, resourcePath.substring(0, lastIndex >= 0 ? lastIndex : 0)); + + if (!outDir.exists()) { + outDir.mkdirs(); + } + + + if (!outFile.exists() || replace) { + OutputStream out = new FileOutputStream(outFile); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } else { + getLogger().warning("Could not save " + outFile.getName() + " to " + outFile + " because " + outFile.getName() + " already exists."); + } + jar.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + public void setDataFolder(File file) { + this.dataFolder = file; + } + + public void setDescription(AddonDescription desc){ + this.description = desc; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * @param f the file to set + */ + public void setFile(File f) { + this.file = f; + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/AddonClassLoader.java b/src/main/java/us/tastybento/bskyblock/api/addons/AddonClassLoader.java new file mode 100644 index 000000000..fcc9f42eb --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/AddonClassLoader.java @@ -0,0 +1,67 @@ +package us.tastybento.bskyblock.api.addons; + +import java.io.BufferedReader; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Map; + +import us.tastybento.bskyblock.api.addons.AddonDescription.AddonDescriptionBuilder; +import us.tastybento.bskyblock.api.addons.exception.InvalidAddonFormatException; +import us.tastybento.bskyblock.api.addons.exception.InvalidAddonInheritException; + +/** + * @author Tastybento, ComminQ + */ +public class AddonClassLoader extends URLClassLoader { + + public Addon addon; + + public AddonClassLoader(Mapdata, File path, BufferedReader reader, ClassLoader loaders) throws InvalidAddonInheritException, MalformedURLException, InvalidAddonFormatException { + super(new URL[]{path.toURI().toURL()}, loaders); + + Addon addon = null; + + Class javaClass = null; + try { + //Bukkit.getLogger().info("data " + data.get("main")); + /* + for (Entry en : data.entrySet()) { + Bukkit.getLogger().info(en.getKey() + " => " + en.getValue()); + }*/ + javaClass = Class.forName(data.get("main"), true, this); + if(data.get("main").contains("us.tastybento")){ + throw new InvalidAddonFormatException("Packages declaration cannot start with 'us.tastybento'"); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + Class addonClass; + try{ + addonClass = javaClass.asSubclass(Addon.class); + }catch(ClassCastException e){ + throw new InvalidAddonInheritException("Main class doesn't not extends super class 'Addon'"); + } + + try { + addon = addonClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + addon.setDescription(this.asDescription(data)); + + this.addon = addon; + } + + private AddonDescription asDescription(Map data){ + String[] authors = data.get("authors").split("\\,"); + + return new AddonDescriptionBuilder(data.get("name")) + .withVersion(data.get("version")) + .withAuthor(authors).build(); + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/AddonDescription.java b/src/main/java/us/tastybento/bskyblock/api/addons/AddonDescription.java new file mode 100644 index 000000000..42473922c --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/AddonDescription.java @@ -0,0 +1,111 @@ +package us.tastybento.bskyblock.api.addons; + +import java.util.Arrays; +import java.util.List; + +/** + * @author Tastybento, Poslovitch + */ +public final class AddonDescription { + + private String main; + private String name; + private String version; + private String description; + private List authors; + + public AddonDescription() {} + + public AddonDescription(String main, String name, String version, String description, List authors) { + this.main = main; + this.name = name; + this.version = version; + this.description = description; + this.authors = authors; + } + + /** + * @param main the main to set + */ + public void setMain(String main) { + this.main = main; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @param authors the authors to set + */ + public void setAuthors(List authors) { + this.authors = authors; + } + + public String getName() { + return name; + } + + public String getMain() { + return main; + } + + public String getVersion() { + return version; + } + + public String getDescription() { + return description; + } + + public List getAuthors() { + return authors; + } + + public static class AddonDescriptionBuilder{ + + public AddonDescription description; + + public AddonDescriptionBuilder(String name){ + description = new AddonDescription(); + description.setName(name); + } + + public AddonDescriptionBuilder withAuthor(String... authors){ + this.description.setAuthors(Arrays.asList(authors)); + return this; + } + + public AddonDescriptionBuilder withDescription(String desc){ + this.description.setDescription(desc); + return this; + } + + public AddonDescriptionBuilder withVersion(String version){ + this.description.setVersion(version); + return this; + } + + public AddonDescription build(){ + return this.description; + } + + } +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/AddonInterface.java b/src/main/java/us/tastybento/bskyblock/api/addons/AddonInterface.java new file mode 100644 index 000000000..07fb8250e --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/AddonInterface.java @@ -0,0 +1,7 @@ +package us.tastybento.bskyblock.api.addons; + +public interface AddonInterface { + void onEnable(); + void onDisable(); + default void onLoad() {} +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/AddonState.java b/src/main/java/us/tastybento/bskyblock/api/addons/AddonState.java new file mode 100644 index 000000000..0a4b641bd --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/AddonState.java @@ -0,0 +1,49 @@ +package us.tastybento.bskyblock.api.addons; + +/** + * Represents the current run-time state of a {@link Addon}. + * + * @author Poslovitch + * @since 1.0 + */ +public enum AddonState { + /** + * The addon is being loaded. It has just been found by the {@link us.tastybento.bskyblock.managers.AddonsManager}. + */ + LOADING, + + /** + * The addon has been correctly loaded and is being enabled. It is currently registering its content into the different Managers. + */ + ENABLING, + + /** + * The addon has been correctly enabled and is now fully working. + */ + ENABLED, + + /** + * The addon has somehow been asked to reload and is doing so. The reload could have been ordered by an user or another addon. + */ + RELOADING, + + /** + * The addon is being disabled. This could have been ordered by an user or by the server shutting down. + */ + DISABLING, + + /** + * The addon is fully disabled. + */ + DISABLED, + + /** + * The addon has not been loaded because it requires a different version of BSkyBlock or of the server software. + */ + INCOMPATIBLE, + + /** + * The addon loading or enabling process has been interrupted by an unhandled error. + */ + ERROR +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonDisableEvent.java b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonDisableEvent.java new file mode 100644 index 000000000..76e29830a --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonDisableEvent.java @@ -0,0 +1,25 @@ +package us.tastybento.bskyblock.api.addons.event; + +import us.tastybento.bskyblock.api.addons.Addon; + +/** + * This event is run when an addon is getting disabled. + * + * @author ComminQ + */ +public class AddonDisableEvent extends PremadeEvent { + private Addon addon; + + public AddonDisableEvent(Addon addon){ + this.addon = addon; + } + + public Addon getAddon() { + return addon; + } + + public void setAddon(Addon addon) { + this.addon = addon; + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonEnableEvent.java b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonEnableEvent.java new file mode 100644 index 000000000..ab6516fca --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonEnableEvent.java @@ -0,0 +1,25 @@ +package us.tastybento.bskyblock.api.addons.event; + +import us.tastybento.bskyblock.api.addons.Addon; + +/** + * This event is run when an addon is getting enabled. + * + * @author ComminQ + */ +public class AddonEnableEvent extends PremadeEvent { + private Addon addon; + + public AddonEnableEvent(Addon addon){ + this.addon = addon; + } + + public Addon getAddon() { + return addon; + } + + public void setAddon(Addon addon) { + this.addon = addon; + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonLoadEvent.java b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonLoadEvent.java new file mode 100644 index 000000000..452a1f1e2 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/event/AddonLoadEvent.java @@ -0,0 +1,25 @@ +package us.tastybento.bskyblock.api.addons.event; + +import us.tastybento.bskyblock.api.addons.Addon; + +/** + * This event is run when an addon is getting loaded. + * + * @author ComminQ + */ +public class AddonLoadEvent extends PremadeEvent { + private Addon addon; + + public AddonLoadEvent(Addon addon){ + this.addon = addon; + } + + public Addon getAddon() { + return addon; + } + + public void setAddon(Addon addon) { + this.addon = addon; + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/event/PremadeEvent.java b/src/main/java/us/tastybento/bskyblock/api/addons/event/PremadeEvent.java new file mode 100644 index 000000000..d7cb5a687 --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/event/PremadeEvent.java @@ -0,0 +1,19 @@ +package us.tastybento.bskyblock.api.addons.event; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public abstract class PremadeEvent extends Event{ + + public static final HandlerList handlers = new HandlerList(); + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandleList(){ + return handlers; + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/exception/AddonException.java b/src/main/java/us/tastybento/bskyblock/api/addons/exception/AddonException.java new file mode 100644 index 000000000..a0960e33e --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/exception/AddonException.java @@ -0,0 +1,14 @@ +package us.tastybento.bskyblock.api.addons.exception; + +public abstract class AddonException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 4203162022348693854L; + + public AddonException(String errorMessage){ + super("AddonException : " + errorMessage); + } + +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonFormatException.java b/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonFormatException.java new file mode 100644 index 000000000..8f683b18b --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonFormatException.java @@ -0,0 +1,30 @@ +package us.tastybento.bskyblock.api.addons.exception; + +import java.util.logging.Level; + +import org.bukkit.Bukkit; + +public class InvalidAddonFormatException extends AddonException { + + /** + * + */ + private static final long serialVersionUID = 7741502900847049986L; + + public InvalidAddonFormatException(String errorMessage) { + super(errorMessage); + } + + @Override + public void printStackTrace(){ + super.printStackTrace(); + + System.out.println(""); + + Bukkit.getLogger().log(Level.WARNING, " Basic format : (addon.yml)"); + Bukkit.getLogger().log(Level.WARNING, " main: path.to.your.MainClass"); + Bukkit.getLogger().log(Level.WARNING, " name: "); + Bukkit.getLogger().log(Level.WARNING, " authors: | "); + Bukkit.getLogger().log(Level.WARNING, " version: YourVersion"); + } +} diff --git a/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonInheritException.java b/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonInheritException.java new file mode 100644 index 000000000..00ee7cb2c --- /dev/null +++ b/src/main/java/us/tastybento/bskyblock/api/addons/exception/InvalidAddonInheritException.java @@ -0,0 +1,14 @@ +package us.tastybento.bskyblock.api.addons.exception; + +public class InvalidAddonInheritException extends AddonException { + + /** + * + */ + private static final long serialVersionUID = -5847358994397613244L; + + public InvalidAddonInheritException(String errorMessage) { + super(errorMessage); + } + +}