create parent classloader for addons

This commit is contained in:
dfsek
2021-12-02 21:10:05 -07:00
parent 275320af0b
commit b925fe8ff5
@@ -13,21 +13,6 @@ import ca.solostudios.strata.version.VersionRange;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.yaml.YamlConfiguration; import com.dfsek.tectonic.yaml.YamlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.addons.manifest.impl.config.AddonManifest; import com.dfsek.terra.addons.manifest.impl.config.AddonManifest;
@@ -39,6 +24,23 @@ import com.dfsek.terra.addons.manifest.impl.exception.ManifestException;
import com.dfsek.terra.addons.manifest.impl.exception.ManifestNotPresentException; import com.dfsek.terra.addons.manifest.impl.exception.ManifestNotPresentException;
import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon; import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> { public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
private static final Logger logger = LoggerFactory.getLogger(ManifestAddonLoader.class); private static final Logger logger = LoggerFactory.getLogger(ManifestAddonLoader.class);
@@ -49,7 +51,7 @@ public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
.registerLoader(VersionRange.class, new VersionRangeLoader()) .registerLoader(VersionRange.class, new VersionRangeLoader())
.registerLoader(WebsiteConfig.class, WebsiteConfig::new); .registerLoader(WebsiteConfig.class, WebsiteConfig::new);
public ManifestAddon loadAddon(Path addonPath) { public ManifestAddon loadAddon(Path addonPath, ClassLoader loader) {
try(JarFile jar = new JarFile(addonPath.toFile())) { try(JarFile jar = new JarFile(addonPath.toFile())) {
logger.debug("Loading addon from JAR {}", addonPath); logger.debug("Loading addon from JAR {}", addonPath);
@@ -72,12 +74,12 @@ public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
} }
@SuppressWarnings({ "IOResourceOpenedButNotSafelyClosed", "resource" }) @SuppressWarnings({ "IOResourceOpenedButNotSafelyClosed", "resource" })
ManifestAddonClassLoader loader = new ManifestAddonClassLoader(new URL[]{ addonPath.toUri().toURL() }, ManifestAddonClassLoader childLoader = new ManifestAddonClassLoader(new URL[]{ addonPath.toUri().toURL() },
getClass().getClassLoader()); loader);
List<AddonInitializer> initializers = manifest.getEntryPoints().stream().map(entryPoint -> { List<AddonInitializer> initializers = manifest.getEntryPoints().stream().map(entryPoint -> {
try { try {
Object in = loader.loadClass(entryPoint).getConstructor().newInstance(); Object in = childLoader.loadClass(entryPoint).getConstructor().newInstance();
if(!(in instanceof AddonInitializer)) { if(!(in instanceof AddonInitializer)) {
throw new AddonException(in.getClass() + " does not extend " + AddonInitializer.class); throw new AddonException(in.getClass() + " does not extend " + AddonInitializer.class);
} }
@@ -97,7 +99,7 @@ public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
throw new ManifestException("Failed to load addon manifest", e); throw new ManifestException("Failed to load addon manifest", e);
} }
} catch(IOException e) { } catch(IOException e) {
throw new UncheckedIOException(e); throw new AddonException("Failed to load addon from JAR " + addonPath, e);
} }
} }
@@ -105,11 +107,22 @@ public class ManifestAddonLoader implements BootstrapBaseAddon<ManifestAddon> {
public Iterable<ManifestAddon> loadAddons(Path addonsFolder, ClassLoader parent) { public Iterable<ManifestAddon> loadAddons(Path addonsFolder, ClassLoader parent) {
logger.debug("Loading addons..."); logger.debug("Loading addons...");
try(Stream<Path> addons = Files.walk(addonsFolder, 1, FileVisitOption.FOLLOW_LINKS)) { try(Stream<Path> files = Files.walk(addonsFolder, 1, FileVisitOption.FOLLOW_LINKS)) {
return addons.filter(path -> path.toFile().isFile()) List<Path> addons = files.filter(path -> path.toFile().isFile())
.filter(path -> path.toFile().canRead()) .filter(path -> path.toFile().canRead())
.filter(path -> path.toString().endsWith(".jar")) .filter(path -> path.toString().endsWith(".jar"))
.map(this::loadAddon) .toList();
ManifestAddonClassLoader loader = new ManifestAddonClassLoader(addons.stream().map(path -> {
try {
return path.toUri().toURL();
} catch(MalformedURLException e) {
throw new UncheckedIOException(e);
}
}).toArray(URL[]::new), getClass().getClassLoader());
return addons.stream()
.map(jar -> loadAddon(jar, loader))
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch(IOException e) { } catch(IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);