Minestom/src/main/java/net/minestom/server/extensions/DiscoveredExtension.java

237 lines
7.1 KiB
Java
Raw Normal View History

package net.minestom.server.extensions;
2021-04-17 21:00:52 +02:00
import com.google.gson.JsonObject;
2021-12-04 06:15:00 +01:00
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull;
2020-11-03 21:26:46 +01:00
import org.jetbrains.annotations.Nullable;
2020-11-18 09:24:59 +01:00
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
2020-10-25 19:58:19 +01:00
import java.net.URL;
import java.nio.file.Path;
2020-10-25 19:58:19 +01:00
import java.util.LinkedList;
import java.util.List;
2021-03-24 16:23:56 +01:00
/**
* Represents an extension from an `extension.json` that is capable of powering an Extension object.
*
* This has no constructor as its properties are set via GSON.
*/
public final class DiscoveredExtension {
2021-03-24 16:23:56 +01:00
/** Static logger for this class. */
public static final Logger LOGGER = LoggerFactory.getLogger(DiscoveredExtension.class);
2020-11-18 09:24:59 +01:00
2021-03-24 16:23:56 +01:00
/** The regex that this name must pass. If it doesn't, it will not be accepted. */
2020-10-25 10:41:51 +01:00
public static final String NAME_REGEX = "[A-Za-z][_A-Za-z0-9]+";
2021-03-24 16:23:56 +01:00
/** Name of the DiscoveredExtension. Unique for all extensions. */
private String name;
2021-03-24 16:23:56 +01:00
/** Main class of this DiscoveredExtension, must extend Extension. */
private String entrypoint;
2021-03-24 16:23:56 +01:00
/** Version of this extension, highly reccomended to set it. */
2020-10-25 10:41:51 +01:00
private String version;
2021-03-24 16:23:56 +01:00
/** People who have made this extension. */
2020-10-25 10:41:51 +01:00
private String[] authors;
2021-03-24 16:23:56 +01:00
/** List of extension names that this depends on. */
private String[] dependencies;
2021-03-24 16:23:56 +01:00
/** List of Repositories and URLs that this depends on. */
private ExternalDependencies externalDependencies;
2021-03-24 16:23:56 +01:00
2021-04-17 21:00:52 +02:00
/**
* Extra meta on the object.
* Do NOT use as configuration:
*
* Meta is meant to handle properties that will
* be accessed by other extensions, not accessed by itself
*/
private JsonObject meta;
2021-03-24 16:23:56 +01:00
/** All files of this extension */
2020-10-25 19:58:19 +01:00
transient List<URL> files = new LinkedList<>();
2021-03-24 16:23:56 +01:00
/** The load status of this extension -- LOAD_SUCCESS is the only good one. */
2020-10-25 10:41:51 +01:00
transient LoadStatus loadStatus = LoadStatus.LOAD_SUCCESS;
2021-03-24 16:23:56 +01:00
/** The original jar this is from. */
2020-11-03 21:26:46 +01:00
transient private File originalJar;
2021-03-24 16:23:56 +01:00
transient private Path dataDirectory;
2021-03-24 16:23:56 +01:00
/** The class loader that powers it. */
transient private ExtensionClassLoader classLoader;
@NotNull
public String getName() {
return name;
}
@NotNull
public String getEntrypoint() {
return entrypoint;
}
@NotNull
public String getVersion() {
return version;
}
2020-10-25 10:41:51 +01:00
@NotNull
public String[] getAuthors() {
return authors;
}
@NotNull
public String[] getDependencies() {
return dependencies;
}
2020-10-25 10:41:51 +01:00
@NotNull
public ExternalDependencies getExternalDependencies() {
return externalDependencies;
}
2020-10-25 10:41:51 +01:00
2021-03-24 16:23:56 +01:00
public void setOriginalJar(@Nullable File file) {
2020-11-03 21:26:46 +01:00
originalJar = file;
}
@Nullable
public File getOriginalJar() {
2020-11-03 21:26:46 +01:00
return originalJar;
}
public @NotNull Path getDataDirectory() {
return dataDirectory;
}
public void setDataDirectory(@NotNull Path dataDirectory) {
this.dataDirectory = dataDirectory;
}
void createClassLoader() {
2021-12-04 06:15:00 +01:00
Check.stateCondition(classLoader != null, "Extension classloader has already been created");
2021-11-16 18:23:15 +01:00
final URL[] urls = this.files.toArray(new URL[0]);
classLoader = new ExtensionClassLoader(this.getName(), urls);
2021-03-24 13:39:47 +01:00
}
2021-11-16 18:23:15 +01:00
@NotNull
public ExtensionClassLoader getClassLoader() {
2021-11-16 18:23:15 +01:00
return classLoader;
2021-03-24 13:39:47 +01:00
}
2021-03-24 16:23:56 +01:00
/**
* Ensures that all properties of this extension are properly set if they aren't
*
* @param extension The extension to verify
*/
public static void verifyIntegrity(@NotNull DiscoveredExtension extension) {
2020-10-25 10:41:51 +01:00
if (extension.name == null) {
StringBuilder fileList = new StringBuilder();
2020-10-25 19:58:19 +01:00
for (URL f : extension.files) {
fileList.append(f.toExternalForm()).append(", ");
2020-10-25 10:41:51 +01:00
}
2020-11-18 09:24:59 +01:00
LOGGER.error("Extension with no name. (at {}})", fileList);
LOGGER.error("Extension at ({}) will not be loaded.", fileList);
2020-10-25 10:41:51 +01:00
extension.loadStatus = DiscoveredExtension.LoadStatus.INVALID_NAME;
// To ensure @NotNull: name = INVALID_NAME
extension.name = extension.loadStatus.name();
return;
}
2021-03-23 16:50:42 +01:00
2020-10-25 10:41:51 +01:00
if (!extension.name.matches(NAME_REGEX)) {
2020-11-18 09:24:59 +01:00
LOGGER.error("Extension '{}' specified an invalid name.", extension.name);
LOGGER.error("Extension '{}' will not be loaded.", extension.name);
2020-10-25 10:41:51 +01:00
extension.loadStatus = DiscoveredExtension.LoadStatus.INVALID_NAME;
// To ensure @NotNull: name = INVALID_NAME
extension.name = extension.loadStatus.name();
return;
}
2021-03-23 16:50:42 +01:00
2020-10-25 10:41:51 +01:00
if (extension.entrypoint == null) {
2020-11-18 09:24:59 +01:00
LOGGER.error("Extension '{}' did not specify an entry point (via 'entrypoint').", extension.name);
LOGGER.error("Extension '{}' will not be loaded.", extension.name);
2020-10-25 10:41:51 +01:00
extension.loadStatus = DiscoveredExtension.LoadStatus.NO_ENTRYPOINT;
// To ensure @NotNull: entrypoint = NO_ENTRYPOINT
extension.entrypoint = extension.loadStatus.name();
return;
}
2021-03-23 16:50:42 +01:00
2020-10-25 10:41:51 +01:00
// Handle defaults
// If we reach this code, then the extension will most likely be loaded:
if (extension.version == null) {
2020-11-18 09:24:59 +01:00
LOGGER.warn("Extension '{}' did not specify a version.", extension.name);
LOGGER.warn("Extension '{}' will continue to load but should specify a plugin version.", extension.name);
2020-10-25 10:41:51 +01:00
extension.version = "Unspecified";
}
2021-03-23 16:50:42 +01:00
2020-10-25 10:41:51 +01:00
if (extension.authors == null) {
extension.authors = new String[0];
}
2021-03-23 16:50:42 +01:00
2020-10-25 10:41:51 +01:00
// No dependencies were specified
if (extension.dependencies == null) {
extension.dependencies = new String[0];
}
2021-03-23 16:50:42 +01:00
// No external dependencies were specified;
if (extension.externalDependencies == null) {
extension.externalDependencies = new ExternalDependencies();
2020-10-25 10:41:51 +01:00
}
2021-04-17 21:00:52 +02:00
// No meta was provided
if (extension.meta == null) {
extension.meta = new JsonObject();
}
}
@NotNull
public JsonObject getMeta() {
return meta;
2020-10-25 10:41:51 +01:00
}
2021-03-24 16:23:56 +01:00
/**
* The status this extension has, all are breakpoints.
*
* LOAD_SUCCESS is the only valid one.
*/
2020-10-25 10:41:51 +01:00
enum LoadStatus {
LOAD_SUCCESS("Actually, it did not fail. This message should not have been printed."),
MISSING_DEPENDENCIES("Missing dependencies, check your logs."),
INVALID_NAME("Invalid name."),
NO_ENTRYPOINT("No entrypoint specified."),
FAILED_TO_SETUP_CLASSLOADER("Extension classloader could not be setup."),
LOAD_FAILED("Load failed. See logs for more information."),
2020-10-25 10:41:51 +01:00
;
private final String message;
LoadStatus(@NotNull String message) {
this.message = message;
}
@NotNull
public String getMessage() {
return message;
}
}
2021-03-23 16:50:42 +01:00
public static final class ExternalDependencies {
2020-10-25 10:41:51 +01:00
Repository[] repositories = new Repository[0];
String[] artifacts = new String[0];
2021-03-23 16:50:42 +01:00
public static class Repository {
2020-10-25 10:41:51 +01:00
String name = "";
String url = "";
}
}
}