From 279f8cb1398ef6b3c4954853b09cb35d189a4f9c Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Thu, 11 Jul 2019 10:40:16 -0700 Subject: [PATCH 01/20] Ducktape work --- .../module/{internal => }/ModuleHandle.java | 0 .../utilities/ducktape/module/ModuleInfo.java | 93 +----------------- .../ducktape/module/internal/ModuleInfo.java | 95 +++++++++++++++++++ 3 files changed, 96 insertions(+), 92 deletions(-) rename core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/{internal => }/ModuleHandle.java (100%) create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleHandle.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java similarity index 100% rename from core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleHandle.java rename to core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java index 8bf231f..72ff6d3 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java @@ -1,95 +1,4 @@ -/* - * Copyright 2019 Year4000. All Rights Reserved. - */ package net.year4000.utilities.ducktape.module; -import net.year4000.utilities.Conditions; - -public final class ModuleInfo implements Loader, Enabler { - private Phase phase = Phase.CONSTRUCTING; - private Class moduleClass; - private Module annotation; - - public ModuleInfo(Class moduleClass) { - this.moduleClass = Conditions.nonNull(moduleClass, "module class must not be empty"); - Conditions.condition(moduleClass.isAnnotationPresent(Module.class), "the module class must have the @Module annotation"); - this.annotation = moduleClass.getAnnotation(Module.class); - } - - /** Get the current phase the module is on */ - public Phase getPhase() { - return this.phase; - } - - /** Get the module class */ - public Class getModuleClass() { - return this.moduleClass; - } - - /** Get the id of the module */ - public String getId() { - return this.annotation.id().toLowerCase(); - } - - /** Called when the module class is being constructed */ - public void constructing() { - System.out.println("Constructing: " + this); - } - - /** Called when the module is being loaded*/ - @Override - public void load() { - System.out.println("Loading: " + this); - this.phase = Phase.LOADED; - } - - /** Called when the module is being enabled */ - @Override - public void enable() { - System.out.println("Enabling: " + this); - this.phase = Phase.ENABLED; - } - - @Override - public String toString() { - return String.format("ModuleInfo{id=%s, class=%s}", this.getId(), this.moduleClass); - } - - @Override - public int hashCode() { - return this.getId().hashCode(); - } - - @Override - public boolean equals(Object other) { - return other instanceof ModuleInfo && this.getId().equals(((ModuleInfo) other).getId()); - } - - /** The current phase of this module */ - public enum Phase { - /** This is a special phase when the classes are being loaded into the system to be constructed by Guice */ - LOADING, - /** The default phase state as this is created when the mode is constructing */ - CONSTRUCTING, - /** This is when the module has been loaded, settings have been populated and module specific stuff should be loaded here */ - LOADED, - /** This is when the module has been enable, at this point all loading has been done and can do what they need */ - ENABLED - ; - - /** Return true when the phase is constructing */ - public boolean isConstructing() { - return this == CONSTRUCTING; - } - - /** Return true when the phase is loaded */ - public boolean isLoaded() { - return this == LOADED; - } - - /** Return true with the phase is enabled */ - public boolean isEnabled() { - return this == ENABLED; - } - } +public interface ModuleInfo { } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java new file mode 100644 index 0000000..8bf231f --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.module; + +import net.year4000.utilities.Conditions; + +public final class ModuleInfo implements Loader, Enabler { + private Phase phase = Phase.CONSTRUCTING; + private Class moduleClass; + private Module annotation; + + public ModuleInfo(Class moduleClass) { + this.moduleClass = Conditions.nonNull(moduleClass, "module class must not be empty"); + Conditions.condition(moduleClass.isAnnotationPresent(Module.class), "the module class must have the @Module annotation"); + this.annotation = moduleClass.getAnnotation(Module.class); + } + + /** Get the current phase the module is on */ + public Phase getPhase() { + return this.phase; + } + + /** Get the module class */ + public Class getModuleClass() { + return this.moduleClass; + } + + /** Get the id of the module */ + public String getId() { + return this.annotation.id().toLowerCase(); + } + + /** Called when the module class is being constructed */ + public void constructing() { + System.out.println("Constructing: " + this); + } + + /** Called when the module is being loaded*/ + @Override + public void load() { + System.out.println("Loading: " + this); + this.phase = Phase.LOADED; + } + + /** Called when the module is being enabled */ + @Override + public void enable() { + System.out.println("Enabling: " + this); + this.phase = Phase.ENABLED; + } + + @Override + public String toString() { + return String.format("ModuleInfo{id=%s, class=%s}", this.getId(), this.moduleClass); + } + + @Override + public int hashCode() { + return this.getId().hashCode(); + } + + @Override + public boolean equals(Object other) { + return other instanceof ModuleInfo && this.getId().equals(((ModuleInfo) other).getId()); + } + + /** The current phase of this module */ + public enum Phase { + /** This is a special phase when the classes are being loaded into the system to be constructed by Guice */ + LOADING, + /** The default phase state as this is created when the mode is constructing */ + CONSTRUCTING, + /** This is when the module has been loaded, settings have been populated and module specific stuff should be loaded here */ + LOADED, + /** This is when the module has been enable, at this point all loading has been done and can do what they need */ + ENABLED + ; + + /** Return true when the phase is constructing */ + public boolean isConstructing() { + return this == CONSTRUCTING; + } + + /** Return true when the phase is loaded */ + public boolean isLoaded() { + return this == LOADED; + } + + /** Return true with the phase is enabled */ + public boolean isEnabled() { + return this == ENABLED; + } + } +} From 345131fb72b52a8ba3c4e7dbb88e464af5482dbc Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Thu, 11 Jul 2019 10:42:18 -0700 Subject: [PATCH 02/20] More ducktape work --- .../year4000/utilities/ducktape/Ducktape.java | 21 +++- .../utilities/ducktape/DucktapeManager.java | 68 +++++------ .../utilities/ducktape/DucktapeModule.java | 2 +- .../utilities/ducktape/SettingsModule.java | 4 +- .../ducktape/loaders/ClassModuleLoader.java | 3 +- .../ducktape/loaders/GroovyModuleLoader.java | 25 +++- .../ducktape/loaders/ModuleLoader.java | 24 +--- .../ducktape/module/ModuleHandle.java | 2 +- .../utilities/ducktape/module/ModuleInfo.java | 44 ++++++- .../ducktape/module/ModuleWrapper.java | 2 + .../ducktape/module/internal/ModuleInfo.java | 49 +++----- .../year4000/utilities/sponge/Utilities.java | 21 ++-- .../sponge/command/PluginCommand.java | 2 +- .../sponge/ducktape/SpongeModuleManager.java | 113 +++++++++++------- .../ducktape/WrappedPluginContainer.java | 24 ++-- 15 files changed, 237 insertions(+), 167 deletions(-) diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/Ducktape.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/Ducktape.java index 23ecb59..4b0965b 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/Ducktape.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/Ducktape.java @@ -16,12 +16,27 @@ static DucktapeManager.DucktapeManagerBuilder builder() { return DucktapeManager.builder(); } - /** This will init the Ducktape systems */ - void init() throws ModuleInitException; + /** Load the modules */ + void load() throws ModuleInitException; + + /** Enable the modules */ + void enable() throws ModuleInitException; + + /** This will init the Ducktape systems by calling the load and enable */ + default void init() throws ModuleInitException { + load(); + enable(); + } + + /** Get the module from the class, avoid this call and prefer the id method over this one */ + default Value getModule(Module module) { + Conditions.nonNull(module, "annotation can not be null"); + return getModule(module.id()); + } /** Get the module from the class, avoid this call and prefer the id method over this one */ default Value getModule(Class clazz) { - if (clazz.isAnnotationPresent(Module.class)) { + if (Conditions.nonNull(clazz, "class can not be null").isAnnotationPresent(Module.class)) { return getModule(clazz.getAnnotation(Module.class).id().toLowerCase()); } return Value.empty(); diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java index fb4c762..0a6a50d 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java @@ -8,42 +8,30 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.inject.*; -import com.google.inject.name.Named; -import com.google.inject.name.Names; import net.year4000.utilities.Builder; import net.year4000.utilities.Conditions; import net.year4000.utilities.ducktape.loaders.ModuleLoader; import net.year4000.utilities.ducktape.module.Enabler; -import net.year4000.utilities.ducktape.module.Module; -import net.year4000.utilities.ducktape.module.ModuleInfo; +import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.ducktape.module.ModuleWrapper; import net.year4000.utilities.value.Value; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; public class DucktapeManager extends AbstractModule implements Ducktape { /** The set of current loaded modules */ - private Set> loaded = new LinkedHashSet<>(); - + protected Set> loaded = new LinkedHashSet<>(); /** A map of all loaders stored by their class */ - private ClassToInstanceMap loaders; - + protected ClassToInstanceMap loaders; /** The guice injector that will init the modules */ - private Injector injector; - - private Path modsPath = Paths.get("mods/"); - + protected Injector injector; /** * The modules that are loaded, at first the order is when they are constructed but while they are loading * it resorts them based on load order, so when loading is done it will enable them properly. */ - private final Map modules = new LinkedHashMap<>(); - + protected final Map modules = new LinkedHashMap<>(); - private DucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { + protected DucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { this.injector = Conditions.nonNull(injector, "extra injector must not be null"); this.loaders = ImmutableClassToInstanceMap.builder() .putAll(loaderMap) @@ -52,20 +40,24 @@ private DucktapeManager(Injector injector, Map, Mo /** Create a snapshot of the modules that are currently in the system when this method is called */ @Override - public ImmutableList getModules() { - ImmutableList.Builder moduleBuilder = ImmutableList.builder(); + public ImmutableList getModules() { + ImmutableList.Builder moduleBuilder = ImmutableList.builder(); this.modules.forEach(((moduleInfo, moduleWrapper) -> moduleBuilder.add(moduleInfo))); return moduleBuilder.build(); } @Override - public void init() throws ModuleInitException { + public void load() throws ModuleInitException { System.out.println("Loading module classes from the loaders"); - Set> classes = loadAll(this.modsPath); + Set> classes = loadAll(); System.out.println("Setting up the injector"); // todo think? use child injector or our own injector, is we use a child injector sponge plugins will work, if not modules only have our bindings this.injector = this.injector.createChildInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); //this.injector = Guice.createInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); + } + + @Override + public void enable() throws ModuleInitException { System.out.println("Enabling modules: " + this.modules); this.modules.values().forEach(Enabler::enable); } @@ -73,23 +65,17 @@ public void init() throws ModuleInitException { @Override protected void configure() { bind(Ducktape.class).toInstance(this); - bind(Path.class).annotatedWith(Names.named("mods")).toInstance(this.modsPath); } /** Load all classes from the selected path */ - protected Set> loadAll(Path path) throws ModuleInitException { - System.out.println("path: " + path); + protected Set> loadAll() throws ModuleInitException { Set> classes = new HashSet<>(); this.loaders.forEach((key, value) -> { - try { - if (loaded.contains(key)) { - throw new ModuleInitException(ModuleInfo.Phase.LOADING, new IllegalStateException("Can not load the same loader twice.")); - } - classes.addAll(value.load(path)); - loaded.add(key); - } catch (IOException error) { - throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); + if (loaded.contains(key)) { + throw new ModuleInitException(ModuleInfo.Phase.LOADING, new IllegalStateException("Can not load the same loader twice.")); } + classes.addAll(value.load()); + loaded.add(key); }); return classes; } @@ -99,9 +85,9 @@ public static DucktapeManagerBuilder builder() { } /** This will build the ducktape manager environment with the correct module loaders and guice injector */ - public static class DucktapeManagerBuilder implements Builder { - private final Set loaders = new HashSet<>(); - private Value injectorValue = Value.empty(); + public static class DucktapeManagerBuilder implements Builder { + protected final Set loaders = new HashSet<>(); + protected Value injectorValue = Value.empty(); /** Add a module loader system */ public DucktapeManagerBuilder addLoader(ModuleLoader moduleLoader) { @@ -115,11 +101,15 @@ public DucktapeManagerBuilder setInjector(Injector injector) { return this; } - @Override - public DucktapeManager build() { - Map, ModuleLoader> loaderMap = loaders.stream().map(loader -> ImmutableMap., ModuleLoader>of(loader.getClass(), loader)) + /** Internal reuse able method that will map reduce the module loader map */ + protected Map, ModuleLoader> loaderMapReduce() { + return loaders.stream().map(loader -> ImmutableMap., ModuleLoader>of(loader.getClass(), loader)) .reduce((left, right) -> ImmutableMap., ModuleLoader>builder().putAll(left).putAll(right).build()).get(); + } + @Override + public Ducktape build() { + Map, ModuleLoader> loaderMap = loaderMapReduce(); return new DucktapeManager(injectorValue.getOrElse(Guice.createInjector()), loaderMap); } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeModule.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeModule.java index d5bec26..b9830c3 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeModule.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeModule.java @@ -8,7 +8,7 @@ import com.google.inject.matcher.Matchers; import com.google.inject.spi.*; import net.year4000.utilities.ducktape.module.Module; -import net.year4000.utilities.ducktape.module.ModuleInfo; +import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.ducktape.module.ModuleWrapper; import java.util.Map; diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java index cf1d50f..03b9e0e 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java @@ -33,7 +33,7 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { String typeString = type.toString(); String genericType = typeString.substring(typeString.indexOf("<") + 1, typeString.indexOf(">")); Class settingsClass = Reflections.clazz(genericType).getOrThrow(); - System.out.println("foundSettingsClass: " + settingsClass); + //System.out.println("foundSettingsClass: " + settingsClass); // when members are injected encounter.register((MembersInjector) instance -> { @@ -41,7 +41,7 @@ public void hear(TypeLiteral type, TypeEncounter encounter) { // create instance right now, later have something else handle it //((Settings) instance).instance = Reflections.instance(settingsClass).getOrThrow(); - System.out.println("MembersInjector settings: " + instance); + //System.out.println("MembersInjector settings: " + instance); }); // after members has been injected diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassModuleLoader.java index d29671a..6adad10 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassModuleLoader.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassModuleLoader.java @@ -5,7 +5,6 @@ import com.google.common.collect.Sets; -import java.nio.file.Path; import java.util.Collection; /** Create the module loader with a fixed set of classes */ @@ -17,7 +16,7 @@ public ClassModuleLoader(Class... classes) { } @Override - public Collection> load(Path path) { + public Collection> load() { return Sets.newHashSet(this.classes); } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java index e1a6708..a39232f 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java @@ -1,14 +1,15 @@ /* - * Copyright 2016 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.ducktape.loaders; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.Sets; import groovy.lang.GroovyClassLoader; -import net.year4000.utilities.ducktape.ModuleManager; +import net.year4000.utilities.Conditions; +import net.year4000.utilities.ducktape.ModuleInitException; +import net.year4000.utilities.ducktape.module.ModuleInfo; import java.io.IOException; import java.net.URL; @@ -26,12 +27,25 @@ * into the class loader for the current running JVM. */ public class GroovyModuleLoader implements ModuleLoader { + private final Path dir; + + public GroovyModuleLoader(Path dir) { + this.dir = Conditions.nonNull(dir, "dir must exist"); + } - /** Load any groovy script that ends with .groovy */ @Override + public Collection> load() throws ModuleInitException { + try { + return load(this.dir); + } catch (IOException error) { + throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); + } + } + + /** Load any groovy script that ends with .groovy */ public Collection> load(Path dir) throws IOException { Set> classes = Sets.newLinkedHashSet(); - Class clazzLoader = ModuleManager.class; + Class clazzLoader = GroovyModuleLoader.class; try (DirectoryStream stream = Files.newDirectoryStream(checkNotNull(dir))) { for (Path path : stream) { if (!path.toString().endsWith(".groovy")) { @@ -50,7 +64,6 @@ public Collection> load(Path dir) throws IOException { classes.add(clazz); } } - return classes; } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ModuleLoader.java index f75b1ea..e3e8339 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ModuleLoader.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ModuleLoader.java @@ -1,31 +1,19 @@ /* - * Copyright 2016 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.ducktape.loaders; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; +import net.year4000.utilities.ducktape.ModuleInitException; + import java.util.Collection; /** * This is a functional interface that will load * a module from the select file path. */ +@FunctionalInterface public interface ModuleLoader { - /** This will search the path and load the module */ - Collection> load(Path path) throws IOException; - - /** This will create a file object from a string and load the class paths */ - default Collection> load(String path) throws IOException { - return load(Paths.get(path)); - } - - /** This will create a file object from a string and load the class paths */ - default Collection> load(File file) throws IOException { - return load(file.toPath()); - } + /** Load classes from where ever and create the collection of classes for the modules */ + Collection> load() throws ModuleInitException; } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java index 358ae22..1a21655 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleHandle.java @@ -1,7 +1,7 @@ /* * Copyright 2019 Year4000. All Rights Reserved. */ -package net.year4000.utilities.ducktape.module.internal; +package net.year4000.utilities.ducktape.module; /** This is the base interface that the module will inherit */ public interface ModuleHandle { diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java index 72ff6d3..f86ea33 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java @@ -1,4 +1,46 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ package net.year4000.utilities.ducktape.module; -public interface ModuleInfo { +import net.year4000.utilities.value.Value; + +public interface ModuleInfo extends Loader, Enabler { + + /** Get the module handle of the module */ + Value getHandle(); + + /** Get the id of this module */ + String getId(); + + /** Get the current phase of the module */ + Phase getPhase(); + + /** The current phase of this module */ + enum Phase { + /** This is a special phase when the classes are being loaded into the system to be constructed by Guice */ + LOADING, + /** The default phase state as this is created when the mode is constructing */ + CONSTRUCTING, + /** This is when the module has been loaded, settings have been populated and module specific stuff should be loaded here */ + LOADED, + /** This is when the module has been enable, at this point all loading has been done and can do what they need */ + ENABLED + ; + + /** Return true when the phase is constructing */ + public boolean isConstructing() { + return this == CONSTRUCTING; + } + + /** Return true when the phase is loaded */ + public boolean isLoaded() { + return this == LOADED; + } + + /** Return true with the phase is enabled */ + public boolean isEnabled() { + return this == ENABLED; + } + } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java index 94e97e7..d858701 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java @@ -4,6 +4,7 @@ package net.year4000.utilities.ducktape.module; import net.year4000.utilities.Conditions; +import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.ducktape.module.internal.ModuleInvocationHandler; public class ModuleWrapper implements Loader, Enabler { @@ -14,6 +15,7 @@ public class ModuleWrapper implements Loader, Enabler { public ModuleWrapper(ModuleInfo moduleInfo, Object instance) { this.moduleInfo = Conditions.nonNull(moduleInfo, "moduleInfo must exists"); this.proxyInstance = ModuleInvocationHandler.createProxy(moduleInfo.getModuleClass(), Conditions.nonNull(instance, "instance must exists")); + this.moduleInfo.setHandle((ModuleHandle) this.proxyInstance); } /** Load the module and call the method with @Load */ diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java index 8bf231f..a723d26 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java @@ -1,14 +1,20 @@ /* * Copyright 2019 Year4000. All Rights Reserved. */ -package net.year4000.utilities.ducktape.module; +package net.year4000.utilities.ducktape.module.internal; import net.year4000.utilities.Conditions; +import net.year4000.utilities.annotations.Nullable; +import net.year4000.utilities.ducktape.module.Module; +import net.year4000.utilities.ducktape.module.ModuleHandle; +import net.year4000.utilities.value.Value; -public final class ModuleInfo implements Loader, Enabler { +/** The module info class is for the implementation of it's interface */ +public final class ModuleInfo implements net.year4000.utilities.ducktape.module.ModuleInfo { private Phase phase = Phase.CONSTRUCTING; private Class moduleClass; private Module annotation; + private ModuleHandle handle; public ModuleInfo(Class moduleClass) { this.moduleClass = Conditions.nonNull(moduleClass, "module class must not be empty"); @@ -16,6 +22,16 @@ public ModuleInfo(Class moduleClass) { this.annotation = moduleClass.getAnnotation(Module.class); } + /** This will set the handle of the module info */ + public void setHandle(@Nullable ModuleHandle handle) { + this.handle = handle; + } + + /** Returns the handle for the module this will be null until the module has been loaded */ + public Value getHandle() { + return Value.of(handle); + } + /** Get the current phase the module is on */ public Phase getPhase() { return this.phase; @@ -27,6 +43,7 @@ public Class getModuleClass() { } /** Get the id of the module */ + @Override public String getId() { return this.annotation.id().toLowerCase(); } @@ -64,32 +81,4 @@ public int hashCode() { public boolean equals(Object other) { return other instanceof ModuleInfo && this.getId().equals(((ModuleInfo) other).getId()); } - - /** The current phase of this module */ - public enum Phase { - /** This is a special phase when the classes are being loaded into the system to be constructed by Guice */ - LOADING, - /** The default phase state as this is created when the mode is constructing */ - CONSTRUCTING, - /** This is when the module has been loaded, settings have been populated and module specific stuff should be loaded here */ - LOADED, - /** This is when the module has been enable, at this point all loading has been done and can do what they need */ - ENABLED - ; - - /** Return true when the phase is constructing */ - public boolean isConstructing() { - return this == CONSTRUCTING; - } - - /** Return true when the phase is loaded */ - public boolean isLoaded() { - return this == LOADED; - } - - /** Return true with the phase is enabled */ - public boolean isEnabled() { - return this == ENABLED; - } - } } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java index fb0b204..57a0090 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java @@ -1,16 +1,16 @@ /* - * Copyright 2016 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.sponge; import com.google.inject.Inject; import com.google.inject.Injector; import net.year4000.utilities.ErrorReporter; import net.year4000.utilities.Tokens; +import net.year4000.utilities.ducktape.loaders.GroovyModuleLoader; import net.year4000.utilities.sponge.command.PluginCommand; import net.year4000.utilities.sponge.command.SystemCommand; -import net.year4000.utilities.sponge.ducktape.SpongeModuleManager; +import net.year4000.utilities.sponge.ducktape.SpongeDucktapeManager; import net.year4000.utilities.sponge.hologram.Holograms; import net.year4000.utilities.sponge.protocol.Packets; import org.spongepowered.api.Sponge; @@ -20,6 +20,8 @@ import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.plugin.Plugin; +import java.nio.file.Paths; + @Plugin( id = "utilities", name = "Utilities", @@ -29,7 +31,7 @@ authors = {"ewized"} ) public final class Utilities extends AbstractSpongePlugin { - private SpongeModuleManager moduleManager; + private SpongeDucktapeManager moduleManager; // Services private Packets packets; @@ -49,21 +51,24 @@ public static Utilities get() { } /** Get the module manager */ - public SpongeModuleManager getModuleManager() { + public SpongeDucktapeManager getModuleManager() { return moduleManager; } @Listener public void onConstruct(GameConstructionEvent event) { - this.moduleManager = new SpongeModuleManager(); - this.moduleManager.injectModules(this.injector); + this.moduleManager = (SpongeDucktapeManager) SpongeDucktapeManager.builder() + .setInjector(this.injector) + .addLoader(new GroovyModuleLoader(Paths.get("/mods"))) + .build(); + this.moduleManager.load(); } @Listener public void onUtilitiesPreInit(GamePreInitializationEvent event) { packets = setProvider(Packets.class, Packets.manager()); holograms = setProvider(Holograms.class, Holograms.manager()); - moduleManager.registerListeners(); // Register the listeners of the modules + moduleManager.enable(); } @Listener diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/command/PluginCommand.java b/sponge/src/main/java/net/year4000/utilities/sponge/command/PluginCommand.java index 634c264..168d2b0 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/command/PluginCommand.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/command/PluginCommand.java @@ -134,7 +134,7 @@ public Text toText(PluginContainer plugin, CommandSource src) { public List plugins() { return ImmutableList.builder() .addAll(new ArrayList<>(pluginManager.getPlugins())) - .addAll(Utilities.get().getModuleManager().getModules()) + .addAll(Utilities.get().getModuleManager().getWrappedModules()) .build(); } } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java index c89c0fa..9f94cec 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java @@ -1,72 +1,90 @@ /* - * Copyright 2016 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.sponge.ducktape; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import com.google.inject.Guice; import com.google.inject.Injector; import net.year4000.utilities.Conditions; import net.year4000.utilities.ErrorReporter; -import net.year4000.utilities.ducktape.ModuleManager; +import net.year4000.utilities.ducktape.*; +import net.year4000.utilities.ducktape.loaders.ModuleLoader; +import net.year4000.utilities.ducktape.module.Module; +import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.reflection.Reflections; import net.year4000.utilities.sponge.Utilities; import org.spongepowered.api.Sponge; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.plugin.Plugin; -import org.spongepowered.api.plugin.PluginContainer; import java.lang.reflect.Method; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Map; -import java.util.Set; +import java.util.*; /** Uses the SpongeAPI to add additional modules for Utilities */ -public class SpongeModuleManager extends ModuleManager { +public class SpongeDucktapeManager extends DucktapeManager { private static final String MOD_PATH = "mods/"; - private final Map modules = Maps.newConcurrentMap(); + private final List modules = new ArrayList<>(); - /** Get the modules that were added */ - public Collection getModules() { - return ImmutableList.copyOf(modules.keySet()); + protected SpongeDucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { + super(injector, loaderMap); } - /** Inject modules with the parent injector */ - public void injectModules(Injector injector) { - Set> pluginClasses = Sets.newHashSet(); - // Find all modules - loadAll(Paths.get(MOD_PATH), collection -> { - collection.forEach(clazz -> { - Plugin plugin = clazz.getAnnotation(Plugin.class); - if (plugin != null) { - pluginClasses.add(clazz); + /** Load all classes from the selected path */ + protected Set> loadAll() throws ModuleInitException { + Set> classes = new HashSet<>(); + this.loaders.forEach((key, value) -> { + if (loaded.contains(key)) { + throw new ModuleInitException(ModuleInfo.Phase.LOADING, new IllegalStateException("Can not load the same loader twice.")); + } + Collection> loadedClasses = value.load(); + loadedClasses.forEach(clazz -> { + Module module = clazz.getAnnotation(Module.class); + if (module != null) { + modules.add(new WrappedPluginContainer(clazz)); } }); + classes.addAll(loadedClasses); + loaded.add(key); }); - // Init the modules and inject the fields - pluginClasses.forEach(clazz -> { - try { - Object plugin = Reflections.instance(clazz).getOrThrow(); - injector.injectMembers(plugin); // Inject - modules.put(new WrappedPluginContainer(plugin), plugin); - } catch (Exception error) { - ErrorReporter.builder(error) - .add("Problem constructing module") - .add("Class: ", clazz) - .buildAndReport(System.err); - } - }); + return classes; + } + + public Collection getWrappedModules() { + return this.modules; } +// /** Inject modules with the parent injector */ +// public void injectModules(Injector injector) { +// Set> pluginClasses = Sets.newHashSet(); +// // Find all modules +// loadAll(Paths.get(MOD_PATH), collection -> { +// collection.forEach(clazz -> { +// Plugin plugin = clazz.getAnnotation(Plugin.class); +// if (plugin != null) { +// pluginClasses.add(clazz); +// } +// }); +// }); +// // Init the modules and inject the fields +// pluginClasses.forEach(clazz -> { +// try { +// Object plugin = Reflections.instance(clazz).getOrThrow(); +// injector.injectMembers(plugin); // Inject +// modules.put(new WrappedPluginContainer(plugin), plugin); +// } catch (Exception error) { +// ErrorReporter.builder(error) +// .add("Problem constructing module") +// .add("Class: ", clazz) +// .buildAndReport(System.err); +// } +// }); +// } + /** Register the listeners found in the modules */ public void registerListeners() { - modules.forEach((container, object) -> { + modules.forEach(container -> { try { - registerModuleListeners(container, object); + registerModuleListeners(container, getModule(container.getId())); } catch (Throwable throwable) { ErrorReporter.builder(throwable) .hideStackTrace() @@ -103,4 +121,17 @@ private void registerModuleListeners(WrappedPluginContainer container, Object mo }); } } + + public static SpongeDucktapeManagerBuilder builder() { + return new SpongeDucktapeManagerBuilder(); + } + + /** This will build the ducktape manager environment with the correct module loaders and guice injector */ + public static class SpongeDucktapeManagerBuilder extends DucktapeManagerBuilder { + @Override + public Ducktape build() { + Map, ModuleLoader> loaderMap = loaderMapReduce(); + return new SpongeDucktapeManager(injectorValue.getOrElse(Guice.createInjector()), loaderMap); + } + } } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/WrappedPluginContainer.java b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/WrappedPluginContainer.java index f107e90..c3a511d 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/WrappedPluginContainer.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/WrappedPluginContainer.java @@ -1,48 +1,44 @@ /* - * Copyright 2016 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.sponge.ducktape; import static com.google.common.base.Preconditions.checkNotNull; -import net.year4000.utilities.Utils; -import org.spongepowered.api.plugin.Plugin; +import net.year4000.utilities.ducktape.module.ModuleInfo; import org.spongepowered.api.plugin.PluginContainer; import java.util.Optional; public class WrappedPluginContainer implements PluginContainer { - private final Object plugin; - private final Plugin pluginData; + private final ModuleInfo moduleInfo; - public WrappedPluginContainer(Object object) { - this.plugin = checkNotNull(object, "object"); - this.pluginData = object.getClass().getAnnotation(Plugin.class); + public WrappedPluginContainer(Class clazz) { + this.moduleInfo = new net.year4000.utilities.ducktape.module.internal.ModuleInfo(checkNotNull(clazz, "clazz")); } @Override public String getId() { - return Optional.ofNullable(pluginData).map(Plugin::id).orElse("unknown"); + return this.moduleInfo.getId(); } @Override public String getName() { - return Optional.ofNullable(pluginData).map(Plugin::name).orElse("Unknown"); + return this.moduleInfo.getId(); } @Override public Optional getVersion() { - return Optional.ofNullable(pluginData).map(Plugin::version); + return Optional.empty(); } @Override public Optional getInstance() { - return Optional.ofNullable(plugin); + return Optional.empty(); } @Override public String toString() { - return Utils.toString(pluginData); + return this.moduleInfo.toString(); } } From ded7631d073f2f1fea3ed1bff8b15b5a229f5efb Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 08:25:10 -0700 Subject: [PATCH 03/20] Move the ducktape groovy loader into it's own module --- core-ducktape/build.gradle | 16 -------- core-ducktape/loaders-groovy/build.gradle | 16 ++++++++ .../ducktape/loaders/GroovyModuleLoader.java | 25 ++++++------- .../loaders/GroovyModuleLoaderTest.java | 37 +++++++++++++++++++ .../modules/AnotherGroovyModule.groovy | 14 +++++++ .../resources/modules/GroovyModule.groovy | 15 ++++++++ .../resources/modules/GroovyUtility.groovy | 14 +++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 1 + sponge/build.gradle | 17 +++++---- .../sponge/hologram/FrameBuffer.java | 2 +- .../sponge/protocol/PacketManagerTest.java | 2 +- 12 files changed, 121 insertions(+), 40 deletions(-) create mode 100644 core-ducktape/loaders-groovy/build.gradle rename core-ducktape/{ => loaders-groovy}/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java (68%) create mode 100644 core-ducktape/loaders-groovy/src/test/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoaderTest.java create mode 100644 core-ducktape/loaders-groovy/src/test/resources/modules/AnotherGroovyModule.groovy create mode 100644 core-ducktape/loaders-groovy/src/test/resources/modules/GroovyModule.groovy create mode 100644 core-ducktape/loaders-groovy/src/test/resources/modules/GroovyUtility.groovy diff --git a/core-ducktape/build.gradle b/core-ducktape/build.gradle index ea1d9e1..9eb50d2 100644 --- a/core-ducktape/build.gradle +++ b/core-ducktape/build.gradle @@ -4,29 +4,13 @@ plugins { id 'java' - id 'com.github.johnrengelman.shadow' version '1.2.3' } apply from: utilities.file('gradle/utilities.gradle') compileJava.options.encoding = 'UTF-8' -assemble.dependsOn shadowJar { - baseName = 'ducktape-libs' - version = utilities.version - - dependencies { - include dependency('org.codehaus.groovy:groovy-all:.*') // core:ducktape - } -} - dependencies { compile utilities.project('core') compile 'com.google.inject:guice:4.0' - compile 'org.codehaus.groovy:groovy-all:2.4.6' - compile 'org.scala-lang:scala-library:2.11.7' - compile 'org.scala-lang:scala-reflect:2.11.7' - compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.0" - compile "org.jetbrains.kotlin:kotlin-reflect:1.0.0" - compile "org.jetbrains.kotlin:kotlin-runtime:1.0.0" } diff --git a/core-ducktape/loaders-groovy/build.gradle b/core-ducktape/loaders-groovy/build.gradle new file mode 100644 index 0000000..6c4c7a2 --- /dev/null +++ b/core-ducktape/loaders-groovy/build.gradle @@ -0,0 +1,16 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +plugins { + id 'java' +} + +apply from: utilities.file('gradle/utilities.gradle') + +compileJava.options.encoding = 'UTF-8' + +dependencies { + compile utilities.project('core') + compile utilities.project('core-ducktape') + compile 'org.codehaus.groovy:groovy-all:2.4.6' +} diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java similarity index 68% rename from core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java rename to core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java index a39232f..9dce9c8 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java +++ b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java @@ -3,8 +3,6 @@ */ package net.year4000.utilities.ducktape.loaders; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.Sets; import groovy.lang.GroovyClassLoader; import net.year4000.utilities.Conditions; @@ -43,24 +41,23 @@ public Collection> load() throws ModuleInitException { } /** Load any groovy script that ends with .groovy */ - public Collection> load(Path dir) throws IOException { + private Collection> load(Path dir) throws IOException { Set> classes = Sets.newLinkedHashSet(); - Class clazzLoader = GroovyModuleLoader.class; - try (DirectoryStream stream = Files.newDirectoryStream(checkNotNull(dir))) { + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { for (Path path : stream) { if (!path.toString().endsWith(".groovy")) { continue; } URL url = path.toUri().toURL(); - URL[] urls = new URL[] {url}; - ClassLoader parent = AccessController.doPrivileged((PrivilegedAction) () -> - new URLClassLoader(urls, clazzLoader.getClassLoader()) - ); - // Convert the Groovy script to a Java Class - GroovyClassLoader loader = new GroovyClassLoader(parent); - loader.addURL(clazzLoader.getResource("/")); - loader.addURL(url); - Class clazz = loader.parseClass(path.toFile()); + GroovyClassLoader loader = AccessController.doPrivileged((PrivilegedAction) () -> { + // Convert the Groovy script to a Java Class + Class clazz = getClass(); + GroovyClassLoader groovyLoader = new GroovyClassLoader(new URLClassLoader(new URL[] {url}, clazz.getClassLoader())); + groovyLoader.addURL(clazz.getResource("/")); + groovyLoader.addURL(url); + return groovyLoader; + }); + Class clazz = loader.parseClass(path.toFile()); classes.add(clazz); } } diff --git a/core-ducktape/loaders-groovy/src/test/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoaderTest.java b/core-ducktape/loaders-groovy/src/test/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoaderTest.java new file mode 100644 index 0000000..2984568 --- /dev/null +++ b/core-ducktape/loaders-groovy/src/test/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoaderTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class GroovyModuleLoaderTest { + private static final Path modulePath = Paths.get("src/test/resources/modules"); + private int groovyFiles; + + @Before + public void getGroovyFiles() throws IOException { + this.groovyFiles = 0; + try (DirectoryStream pathStream = Files.newDirectoryStream(modulePath)) { + for (Path path : pathStream) { + if (path.toString().endsWith(".groovy")) { + this.groovyFiles++; + } + } + } + } + + @Test + public void groovyLoaderTest() { + GroovyModuleLoader loader = new GroovyModuleLoader(modulePath); + Assert.assertEquals(groovyFiles, loader.load().size()); + } +} diff --git a/core-ducktape/loaders-groovy/src/test/resources/modules/AnotherGroovyModule.groovy b/core-ducktape/loaders-groovy/src/test/resources/modules/AnotherGroovyModule.groovy new file mode 100644 index 0000000..831264a --- /dev/null +++ b/core-ducktape/loaders-groovy/src/test/resources/modules/AnotherGroovyModule.groovy @@ -0,0 +1,14 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +import net.year4000.utilities.ducktape.module.Enable +import net.year4000.utilities.ducktape.module.Module + +@Module(id = "another-module") +class AnotherGroovyModule { + @Enable + def enable() { + println 'Groovy Module load()' + GroovyUtility.helloWorld() + } +} diff --git a/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyModule.groovy b/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyModule.groovy new file mode 100644 index 0000000..3cf867c --- /dev/null +++ b/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyModule.groovy @@ -0,0 +1,15 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +import net.year4000.utilities.ducktape.module.Load +import net.year4000.utilities.ducktape.module.Module + +@Module(id = "groovy") +class GroovyModule { + + @Load + def load() { + println 'Groovy Module load()' + GroovyUtility.helloWorld() + } +} diff --git a/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyUtility.groovy b/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyUtility.groovy new file mode 100644 index 0000000..1360c4c --- /dev/null +++ b/core-ducktape/loaders-groovy/src/test/resources/modules/GroovyUtility.groovy @@ -0,0 +1,14 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +import net.year4000.utilities.utils.UtilityConstructError + +final class GroovyUtility { + private GroovyUtility() { + UtilityConstructError.raise() + } + + static def helloWorld() { + println 'Hello World!' + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d82435f..58bd77c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/settings.gradle b/settings.gradle index e3a75e6..835d835 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,6 +6,7 @@ rootProject.name = 'Utilities' include 'core' include 'core-ducktape' +include 'core-ducktape:loaders-groovy' include 'core-redis' include 'core-router' diff --git a/sponge/build.gradle b/sponge/build.gradle index 1edfa4e..3f18ef8 100644 --- a/sponge/build.gradle +++ b/sponge/build.gradle @@ -14,7 +14,7 @@ buildscript { plugins { id 'java' - id 'com.github.johnrengelman.shadow' version '1.2.3' + id 'com.github.johnrengelman.shadow' version '4.0.4' } apply plugin: 'org.spongepowered.plugin' @@ -37,20 +37,23 @@ jar { assemble.dependsOn shadowJar { baseName = utilities.name.toLowerCase() version = utilities.version + configurations += [project.configurations.compile] + configurations += [project.configurations.shadow] - dependencies { - include dependency('org.codehaus.groovy:groovy-all:.*') // core:ducktape - include dependency('redis.clients:jedis:.*') // core:redis - include dependency('net.year4000.utilities:.*') - } + exclude 'overview.html' + exclude 'overviewj.html' + exclude 'NOTICE' + exclude 'LICENSE' } dependencies { compile utilities.project('core') compile utilities.project('core-redis') compile utilities.project('core-ducktape') - compile 'org.spongepowered:spongeapi:7.1.0-SNAPSHOT' + compile utilities.project('core-ducktape:loaders-groovy') compile 'io.netty:netty-all:4.1.5.Final' + compileOnly 'org.spongepowered:spongeapi:7.1.0-SNAPSHOT' + testCompile 'org.spongepowered:spongeapi:7.1.0-SNAPSHOT' } idea { diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/hologram/FrameBuffer.java b/sponge/src/main/java/net/year4000/utilities/sponge/hologram/FrameBuffer.java index eb4052e..8aecd9d 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/hologram/FrameBuffer.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/hologram/FrameBuffer.java @@ -52,7 +52,7 @@ public static Builder builder() { /** Create the buffer that will create each frame */ static class Builder implements net.year4000.utilities.Builder { - private static final Text.Builder BLOCK = Text.builder('\u2013'); + private static final Text.Builder BLOCK = Text.builder('\u2588'); private static final ImmutableBiMap COLORS = ImmutableBiMap.builder() .put(TextColors.AQUA.getColor(), TextColors.AQUA) .put(TextColors.BLACK.getColor(), TextColors.BLACK) diff --git a/sponge/src/test/java/net/year4000/utilities/sponge/protocol/PacketManagerTest.java b/sponge/src/test/java/net/year4000/utilities/sponge/protocol/PacketManagerTest.java index 5fc084d..cda1f8a 100644 --- a/sponge/src/test/java/net/year4000/utilities/sponge/protocol/PacketManagerTest.java +++ b/sponge/src/test/java/net/year4000/utilities/sponge/protocol/PacketManagerTest.java @@ -9,7 +9,7 @@ public class PacketManagerTest { private final PacketManager packets = new PacketManager(); - private final Class clazz = PacketManagerTest.class; + private final Class clazz = getClass(); private final PacketListener packetListener = (player, packet) -> false; @Test From 4bee7d0882a27b667600c963bf2306c9b3880357 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 09:56:09 -0700 Subject: [PATCH 04/20] Restore functionaly of ducktape for sponge --- core-ducktape/build.gradle | 1 + .../utilities/ducktape/DucktapeManager.java | 9 +++-- .../ducktape/module/internal/ModuleInfo.java | 9 +++-- .../year4000/utilities/sponge/Utilities.java | 2 +- .../sponge/ducktape/SpongeModuleManager.java | 39 ++++--------------- .../test/resources/modules/ducktape.groovy | 21 ++++++++++ 6 files changed, 42 insertions(+), 39 deletions(-) create mode 100644 sponge/src/test/resources/modules/ducktape.groovy diff --git a/core-ducktape/build.gradle b/core-ducktape/build.gradle index 9eb50d2..2ba747d 100644 --- a/core-ducktape/build.gradle +++ b/core-ducktape/build.gradle @@ -13,4 +13,5 @@ compileJava.options.encoding = 'UTF-8' dependencies { compile utilities.project('core') compile 'com.google.inject:guice:4.0' + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java index 0a6a50d..2c96b74 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java @@ -15,10 +15,13 @@ import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.ducktape.module.ModuleWrapper; import net.year4000.utilities.value.Value; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.*; public class DucktapeManager extends AbstractModule implements Ducktape { + private final Logger logger = LogManager.getLogger("utilities/ducktape"); /** The set of current loaded modules */ protected Set> loaded = new LinkedHashSet<>(); /** A map of all loaders stored by their class */ @@ -48,9 +51,9 @@ public ImmutableList getModul @Override public void load() throws ModuleInitException { - System.out.println("Loading module classes from the loaders"); + logger.info("Loading module classes from the loaders"); Set> classes = loadAll(); - System.out.println("Setting up the injector"); + logger.info("Setting up the injector"); // todo think? use child injector or our own injector, is we use a child injector sponge plugins will work, if not modules only have our bindings this.injector = this.injector.createChildInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); //this.injector = Guice.createInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); @@ -58,7 +61,7 @@ public void load() throws ModuleInitException { @Override public void enable() throws ModuleInitException { - System.out.println("Enabling modules: " + this.modules); + logger.info("Enabling modules: " + this.modules); this.modules.values().forEach(Enabler::enable); } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java index a723d26..33d3765 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java @@ -8,9 +8,12 @@ import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.module.ModuleHandle; import net.year4000.utilities.value.Value; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** The module info class is for the implementation of it's interface */ public final class ModuleInfo implements net.year4000.utilities.ducktape.module.ModuleInfo { + private final Logger logger = LogManager.getLogger("utilities/ducktape"); private Phase phase = Phase.CONSTRUCTING; private Class moduleClass; private Module annotation; @@ -50,20 +53,20 @@ public String getId() { /** Called when the module class is being constructed */ public void constructing() { - System.out.println("Constructing: " + this); + logger.info("Constructing: {}", this); } /** Called when the module is being loaded*/ @Override public void load() { - System.out.println("Loading: " + this); + logger.info("Loading: {}", this); this.phase = Phase.LOADED; } /** Called when the module is being enabled */ @Override public void enable() { - System.out.println("Enabling: " + this); + logger.info("Enabling: {}", this); this.phase = Phase.ENABLED; } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java index 57a0090..836cfe8 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java @@ -59,7 +59,7 @@ public SpongeDucktapeManager getModuleManager() { public void onConstruct(GameConstructionEvent event) { this.moduleManager = (SpongeDucktapeManager) SpongeDucktapeManager.builder() .setInjector(this.injector) - .addLoader(new GroovyModuleLoader(Paths.get("/mods"))) + .addLoader(new GroovyModuleLoader(Paths.get(SpongeDucktapeManager.MOD_PATH))) .build(); this.moduleManager.load(); } diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java index 9f94cec..9654b87 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java @@ -11,18 +11,19 @@ import net.year4000.utilities.ducktape.loaders.ModuleLoader; import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.module.internal.ModuleInfo; -import net.year4000.utilities.reflection.Reflections; import net.year4000.utilities.sponge.Utilities; import org.spongepowered.api.Sponge; import org.spongepowered.api.event.Event; import org.spongepowered.api.event.Listener; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.*; /** Uses the SpongeAPI to add additional modules for Utilities */ public class SpongeDucktapeManager extends DucktapeManager { - private static final String MOD_PATH = "mods/"; + public static final String MOD_PATH = "mods/"; private final List modules = new ArrayList<>(); protected SpongeDucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { @@ -53,38 +54,11 @@ public Collection getWrappedModules() { return this.modules; } -// /** Inject modules with the parent injector */ -// public void injectModules(Injector injector) { -// Set> pluginClasses = Sets.newHashSet(); -// // Find all modules -// loadAll(Paths.get(MOD_PATH), collection -> { -// collection.forEach(clazz -> { -// Plugin plugin = clazz.getAnnotation(Plugin.class); -// if (plugin != null) { -// pluginClasses.add(clazz); -// } -// }); -// }); -// // Init the modules and inject the fields -// pluginClasses.forEach(clazz -> { -// try { -// Object plugin = Reflections.instance(clazz).getOrThrow(); -// injector.injectMembers(plugin); // Inject -// modules.put(new WrappedPluginContainer(plugin), plugin); -// } catch (Exception error) { -// ErrorReporter.builder(error) -// .add("Problem constructing module") -// .add("Class: ", clazz) -// .buildAndReport(System.err); -// } -// }); -// } - /** Register the listeners found in the modules */ public void registerListeners() { modules.forEach(container -> { try { - registerModuleListeners(container, getModule(container.getId())); + registerModuleListeners(container, getModule(container.getId()).getOrThrow().getHandle().getOrThrow().$this()); } catch (Throwable throwable) { ErrorReporter.builder(throwable) .hideStackTrace() @@ -99,7 +73,7 @@ public void registerListeners() { /** Register the listeners for the module */ @SuppressWarnings("unchecked") - private void registerModuleListeners(WrappedPluginContainer container, Object module) { + private void registerModuleListeners(WrappedPluginContainer container, Object module) throws IllegalAccessException { for (Method method : module.getClass().getDeclaredMethods()) { if (method.getAnnotation(Listener.class) == null) { continue; // Must register methods with a listener annotation @@ -108,9 +82,10 @@ private void registerModuleListeners(WrappedPluginContainer container, Object mo Conditions.condition(types.length > 0, "Must have more than 0 arguments"); Conditions.condition(Event.class.isAssignableFrom(types[0]), "First arg must be an Event"); Class eventClass = (Class) types[0]; + MethodHandle handle = MethodHandles.publicLookup().unreflect(method).bindTo(module); Sponge.getEventManager().registerListener(Utilities.get(), eventClass, event -> { try { // Proxy the event to the module - Reflections.invoke(module, method, event); + handle.invokeWithArguments(event); } catch (Throwable throwable) { ErrorReporter.builder(throwable) .add("Parameter Count: ", method.getParameterCount()) diff --git a/sponge/src/test/resources/modules/ducktape.groovy b/sponge/src/test/resources/modules/ducktape.groovy new file mode 100644 index 0000000..b6d94ff --- /dev/null +++ b/sponge/src/test/resources/modules/ducktape.groovy @@ -0,0 +1,21 @@ +import org.spongepowered.api.event.Listener +import org.spongepowered.api.event.game.state.GameInitializationEvent +import net.year4000.utilities.ducktape.module.Module +import org.spongepowered.api.event.message.MessageChannelEvent + +@Module(id = 'ducktape') +class DucktapeModule { + DucktapeModule() { + println 'I have been loaded yea!!!' + } + + @Listener + void onInit(GameInitializationEvent event) { + println 'I ran the GameInitializationEvent listener' + } + + @Listener + void onChat(MessageChannelEvent.Chat event) { + println 'I spoke in the chat' + } +} From f98d5a49e2cf9e734aee64dac8f39f649e68a42e Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 09:57:00 -0700 Subject: [PATCH 05/20] Allow telling spongestarter which is the root project --- .../main/groovy/net/year4000/utilities/gradle/sponge.gradle | 5 ++++- sponge/build.gradle | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/gradle/src/main/groovy/net/year4000/utilities/gradle/sponge.gradle b/gradle/src/main/groovy/net/year4000/utilities/gradle/sponge.gradle index 6899c62..6d7e0df 100644 --- a/gradle/src/main/groovy/net/year4000/utilities/gradle/sponge.gradle +++ b/gradle/src/main/groovy/net/year4000/utilities/gradle/sponge.gradle @@ -70,6 +70,9 @@ class SpongeExtension { /** The port the debugger will bind on */ int debugPort = 5005 + + /** The root project id */ + String rootProject } /** Sponge starter runs the needed things to start a sponge instance */ @@ -131,7 +134,7 @@ class SpongeForgeClient extends DefaultTask { pluginJar.deleteOnExit() } - if (project == project.rootProject) { // only start the client when its the root + if (project.name.toLowerCase() == project.rootProject.name.toLowerCase() || project.name.toLowerCase() == project.spongestarter.rootProject) { // only start the client when its the root logger.lifecycle 'Setting up the client enverionment' MinecraftVersion version = makeMCVersion forge.get() ClassPaths classPaths = generateLibs version; diff --git a/sponge/build.gradle b/sponge/build.gradle index 3f18ef8..8373a4e 100644 --- a/sponge/build.gradle +++ b/sponge/build.gradle @@ -25,6 +25,7 @@ compileJava.options.encoding = 'UTF-8' spongestarter { deleteJar false + rootProject 'sponge' } jar { From 6f12fddaff8771996ad36e3258548a2d66e494f7 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 09:57:23 -0700 Subject: [PATCH 06/20] Enable the fly command --- .../src/main/java/net/year4000/utilities/sponge/Utilities.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java index 836cfe8..1b0d583 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java @@ -8,6 +8,7 @@ import net.year4000.utilities.ErrorReporter; import net.year4000.utilities.Tokens; import net.year4000.utilities.ducktape.loaders.GroovyModuleLoader; +import net.year4000.utilities.sponge.command.FlyCommand; import net.year4000.utilities.sponge.command.PluginCommand; import net.year4000.utilities.sponge.command.SystemCommand; import net.year4000.utilities.sponge.ducktape.SpongeDucktapeManager; @@ -75,7 +76,7 @@ public void onUtilitiesPreInit(GamePreInitializationEvent event) { public void onUtilitiesInit(GameInitializationEvent event) { Messages.Factory.inst.get(); // Trigger a download from server now so it can cache it for later PluginCommand.register(this, injector); - // FlyCommand.register(this, injector); todo disable, should be in drip + FlyCommand.register(this, injector); SystemCommand.register(this, injector); } From 293d9c5f282407d9d0ad532bad690f900d3f0b14 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 09:57:36 -0700 Subject: [PATCH 07/20] Register the module listeners --- .../src/main/java/net/year4000/utilities/sponge/Utilities.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java index 1b0d583..322d677 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/Utilities.java @@ -70,6 +70,7 @@ public void onUtilitiesPreInit(GamePreInitializationEvent event) { packets = setProvider(Packets.class, Packets.manager()); holograms = setProvider(Holograms.class, Holograms.manager()); moduleManager.enable(); + moduleManager.registerListeners(); } @Listener From f21ad5012df511cd11df201d35ccb18f8d37c0ce Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 10:29:58 -0700 Subject: [PATCH 08/20] Copy the module into the mods path so ducktape can load it for testing --- .../utilities/sponge/UtilitiesDebug.java | 19 +++++++++++++++---- .../resources/mods}/ducktape.groovy | 0 2 files changed, 15 insertions(+), 4 deletions(-) rename sponge/src/{test/resources/modules => debug/resources/mods}/ducktape.groovy (100%) diff --git a/sponge/src/debug/java/net/year4000/utilities/sponge/UtilitiesDebug.java b/sponge/src/debug/java/net/year4000/utilities/sponge/UtilitiesDebug.java index 9bb958b..c903fd6 100644 --- a/sponge/src/debug/java/net/year4000/utilities/sponge/UtilitiesDebug.java +++ b/sponge/src/debug/java/net/year4000/utilities/sponge/UtilitiesDebug.java @@ -16,15 +16,17 @@ import org.spongepowered.api.command.spec.CommandSpec; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; -import org.spongepowered.api.event.game.state.GameInitializationEvent; -import org.spongepowered.api.event.game.state.GamePostInitializationEvent; -import org.spongepowered.api.event.game.state.GameStartedServerEvent; -import org.spongepowered.api.event.game.state.GameStartingServerEvent; +import org.spongepowered.api.event.Order; +import org.spongepowered.api.event.game.state.*; import org.spongepowered.api.plugin.Dependency; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.text.Text; +import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.List; import javax.imageio.ImageIO; @@ -40,6 +42,15 @@ public class UtilitiesDebug { private static final List activeHolograms = Lists.newArrayList(); + // This must be the first thing the system does to allow the module to exist when ducktape finds and locates it + @Listener(order = Order.PRE) + public void onConstruct(GameConstructionEvent event) throws IOException { + // extract the groovy module to test it + try (InputStream file = UtilitiesDebug.class.getResourceAsStream("/mods/ducktape.groovy")) { + Files.copy(file, Paths.get("mods/ducktape.groovy"), StandardCopyOption.REPLACE_EXISTING); + } + } + @Listener public void onInit(GameInitializationEvent event) { Packets packets = Sponge.getServiceManager().provide(Packets.class).orElseThrow(RuntimeException::new); diff --git a/sponge/src/test/resources/modules/ducktape.groovy b/sponge/src/debug/resources/mods/ducktape.groovy similarity index 100% rename from sponge/src/test/resources/modules/ducktape.groovy rename to sponge/src/debug/resources/mods/ducktape.groovy From 33ee091645f052fd507fe36757f79c8c323fa018 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Fri, 12 Jul 2019 10:30:17 -0700 Subject: [PATCH 09/20] Enums need the signature now --- .../sponge/protocol/proxy/ProxyEnumConnectionState.java | 2 +- .../sponge/protocol/proxy/ProxyEnumPacketDirection.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumConnectionState.java b/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumConnectionState.java index 41bc614..d509709 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumConnectionState.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumConnectionState.java @@ -44,7 +44,7 @@ default Class packet(PacketType type) { // enum - @Invoke + @Invoke(signature = "()[Lnet/minecraft/network/EnumConnectionState;") @Static Object[] values(); diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumPacketDirection.java b/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumPacketDirection.java index 4e109c4..b4c7969 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumPacketDirection.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/protocol/proxy/ProxyEnumPacketDirection.java @@ -24,7 +24,7 @@ static ProxyEnumPacketDirection get() { // enum - @Invoke + @Invoke(signature = "()[Lnet/minecraft/network/EnumPacketDirection;") @Static Object[] values(); From 6096d2844167a3baf2ac74a22d104d8312719573 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Wed, 17 Jul 2019 07:57:30 -0700 Subject: [PATCH 10/20] Change depend to the api version not implementation --- core-ducktape/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-ducktape/build.gradle b/core-ducktape/build.gradle index 2ba747d..8048986 100644 --- a/core-ducktape/build.gradle +++ b/core-ducktape/build.gradle @@ -13,5 +13,5 @@ compileJava.options.encoding = 'UTF-8' dependencies { compile utilities.project('core') compile 'com.google.inject:guice:4.0' - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + compile 'org.apache.logging.log4j:log4j-api:2.8.1' } From aa808d616fe57afe50e4e11a67631728d4e659b7 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sat, 20 Jul 2019 08:50:01 -0700 Subject: [PATCH 11/20] Seperate the path loading logic --- .../ducktape/loaders/GroovyModuleLoader.java | 24 ++------ .../ducktape/loaders/AbstractPathLoader.java | 56 +++++++++++++++++++ 2 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java diff --git a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java index 9dce9c8..99fe1b0 100644 --- a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java +++ b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java @@ -5,9 +5,6 @@ import com.google.common.collect.Sets; import groovy.lang.GroovyClassLoader; -import net.year4000.utilities.Conditions; -import net.year4000.utilities.ducktape.ModuleInitException; -import net.year4000.utilities.ducktape.module.ModuleInfo; import java.io.IOException; import java.net.URL; @@ -24,26 +21,15 @@ * This class will support for loading Groovy files * into the class loader for the current running JVM. */ -public class GroovyModuleLoader implements ModuleLoader { - private final Path dir; - - public GroovyModuleLoader(Path dir) { - this.dir = Conditions.nonNull(dir, "dir must exist"); - } - - @Override - public Collection> load() throws ModuleInitException { - try { - return load(this.dir); - } catch (IOException error) { - throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); - } +public class GroovyModuleLoader extends AbstractPathLoader implements ModuleLoader { + public GroovyModuleLoader(Path directory) { + super(AbstractPathLoader.createDirectories(directory)); } /** Load any groovy script that ends with .groovy */ - private Collection> load(Path dir) throws IOException { + protected Collection> load(Path directory) throws IOException { Set> classes = Sets.newLinkedHashSet(); - try (DirectoryStream stream = Files.newDirectoryStream(dir)) { + try (DirectoryStream stream = Files.newDirectoryStream(directory)) { for (Path path : stream) { if (!path.toString().endsWith(".groovy")) { continue; diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java new file mode 100644 index 0000000..6d81db2 --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java @@ -0,0 +1,56 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import net.year4000.utilities.Conditions; +import net.year4000.utilities.ErrorReporter; +import net.year4000.utilities.ducktape.ModuleInitException; +import net.year4000.utilities.ducktape.module.ModuleInfo; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; + +/** An abstract class that will handle the checking of directory */ +public abstract class AbstractPathLoader { + private final Path directory; + + public AbstractPathLoader(Path directory) { + this.directory = Conditions.nonNull(directory, "directory must exist"); + Conditions.condition(Files.isDirectory(directory), "directory must be a valid directory"); + } + + /** Get the directory of the path */ + public Path directory() { + return this.directory; + } + + /** Create the parent directories and return the newly created directory */ + public static Path createDirectories(Path directory) { + Conditions.nonNull(directory, "directory must exist"); + try { + if (!Files.isDirectory(directory)) { + Files.createDirectories(directory); + } + } catch (IOException error) { + throw ErrorReporter.builder(error) + .add("Directory: ", directory.toAbsolutePath()) + .buildAndReport(); + } + return directory; + } + + /** Load classes from where ever and create the collection of classes for the modules */ + public Collection> load() throws ModuleInitException { + try { + return load(this.directory()); + } catch (IOException error) { + throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); + } + } + + /** The implementation to gather the collection of classes */ + protected abstract Collection> load(Path dir) throws IOException; +} From ceb36220dfa74615089cb92c6daeea30d7e192b2 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sun, 21 Jul 2019 08:52:39 -0700 Subject: [PATCH 12/20] Reuse the directory stream load code --- .../ducktape/loaders/GroovyModuleLoader.java | 29 ++++--------------- .../ducktape/loaders/AbstractPathLoader.java | 16 ++++++++-- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java index 99fe1b0..c4a376c 100644 --- a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java +++ b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java @@ -3,19 +3,16 @@ */ package net.year4000.utilities.ducktape.loaders; -import com.google.common.collect.Sets; import groovy.lang.GroovyClassLoader; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; -import java.util.Set; +import java.util.Collections; /** * This class will support for loading Groovy files @@ -28,25 +25,11 @@ public GroovyModuleLoader(Path directory) { /** Load any groovy script that ends with .groovy */ protected Collection> load(Path directory) throws IOException { - Set> classes = Sets.newLinkedHashSet(); - try (DirectoryStream stream = Files.newDirectoryStream(directory)) { - for (Path path : stream) { - if (!path.toString().endsWith(".groovy")) { - continue; - } - URL url = path.toUri().toURL(); - GroovyClassLoader loader = AccessController.doPrivileged((PrivilegedAction) () -> { - // Convert the Groovy script to a Java Class - Class clazz = getClass(); - GroovyClassLoader groovyLoader = new GroovyClassLoader(new URLClassLoader(new URL[] {url}, clazz.getClassLoader())); - groovyLoader.addURL(clazz.getResource("/")); - groovyLoader.addURL(url); - return groovyLoader; - }); - Class clazz = loader.parseClass(path.toFile()); - classes.add(clazz); - } + if (directory.toString().endsWith(".groovy")) { + URL[] urls = new URL[] {directory.toUri().toURL()}; + GroovyClassLoader loader = AccessController.doPrivileged((PrivilegedAction) () -> new GroovyClassLoader(new URLClassLoader(urls))); + return Collections.singleton(loader.parseClass(directory.toFile())); } - return classes; + return Collections.emptySet(); } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java index 6d81db2..fd47bf9 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/AbstractPathLoader.java @@ -3,15 +3,18 @@ */ package net.year4000.utilities.ducktape.loaders; +import com.google.common.collect.Sets; import net.year4000.utilities.Conditions; import net.year4000.utilities.ErrorReporter; import net.year4000.utilities.ducktape.ModuleInitException; import net.year4000.utilities.ducktape.module.ModuleInfo; import java.io.IOException; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.Set; /** An abstract class that will handle the checking of directory */ public abstract class AbstractPathLoader { @@ -44,13 +47,20 @@ public static Path createDirectories(Path directory) { /** Load classes from where ever and create the collection of classes for the modules */ public Collection> load() throws ModuleInitException { + Set> classes = Sets.newLinkedHashSet(); try { - return load(this.directory()); + classes.addAll(load(this.directory())); + try (DirectoryStream stream = Files.newDirectoryStream(this.directory())) { + for (Path path : stream) { + classes.addAll(load(path)); + } + } } catch (IOException error) { throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); } + return classes; } - /** The implementation to gather the collection of classes */ - protected abstract Collection> load(Path dir) throws IOException; + /** The implementation to gather the class for each directory */ + protected abstract Collection> load(Path directory) throws IOException; } From 9747bb1396a3e25b32bfaac9db4255f44734ec60 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sun, 21 Jul 2019 08:55:37 -0700 Subject: [PATCH 13/20] Add a jar module loader --- .../ducktape/loaders/JarModuleLoader.java | 39 ++++++++++++++++++ .../utilities/ducktape/loaders/Loaders.java | 37 +++++++++++++++++ .../loaders/AbstractModuleClasses.java | 28 +++++++++++++ .../ducktape/loaders/JarModuleLoaderTest.java | 23 +++++++++++ .../test/resources/modules/jars/module-a.jar | Bin 0 -> 5914 bytes .../test/resources/modules/jars/module-b.jar | Bin 0 -> 6660 bytes .../test/resources/modules/jars/module-c.jar | Bin 0 -> 6611 bytes .../test/resources/modules/jars/module-d.jar | Bin 0 -> 5623 bytes 8 files changed, 127 insertions(+) create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/JarModuleLoader.java create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/Loaders.java create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/AbstractModuleClasses.java create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/JarModuleLoaderTest.java create mode 100644 core-ducktape/src/test/resources/modules/jars/module-a.jar create mode 100644 core-ducktape/src/test/resources/modules/jars/module-b.jar create mode 100644 core-ducktape/src/test/resources/modules/jars/module-c.jar create mode 100644 core-ducktape/src/test/resources/modules/jars/module-d.jar diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/JarModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/JarModuleLoader.java new file mode 100644 index 0000000..1d7b464 --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/JarModuleLoader.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import net.year4000.utilities.ErrorReporter; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +public class JarModuleLoader extends AbstractPathLoader implements ModuleLoader { + public JarModuleLoader(Path directory) { + super(AbstractPathLoader.createDirectories(directory)); + } + + /** Load any groovy script that ends with .groovy */ + @Override + protected Collection> load(Path directory) throws IOException, RuntimeException { + if (directory.toString().endsWith(".jar")) { + ClassLoader loader = Loaders.classLoaderFromPath(directory); + // And then the files in the jar + return new JarFile(directory.toFile()).stream() + .filter(jarEntry -> jarEntry.getName().endsWith(".class")) + .map(entry -> { + try { + return Class.forName(Loaders.formatPath(entry.getName()), true, loader); + } catch (ClassNotFoundException error) { + throw ErrorReporter.builder(error).buildAndReport(); + } + }) + .collect(Collectors.toSet()); + } + return Collections.emptySet(); + } +} diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/Loaders.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/Loaders.java new file mode 100644 index 0000000..bb657a3 --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/Loaders.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import net.year4000.utilities.ErrorReporter; +import net.year4000.utilities.utils.UtilityConstructError; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; + +final class Loaders { + private Loaders() { + UtilityConstructError.raise(); + } + + /** Format the path */ + static String formatPath(String path) { + return path.length() < 6 ? path : path.substring(0, path.length() - 6).replaceAll("/", "."); + } + + /** Create the class loader from the path */ + static ClassLoader classLoaderFromPath(Path directory) throws IOException { + URL[] urls = new URL[] {directory.toUri().toURL()}; + return AccessController.doPrivileged((PrivilegedAction) () -> { + try (URLClassLoader classLoader = new URLClassLoader(urls)) { + return classLoader; + } catch (IOException error) { + throw ErrorReporter.builder(error).buildAndReport(); + } + }); + } +} diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/AbstractModuleClasses.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/AbstractModuleClasses.java new file mode 100644 index 0000000..a06fa19 --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/AbstractModuleClasses.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import java.util.Collection; +import java.util.stream.Collectors; + +/** Shared code to test if the modules have been loaded properly */ +public abstract class AbstractModuleClasses { + protected static final String[] MODULE_CLASSES = new String[] { + "class net.year4000.utilities.ducktape.modules.ModuleA", + "class net.year4000.utilities.ducktape.modules.ModuleA$ModuleASettings", + "class net.year4000.utilities.ducktape.modules.ModuleB", + "class net.year4000.utilities.ducktape.modules.ModuleB$ModuleBModule", + "class net.year4000.utilities.ducktape.modules.ModuleC", + "class net.year4000.utilities.ducktape.modules.ModuleC$ModuleCSettings", + "class net.year4000.utilities.ducktape.modules.ModuleD", + }; + + protected String[] classStreamStringMap(Collection> classes) { + return classes.stream() + .map(Class::toString) + .sorted() + .collect(Collectors.toList()) + .toArray(new String[] {}); + } +} diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/JarModuleLoaderTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/JarModuleLoaderTest.java new file mode 100644 index 0000000..29958cd --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/JarModuleLoaderTest.java @@ -0,0 +1,23 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import org.junit.Assert; +import org.junit.Test; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; + +public class JarModuleLoaderTest extends AbstractModuleClasses { + private static final Path modulePath = Paths.get("src/test/resources/modules/jars"); + + @Test + public void jarTest() { + JarModuleLoader jarModuleLoader = new JarModuleLoader(modulePath); + Collection> classes = jarModuleLoader.load(); + System.out.println(classes); + Assert.assertArrayEquals(MODULE_CLASSES, classStreamStringMap(classes)); + } +} diff --git a/core-ducktape/src/test/resources/modules/jars/module-a.jar b/core-ducktape/src/test/resources/modules/jars/module-a.jar new file mode 100644 index 0000000000000000000000000000000000000000..121d81909ff8f3e7682c5d2f740c6a18789217d5 GIT binary patch literal 5914 zcmcIo2{e@Z8y?0o_9@1o5+Um_%qVLNrb43ZZDU`uYm}vKvP@)&P_ClfNQDU(DQ!}g z5|NNSxzUv^Yoz(lhxE;$<(&VWIkTSgKEL;U-sgLl&%_YQ#0~)-MyeCL=f5nzF+t!E zPe-DHxfLhG!xwvSFZDISzy~p*TJS+&)aRHAtp(Sjg}k0A!IbFb>j;?IQO$1nESL@^ zYqCGqhKF}O;bXXnLQTQgg>B;f85O#XKQe~c*6Pdq;Ii6cOIGw|) zt25XnoKR$3AIw>=(jy^g85&kxBClK_&}5mvKk1g6a-Q2Lw8_e5_R_<4cLO(TJ(y@1 zJl8hp#Z1Qo61<1w#uTeD>)kV3I*t3sr7P>xxQPglXv6-*T9+L`YA?;PTT$;uY>yZC z=qOTuA0MyQ`NDNy%5sV#-C0Y~iP%`taQwWn_ePjd zBVNgN*}xLkAA&J4WQAdykW|j3S+|ki9jFh2ZCjVaYQ^)QKkm(PkjLjSy@xx6cXTQ>x)IB(Mtp@7nd0w zZ~TkmS~8`H!HPvy&1BfZq!eeNc(l?9AAh18d0*THnIjt?i_Gaj zwif6`1+|D*ox>j&yZI1V;Lv+SGCnVPYnIx{uZ`XsV%aA!*J1}*Q)|@`LOrcBEcQlC z?S~J!@hUVhYQj#KU*;Oi#%LxB#A!`w^vT{@hb%_K^rqU^aS_{!obb+Vg$0`}FBH24 z#{U~m{=g%Ph}PdFRGq6bG{Mt)?{=3_tH#ijdcaq-zIbtIv!>dHE=`RJLSO!1u-TM<}6SnmLoRkphj8y?6Y zXE9S{!)@`%)s=maDG%mkBUn?$u7cu<;twxp4VN@kNjIVX^X#(D_PCR}R}(J{QzXag zD6o(mwAp$WXi^QOEPl91!|+`lckk?JNMhv6EnR2!C;84Jet~Pp;YS$&Vf;B5-f@QE zXIBM~T^e~WrTJU=S*~+>g@~?-K__^ySpH+dBk5J^M|5>}CAvBu`GNE&=<2G->L4^1 z0Z?kmOQlwkJ473fr-(2|zBqqAh}kPoky>f5gd}ZFzOI?n_sJz>)_g6t-ry=lBEb@^ z&hes_8{+OORT&J86BXK_A#Oju(Ge65+?%o0)cL~b%va7xH%I|GL6i{emz3Zrj zcEIHzOV~7%Ga#udm9*)WpB7qxwUs5cJO|6gMV|xNUqGXi88{vPvCMv;5C=bdH=?b# z;}7)4N>^&7SJ>+A`tQE)!m)_?G?qh7kA4NZoArg7q@~3qaSl+7-H)sdSsAO}-`z6Wp{d)hpL18(f;5@N-mMuO#cl zff70Poo_%lnI6oiuxR{>j$!Or*V!F>$VsL}teS{f;bjJDk z8qcVmnMa$g^M=jaPrhmHKOl+S#La}SyR4KFw4I61+A~G`(?1+ZPTfZ%IZEva=#f_i zYPNdMZv>xWLtgNHQ+5JrXyqjE!7i)WmD@dWx=D{)xWqqV2dD0R^SintVn{@^ivPzR zwlt-jw0xAjkX3s2c%*GfTvPCAo!isdsl=TWUu7OU*|tXKgqM$#FXT#<6LuK1U5m+Z zF;(5Z+uQW-$-T0Te3lcjBB(q2V~C#ov%-WKsPxU;m)nYb3ipl0I$ti{H~k>`owc3P zz3jArZa2#2vw|62Vj?^0;3OPg%q@8QX^r813DuN2VfEsQh8v=)yPFO>LHqh11fS3$ zpVQKNYhUaU(hL72E-MAEm1q~Y_LPKJqVXwjWy*X7-Lp9^8sPe1dVxb27VfuSv`1wP zB=agiTvf&8REvGQAzyl7Qn?}EK;5P+%&1*L-emD3WkfZ20gY>$mv3Vr zBLwm{^TLq4ve@yzFLv=o(VIFFiLRc`M^+KPshig;G@s^>tOv4~?D$Ba?XlELek++m z1sGF`jHtN`XMO#!=V8*0o?ZEv{FBTPr=PI?0nuXj>DUgf5Z6vvOXz4Gy;C`PdzkQm zu|?-LBdeQvV*VkLWtq8qqEGIb&1ChG4_BUcyVypX1#wQ4ZPV)gqv~~<7MAVl5JpbR zI4M3}Kp$0^-eMuMrM=3^l~f9qh(0OqU+{YH=v-r!iI8-mmVRh6X(LRlyy*{x*iGr2 z4E#I+$?T-39hQ58#(fl$B?Jw4GS0mh)qU_mBs0@FTwY;N{2f$6=!77}50Q0__vT5F9$fRK<^ zAi5RThG)GkV6i)IJdpVBW_>8HB)4a2NvIL)w(_f(*gBJ0)vvWJN^>ZzM#FYJqHIs% zT0=~(!$&Q#bk1rCe?4F2-E6NWw&fkVe*M-&R@LPB&y?yk;dosh_A9&vO6O9=ykc_< zDXK96254FN+^EEVjZa*u{~UcFD~$r16b=s@*9_S5nF?o_& z)T1HKSfnIxs~S2{-FhH@jN#*;qKT`}fw{~(5zmVS19Em{lXtPT-8C;j_TSc3DLEx! z_Q!mK zW z9#oYqQNE&o^uz)Ffr%5P@h^W>JURwfa+RJzBnWyCho=@?8V|uMz{*?#3jlc05CH*Z zoI0~QAPuYEc7PwT3Pzs8Jz`mn)#X0Z^9%S4=2w=+XKvP?BhxXxlKb>bgWVs*~9A zWP?7S<@5LVsyK+-LapCF%f|OLD_wfWgxG2-a6a5<}&`svBrOBNBIB*}r i(;OGT_3HsG9=F&!S7j;JzGYvg2-(+cA;~gQ+|Gc|9|)G3JkRzUO?-`+L6M^V8R*p=E>sFNa;@2N(YN z@rM=ygSgsyOCL67hMe_8nS~NR<5XM_eWC>ygn{@TQzo@w`C%co*U;S1+s)H<$@Hqn zqUlK59>#m>u<)0)TvQoI5MR|=v!^+B~6zbs5jEaw*D|AvQa{5g3%-CWkv#Q%!$H`#cId0bgEl;?H@8cy?odjLgQnl^*25?zqE>eOQpEc#Jogr%RDAZsIJ{V73(gC1n<7I6DeV4SQ zYzAn%Yz8h1*pzZv;N+%K=4)2S+Jf8K-onaaRPVr%QMMyd`a#r*a2hcff~pt+3!UUv zZ-N-U60Q!SQH}_sMPJ~SF&hGsrDtG@s#aDYChtT10EAFxYKahETT4%rjEu~(0PDlW z^8>DB(=~G#Nt0y_QHSlD7pAMT(`~E_QR;;63EnId6Aq0I?=tk2O4wd*E=t959W`w( z=SwI5pVki_Ak~9!{WmE?crSUN#dt68!yJu09=GS<;ScUj2|Z3X^PL_jzZ{OSn=9+& zXANgLwjY3u#?q^Kdv*YeNbTm|v)PDX@w)iqTOBXg0g&;!G%Z7Bi(&&H>wd1BlXiKJ zK<~7T$oB|?l)q-?IV#7hVEvKB-o>U(pZOU~iI5o;+qH}vbb7IC^|RGT{NW4uDrgLX zW%q3YbQV83;P8B1$N;fOXjxWmX-lq;jmVll{(t;zCWip$?da_2?P%-u6OzWs+LZ9x zPF68RSngcQOhq@Rruxyj70D7C*Ts-?+tc#*oO}DlA!Oz-2dYiy^1NuWk&Fsca|8pQh?I>#tf4XWE{0S_dPKydiX|5}wvb-Ph&Ux9Bmex_&LL(s-e7N!NT! zXHlEs!$e8v?h#TI7~0)6shab+g%9XexKdf^9K+q01xDVfceJUN#@0l7*bjtR#eehm z8BPwLL~Jr3jLaLVX3dAg)ME3dc4qe}!oE8A6}VZoWIo2dNwX6a!dYj@=(~sO0cO&|s6+s3cWVq_^z=0`31W$Mgyc-MP?NmE2Sxr?B zi(}gV5KhC9ah$ER6tR(EqLeH`n|T&nS$h`H z$~YHVS>Zw};{>%bJxZ<2BxQJdo-cW^m6djK?GmK98${@sRxE3})ypI%MXfz+Szasu z=y9;?B^)oTpR;@6$cU9TM|P~s9iZNN+%3zvc6TE$3Th*6DUi5SpMRM|S2A|Qe}Nqr zHyfNYr~@W~E)$D40&=gi8}Ld(Cg6I>{YaV$>pdCRUi&yEU6hnWk2}QGV&6k(IfTyW z;zXNB7kdfU@A{%4zDeUpVgeocv5?Nua`PZ&;k$A2za@3@gb@^57T620CU|$BKwzQ- z%sHov$vYv{n{+wING8jbMZVkHrrF|y&tIm1SUJ8NIM zyT6&5QL|K-XA(ILKQn;iA7!O&WGy@~{61n_SA8@){EDk{j$}{wZ3c#7ZY_*I<_oQGPl9NpDvTz@I*K69$4Pf#RJs@G5r zW|QRpFFRc?+T1yUR4p0pyvL_8Pw?D|bv{WKS~)PYCEw>DJSI^@;Jx}ZGQxknb(d%P z+ezdf3B__XlaciuCCG2K;t0IYn;9Jy(;eAc#IET*9Yp4t;``dwxb&J&TA_mbDBdF*xaTgt<>VDa%*Ji*@g~z?)iF-xQ}(JotVGV|ssFEPZcdnblxpbz#F(maS!B zxg5r!A}<7T8S|eP3@fSxy0SGW*10#{<3wOT$L6%&XgM_Gii2I)$%B946O4-}4m7e> zNy1A~N90s_*u`%#&Mr2ni-;3pe$h#5CSGNiRqLBNVpfA{Dw;BH#$UcJ6lq%O*mh`d z?d6_=^D$Ld?x1jDnTpL7?$9O+Te!9JNiu?AewN8BIdRKu9X=+!p(asb; z8Lz6zaj0<{dnP+}JWB7gBj#h`0jurt>2Yn;IVZIpLT>5Mk6O^I_f zKwrqHb^7x>H3Y&#w>ZC0-U%8T-wE4(?1;s$wf2RH+hcXucg6Ew<@CXxDP^Vl!cY`K z$A>YpopEoT{HDOiWSUg{-lRtgIgMs=!&= z*4pGP&fP^t$M!;%#*8JbxSd41@0}7vh<4XysVa_@JH5IS&ZzP6YI}pKy_V6nNahP> zRg%0syLB4p@;}x0Rl2LTr>NYKtk7W3Hx}F>Kd2SX?BzD=`ubrOm37fXY3f~q*ggHE zsePKdHP}3c^tk<@n)`hl#CgBCzQ)5pYkxV-0smr&Z?5`s6V6B|RJ-;Em;RUjU?Dn! ze;!9}j{TgmKab*|%%dWB;Vm)m1fewbclfv+$32SWP&|U2K2b;}9D<+ac=hm!*`q!- z)`*0w?D3yuY@&Bx;YnwH^!+dY2wcafG5n_q)raSPOC`K=5km#LH`j{}i1*m~n7lg> zgPrcUcA`b|L5p0UOF_Wa*bl_=&vZwpXr6lC(J%!^PA7fh%%OQ$M}5}?Tf=e+C(^52 zrh5x<j?ltN9Y!&ITmV+Z`PqPGPXs2$>CtFCBlE!CYfPbUl& zaBBYDKU{6Eddj)=<_-2hi6S4tXsN{7X!-uwv zJCkfua*rGg*mpZ~D*gknr$kDD{A)w_H70AEtO3?y@a*>6F;2!BS-l}pexZAL^*oP< z%P|#NWgH)0$uR~l+?d39vtMl^LTXA2KuSf;O+$IiriCyQkGO@G`Uo2MUVLJ}u>2rr z(R$^10r=Sk3&=V*Snh{4=pL}>26(6g4r29#j+G$h&_+~{l@s-_@uCahr2Lr+a3pi+ zc(4m_LMv`o5&}PufRiNjklYQ)!Adzd@@He0@j-~xQN9%Y0|hsOT#ukrh^|Q@1kaR|wFD+g@Z>5Ca+n+Z zd~JuTR3)qfGT8GRnr+isDy)u~Twfq&Fqo1gF`NB@X9`M_hfmHbIQ$Xx3~`Y)lm<;v zlqCmdDDcoGK@z?;{ra9)X%CE1KkESCCFanP4C`yZDhu)=09k;GfFjAFcOy$ss0MjL zjS;}kiy0<(B sF)YtP;L-tu7WhopAX$!!ZNtk^zHEXQrz7rv2xK$ytw1FG7CZ3kzw3W@r2qf` literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/jars/module-c.jar b/core-ducktape/src/test/resources/modules/jars/module-c.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c4490ff954b216b8eebc8ef4b1730e90e828fb8 GIT binary patch literal 6611 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 literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/jars/module-d.jar b/core-ducktape/src/test/resources/modules/jars/module-d.jar new file mode 100644 index 0000000000000000000000000000000000000000..acfa85354822e203c198364e145383e1374c179a GIT binary patch literal 5623 zcmc&%dpy(o8y|)tv*a?jvfnB3lgk)M#H3TljwoqL&fG7@y^X^woi-UNy17KkC7n~9 zP%4f(Ijt0Ruu>;UbWxpFTCF4wY3KX3%y-{ymR{%g`faa`{qej%&+~rX&-?p)yh#d3 zRRs8|T{O6I{GU%>NCXBE7e=%4^_zh(p%Mbnz-LfS3*ik!XdzI*d%!_7Lj6;OrMnNs zhZesvY$Ehnq9Bx8B`-d7JU_hV&U74t?|V$Xhe&8!YXbv7O{v|AG_Ib|<6XD0KP- zjvlzs6XOxR&K-rzz*GlqY9HzSJrmQXc5F!5OZnV(`}hNT7B|L|||r&-2^0JdL&4-gNohScUl* z1G!oQ%+_IT*EWRDBV!g_!67pPNi5d34&Z>rDx=i0Sq^qU@hQLuRET6vO(-NaENCOa z+S*!3fNXK;d=i&1RB8>}B0M_X6|;WdJ@$w~t_1CjBB?pAwp+w?*y~<^7{yE?0I#i=-0EDF%n^t-wsM zR1mAWm5wQUs08wC`orVMyD~)vk|m-RA!`#ODO)x;sTlu1{pi9)kVK1$iK0b?QKwMS zAk3zWrGtoRsz&HsLQQRJFD%@o7=IEE7*~0Efl1L(=YnT%BhyEHH3=OamHc^mWb4Ih z?QAq6W}|5fU12v)f4S4#kasI0cXa&O6~eGs`?RLZspfW*ws_d zM+PWm3?m~zNnLd)9qy7TDUdbEk`nKMxVYdwF#ilR2{M~#$N$)-rcg*|Qb;r{C?RYL zy(z;S-%PsRglJ;IV~YuI+gyA9^{=$gU(9@{a-P2GrL|UbDfqy|0m3t$5Z>u=;Vp34 zXU>wlipf>``WjY2vpe`q^cshUYf9hWu9;1Vb|o)vnQ7;7V017k%*qllGPmr7fm_>k z1XgzQAZTT?#;xqcxRuR3~6Ij`qF0Dng6)w_i?u^*ix1GJOHs4bI zn-4(^mu;`#V#FOv(!=!4>KT7z~$et|S32Bt>Zt$iMrUNTMi4*<#mz47r5-2 zN&`ZXTt3u+>z;W^Yqj^h^whnBYqxKSGW0@p@fs-f8O9fLZI|rr(#fc?XOC-db4U%X zC)vO)+sLL&gIPnP8k8wJCWqJra6A_NT1zSa>LBM^-E%kF+n2Utm*kim%-W7;`c?Fk zPb|3nAR*!D-=i);c6>G5kJufLlMH!iWGnhaa{r6WL6R%4jCmw3roz0p=Nt-EtL+7v z-S>#>*i$k^2NLwzqJ#41 zoO~6ultqfkZyDLj>SsmHx2p5d=;qe98C`j@BEsg6Cfg(II>X%Xw*%QXXZkH+=T^E8 znNWd~|2-bZH*)y3N$w z%|EuVFr-d(nf!m=;&&|4C|Od^+fZ&-*vomV9k4%({qyYahP#?c$;Am#3}&#ip1Ey4 zMfu9$Yhq(-+w%;KC~DjS#jva@Cy#3lrKCEKlv|xHfgdxUEz>smi;MhWu2EAHJ8n)% z3X5;#{ivl$3;FZeU#M~UoEaZ3SpU8}QGMsYhQ`Nw7gLj8>-6atgbym!9p8J7m59D= z)0xs0@dQWym`yiX|FkDqZ=Xk=-Ye(6p~TGj7v#WUQT*!1TUBxhgnLN{a;WC}TrOJu6Z=4^7E5p)GyG@$kk`Yv>f!b46t%(yp=6GXZ*vCmA^ z9q3VG#1Fv3NV4BdPKK~M@T%Zl0;_^{$w{Otf3+_-3f3*r0w*^u=tI^{ Date: Sun, 21 Jul 2019 08:56:28 -0700 Subject: [PATCH 14/20] Add package module loader --- .../ducktape/loaders/PackageModuleLoader.java | 56 ++++++++++++++++++ .../loaders/PackageModuleLoaderTest.java | 23 +++++++ .../modules/ModuleA$ModuleASettings.class | Bin 0 -> 1084 bytes .../utilities/ducktape/modules/ModuleA.class | Bin 0 -> 1459 bytes .../modules/ModuleB$ModuleBModule.class | Bin 0 -> 1114 bytes .../utilities/ducktape/modules/ModuleB.class | Bin 0 -> 1302 bytes .../modules/ModuleC$ModuleCSettings.class | Bin 0 -> 1083 bytes .../utilities/ducktape/modules/ModuleC.class | Bin 0 -> 1377 bytes .../utilities/ducktape/modules/ModuleD.class | Bin 0 -> 795 bytes 9 files changed, 79 insertions(+) create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoader.java create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoaderTest.java create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA$ModuleASettings.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB$ModuleBModule.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleC$ModuleCSettings.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleC.class create mode 100644 core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleD.class diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoader.java new file mode 100644 index 0000000..6776c22 --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoader.java @@ -0,0 +1,56 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PackageModuleLoader extends AbstractPathLoader implements ModuleLoader { + public PackageModuleLoader(Path directory) { + super(AbstractPathLoader.createDirectories(directory)); + } + + /** Get all the class names */ + public Set getClassNames(Path classDir) { + return recursiveGetClasses(classDir.toFile(), ""); + } + + /** Get all the class names */ + @SuppressWarnings("ConstantConditions") + public Set recursiveGetClasses(File dir, String parentName) { + File[] files = dir.listFiles(); + if (files != null) { + return Stream.of(dir.listFiles()) + .flatMap(file -> { + if (file.isDirectory()) { + return recursiveGetClasses(file, parentName + file.getName() + ".").stream(); + } else if (file.getName().endsWith(".class")) { + return Stream.of(parentName + Loaders.formatPath(file.getName())); + } + return Stream.empty(); + }) + .collect(Collectors.toSet()); + } + return Collections.emptySet(); + } + + @Override + protected Collection> load(Path directory) throws IOException { + ClassLoader loader = Loaders.classLoaderFromPath(directory); + return getClassNames(directory).stream() + .map(entry -> { + try { + return loader.loadClass(entry); + } catch (ClassNotFoundException error) { + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } +} diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoaderTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoaderTest.java new file mode 100644 index 0000000..66eb859 --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/PackageModuleLoaderTest.java @@ -0,0 +1,23 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import org.junit.Assert; +import org.junit.Test; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; + +public class PackageModuleLoaderTest extends AbstractModuleClasses { + private static final Path modulePath = Paths.get("src/test/resources/modules/classes"); + + @Test + public void packageTest() { + PackageModuleLoader packageModuleLoader = new PackageModuleLoader(modulePath); + Collection> classes = packageModuleLoader.load(); + System.out.println(classes); + Assert.assertArrayEquals(MODULE_CLASSES, classStreamStringMap(classes)); + } +} diff --git a/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA$ModuleASettings.class b/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA$ModuleASettings.class new file mode 100644 index 0000000000000000000000000000000000000000..3fb199f265f919713556197edcf423fc015f5d22 GIT binary patch literal 1084 zcmbtT*>2N76g`urPEymR2?a`NYf6A5KpmmJpdwHe2`N%oL`vQ#&QPY<be7ECsm-+Jb(`NwN=#=4Ly@C=pO7P0KjLj0RRM5ax2iF}m z85}K)k!qiz)<57!+z+|h_Xj2++YZCZ(^MH5iJ{bT6pCG?V#AG$m1elzSHk$mf+yRZ zPRCD;45g7m`{OitY51Y=r`X!>#!)1cA;97h4^zRgwD&@4j~?y?6DPymU8$tG$B=Kf zh75&nJf_ISzEt8-8jVD<$BBbw8V5Wa@rbuEy&~|+AWoA&Jdn0-cgkeT4vOK< z%>VxAe@`8Vz5sG&_2JffM@GmMjF zTJJ*}6e`MV{@!G}W&S_1r%U9}g#s9IwvBYolQvJMOYa$t1#-|LqDpd!T)j*O>g|un zwQKqJU~f^V6+d9^4Y_luk*uLWa-HNRVQ!G_p-vWyNvSxC^FXzP3s{-L`gB@fvHcG0 nHGNEg<}%~jFUdt*w8_Y0HH*5G5w>w_q@SbL7UAF;mQnr&BGeh6 literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA.class b/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleA.class new file mode 100644 index 0000000000000000000000000000000000000000..5c7610d619f75deefde46c0146acc8441666b005 GIT binary patch literal 1459 zcmb7ET~8B16g|^cwp|v`0t$!sIY!P!MxOm{=A?6({ zxF~`wG7t-5k-`9)PMm*!(s4T7l$B?@HhD z&2%GRF**up>0G~ETi(rr2ucmr(!$1}WZ3VWVdY%N$z<1NvZRj+S$jo6^sOkZ>??+R zWp3}n~8rVKrlG3?-(hv#^~u-e-Uo@$GS8dfNk9%&dZCpF-K&@KLU zCz;g~M~#EX$~N`c#H1Llr^d?gccId@VM8g}RF2^@j;UFDiBX^lSIK~>7edj6tR-`^ zcwV%pE&yF1MYR>$r#6mMW{>e^(I>4IzAvL_hAuP1$I1np+r8bVDqB15q!T=*>EY?8 zhbc$DK@5S4Mp7T`SJG4JEony5@6rEsESVaz93$;2SuxrN=Dve{MXsDbMBz&c8>e*; zd0NXT5S>SK6C`;V0M{`|62lE5%cW#n9kR)U=n@gpKKBiMhj4zQ_yeUgxX0+x94D@c nW89M+?rusq$xj})Xw6|NO{SmxPSgK(ggY1@g-b$_Ru83r(NKjy literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB$ModuleBModule.class b/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB$ModuleBModule.class new file mode 100644 index 0000000000000000000000000000000000000000..7d209c9b8a62d84902abdeaf39a2772041153edd GIT binary patch literal 1114 zcmbtU+iuf95IvhqojC4=K)IB*v``=kG#g5IDi@^{h)SVI6qV<-y`wtI$sZxiwrEoE@!Yv>k{zmgIic)za`|DWZ0()#8a!figHz%d_@dzDY+FbLpN3LihNdiIna+ zsG~up85tW3_Z-~Ex`n0#jutiGWhebCJaDjqhtvo+bQy{y-D3-FhA00;pJBxd`@9#1 zy+CrM52a^#$Bj)SJTs(E++3x7hUc~Ji2R^`oAvH^bb44uyrXq!gpvLh=~U-dq5`s0 zzZS=1wCGE|OM)(>m?{LfaUO2itBH7Lu|DN)jpzP5ADRzw%JiKw2Mlk{<7Pe;>eGT~ zJCQ~PL!)^#q2~2J@|qMtb7aCD9UGxNnxpyij9$Cx9c`x1f&b&xW0jtrLoX4?feObA z$yw4kt&G-U;|tiQfqRbR)WEoa3$%BJ2T;X4X$4$93l@W9l%!G3eMY`o_=@5QrgErS wCn)8RnagKpdte^H%pgxGmv9BkXwtu61jjSD9QjhtS8<6}o2XQ92NzNP1rGQog8%>k literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB.class b/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleB.class new file mode 100644 index 0000000000000000000000000000000000000000..513b9472870b21a46e20e634f78f395b12091a46 GIT binary patch literal 1302 zcmb7ETTc@~6#k|y-L@_QEyzVs6qJI(6vZ1CiPV@7OEp4Bj8D_LCmAY>7hSm*VaupoPy5ZYxL5a66a0a3&d6f>2 z0{V`GA4`Umk&z)9>nc#@B}1|}zfab(_Q*LbmgvMX0RaHKxpg zB0|fRKpK85MYvKbm3VBFuZ)rr_u~3zBU+L-+pUOrw)^queFS-+Ek_V z_Vku43*VPsh1?8_mqg|^oKSPSIu7gdjk1*8?rlr9zYP4cSe-ONODLkiY7E&dJ(`9;F6UKF;LkG`Yyud2M=>Ma!6)WG9A;aL` zJljVZu1>pH!@7$>47u0DO~(X0(wTat z`FmOeLxV3xlX_lgbLcfQI4v9G2b5PlzbaDfi3wo!QCdA#5A1=D$!aCWW7t;OoUn7`vg|UeX0}4k)xlwa2?q{ Dhdxgv literal 0 HcmV?d00001 diff --git a/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleC$ModuleCSettings.class b/core-ducktape/src/test/resources/modules/classes/net/year4000/utilities/ducktape/modules/ModuleC$ModuleCSettings.class new file mode 100644 index 0000000000000000000000000000000000000000..3679f7e4da0f3a8cf82bf82fac557a5d923b8381 GIT binary patch literal 1083 zcmbtT*>2N76g`v8N$S!xp+M=DLVzSd9ihIUB2X0xDN>+_l)O)zp-i#Im1kVhzXHS} z@xTZ0QHVQESXvMfLbC7pZpU{y^X2QO&j7a3DZ#;d8AWUqQ7>T=SBkh=Mg!Lz+;Grj zaI`Q+ssn~<|BxSZFW~CH8Aa<3C3^y`Tn&D1g3FDmz9&dL# z9WOC5kVXpajT8T+;YY%oVr#D(g`rS}0Q1K@NCd;;{tKz=^zgbraWWL{NhQsFhHSGn zWXN@+F-0!)r4o;ma3tb=PBqv{BcBID9!slFjX6Vr6#Xa~CxPe=CT)?$?I|VVZost` zr0&kFI!qC?H$`fkL8KCH;-R#CyVFXx?4lU% z&iwC>`S;YJ@Xhy`?6@eQ>|y~GhWW90&Xd5@)5SPwxoG1i!^)Yq>s?y9i4)&Mv4dMK zZez=V$M9el3&Ow8lcDmHczYvT=qc0SL>mzjDWZfNOOsK_$a_K*HAGawLt05K#W-yy zb|2ZGKv7=v_ZeG~dH+~F-64nW6TpzMQ>1f_v^hFmdgnFHk%M@M3du!s^->+EwLc=$ zu4dnZy+y8?|A4|9a%WH_Sw)WI8p%zqtp8G?RQ|W m>0<&^NR6w%BVcfbGm@)f`u>Mr_my@DH~n;;Ekqb03Xx}7k1TUyJw5sD;{_11ssGN3eaU-wd5^BnP-&^Q7B-C~!@>C()=z~*xq^gumCXO4sJ=l-OutICRgv6L ziP{b2Q>~2^RvAqSXPUl=c-xqED7n&m(zkpoUkKQ@uC%fn48`ig4nwJ70@5+mR9bGQ z(XNbN3*uuKZ5m&MJ0ez@-`ylR~qPaFsaepapyjMxe)U|_z7aZEU+O}*gMMUKoJ7JrewVz!IHQ}lqU>=1~G*b2K-K?CJ?O&5alc%V*Li^Ol z@#?}c-cI&etA+2&B$=maWO!3OV{`vKDaV6!lgBmsb@bD(g`PszN3z4@6)=KPTKi~! zEcYo%OptexyiGc1v<@tO0{ei%Xz>W8_xZI+vV$m+9YKjGJc3V==XC&>#teB3mx!#8 zlWlj&W;3D-L`3W2NAw-R`G)dmR8HWYq+i?=aZDfMp6zn?(w?O_MO-FZz?ED~KgGRD R-&{hf2k5{hr%cvE4PRd z_y_n$5$3La!T3P4xtYxDeDlqIbANAt{{e7>R}Iv$GK*C_pTSxKFR-PeOfzeLhXq6syIvtriipi1AWR!uigf`hOpjz4*7yD@9F-Jv1 Y2B3vD`wE_vcBv$u Date: Sun, 21 Jul 2019 10:58:32 -0700 Subject: [PATCH 15/20] Add classpath module loader --- .../loaders/ClassPathModuleLoader.java | 75 +++++++++++++++++++ .../loaders/ClassPathModuleLoaderTest.java | 29 +++++++ 2 files changed, 104 insertions(+) create mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoader.java create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoaderTest.java diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoader.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoader.java new file mode 100644 index 0000000..23b20aa --- /dev/null +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoader.java @@ -0,0 +1,75 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import com.google.common.reflect.ClassPath; +import net.year4000.utilities.Conditions; +import net.year4000.utilities.ducktape.ModuleInitException; +import net.year4000.utilities.ducktape.module.ModuleInfo; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** This module loader will search the classpath for classes that are annotated with an annotation. */ +public class ClassPathModuleLoader implements ModuleLoader { + private final ClassLoader classLoader; + private final Class[] annotations; + private final String packageName; + + /** Load classes from the classpath from the packageName that are annotated with any of the annotations */ + public ClassPathModuleLoader(ClassLoader classLoader, String packageName, Class... annotations) { + this.classLoader = Conditions.nonNull(classLoader, "class load must exist"); + this.packageName = packageName; + this.annotations = Conditions.nonNull(annotations, "must give a annotation to find classes"); + } + + /** Loads all classes and get the classes that are annotated with any of the annotations */ + public ClassPathModuleLoader(ClassLoader classLoader, Class... annotations) { + this(classLoader, null, annotations); + } + + /** Loads all classes and get the classes that are annotated with any of the annotations */ + public ClassPathModuleLoader(String packageName, Class... annotations) { + this(ClassLoader.getSystemClassLoader(), packageName, annotations); + } + + /** Loads all classes and get the classes that are annotated with any of the annotations */ + public ClassPathModuleLoader(Class... annotations) { + this(ClassLoader.getSystemClassLoader(), null, annotations); + } + + @Override + public Collection> load() throws ModuleInitException { + try { + ClassPath classPath = ClassPath.from(this.classLoader); + Stream classInfoStream = this.packageName == null + ? classPath.getTopLevelClasses().stream() + : classPath.getTopLevelClassesRecursive(this.packageName).stream(); + return classInfoStream + .map(classInfo -> { + try { + return classInfo.load(); + } catch (Throwable error) { + return null; + } + }) + .filter(Objects::nonNull) + .filter(clazz -> { + for (Class annotation : this.annotations) { + if (clazz.isAnnotationPresent(annotation)) { + return true; + } + } + return false; + }) + .collect(Collectors.toSet()); + } catch (IOException error) { + throw new ModuleInitException(ModuleInfo.Phase.LOADING, error); + } + } +} diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoaderTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoaderTest.java new file mode 100644 index 0000000..4dc7b42 --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/loaders/ClassPathModuleLoaderTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.loaders; + +import net.year4000.utilities.ducktape.module.Module; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collection; + +public class ClassPathModuleLoaderTest extends AbstractModuleClasses { + private static final String PACKAGE_PREFIX = "net.year4000.utilities.ducktape.modules"; + private static final String[] MODULE_CLASSES = new String[] { + "class net.year4000.utilities.ducktape.modules.ModuleA", + "class net.year4000.utilities.ducktape.modules.ModuleB", + "class net.year4000.utilities.ducktape.modules.ModuleC", + "class net.year4000.utilities.ducktape.modules.ModuleD", + }; + + @Test + public void classPathTest() { + // We are testing the package prefix to speed up the unit test + ClassPathModuleLoader classPathModuleLoader = new ClassPathModuleLoader(PACKAGE_PREFIX, Module.class); + Collection> classes = classPathModuleLoader.load(); + System.out.println(classes); + Assert.assertArrayEquals(MODULE_CLASSES, classStreamStringMap(classes)); + } +} From 60ecdb4d608857a2bd7c7a2513a4b1a630fcda54 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Thu, 20 Aug 2020 18:50:42 -0700 Subject: [PATCH 16/20] WIP add settings config to ducktape --- .../utilities/ducktape/DucktapeManager.java | 31 ++++++++++------ .../utilities/ducktape/SettingsModule.java | 36 +++++++++---------- .../utilities/ducktape/settings/SaveLoad.java | 1 - .../utilities/ducktape/settings/Settings.java | 10 +++--- ...{InjectSettings.java => SettingsBase.java} | 9 +++-- .../utilities/ducktape/DucktapeTest.java | 2 ++ .../utilities/ducktape/modules/ModuleA.java | 4 +-- .../utilities/ducktape/modules/ModuleC.java | 4 +-- .../sponge/ducktape/SpongeModuleManager.java | 7 ++-- 9 files changed, 57 insertions(+), 47 deletions(-) rename core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/{InjectSettings.java => SettingsBase.java} (65%) diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java index 2c96b74..0a68640 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java @@ -3,17 +3,16 @@ */ package net.year4000.utilities.ducktape; -import com.google.common.collect.ClassToInstanceMap; -import com.google.common.collect.ImmutableClassToInstanceMap; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.*; import com.google.inject.*; import net.year4000.utilities.Builder; import net.year4000.utilities.Conditions; +import net.year4000.utilities.annotations.Nullable; import net.year4000.utilities.ducktape.loaders.ModuleLoader; import net.year4000.utilities.ducktape.module.Enabler; import net.year4000.utilities.ducktape.module.internal.ModuleInfo; import net.year4000.utilities.ducktape.module.ModuleWrapper; +import net.year4000.utilities.ducktape.settings.SaveLoad; import net.year4000.utilities.value.Value; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -28,17 +27,20 @@ public class DucktapeManager extends AbstractModule implements Ducktape { protected ClassToInstanceMap loaders; /** The guice injector that will init the modules */ protected Injector injector; + /** The save load provider for configs */ + protected SaveLoad saveLoadProvider; /** * The modules that are loaded, at first the order is when they are constructed but while they are loading * it resorts them based on load order, so when loading is done it will enable them properly. */ protected final Map modules = new LinkedHashMap<>(); - protected DucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { + protected DucktapeManager(Injector injector, Map, ModuleLoader> loaderMap, @Nullable SaveLoad saveLoadProvider) { this.injector = Conditions.nonNull(injector, "extra injector must not be null"); this.loaders = ImmutableClassToInstanceMap.builder() .putAll(loaderMap) .build(); + this.saveLoadProvider = saveLoadProvider; } /** Create a snapshot of the modules that are currently in the system when this method is called */ @@ -54,9 +56,11 @@ public void load() throws ModuleInitException { logger.info("Loading module classes from the loaders"); Set> classes = loadAll(); logger.info("Setting up the injector"); - // todo think? use child injector or our own injector, is we use a child injector sponge plugins will work, if not modules only have our bindings - this.injector = this.injector.createChildInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); - //this.injector = Guice.createInjector(this, new ModulesInitModule(classes), new DucktapeModule(this.modules), new SettingsModule()); + List modules = Lists.newArrayList(this, new ModulesInitModule(classes), new DucktapeModule(this.modules)); + if (this.saveLoadProvider != null) { + modules.add(new SettingsModule(this.saveLoadProvider)); + } + this.injector = this.injector.createChildInjector(modules); } @Override @@ -91,6 +95,7 @@ public static DucktapeManagerBuilder builder() { public static class DucktapeManagerBuilder implements Builder { protected final Set loaders = new HashSet<>(); protected Value injectorValue = Value.empty(); + protected SaveLoad saveLoadProvider; /** Add a module loader system */ public DucktapeManagerBuilder addLoader(ModuleLoader moduleLoader) { @@ -98,6 +103,12 @@ public DucktapeManagerBuilder addLoader(ModuleLoader moduleLoader) { return this; } + /** Set the save load provider for configs support, if this is not set but modules use Settings<> it will throw errors */ + public DucktapeManagerBuilder setSaveLoadProvider(@Nullable SaveLoad saveLoadProvider) { + this.saveLoadProvider = saveLoadProvider; + return this; + } + /** Set the injector for ducktape to use */ public DucktapeManagerBuilder setInjector(Injector injector) { this.injectorValue = Value.of(injector); @@ -106,14 +117,14 @@ public DucktapeManagerBuilder setInjector(Injector injector) { /** Internal reuse able method that will map reduce the module loader map */ protected Map, ModuleLoader> loaderMapReduce() { - return loaders.stream().map(loader -> ImmutableMap., ModuleLoader>of(loader.getClass(), loader)) + return this.loaders.stream().map(loader -> ImmutableMap., ModuleLoader>of(loader.getClass(), loader)) .reduce((left, right) -> ImmutableMap., ModuleLoader>builder().putAll(left).putAll(right).build()).get(); } @Override public Ducktape build() { Map, ModuleLoader> loaderMap = loaderMapReduce(); - return new DucktapeManager(injectorValue.getOrElse(Guice.createInjector()), loaderMap); + return new DucktapeManager(this.injectorValue.getOrElse(Guice.createInjector()), loaderMap, this.saveLoadProvider); } } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java index 03b9e0e..4d78fb3 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/SettingsModule.java @@ -3,51 +3,49 @@ */ package net.year4000.utilities.ducktape; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.inject.AbstractModule; -import com.google.inject.MembersInjector; import com.google.inject.TypeLiteral; import com.google.inject.matcher.Matchers; import com.google.inject.spi.InjectionListener; import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; -import net.year4000.utilities.ducktape.settings.GsonSaveLoadProvider; +import net.year4000.utilities.Conditions; +import net.year4000.utilities.Utils; import net.year4000.utilities.ducktape.settings.SaveLoad; import net.year4000.utilities.ducktape.settings.Settings; +import net.year4000.utilities.ducktape.settings.SettingsBase; import net.year4000.utilities.reflection.Reflections; public class SettingsModule extends AbstractModule { + private final SaveLoad saveLoad; + + public SettingsModule(SaveLoad saveLoad) { + this.saveLoad = Conditions.nonNull(saveLoad, "save load must exist"); + } + @Override protected void configure() { - bind(SaveLoad.class).to(GsonSaveLoadProvider.class); - + bind(SaveLoad.class).toInstance(this.saveLoad); bindListener(Matchers.any(), new TypeListener() { @Override public void hear(TypeLiteral type, TypeEncounter encounter) { - //System.out.println("hear: " + type); - // inject the settings if (type.getRawType() == Settings.class) { //System.out.println("load settings: " + type); String typeString = type.toString(); String genericType = typeString.substring(typeString.indexOf("<") + 1, typeString.indexOf(">")); Class settingsClass = Reflections.clazz(genericType).getOrThrow(); - //System.out.println("foundSettingsClass: " + settingsClass); + System.out.println("foundSettingsClass: " + settingsClass); + String fileName = settingsClass.getAnnotation(SettingsBase.class).value(); + System.out.println("foundSettingsClass: " + fileName); - // when members are injected - encounter.register((MembersInjector) instance -> { - Gson gson = new GsonBuilder().create(); - - // create instance right now, later have something else handle it - //((Settings) instance).instance = Reflections.instance(settingsClass).getOrThrow(); - //System.out.println("MembersInjector settings: " + instance); - - }); // after members has been injected encounter.register((InjectionListener) instance -> { + + Settings settings = (Settings) instance; // todo load settings here - //System.out.println("InjectionListener settings: " + instance); + System.out.println("InjectionListener settings: " + Utils.toString(settings)); + Reflections.setter(settings, Reflections.field(Settings.class, "instance").get(), Reflections.instance(settingsClass).get()); }); } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SaveLoad.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SaveLoad.java index 7975e08..f44ee33 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SaveLoad.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SaveLoad.java @@ -1,7 +1,6 @@ /* * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.ducktape.settings; /** The provider that will use the feature to save and/or load settings */ diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/Settings.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/Settings.java index 3fe1d50..1d43536 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/Settings.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/Settings.java @@ -1,7 +1,6 @@ /* - * Copyright 2018 Year4000. All Rights Reserved. + * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.ducktape.settings; import com.google.inject.Inject; @@ -10,14 +9,15 @@ /** The settings wrapper that will load and save the settings from the settings provider */ public class Settings implements Loader { - @Inject private T instance; + /** This is the instance of the settings, it will be init dynamic at the time this instance is injected */ + private T instance; @Inject private SaveLoad saveLoad; /** Save the settings from the provider */ public void save() { try { - saveLoad.save(instance); + this.saveLoad.save(instance); } catch (SettingsException error) { ErrorReporter.builder(error) .buildAndReport(System.err); @@ -27,7 +27,7 @@ public void save() { /** Load the settings instance with the config from the provider */ public void load() { try { - this.instance = saveLoad.load((Class) this.instance.getClass()); + this.instance = this.saveLoad.load((Class) this.instance.getClass()); } catch (SettingsException error) { ErrorReporter.builder(error) .buildAndReport(System.err); diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/InjectSettings.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SettingsBase.java similarity index 65% rename from core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/InjectSettings.java rename to core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SettingsBase.java index 17e82ac..fc630da 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/InjectSettings.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/settings/SettingsBase.java @@ -1,7 +1,6 @@ /* * Copyright 2019 Year4000. All Rights Reserved. */ - package net.year4000.utilities.ducktape.settings; import java.lang.annotation.ElementType; @@ -9,9 +8,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface InjectSettings { - /** This value will be given too the settings provider to know where or how to save and load the settings */ - String value() default ""; +@Retention(RetentionPolicy.RUNTIME) +public @interface SettingsBase { + /** The base name for the settings used for the file name */ + String value(); } diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java index d679cf1..449efed 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java @@ -9,6 +9,7 @@ import net.year4000.utilities.ducktape.modules.ModuleA; import net.year4000.utilities.ducktape.modules.ModuleB; import net.year4000.utilities.ducktape.modules.ModuleC; +import net.year4000.utilities.ducktape.settings.GsonSaveLoadProvider; import org.junit.Assert; import org.junit.Test; @@ -18,6 +19,7 @@ public class DucktapeTest { public void test() { Ducktape ducktape = Ducktape.builder() .addLoader(new ClassModuleLoader(ModuleA.class, ModuleB.class, ModuleC.class, ModuleD.class)) + .setSaveLoadProvider(new GsonSaveLoadProvider()) .build(); ducktape.init(); } diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java index 0882e7f..60f8bcd 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java @@ -7,8 +7,8 @@ import net.year4000.utilities.ducktape.module.Load; import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.settings.Comment; -import net.year4000.utilities.ducktape.settings.InjectSettings; import net.year4000.utilities.ducktape.settings.Settings; +import net.year4000.utilities.ducktape.settings.SettingsBase; @Module(id = "a") public class ModuleA { @@ -25,7 +25,7 @@ public void loasdas() { System.out.println(settings.instance().setting); } - @InjectSettings + @SettingsBase("a") public static class ModuleASettings { public ModuleASettings() { System.out.println("ModuleASettings Constructor"); diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java index 68e4a78..392bf1e 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java @@ -7,8 +7,8 @@ import net.year4000.utilities.ducktape.module.Load; import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.settings.Comment; -import net.year4000.utilities.ducktape.settings.InjectSettings; import net.year4000.utilities.ducktape.settings.Settings; +import net.year4000.utilities.ducktape.settings.SettingsBase; @Module(id = "c") public class ModuleC { @@ -24,7 +24,7 @@ public void loasdas() { System.out.println(settings.instance().setting); } - @InjectSettings + @SettingsBase("c") public static class ModuleCSettings { public ModuleCSettings() { System.out.println("ModuleCSettings Constructor"); diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java index 9654b87..f24aa6d 100644 --- a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java +++ b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java @@ -11,6 +11,7 @@ import net.year4000.utilities.ducktape.loaders.ModuleLoader; import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.module.internal.ModuleInfo; +import net.year4000.utilities.ducktape.settings.SaveLoad; import net.year4000.utilities.sponge.Utilities; import org.spongepowered.api.Sponge; import org.spongepowered.api.event.Event; @@ -26,8 +27,8 @@ public class SpongeDucktapeManager extends DucktapeManager { public static final String MOD_PATH = "mods/"; private final List modules = new ArrayList<>(); - protected SpongeDucktapeManager(Injector injector, Map, ModuleLoader> loaderMap) { - super(injector, loaderMap); + protected SpongeDucktapeManager(Injector injector, Map, ModuleLoader> loaderMap, SaveLoad saveLoadProvider) { + super(injector, loaderMap, saveLoadProvider); } /** Load all classes from the selected path */ @@ -106,7 +107,7 @@ public static class SpongeDucktapeManagerBuilder extends DucktapeManagerBuilder @Override public Ducktape build() { Map, ModuleLoader> loaderMap = loaderMapReduce(); - return new SpongeDucktapeManager(injectorValue.getOrElse(Guice.createInjector()), loaderMap); + return new SpongeDucktapeManager(this.injectorValue.getOrElse(Guice.createInjector()), loaderMap, this.saveLoadProvider); } } } From 1ee01fd1257c2108d314c394fbf2b6ca3806f2b0 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sat, 5 Sep 2020 09:26:26 -0700 Subject: [PATCH 17/20] Fix rebase conflicts --- .../utilities/ducktape/DucktapeManager.java | 4 +- .../utilities/ducktape/ModuleManager.java | 51 ------------------- ...anager.java => SpongeDucktapeManager.java} | 0 3 files changed, 3 insertions(+), 52 deletions(-) delete mode 100644 core-ducktape/src/main/java/net/year4000/utilities/ducktape/ModuleManager.java rename sponge/src/main/java/net/year4000/utilities/sponge/ducktape/{SpongeModuleManager.java => SpongeDucktapeManager.java} (100%) diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java index 0a68640..9bcd7f5 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/DucktapeManager.java @@ -1,10 +1,12 @@ /* - * Copyright 2019 Year4000. All Rights Reserved. + * Copyright 2020 Year4000. All Rights Reserved. */ + package net.year4000.utilities.ducktape; import com.google.common.collect.*; import com.google.inject.*; +import com.google.inject.Module; import net.year4000.utilities.Builder; import net.year4000.utilities.Conditions; import net.year4000.utilities.annotations.Nullable; diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/ModuleManager.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/ModuleManager.java deleted file mode 100644 index 93594ff..0000000 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/ModuleManager.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2016 Year4000. All Rights Reserved. - */ - -package net.year4000.utilities.ducktape; - -import com.google.common.collect.ClassToInstanceMap; -import com.google.common.collect.ImmutableClassToInstanceMap; -import com.google.common.collect.Sets; -import net.year4000.utilities.ducktape.loaders.GroovyModuleLoader; -import net.year4000.utilities.ducktape.loaders.ModuleLoader; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Set; -import java.util.function.Consumer; - -/** Deprecated see DucktapeManager for future module stuff */ -@Deprecated -public class ModuleManager { - /** The set of current loaded modules */ - private Set> loaded = Sets.newLinkedHashSet(); - - /** A map of all loaders stored by their class, should not be final as support for adding custom loaders */ - private ClassToInstanceMap loaders = ImmutableClassToInstanceMap.builder() - .put(GroovyModuleLoader.class, new GroovyModuleLoader()) - .build(); - - /** Load all classes from the selected path */ - public void loadAll(Path path, Consumer>> consumer) { - loaders.forEach((key, value) -> { - try { - if (loaded.contains(key)) { - throw new IllegalStateException("Can not load the same loader twice."); - } - consumer.accept(value.load(path)); - loaded.add(key); - } catch (IOException | IllegalStateException error) { - // todo - System.err.println(error.getMessage()); - } - }); - } - - /** Format the path */ - public static String formatPath(String path) { - if (path.length() < 6) return path; - return path.substring(0, path.length() - 6).replaceAll("/", "."); - } -} diff --git a/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java b/sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeDucktapeManager.java similarity index 100% rename from sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeModuleManager.java rename to sponge/src/main/java/net/year4000/utilities/sponge/ducktape/SpongeDucktapeManager.java From cdd7c039204caf0bdf8cd8a6ce7a411dea41d140 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sat, 5 Sep 2020 10:07:56 -0700 Subject: [PATCH 18/20] Comment out settings injection for unit tests --- core-ducktape/build.gradle | 1 + .../java/net/year4000/utilities/ducktape/DucktapeTest.java | 3 +-- .../java/net/year4000/utilities/ducktape/modules/ModuleA.java | 4 ++-- .../java/net/year4000/utilities/ducktape/modules/ModuleC.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core-ducktape/build.gradle b/core-ducktape/build.gradle index 8048986..86df5ca 100644 --- a/core-ducktape/build.gradle +++ b/core-ducktape/build.gradle @@ -14,4 +14,5 @@ dependencies { compile utilities.project('core') compile 'com.google.inject:guice:4.0' compile 'org.apache.logging.log4j:log4j-api:2.8.1' + testCompile 'org.apache.logging.log4j:log4j-core:2.8.1' } diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java index 449efed..8c396dd 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java @@ -9,7 +9,6 @@ import net.year4000.utilities.ducktape.modules.ModuleA; import net.year4000.utilities.ducktape.modules.ModuleB; import net.year4000.utilities.ducktape.modules.ModuleC; -import net.year4000.utilities.ducktape.settings.GsonSaveLoadProvider; import org.junit.Assert; import org.junit.Test; @@ -19,7 +18,7 @@ public class DucktapeTest { public void test() { Ducktape ducktape = Ducktape.builder() .addLoader(new ClassModuleLoader(ModuleA.class, ModuleB.class, ModuleC.class, ModuleD.class)) - .setSaveLoadProvider(new GsonSaveLoadProvider()) + //.setSaveLoadProvider(new GsonSaveLoadProvider()) .build(); ducktape.init(); } diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java index 60f8bcd..5b85989 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleA.java @@ -13,7 +13,7 @@ @Module(id = "a") public class ModuleA { @Inject private ModuleD moduleD; - @Inject private Settings settings; + //@Inject private Settings settings; public ModuleA() { System.out.println("ModuleA Constructor"); @@ -22,7 +22,7 @@ public ModuleA() { @Load public void loasdas() { System.out.println("ModuleA loader"); - System.out.println(settings.instance().setting); + //System.out.println(settings.instance().setting); } @SettingsBase("a") diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java index 392bf1e..fac4c2a 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleC.java @@ -12,7 +12,7 @@ @Module(id = "c") public class ModuleC { - @Inject private Settings settings; + //@Inject private Settings settings; public ModuleC() { System.out.println("ModuleC Constructor"); @@ -21,7 +21,7 @@ public ModuleC() { @Load public void loasdas() { System.out.println("ModuleC loader"); - System.out.println(settings.instance().setting); + //System.out.println(settings.instance().setting); } @SettingsBase("c") From 902764070e7f833aec47656c0380450ab40fa51e Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sun, 13 Sep 2020 12:07:03 -0700 Subject: [PATCH 19/20] Make sure the groovy has access to classes at runtime --- .../ducktape/loaders/GroovyModuleLoader.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java index c4a376c..3c6af04 100644 --- a/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java +++ b/core-ducktape/loaders-groovy/src/main/java/net/year4000/utilities/ducktape/loaders/GroovyModuleLoader.java @@ -26,8 +26,15 @@ public GroovyModuleLoader(Path directory) { /** Load any groovy script that ends with .groovy */ protected Collection> load(Path directory) throws IOException { if (directory.toString().endsWith(".groovy")) { - URL[] urls = new URL[] {directory.toUri().toURL()}; - GroovyClassLoader loader = AccessController.doPrivileged((PrivilegedAction) () -> new GroovyClassLoader(new URLClassLoader(urls))); + URL[] urls = new URL[] { directory.toUri().toURL() }; + GroovyClassLoader loader = AccessController.doPrivileged((PrivilegedAction) () -> { + ClassLoader parentClassLoader = ModuleLoader.class.getClassLoader(); + GroovyClassLoader classLoader = new GroovyClassLoader(new URLClassLoader(urls, parentClassLoader)); + // add the urls to the classloader to use environment libs + classLoader.addURL(parentClassLoader.getResource("/")); + classLoader.addURL(urls[0]); + return classLoader; + }); return Collections.singleton(loader.parseClass(directory.toFile())); } return Collections.emptySet(); From 3566ccdf476e049e11062d7d9e028dab05a56c77 Mon Sep 17 00:00:00 2001 From: Joshua Rodriguez Date: Sun, 13 Sep 2020 13:11:19 -0700 Subject: [PATCH 20/20] Disable the module if it errors out durring load or enable --- .../utilities/ducktape/module/ModuleInfo.java | 11 ++++++++- .../ducktape/module/ModuleWrapper.java | 23 ++++++++++++++----- .../ducktape/module/internal/ModuleInfo.java | 16 ++++++++++++- .../utilities/ducktape/DucktapeTest.java | 18 +++++++++++---- .../utilities/ducktape/modules/ModuleE.java | 21 +++++++++++++++++ .../ducktape/modules/ModuleError.java | 16 +++++++++++++ 6 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleE.java create mode 100644 core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleError.java diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java index f86ea33..8b5bb26 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleInfo.java @@ -25,7 +25,11 @@ enum Phase { /** This is when the module has been loaded, settings have been populated and module specific stuff should be loaded here */ LOADED, /** This is when the module has been enable, at this point all loading has been done and can do what they need */ - ENABLED + ENABLED, + /** This is when the module has been disabled, at any point the module was disabled and will not load */ + DISABLED, + /** This is when the module has been disabled, at any point the module was disabled and will not load */ + ERROR, ; /** Return true when the phase is constructing */ @@ -42,5 +46,10 @@ public boolean isLoaded() { public boolean isEnabled() { return this == ENABLED; } + + /** Return true with the phase is disabled */ + public boolean isDisabled() { + return this == DISABLED || this == ERROR; + } } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java index d858701..41f219a 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/ModuleWrapper.java @@ -21,18 +21,29 @@ public ModuleWrapper(ModuleInfo moduleInfo, Object instance) { /** Load the module and call the method with @Load */ @Override public void load() { - this.moduleInfo.load(); - if (this.proxyInstance instanceof Loader) { - ((Loader) this.proxyInstance).load(); + try { + this.moduleInfo.load(); + if (this.proxyInstance instanceof Loader) { + ((Loader) this.proxyInstance).load(); + } + } catch (Exception error) { + this.moduleInfo.disableWithException(error); } } /** Enable the module and call the method with @Enable */ @Override public void enable() { - this.moduleInfo.enable(); - if (this.proxyInstance instanceof Enabler) { - ((Enabler) this.proxyInstance).enable(); + if (this.moduleInfo.getPhase().isDisabled()) { + return; // dont try to enable the module if it failed to load + } + try { + this.moduleInfo.enable(); + if (this.proxyInstance instanceof Enabler) { + ((Enabler) this.proxyInstance).enable(); + } + } catch (Exception error) { + this.moduleInfo.disableWithException(error); } } diff --git a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java index 33d3765..dbe6e77 100644 --- a/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java +++ b/core-ducktape/src/main/java/net/year4000/utilities/ducktape/module/internal/ModuleInfo.java @@ -4,6 +4,7 @@ package net.year4000.utilities.ducktape.module.internal; import net.year4000.utilities.Conditions; +import net.year4000.utilities.ErrorReporter; import net.year4000.utilities.annotations.Nullable; import net.year4000.utilities.ducktape.module.Module; import net.year4000.utilities.ducktape.module.ModuleHandle; @@ -70,9 +71,22 @@ public void enable() { this.phase = Phase.ENABLED; } + /** Called when the module is disabled */ + public void disable() { + logger.info("Disabling: {}", this); + this.phase = Phase.DISABLED; + } + + /** Called when the module is disabled with an error */ + public void disableWithException(Exception error) { + logger.info("Disabling: {}", this); + this.phase = Phase.ERROR; + ErrorReporter.builder(error).buildAndReport().printStackTrace(); + } + @Override public String toString() { - return String.format("ModuleInfo{id=%s, class=%s}", this.getId(), this.moduleClass); + return String.format("ModuleInfo{id=%s, phase=%s, class=%s}", this.getId(), this.phase, this.moduleClass); } @Override diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java index 8c396dd..08724e2 100644 --- a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/DucktapeTest.java @@ -5,10 +5,7 @@ import net.year4000.utilities.ducktape.loaders.ClassModuleLoader; import net.year4000.utilities.ducktape.module.ModuleInfo; -import net.year4000.utilities.ducktape.modules.ModuleD; -import net.year4000.utilities.ducktape.modules.ModuleA; -import net.year4000.utilities.ducktape.modules.ModuleB; -import net.year4000.utilities.ducktape.modules.ModuleC; +import net.year4000.utilities.ducktape.modules.*; import org.junit.Assert; import org.junit.Test; @@ -23,6 +20,16 @@ public void test() { ducktape.init(); } + @Test + public void errorText() { + Ducktape ducktape = Ducktape.builder() + .addLoader(new ClassModuleLoader(ModuleE.class, ModuleError.class)) + .build(); + ducktape.init(); + Assert.assertArrayEquals(ducktape.getModules().stream().map(ModuleInfo::getPhase).toArray(), + new ModuleInfo.Phase[] {ModuleInfo.Phase.ENABLED, ModuleInfo.Phase.ERROR}); + } + @Test public void loadModules() { // Modules were created in a way to have the dependency graph the same when shuffled @@ -34,6 +41,7 @@ public void loadModules() { .addLoader(new ClassModuleLoader(ModuleB.class, ModuleD.class, ModuleA.class, ModuleC.class)) .build(); randomLoader.init(); - Assert.assertArrayEquals(sortedLoader.getModules().stream().map(ModuleInfo::getId).toArray(), randomLoader.getModules().stream().map(ModuleInfo::getId).toArray()); + Assert.assertArrayEquals(sortedLoader.getModules().stream().map(ModuleInfo::getId).toArray(), + randomLoader.getModules().stream().map(ModuleInfo::getId).toArray()); } } diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleE.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleE.java new file mode 100644 index 0000000..ee31086 --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleE.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.modules; + +import net.year4000.utilities.ducktape.module.Enable; +import net.year4000.utilities.ducktape.module.Load; +import net.year4000.utilities.ducktape.module.Module; + +@Module(id = "e") +public class ModuleE { + @Load + public void load() { + System.out.println("ModuleE loader"); + } + + @Enable + public void enable() { + System.out.println("ModuleE enabler"); + } +} diff --git a/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleError.java b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleError.java new file mode 100644 index 0000000..2b196b7 --- /dev/null +++ b/core-ducktape/src/test/java/net/year4000/utilities/ducktape/modules/ModuleError.java @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Year4000. All Rights Reserved. + */ +package net.year4000.utilities.ducktape.modules; + +import net.year4000.utilities.ducktape.module.Load; +import net.year4000.utilities.ducktape.module.Module; + +@Module(id = "error") +public class ModuleError { + + @Load + public void load() { + throw new RuntimeException("error"); + } +}