On 29/07/2016 09:22, Jochen Theodorou wrote:
:
To start off I guess there would be a small gateway program, that
handles the command line arguments and issues the download of the
modules. What comes after that? Is it as easy as spawning a new class
loader and load the modules in that loader as well as the reminder of
the program? Is there an alternative way of doing this? How do I add
the modules to the current layer? Or if a different layer... Will my
program then still have access to the services?
Assuming you've downloaded the module that you will hand off too, plus
all the dependences, then the code fragment below might get you started.
The code fragment assumes the packaged modules are downloaded to some
directory on the file system. It invokes the
Configuration.resolveRequiresAndUses to resolve a module name "rabbit".
This will create a Configuration that is essentially a module graph that
includes "rabbit" and its dependences, the "AddUses" variant deals with
services as you mentioned those. It then instantiates that graph of
modules using Layer.defineModulesWithOneLoader which will create one
class loader for all the modules in the module layer. The rest isn't
anything module specific, it's just using core reflection to invoke
rabbit's entry point, I assume this is a hand off from your mini launcher.
Alex covers a lot of the background in the Under the Hood talk,
specifically part 3 on "Loaders and Layers".
-Alan
Path dir = // download directory
ModuleFinder finder = ModuleFinder.of(dir);
Layer bootLayer = Layer.boot();
Configuration cf = bootLayer.configuration()
.resolveRequiresAndUses(ModuleFinder.of(), finder,
Set.of("rabbit"));
System.out.println("Resolved");
cf.modules().stream()
.map(ResolvedModule::name)
.sorted()
.forEach(System.out::println);
ClassLoader scl = ClassLoader.getSystemClassLoader();
Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
ClassLoader loader = layer.findLoader("rabbit");
Class<?> c = loader.loadClass("rabbit.Main");
Method mainMethod = c.getMethod("main", String[].class);
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(loader);
mainMethod.invoke(null, (Object)new String[0]);
} finally {
Thread.currentThread().setContextClassLoader(tccl);
}