refactor API

This commit is contained in:
dfsek
2021-02-22 16:13:53 -07:00
parent 46a08e49f5
commit a328ff2f2a
177 changed files with 399 additions and 311 deletions

View File

@@ -0,0 +1,60 @@
package com.dfsek.terra.addon;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.addons.annotations.Addon;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class AddonClassLoader extends URLClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
public AddonClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public AddonClassLoader(URL[] urls) {
super(urls);
}
@SuppressWarnings("unchecked")
public static Set<Class<? extends TerraAddon>> fetchAddonClasses(File file) throws IOException {
JarFile jarFile = new JarFile(file);
Enumeration<JarEntry> entries = jarFile.entries();
AddonClassLoader loader = new AddonClassLoader(new URL[] {file.toURI().toURL()}, AddonClassLoader.class.getClassLoader());
Set<Class<? extends TerraAddon>> set = new HashSet<>();
while(entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if(entry.isDirectory() || !entry.getName().endsWith(".class")) continue;
String className = entry.getName().substring(0, entry.getName().length() - 6).replace('/', '.');
try {
Class<?> clazz = loader.loadClass(className);
Addon addon = clazz.getAnnotation(Addon.class);
if(addon == null) continue;
if(!TerraAddon.class.isAssignableFrom(clazz)) throw new IllegalArgumentException("Addon class must extend TerraAddon.");
set.add((Class<? extends TerraAddon>) clazz);
} catch(ClassNotFoundException e) {
throw new IllegalStateException(e); // this should literally never happen, if it does something is very wrong
}
}
return set;
}
}

View File

@@ -0,0 +1,32 @@
package com.dfsek.terra.addon;
import com.dfsek.terra.addon.exception.AddonLoadException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class AddonPool {
private final Map<String, PreLoadAddon> pool = new HashMap<>();
public void add(PreLoadAddon addon) throws AddonLoadException {
if(pool.containsKey(addon.getId()))
throw new AddonLoadException("Duplicate addon ID: " + addon.getId());
pool.put(addon.getId(), addon);
}
public PreLoadAddon get(String id) {
return pool.get(id);
}
public void buildAll() throws AddonLoadException {
for(PreLoadAddon value : pool.values()) {
value.rebuildDependencies(this, value, true);
}
}
public Set<PreLoadAddon> getAddons() {
return new HashSet<>(pool.values());
}
}

View File

@@ -0,0 +1,51 @@
package com.dfsek.terra.addon;
import com.dfsek.terra.addon.exception.AddonLoadException;
import com.dfsek.terra.addon.exception.CircularDependencyException;
import com.dfsek.terra.addon.exception.DependencyMissingException;
import com.dfsek.terra.api.addons.TerraAddon;
import com.dfsek.terra.api.addons.annotations.Addon;
import com.dfsek.terra.api.addons.annotations.Depends;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PreLoadAddon {
private final List<PreLoadAddon> depends = new ArrayList<>();
private final Class<? extends TerraAddon> addonClass;
private final String id;
private final String[] dependencies;
public PreLoadAddon(Class<? extends TerraAddon> addonClass) {
this.addonClass = addonClass;
this.id = addonClass.getAnnotation(Addon.class).value();
Depends depends = addonClass.getAnnotation(Depends.class);
this.dependencies = depends == null ? new String[] {} : depends.value();
}
public List<PreLoadAddon> getDepends() {
return depends;
}
public void rebuildDependencies(AddonPool pool, PreLoadAddon origin, boolean levelG1) throws AddonLoadException {
if(this.equals(origin) && !levelG1)
throw new CircularDependencyException("Detected circular dependency in addon \"" + id + "\", dependencies: " + Arrays.toString(dependencies));
for(String dependency : dependencies) {
PreLoadAddon preLoadAddon = pool.get(dependency);
if(preLoadAddon == null)
throw new DependencyMissingException("Dependency " + dependency + " was not found. Please install " + dependency + " to use " + id + ".");
depends.add(preLoadAddon);
preLoadAddon.rebuildDependencies(pool, origin, false);
}
}
public String getId() {
return id;
}
public Class<? extends TerraAddon> getAddonClass() {
return addonClass;
}
}

View File

@@ -0,0 +1,13 @@
package com.dfsek.terra.addon.exception;
public class AddonLoadException extends Exception {
private static final long serialVersionUID = -4949084729296580176L;
public AddonLoadException(String message) {
super(message);
}
public AddonLoadException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,13 @@
package com.dfsek.terra.addon.exception;
public class CircularDependencyException extends AddonLoadException {
private static final long serialVersionUID = 7398510879124125121L;
public CircularDependencyException(String message) {
super(message);
}
public CircularDependencyException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,13 @@
package com.dfsek.terra.addon.exception;
public class DependencyMissingException extends AddonLoadException {
private static final long serialVersionUID = -8419489102208521583L;
public DependencyMissingException(String message) {
super(message);
}
public DependencyMissingException(String message, Throwable cause) {
super(message, cause);
}
}