From 805f7f666a68aee6950c9bda6ed5d25dc20bfc40 Mon Sep 17 00:00:00 2001 From: ImDaBigBoss <67973871+ImDaBigBoss@users.noreply.github.com> Date: Wed, 12 Jan 2022 13:50:54 +0100 Subject: [PATCH] Added javadocs & fixed API version & more --- .../geyser/api/extension/Extension.java | 51 ---------- .../api/extension/ExtensionDescription.java | 33 ++++++- .../geyser/api/extension/ExtensionLoader.java | 42 +++++++- .../geyser/api/extension/ExtensionLogger.java | 1 + .../geyser/api/extension/GeyserExtension.java | 95 ++++++++++++++----- .../InvalidDescriptionException.java | 3 + .../exception/InvalidExtensionException.java | 3 + .../extension/GeyserExtensionDescription.java | 21 ++-- .../extension/GeyserExtensionLoader.java | 28 +++--- .../extension/GeyserExtensionManager.java | 91 +++++++++--------- 10 files changed, 214 insertions(+), 154 deletions(-) delete mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java deleted file mode 100644 index 8a820d8ac..000000000 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/Extension.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.api.extension; - -import org.geysermc.api.GeyserApiBase; -import java.io.File; -import java.io.InputStream; - -public interface Extension { - void onLoad(); - void onEnable(); - void onDisable(); - - boolean isEnabled(); - boolean isDisabled(); - - File dataFolder(); - ExtensionDescription description(); - String name(); - - InputStream getResource(String filename); - void saveResource(String filename, boolean replace); - - ClassLoader classLoader(); - ExtensionLoader extensionLoader(); - ExtensionLogger logger(); - GeyserApiBase geyserApi(); -} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java index 0f752e72d..d32300e09 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionDescription.java @@ -25,12 +25,41 @@ package org.geysermc.geyser.api.extension; -import java.util.*; +import java.util.List; public interface ExtensionDescription { + /** + * Gets the extension's name + * + * @return the extension's name + */ String name(); + + /** + * Gets the extension's main class + * + * @return the extension's main class + */ String main(); - List ApiVersions(); + + /** + * Gets the extension's api version + * + * @return the extension's api version + */ + String ApiVersion(); + + /** + * Gets the extension's description + * + * @return the extension's description + */ String version(); + + /** + * Gets the extension's authors + * + * @return the extension's authors + */ List authors(); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java index c558957eb..291a34daf 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLoader.java @@ -27,15 +27,47 @@ package org.geysermc.geyser.api.extension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; import org.geysermc.geyser.api.extension.exception.InvalidExtensionException; - import java.io.File; -import java.util.regex.Pattern; public interface ExtensionLoader { + /** + * Loads an extension from a given file + * + * @param file the file to load the extension from + * @return the loaded extension + * @throws InvalidExtensionException + */ GeyserExtension loadExtension(File file) throws InvalidExtensionException; + + /** + * Gets an extension's description from a given file + * + * @param file the file to get the description from + * @return the extension's description + * @throws InvalidDescriptionException + */ ExtensionDescription extensionDescription(File file) throws InvalidDescriptionException; - Pattern[] extensionFilters(); + + /** + * Gets a class by its name from the extension's classloader + * + * @param name the name of the class + * @return the class + * @throws ClassNotFoundException + */ Class classByName(final String name) throws ClassNotFoundException; - void enableExtension(Extension extension); - void disableExtension(Extension extension); + + /** + * Enables an extension + * + * @param extension the extension to enable + */ + void enableExtension(GeyserExtension extension); + + /** + * Disables an extension + * + * @param extension the extension to disable + */ + void disableExtension(GeyserExtension extension); } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java index 6b5d86153..60ee45572 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/ExtensionLogger.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.api.extension; public interface ExtensionLogger { /** * Get the logger prefix + * * @return the logger prefix */ String prefix(); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java index 3ed66b444..a3f911580 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/GeyserExtension.java @@ -30,34 +30,52 @@ import java.io.*; import java.net.URL; import java.net.URLConnection; -public class GeyserExtension implements Extension { +public class GeyserExtension { private boolean initialized = false; private boolean enabled = false; private File file = null; private File dataFolder = null; private ClassLoader classLoader = null; - private ExtensionLoader loader; - private ExtensionLogger logger; + private ExtensionLoader loader = null; + private ExtensionLogger logger = null; private ExtensionDescription description = null; private GeyserApiBase api = null; - @Override + /** + * Called when the extension is loaded + */ public void onLoad() { + } - @Override + /** + * Called when the extension is enabled + */ public void onEnable() { + } - @Override + /** + * Called when the extension is disabled + */ public void onDisable() { + } - @Override + /** + * Gets if the extension is enabled + * + * @return true if the extension is enabled + */ public boolean isEnabled() { return this.enabled; } + /** + * Gets if the extension is enabled + * + * @return true if the extension is enabled + */ public void setEnabled(boolean value) { if (this.enabled != value) { this.enabled = value; @@ -69,27 +87,34 @@ public class GeyserExtension implements Extension { } } - @Override - public boolean isDisabled() { - return !this.enabled; - } - - @Override + /** + * Gets the extension's data folder + * + * @return the extension's data folder + */ public File dataFolder() { return this.dataFolder; } - @Override + /** + * Gets the extension's description + * + * @return the extension's description + */ public ExtensionDescription description() { return this.description; } - @Override + /** + * Gets the extension's name + * + * @return the extension's name + */ public String name() { return this.description.name(); } - public void init(GeyserApiBase api, ExtensionLogger logger, ExtensionLoader loader, ExtensionDescription description, File dataFolder, File file) { + public void init(GeyserApiBase api, ExtensionLoader loader, ExtensionLogger logger, ExtensionDescription description, File dataFolder, File file) { if (!this.initialized) { this.initialized = true; this.file = file; @@ -102,7 +127,12 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Gets a resource from the extension jar file + * + * @param filename the file name + * @return the input stream + */ public InputStream getResource(String filename) { if (filename == null) { throw new IllegalArgumentException("Filename cannot be null"); @@ -123,7 +153,12 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Saves a resource from the extension jar file to the extension's data folder + * + * @param filename the file name + * @param replace whether to replace the file if it already exists + */ public void saveResource(String filename, boolean replace) { if (filename == null || filename.equals("")) { throw new IllegalArgumentException("ResourcePath cannot be null or empty"); @@ -161,22 +196,38 @@ public class GeyserExtension implements Extension { } } - @Override + /** + * Gets the extension's class loader + * + * @return the extension's class loader + */ public ClassLoader classLoader() { return this.classLoader; } - @Override + /** + * Gets the extension's loader + * + * @return the extension's loader + */ public ExtensionLoader extensionLoader() { return this.loader; } - @Override + /** + * Gets the extension's logger + * + * @return the extension's logger + */ public ExtensionLogger logger() { return this.logger; } - @Override + /** + * Gets the {@link GeyserApiBase} instance + * + * @return the {@link GeyserApiBase} instance + */ public GeyserApiBase geyserApi() { return this.api; } diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java index ca2fabad9..1fe88e9e9 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidDescriptionException.java @@ -25,6 +25,9 @@ package org.geysermc.geyser.api.extension.exception; +/** + * Thrown when an extension's description is invalid. + */ public class InvalidDescriptionException extends Exception { public InvalidDescriptionException(Throwable cause) { super(cause); diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java index 1053e6d50..7fb6b6922 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/extension/exception/InvalidExtensionException.java @@ -25,6 +25,9 @@ package org.geysermc.geyser.api.extension.exception; +/** + * Thrown when an extension is invalid. + */ public class InvalidExtensionException extends Exception { public InvalidExtensionException(Throwable cause) { super(cause); diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java index ee215f2e4..e2a09c598 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java @@ -33,7 +33,7 @@ import java.util.*; public class GeyserExtensionDescription implements org.geysermc.geyser.api.extension.ExtensionDescription { private String name; private String main; - private List api; + private String api; private String version; private final List authors = new ArrayList<>(); @@ -47,19 +47,18 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten private void loadMap(Map yamlMap) throws InvalidDescriptionException { this.name = ((String) yamlMap.get("name")).replaceAll("[^A-Za-z0-9 _.-]", ""); if (this.name.equals("")) { - throw new InvalidDescriptionException("Invalid extension name"); + throw new InvalidDescriptionException("Invalid extension name, cannot be empty"); } this.name = this.name.replace(" ", "_"); this.version = String.valueOf(yamlMap.get("version")); this.main = (String) yamlMap.get("main"); Object api = yamlMap.get("api"); - if (api instanceof List) { - this.api = (List) api; + if (api instanceof String) { + this.api = (String) api; } else { - List list = new ArrayList<>(); - list.add((String) api); - this.api = list; + this.api = "0.0.0"; + throw new InvalidDescriptionException("Invalid api version format, should be a string: major.minor.patch"); } if (yamlMap.containsKey("author")) { @@ -67,7 +66,11 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten } if (yamlMap.containsKey("authors")) { - this.authors.addAll((Collection) yamlMap.get("authors")); + try { + this.authors.addAll((Collection) yamlMap.get("authors")); + } catch (Exception e) { + throw new InvalidDescriptionException("Invalid authors format, should be a list of strings", e); + } } } @@ -82,7 +85,7 @@ public class GeyserExtensionDescription implements org.geysermc.geyser.api.exten } @Override - public List ApiVersions() { + public String ApiVersion() { return api; } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java index 9b741fb2d..a7e4bac3d 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionLoader.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.extension; import org.geysermc.api.Geyser; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionLoader; import org.geysermc.geyser.api.extension.GeyserExtension; import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException; @@ -80,7 +79,7 @@ public class GeyserExtensionLoader implements ExtensionLoader { private void setup(GeyserExtension extension, GeyserExtensionDescription description, File dataFolder, File file) { GeyserExtensionLogger logger = new GeyserExtensionLogger(GeyserImpl.getInstance().getLogger(), description.name()); - extension.init(Geyser.api(), logger, this, description, dataFolder, file); + extension.init(Geyser.api(), this, logger, description, dataFolder, file); extension.onLoad(); } @@ -131,7 +130,6 @@ public class GeyserExtensionLoader implements ExtensionLoader { } } - @Override public Pattern[] extensionFilters() { return new Pattern[] { Pattern.compile("^.+\\.jar$") }; } @@ -152,33 +150,29 @@ public class GeyserExtensionLoader implements ExtensionLoader { } } - public void setClass(String name, final Class clazz) { + void setClass(String name, final Class clazz) { if(!classes.containsKey(name)) { classes.put(name,clazz); } } - protected void removeClass(String name) { + void removeClass(String name) { Class clazz = classes.remove(name); } @Override - public void enableExtension(Extension extension) { - if (extension instanceof GeyserExtension) { - if(!extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); - ((GeyserExtension) extension).setEnabled(true); - } + public void enableExtension(GeyserExtension extension) { + if (!extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Enabled extension " + extension.description().name()); + extension.setEnabled(true); } } @Override - public void disableExtension(Extension extension) { - if (extension instanceof GeyserExtension) { - if(extension.isEnabled()) { - GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); - ((GeyserExtension) extension).setEnabled(false); - } + public void disableExtension(GeyserExtension extension) { + if (extension.isEnabled()) { + GeyserImpl.getInstance().getLogger().info("Disabled extension " + extension.description().name()); + extension.setEnabled(false); } } } diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java index c06feba1e..edda15ade 100644 --- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java +++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionManager.java @@ -26,9 +26,9 @@ package org.geysermc.geyser.extension; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.api.extension.Extension; import org.geysermc.geyser.api.extension.ExtensionDescription; import org.geysermc.geyser.api.extension.GeyserExtension; + import java.io.File; import java.lang.reflect.Constructor; import java.util.*; @@ -37,35 +37,34 @@ import java.util.regex.Pattern; public class GeyserExtensionManager { private static GeyserExtensionManager geyserExtensionManager = null; - protected Map extensions = new LinkedHashMap<>(); + protected Map extensions = new LinkedHashMap<>(); protected Map fileAssociations = new HashMap<>(); public static void init() { GeyserImpl.getInstance().getLogger().info("Loading extensions..."); + geyserExtensionManager = new GeyserExtensionManager(); geyserExtensionManager.registerInterface(GeyserExtensionLoader.class); geyserExtensionManager.loadExtensions(new File("extensions")); - GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extensions."); - for (Extension extension : geyserExtensionManager.getExtensions().values()) { - if (!extension.isEnabled()) { - geyserExtensionManager.enableExtension(extension); - } - } + String plural = geyserExtensionManager.extensions.size() == 1 ? "" : "s"; + GeyserImpl.getInstance().getLogger().info("Loaded " + geyserExtensionManager.extensions.size() + " extension" + plural); + + geyserExtensionManager.enableExtensions(); } public static GeyserExtensionManager getExtensionManager() { return geyserExtensionManager; } - public Extension getExtension(String name) { + public GeyserExtension getExtension(String name) { if (this.extensions.containsKey(name)) { return this.extensions.get(name); } return null; } - public Map getExtensions() { + public Map getExtensions() { return this.extensions; } @@ -124,8 +123,8 @@ public class GeyserExtensionManager { return null; } - public Map loadExtensions(File dictionary) { - if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { + public Map loadExtensions(File dictionary) { + if (GeyserImpl.VERSION.equalsIgnoreCase("dev")) { // If your IDE says this is always true, ignore it, it isn't. GeyserImpl.getInstance().getLogger().error("Cannot load extensions in a development environment, aborting extension loading"); return new HashMap<>(); } @@ -134,6 +133,8 @@ public class GeyserExtensionManager { return new HashMap<>(); } + String[] apiVersion = GeyserImpl.VERSION.split("\\."); + if (!dictionary.exists()) { dictionary.mkdir(); } @@ -142,7 +143,7 @@ public class GeyserExtensionManager { } Map extensions = new LinkedHashMap<>(); - Map loadedExtensions = new LinkedHashMap<>(); + Map loadedExtensions = new LinkedHashMap<>(); for (final GeyserExtensionLoader loader : this.fileAssociations.values()) { for (File file : dictionary.listFiles((dir, name) -> { @@ -167,47 +168,35 @@ public class GeyserExtensionManager { continue; } - boolean compatible = false; - - for (String version : description.ApiVersions()) { - try { - //Check the format: majorVersion.minorVersion.patch - if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", version)) { - throw new IllegalArgumentException(); - } - } catch (NullPointerException | IllegalArgumentException e) { - GeyserImpl.getInstance().getLogger().error("Could't load extension " + name + ": Wrong API format"); - continue; + try { + //Check the format: majorVersion.minorVersion.patch + if (!Pattern.matches("^[0-9]+\\.[0-9]+\\.[0-9]+$", description.ApiVersion())) { + throw new IllegalArgumentException(); } - - String[] versionArray = version.split("\\."); - String[] apiVersion = GeyserImpl.VERSION.split("\\."); - - //Completely different API version - if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); - continue; - } - - //If the extension requires new API features, being backwards compatible - if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); - continue; - } - - compatible = true; - break; + } catch (NullPointerException | IllegalArgumentException e) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version format, should be 'majorVersion.minorVersion.patch', current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; } - if (!compatible) { - GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name +": Incompatible API version"); + String[] versionArray = description.ApiVersion().split("\\."); + + //Completely different API version + if (!Objects.equals(Integer.valueOf(versionArray[0]), Integer.valueOf(apiVersion[0]))) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; + } + + //If the extension requires new API features, being backwards compatible + if (Integer.parseInt(versionArray[1]) > Integer.parseInt(apiVersion[1])) { + GeyserImpl.getInstance().getLogger().error("Couldn't load extension " + name + ": Wrong API version, current version: " + apiVersion[0] + "." + apiVersion[1]); + continue; } extensions.put(name, file); loadedExtensions.put(name, this.loadExtension(file, this.fileAssociations)); } } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Couldn't load " +file.getName()+ " in folder " + dictionary + ": ", e); + GeyserImpl.getInstance().getLogger().error("Couldn't load " + file.getName() + " in folder " + dictionary.getAbsolutePath() + ": ", e); } } } @@ -215,7 +204,7 @@ public class GeyserExtensionManager { return loadedExtensions; } - public void enableExtension(Extension extension) { + public void enableExtension(GeyserExtension extension) { if (!extension.isEnabled()) { try { extension.extensionLoader().enableExtension(extension); @@ -226,7 +215,7 @@ public class GeyserExtensionManager { } } - public void disableExtension(Extension extension) { + public void disableExtension(GeyserExtension extension) { if (extension.isEnabled()) { try { extension.extensionLoader().disableExtension(extension); @@ -236,8 +225,14 @@ public class GeyserExtensionManager { } } + public void enableExtensions() { + for (GeyserExtension extension : this.getExtensions().values()) { + this.enableExtension(extension); + } + } + public void disableExtensions() { - for (Extension extension : this.getExtensions().values()) { + for (GeyserExtension extension : this.getExtensions().values()) { this.disableExtension(extension); } }