AddonsAPI - Polishing the API

Temporarily remove api/addons folder to rename files
This commit is contained in:
Florian CUNY 2017-12-28 14:49:27 +01:00
parent 687a71876d
commit 86ad00acab
14 changed files with 157 additions and 711 deletions

View File

@ -9,7 +9,7 @@ import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import us.tastybento.bskyblock.api.BSBModule;
import us.tastybento.bskyblock.api.addons.event.AddOnDisableEvent;
import us.tastybento.bskyblock.api.addons.event.AddonDisableEvent;
import us.tastybento.bskyblock.commands.AdminCommand;
import us.tastybento.bskyblock.commands.IslandCommand;
import us.tastybento.bskyblock.config.PluginConfig;
@ -20,7 +20,7 @@ import us.tastybento.bskyblock.database.managers.island.IslandsManager;
import us.tastybento.bskyblock.generators.IslandWorld;
import us.tastybento.bskyblock.listeners.JoinLeaveListener;
import us.tastybento.bskyblock.listeners.PanelListener;
import us.tastybento.bskyblock.managers.AddOnManager;
import us.tastybento.bskyblock.managers.AddonsManager;
import us.tastybento.bskyblock.managers.CommandsManager;
import us.tastybento.bskyblock.managers.LocalesManager;
import us.tastybento.bskyblock.util.Util;
@ -45,7 +45,7 @@ public class BSkyBlock extends JavaPlugin implements BSBModule {
// Managers
private CommandsManager commandsManager;
private LocalesManager localesManager;
private AddOnManager addonsManager;
private AddonsManager addonsManager;
@Override
public void onEnable(){
@ -106,10 +106,9 @@ public class BSkyBlock extends JavaPlugin implements BSBModule {
registerListeners();
// Load addons
addonsManager = new AddOnManager();
addonsManager = new AddonsManager();
addonsManager.loadAddons();
/*
*DEBUG CODE
Island loadedIsland = islandsManager.getIsland(owner);
@ -150,7 +149,7 @@ public class BSkyBlock extends JavaPlugin implements BSBModule {
// Unload addons
addonsManager.getAddons().forEach(addon -> {
addon.onDisable();
getServer().getPluginManager().callEvent(new AddOnDisableEvent(addon));
getServer().getPluginManager().callEvent(new AddonDisableEvent(addon));
System.out.println("Disabling " + addon.getDescription().getName() + "...");
});

View File

@ -1,167 +0,0 @@
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 ben, 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;
}
}

View File

@ -1,65 +0,0 @@
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;
public class AddOnClassLoader extends URLClassLoader{
public AddOn addon;
public AddOnClassLoader(Map<String, String>data, 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<String, String> 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<? extends AddOn> 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<String, String> data){
String[] authors = data.get("authors").split("\\,");
return new AddonDescriptionBuilder(data.get("name"))
.withVersion(data.get("version"))
.withAuthor(authors).build();
}
}

View File

@ -1,108 +0,0 @@
package us.tastybento.bskyblock.api.addons;
import java.util.Arrays;
import java.util.List;
public final class AddOnDescription {
private String main;
private String name;
private String version;
private String description;
private List<String> authors;
public AddOnDescription() {}
public AddOnDescription(String main, String name, String version, String description, List<String> 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<String> 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<String> 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;
}
}
}

View File

@ -1,7 +0,0 @@
package us.tastybento.bskyblock.api.addons;
public interface AddOnInterface {
public abstract void onEnable();
public abstract void onDisable();
public default void onLoad() {};
}

View File

@ -1,49 +0,0 @@
package us.tastybento.bskyblock.api.addons;
/**
* Represents the current run-time state of a {@link BSBAddon}.
*
* @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
}

View File

@ -1,29 +0,0 @@
package us.tastybento.bskyblock.api.addons.event;
import us.tastybento.bskyblock.api.addons.AddOn;
public class AddOnDisableEvent extends PremadeEvent{
/**
* @author ComminQ_Q
*
* Event active when a addon is being disabled
* // TODO You can disable addon IG
*
*/
private AddOn addon;
public AddOnDisableEvent(AddOn addon){
this.addon = addon;
}
public AddOn getAddon() {
return addon;
}
public void setAddon(AddOn addon) {
this.addon = addon;
}
}

View File

@ -1,29 +0,0 @@
package us.tastybento.bskyblock.api.addons.event;
import us.tastybento.bskyblock.api.addons.AddOn;
public class AddOnEnableEvent extends PremadeEvent{
/**
* @author ComminQ_Q
*
* Event active when a addon is being disabled
* // TODO You can enable Addon IG
*
*/
private AddOn addon;
public AddOnEnableEvent(AddOn addon){
this.addon = addon;
}
public AddOn getAddon() {
return addon;
}
public void setAddon(AddOn addon) {
this.addon = addon;
}
}

View File

@ -1,21 +0,0 @@
package us.tastybento.bskyblock.api.addons.event;
import us.tastybento.bskyblock.api.addons.AddOn;
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;
}
}

View File

@ -1,19 +0,0 @@
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;
}
}

View File

@ -1,14 +0,0 @@
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);
}
}

View File

@ -1,33 +0,0 @@
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: <NameOfYourModule>");
Bukkit.getLogger().log(Level.WARNING, " authors: <AuthorA> | <AuthorA, AuthorB>");
Bukkit.getLogger().log(Level.WARNING, " version: YourVersion");
}
}

View File

@ -1,14 +0,0 @@
package us.tastybento.bskyblock.api.addons.exception;
public class InvalidAddOnInheritException extends AddOnException{
/**
*
*/
private static final long serialVersionUID = -5847358994397613244L;
public InvalidAddOnInheritException(String errorMessage) {
super(errorMessage);
}
}

View File

@ -1,150 +1,152 @@
package us.tastybento.bskyblock.managers;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.bukkit.Bukkit;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.addons.AddOn;
import us.tastybento.bskyblock.api.addons.AddOnClassLoader;
import us.tastybento.bskyblock.api.addons.event.AddOnEnableEvent;
import us.tastybento.bskyblock.api.addons.event.AddOnLoadEvent;
import us.tastybento.bskyblock.api.addons.exception.InvalidAddOnFormatException;
import us.tastybento.bskyblock.api.addons.exception.InvalidAddOnInheritException;
public class AddOnManager {
private static final boolean DEBUG = false;
private List<AddOn> addons;
private List<AddOnClassLoader> loader;
public AddOnManager() {
this.addons = new ArrayList<>();
this.loader = new ArrayList<>();
}
/**
* Loads all the addons from the addons folder
*/
public void loadAddons() {
File f = new File(BSkyBlock.getInstance().getDataFolder(), "addons");
if (f.exists()) {
if (f.isDirectory()) {
for (File file : f.listFiles()) {
if (!file.isDirectory()) {
try {
this.loadAddon(file);
} catch (InvalidAddOnFormatException e) {
e.printStackTrace();
} catch (InvalidAddOnInheritException e) {
e.printStackTrace();
}
}
}
}
} else {
try {
f.mkdir();
} catch (SecurityException e) {
e.printStackTrace();
if (DEBUG) {
Bukkit.getLogger().severe("Cannot create folder 'addons' (Permission ?)");
}
}
}
this.addons.stream().forEach(addon -> {
addon.onEnable();
BSkyBlock.getInstance().getServer().getPluginManager().callEvent(new AddOnEnableEvent(addon));
addon.setEnabled(true);
BSkyBlock.getInstance().getLogger().info("Enabling " + addon.getDescription().getName() + "...");
});
}
public AddOn getAddonByName(String name){
if(name.equals("")) return null;
for(AddOn m : this.addons){
if(m.getDescription().getName().contains(name)) return m;
}
return null;
}
private void loadAddon(File f) throws InvalidAddOnFormatException, InvalidAddOnInheritException {
try {
AddOn addon = null;
if (!f.getName().contains(".jar")) {
return;
}
JarFile jar = new JarFile(f);
JarEntry entry = jar.getJarEntry("addon.yml");
if (entry == null) {
jar.close();
throw new InvalidAddOnFormatException("Addon doesn't contains description file");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(jar.getInputStream(entry)));
Map<String, String> data = this.data(reader);
AddOnClassLoader loader = null;
loader = new AddOnClassLoader(data, f, reader, this.getClass().getClassLoader());
this.loader.add(loader);
addon = loader.addon;
addon.setDataFolder(new File(f.getParent(), f.getName().replace(".jar", "")));
addon.setFile(f);
AddOnLoadEvent event = new AddOnLoadEvent(addon);
Bukkit.getPluginManager().callEvent(event);
this.addons.add(addon);
addon.onLoad();
BSkyBlock.getInstance().getLogger().info("Loading BSkyBlock addon " + addon.getDescription().getName() + "...");
jar.close();
} catch (IOException e) {
if (DEBUG) {
BSkyBlock.getInstance().getLogger().info(f.getName() + "is not a jarfile, ignoring...");
}
}
}
private Map<String, String> data(BufferedReader reader) {
Map<String, String> map = new HashMap<>();
reader.lines().forEach(string -> {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: " + string);
String[] data = string.split("\\: ");
if (data.length > 1) {
map.put(data[0], data[1].substring(0, data[1].length()));
}
});
return map;
}
public List<AddOn> getAddons() {
return addons;
}
public List<AddOnClassLoader> getLoader() {
return loader;
}
public void setLoader(List<AddOnClassLoader> loader) {
this.loader = loader;
}
}
package us.tastybento.bskyblock.managers;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.bukkit.Bukkit;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.addons.Addon;
import us.tastybento.bskyblock.api.addons.AddonClassLoader;
import us.tastybento.bskyblock.api.addons.event.AddonEnableEvent;
import us.tastybento.bskyblock.api.addons.event.AddonLoadEvent;
import us.tastybento.bskyblock.api.addons.exception.InvalidAddonFormatException;
import us.tastybento.bskyblock.api.addons.exception.InvalidAddonInheritException;
/**
* @author Tastybento, ComminQ
*/
public final class AddonsManager {
private static final boolean DEBUG = false;
private List<Addon> addons;
private List<AddonClassLoader> loader;
public AddonsManager() {
this.addons = new ArrayList<>();
this.loader = new ArrayList<>();
}
/**
* Loads all the addons from the addons folder
*/
public void loadAddons() {
File f = new File(BSkyBlock.getInstance().getDataFolder(), "addons");
if (f.exists()) {
if (f.isDirectory()) {
for (File file : f.listFiles()) {
if (!file.isDirectory()) {
try {
this.loadAddon(file);
} catch (InvalidAddonFormatException e) {
e.printStackTrace();
} catch (InvalidAddonInheritException e) {
e.printStackTrace();
}
}
}
}
} else {
try {
f.mkdir();
} catch (SecurityException e) {
e.printStackTrace();
if (DEBUG) {
Bukkit.getLogger().severe("Cannot create folder 'addons' (Permission ?)");
}
}
}
this.addons.stream().forEach(addon -> {
addon.onEnable();
BSkyBlock.getInstance().getServer().getPluginManager().callEvent(new AddonEnableEvent(addon));
addon.setEnabled(true);
BSkyBlock.getInstance().getLogger().info("Enabling " + addon.getDescription().getName() + "...");
});
}
public Addon getAddonByName(String name){
if(name.equals("")) return null;
for(Addon m : this.addons){
if(m.getDescription().getName().contains(name)) return m;
}
return null;
}
private void loadAddon(File f) throws InvalidAddonFormatException, InvalidAddonInheritException {
try {
Addon addon = null;
if (!f.getName().contains(".jar")) {
return;
}
JarFile jar = new JarFile(f);
JarEntry entry = jar.getJarEntry("addon.yml");
if (entry == null) {
jar.close();
throw new InvalidAddonFormatException("Addon doesn't contains description file");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(jar.getInputStream(entry)));
Map<String, String> data = this.data(reader);
AddonClassLoader loader = null;
loader = new AddonClassLoader(data, f, reader, this.getClass().getClassLoader());
this.loader.add(loader);
addon = loader.addon;
addon.setDataFolder(new File(f.getParent(), f.getName().replace(".jar", "")));
addon.setFile(f);
Bukkit.getPluginManager().callEvent(new AddonLoadEvent(addon));
this.addons.add(addon);
addon.onLoad();
BSkyBlock.getInstance().getLogger().info("Loading BSkyBlock addon " + addon.getDescription().getName() + "...");
jar.close();
} catch (IOException e) {
if (DEBUG) {
BSkyBlock.getInstance().getLogger().info(f.getName() + "is not a jarfile, ignoring...");
}
}
}
private Map<String, String> data(BufferedReader reader) {
Map<String, String> map = new HashMap<>();
reader.lines().forEach(string -> {
if (DEBUG)
Bukkit.getLogger().info("DEBUG: " + string);
String[] data = string.split("\\: ");
if (data.length > 1) {
map.put(data[0], data[1].substring(0, data[1].length()));
}
});
return map;
}
public List<Addon> getAddons() {
return addons;
}
public List<AddonClassLoader> getLoader() {
return loader;
}
public void setLoader(List<AddonClassLoader> loader) {
this.loader = loader;
}
}