diff --git a/boot/pom.xml b/boot/pom.xml new file mode 100644 index 0000000..09316fa --- /dev/null +++ b/boot/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + io.smallrye.modules + smallrye-modules-parent + 1.0.beta2-SNAPSHOT + + + smallrye-modules-boot + + SmallRye Modules - Boot + Bootstrap shim for loading the SmallRye Modules runtime from a composite JAR + + + + org.junit.jupiter + junit-jupiter + test + + + + + + + maven-jar-plugin + + + + io.smallrye.modules.boot.Boot + + + + + + + diff --git a/boot/src/main/java/io/smallrye/modules/boot/Boot.java b/boot/src/main/java/io/smallrye/modules/boot/Boot.java new file mode 100644 index 0000000..1772f48 --- /dev/null +++ b/boot/src/main/java/io/smallrye/modules/boot/Boot.java @@ -0,0 +1,176 @@ +package io.smallrye.modules.boot; + +import static java.lang.invoke.MethodHandles.lookup; +import static java.lang.invoke.MethodHandles.publicLookup; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.CodeSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Bootstrap entry point for loading the SmallRye Modules runtime from a + * composite JAR without placing any dependencies on the application module path. + *

+ * The bootstrap sequence: + *

    + *
  1. Locate the composite JAR from the boot module's code source
  2. + *
  3. Memory-map the entire JAR
  4. + *
  5. Load the synthesized {@link JarIndex} implementation from the system class loader
  6. + *
  7. Create a {@link BootClassLoader} backed by the mapped buffer
  8. + *
  9. Build a JPMS {@link ModuleLayer} over the boot class loader
  10. + *
  11. Transfer the {@code jdk.internal.module} export to the infrastructure module
  12. + *
  13. Invoke the runtime's {@code Launcher.main}
  14. + *
+ */ +public final class Boot { + + private Boot() { + } + + /** + * Main entry point. + * + * @param args the command-line arguments, forwarded to the runtime launcher + * @throws Throwable if bootstrap fails + */ + public static void main(String[] args) throws Throwable { + // 1. Locate the composite JAR from our own code source + CodeSource codeSource = Boot.class.getProtectionDomain().getCodeSource(); + if (codeSource == null) { + throw new IllegalStateException("Cannot determine Boot code source location"); + } + Path jarPath = Path.of(codeSource.getLocation().toURI()); + + // 2. Memory-map the entire file + ByteBuffer compositeBuffer; + try (FileChannel channel = FileChannel.open(jarPath, StandardOpenOption.READ)) { + compositeBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + } + + // 3. Load the synthesized JarIndex from the system class loader + Class indexClass = Class.forName("io.smallrye.modules.boot.JarIndexImpl", true, + ClassLoader.getSystemClassLoader()); + JarIndex jarIndex = (JarIndex) indexClass.getDeclaredConstructor().newInstance(); + + // 4. Create boot class loader (reads module descriptors, builds package index — no classes loaded) + BootClassLoader bootCL = new BootClassLoader(compositeBuffer, jarIndex, null); + + // 5. Build the infrastructure ModuleLayer + // 5a. Build a ModuleFinder from the index + Map moduleRefs = buildModuleReferences(compositeBuffer, jarIndex); + java.lang.module.ModuleFinder finder = new java.lang.module.ModuleFinder() { + @Override + public Optional find(String name) { + return Optional.ofNullable(moduleRefs.get(name)); + } + + @Override + public Set findAll() { + return Set.copyOf(moduleRefs.values()); + } + }; + + // 5b. Resolve the configuration against the boot layer + Set roots = Set.copyOf(jarIndex.moduleNames()); + Configuration cf = ModuleLayer.boot().configuration().resolve( + finder, java.lang.module.ModuleFinder.of(), roots); + + // 5c. Define the module layer + ModuleLayer.Controller controller = ModuleLayer.defineModules( + cf, List.of(ModuleLayer.boot()), name -> bootCL); + ModuleLayer infraLayer = controller.layer(); + + // 6. Transfer the jdk.internal.module export to the infrastructure module + Module infraModule = infraLayer.findModule("io.smallrye.modules") + .orElseThrow(() -> new IllegalStateException("io.smallrye.modules not found in infrastructure layer")); + transferInternalExport(infraModule); + + // 7. Set TCCL and invoke Launcher.main + Thread.currentThread().setContextClassLoader(bootCL); + Class launcherClass = Class.forName(infraModule, "io.smallrye.modules.Launcher"); + if (launcherClass == null) { + throw new ClassNotFoundException("io.smallrye.modules.Launcher not found in infrastructure layer"); + } + MethodHandle mainHandle = publicLookup().findStatic(launcherClass, "main", + MethodType.methodType(void.class, String[].class)); + mainHandle.invokeExact(args); + } + + /** + * Build a map of module name to {@link ModuleReference} from the composite index. + * Each reference wraps the {@link ModuleDescriptor} read from the composite buffer. + */ + private static Map buildModuleReferences(ByteBuffer buffer, JarIndex index) { + HashMap refs = new HashMap<>(); + for (String moduleName : index.moduleNames()) { + long offset = index.classOffset(moduleName, "module-info"); + long size = index.classSize(moduleName, "module-info"); + ByteBuffer descriptorBytes = buffer.slice((int) offset, (int) size); + ModuleDescriptor descriptor = ModuleDescriptor.read(descriptorBytes); + ModuleReference ref = new ModuleReference(descriptor, null) { + @Override + public ModuleReader open() { + // module reader is not needed for defineModules — the boot class loader handles all reads + return new ModuleReader() { + @Override + public Optional find(String name) { + return Optional.empty(); + } + + @Override + public Stream list() { + return Stream.empty(); + } + + @Override + public void close() { + } + }; + } + }; + refs.put(moduleName, ref); + } + return refs; + } + + /** + * Use {@code jdk.internal.module.Modules.addExports} to export + * {@code jdk.internal.module} from {@code java.base} to the given module. + *

+ * This requires {@code --add-exports java.base/jdk.internal.module=ALL-UNNAMED} + * on the command line (since the boot module is on the unnamed module of the + * system class loader at startup). + */ + private static void transferInternalExport(Module infraModule) { + try { + @SuppressWarnings("Java9ReflectionClassVisibility") + Class modulesClass = Class.forName("jdk.internal.module.Modules", true, null); + MethodHandle addExports = lookup().findStatic(modulesClass, "addExports", + MethodType.methodType(void.class, Module.class, String.class, Module.class)); + Module javaBase = Object.class.getModule(); + addExports.invokeExact(javaBase, "jdk.internal.module", infraModule); + } catch (Throwable e) { + Module self = Boot.class.getModule(); + String target = self.isNamed() ? self.getName() : "ALL-UNNAMED"; + throw new IllegalStateException( + "Failed to transfer jdk.internal.module export — use: " + + "--add-exports java.base/jdk.internal.module=" + target, + e); + } + } +} diff --git a/boot/src/main/java/io/smallrye/modules/boot/BootClassLoader.java b/boot/src/main/java/io/smallrye/modules/boot/BootClassLoader.java new file mode 100644 index 0000000..fe255ea --- /dev/null +++ b/boot/src/main/java/io/smallrye/modules/boot/BootClassLoader.java @@ -0,0 +1,266 @@ +package io.smallrye.modules.boot; + +import java.io.IOException; +import java.lang.module.ModuleDescriptor; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * A lock-free class loader that defines classes from pre-indexed offsets + * within a memory-mapped composite JAR. + *

+ * This class loader eliminates class-loading locks using the same pattern + * as {@code ModuleClassLoader}: {@link #getClassLoadingLock(String)} eagerly + * loads the class and returns it as the "lock" object, so the JDK's + * {@code ClassLoader.loadClass(Module, String)} never blocks. + *

+ * Boot layer packages are delegated to the boot loader via + * {@link Class#forName(Module, String)}. All other classes are defined + * from zero-copy {@link ByteBuffer} slices of the composite JAR. + */ +public final class BootClassLoader extends ClassLoader { + static { + if (!ClassLoader.registerAsParallelCapable()) { + throw new InternalError("Class loader cannot be made parallel-capable"); + } + } + + /** + * Boot layer index: package name to {@code Module}. + */ + private static final Map bootModuleIndex; + + static { + HashMap map = new HashMap<>(1000); + populateIndex(map, ModuleLayer.boot()); + bootModuleIndex = Map.copyOf(map); + } + + private static void populateIndex(Map map, ModuleLayer layer) { + for (Module module : layer.modules()) { + for (String pn : module.getPackages()) { + map.put(pn, module); + } + } + for (ModuleLayer parent : layer.parents()) { + populateIndex(map, parent); + } + } + + private final ByteBuffer compositeBuffer; + private final JarIndex jarIndex; + /** + * Package name (dots) to module name. + */ + private final Map packageIndex; + private final ProtectionDomain protectionDomain; + + /** + * Construct a new boot class loader. + *

+ * Reads module descriptors from the composite JAR via the index to build + * the package-to-module routing map. No classes are loaded during construction. + * + * @param compositeBuffer the memory-mapped composite JAR buffer (must not be {@code null}) + * @param jarIndex the pre-built index of class entries (must not be {@code null}) + * @param protectionDomain the protection domain to assign to defined classes, or {@code null} + */ + public BootClassLoader(ByteBuffer compositeBuffer, JarIndex jarIndex, ProtectionDomain protectionDomain) { + // no parent class loader — boot layer delegation is handled explicitly + super("boot", null); + this.compositeBuffer = compositeBuffer; + this.jarIndex = jarIndex; + this.protectionDomain = protectionDomain; + this.packageIndex = buildPackageIndex(compositeBuffer, jarIndex); + } + + private static Map buildPackageIndex(ByteBuffer buffer, JarIndex index) { + // scan module descriptors to map package → module name + HashMap map = new HashMap<>(); + for (String moduleName : index.moduleNames()) { + long offset = index.classOffset(moduleName, "module-info"); + long size = index.classSize(moduleName, "module-info"); + if (offset < 0 || size < 0) { + throw new IllegalArgumentException("Module " + moduleName + " has no module-info.class entry"); + } + ByteBuffer descriptorBytes = buffer.slice((int) offset, (int) size); + ModuleDescriptor descriptor = ModuleDescriptor.read(descriptorBytes); + for (String pkg : descriptor.packages()) { + map.put(pkg, moduleName); + } + } + return Map.copyOf(map); + } + + // ── Lock elimination ────────────────────────────────────────────── + + /** + * {@inheritDoc} + *

+ * Overridden as {@code final} to bypass parent delegation. + */ + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return loadClass(name, false); + } + + /** + * {@inheritDoc} + *

+ * Overridden as {@code final} to bypass parent delegation and route + * classes either to the boot layer or to direct definition from the + * composite buffer. + */ + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("[")) { + // array type — delegate to the boot loader + return Class.forName(name, false, null); + } + String binaryName = name.replace('/', '.'); + String packageName = packageName(binaryName); + if (bootModuleIndex.containsKey(packageName)) { + // boot layer class — delegate via boot module + Module module = bootModuleIndex.get(packageName); + Class result = Class.forName(module, binaryName); + if (result != null) { + return result; + } + throw new ClassNotFoundException("Cannot find " + name + " in boot layer module " + module.getName()); + } + return loadClassDirect(binaryName); + } + + /** + * Eagerly loads the requested class and returns it as the "lock" object. + *

+ * The JDK's {@code ClassLoader.loadClass(Module, String)} acquires this + * lock before calling {@link #findClass(String, String)}. By loading the + * class here, the subsequent {@code findClass} call becomes a no-op, + * eliminating all lock contention. + */ + @Override + protected Object getClassLoadingLock(String className) { + try { + return loadClass(className); + } catch (ClassNotFoundException e) { + return new Object(); + } + } + + /** + * Returns {@code null} because the class was already loaded by + * {@link #getClassLoadingLock(String)}. + */ + @Override + protected Class findClass(String moduleName, String name) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected Class findClass(String name) { + throw new UnsupportedOperationException(); + } + + // ── Class definition ────────────────────────────────────────────── + + /** + * Load a class directly from the composite buffer. + *

+ * Looks up the class in the package index, retrieves its byte offset + * and size from the jar index, slices a zero-copy view, and defines + * the class. Concurrent definition races are handled by catching + * {@link LinkageError} and falling back to {@link #findLoadedClass}. + * + * @param binaryName the binary name with dots (e.g. {@code "io.smallrye.modules.Launcher"}) + * @return the defined or previously-loaded class + * @throws ClassNotFoundException if the class is not found in the composite + */ + private Class loadClassDirect(String binaryName) throws ClassNotFoundException { + Class loaded = findLoadedClass(binaryName); + if (loaded != null) { + return loaded; + } + String packageName = packageName(binaryName); + String moduleName = packageIndex.get(packageName); + if (moduleName == null) { + throw new ClassNotFoundException("No module contains package " + packageName); + } + long offset = jarIndex.classOffset(moduleName, binaryName); + long size = jarIndex.classSize(moduleName, binaryName); + if (offset < 0 || size < 0) { + throw new ClassNotFoundException(binaryName + " not found in module " + moduleName); + } + ByteBuffer classBytes = compositeBuffer.slice((int) offset, (int) size); + if (!packageName.isEmpty() && getDefinedPackage(packageName) == null) { + try { + definePackage(packageName, null, null, null, null, null, null, null); + } catch (IllegalArgumentException ignored) { + // concurrent define — package already exists + } + } + return defineOrGetClass(binaryName, classBytes); + } + + /** + * Define the class from the given buffer, handling concurrent definition races. + */ + private Class defineOrGetClass(String binaryName, ByteBuffer buffer) { + try { + return defineClass(binaryName, buffer, protectionDomain); + } catch (LinkageError e) { + // concurrent definition race — check if another thread defined it + Class loaded = findLoadedClass(binaryName); + if (loaded != null) { + return loaded; + } + throw e; + } + } + + // ── Sealed unsupported operations ───────────────────────────────── + + /** + * {@inheritDoc} + */ + @Override + protected URL findResource(String moduleName, String name) throws IOException { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected URL findResource(String name) { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected Enumeration findResources(String name) { + return java.util.Collections.emptyEnumeration(); + } + + // ── Utility ─────────────────────────────────────────────────────── + + /** + * Extract the package name from a binary class name. + * + * @param binaryName the binary name (dots) + * @return the package name, or the empty string for the default package + */ + private static String packageName(String binaryName) { + int lastDot = binaryName.lastIndexOf('.'); + return lastDot < 0 ? "" : binaryName.substring(0, lastDot); + } +} diff --git a/boot/src/main/java/io/smallrye/modules/boot/JarIndex.java b/boot/src/main/java/io/smallrye/modules/boot/JarIndex.java new file mode 100644 index 0000000..c688539 --- /dev/null +++ b/boot/src/main/java/io/smallrye/modules/boot/JarIndex.java @@ -0,0 +1,53 @@ +package io.smallrye.modules.boot; + +import java.util.List; + +/** + * Index of class entries within a composite JAR. + *

+ * An implementation of this interface is synthesized by the composite JAR builder + * and placed at the top level of the composite JAR so that it is visible to the + * system class loader. The boot shim loads the implementation and uses it to + * locate class bytes within the memory-mapped composite without any ZIP parsing. + *

+ * The {@code module-info.class} entries in the composite JAR must contain + * complete package lists. The boot class loader reads + * {@link java.lang.module.ModuleDescriptor#packages()} to build the + * package-to-module routing map; a module descriptor with a missing or + * incomplete package index will cause classes in unlisted packages to be + * unroutable. + *

+ * All offsets and sizes are {@code long} to future-proof for {@code MemorySegment} + * support. + */ +public interface JarIndex { + + /** + * {@return the names of all modules stored in the composite JAR} + * The returned list is unmodifiable and never empty. + */ + List moduleNames(); + + /** + * Return the byte offset within the composite JAR of the given class entry. + *

+ * The {@code className} is a binary name (dots, not slashes), e.g. + * {@code "io.smallrye.modules.Launcher"}. + * Use {@code "module-info"} to retrieve the {@code module-info.class} entry + * for the given module. + * + * @param moduleName the module name (must not be {@code null}) + * @param className the binary class name (must not be {@code null}) + * @return the byte offset, or {@code -1} if the entry is not found + */ + long classOffset(String moduleName, String className); + + /** + * Return the byte size of the given class entry within the composite JAR. + * + * @param moduleName the module name (must not be {@code null}) + * @param className the binary class name (must not be {@code null}) + * @return the byte size, or {@code -1} if the entry is not found + */ + long classSize(String moduleName, String className); +} diff --git a/boot/src/main/java/module-info.java b/boot/src/main/java/module-info.java new file mode 100644 index 0000000..a009cdb --- /dev/null +++ b/boot/src/main/java/module-info.java @@ -0,0 +1,6 @@ +/** + * Boot shim for loading the SmallRye Modules runtime from a composite JAR. + */ +module io.smallrye.modules.boot { + exports io.smallrye.modules.boot; +} diff --git a/pom.xml b/pom.xml index 108a27d..05056ce 100644 --- a/pom.xml +++ b/pom.xml @@ -2,18 +2,24 @@ 4.0.0 - io.smallrye.modules - smallrye-modules - 1.0.beta2-SNAPSHOT - io.smallrye smallrye-parent 50 - SmallRye Modules - A dynamic modular class loading environment + io.smallrye.modules + smallrye-modules-parent + 1.0.beta2-SNAPSHOT + pom + + SmallRye Modules - Parent + Parent and aggregator for SmallRye Modules + + + runtime + boot + 17 @@ -32,54 +38,8 @@ - - - io.smallrye.common - smallrye-common-cpu - - - io.smallrye.common - smallrye-common-os - - - io.smallrye.common - smallrye-common-resource - - - io.smallrye.classfile - jdk-classfile-backport - 27 - - - org.jboss.logging - jboss-logging - 3.6.3.Final - - - org.junit.jupiter - junit-jupiter - test - - - - - maven-surefire-plugin - - --add-exports java.base/jdk.internal.module=io.smallrye.modules - - - - maven-jar-plugin - - - - io.smallrye.modules.Launcher - - - - net.revelc.code impsort-maven-plugin @@ -119,12 +79,6 @@ - - maven-javadoc-plugin - - 17 - - diff --git a/runtime/pom.xml b/runtime/pom.xml new file mode 100644 index 0000000..7faa841 --- /dev/null +++ b/runtime/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + + io.smallrye.modules + smallrye-modules-parent + 1.0.beta2-SNAPSHOT + + + smallrye-modules + + SmallRye Modules + A dynamic modular class loading environment + + + + io.smallrye.common + smallrye-common-cpu + + + io.smallrye.common + smallrye-common-os + + + io.smallrye.common + smallrye-common-resource + + + io.smallrye.classfile + jdk-classfile-backport + 27 + + + org.jboss.logging + jboss-logging + 3.6.3.Final + + + org.junit.jupiter + junit-jupiter + test + + + + + + + maven-surefire-plugin + + --add-exports java.base/jdk.internal.module=io.smallrye.modules + + + + maven-jar-plugin + + + + io.smallrye.modules.Launcher + + + + + + maven-javadoc-plugin + + 17 + + + + + diff --git a/src/main/java/io/smallrye/modules/DefinedModule.java b/runtime/src/main/java/io/smallrye/modules/DefinedModule.java similarity index 100% rename from src/main/java/io/smallrye/modules/DefinedModule.java rename to runtime/src/main/java/io/smallrye/modules/DefinedModule.java diff --git a/src/main/java/io/smallrye/modules/DelegatingModuleLoader.java b/runtime/src/main/java/io/smallrye/modules/DelegatingModuleLoader.java similarity index 100% rename from src/main/java/io/smallrye/modules/DelegatingModuleLoader.java rename to runtime/src/main/java/io/smallrye/modules/DelegatingModuleLoader.java diff --git a/src/main/java/io/smallrye/modules/FoundModule.java b/runtime/src/main/java/io/smallrye/modules/FoundModule.java similarity index 100% rename from src/main/java/io/smallrye/modules/FoundModule.java rename to runtime/src/main/java/io/smallrye/modules/FoundModule.java diff --git a/src/main/java/io/smallrye/modules/JarFileModuleFinder.java b/runtime/src/main/java/io/smallrye/modules/JarFileModuleFinder.java similarity index 100% rename from src/main/java/io/smallrye/modules/JarFileModuleFinder.java rename to runtime/src/main/java/io/smallrye/modules/JarFileModuleFinder.java diff --git a/src/main/java/io/smallrye/modules/Launcher.java b/runtime/src/main/java/io/smallrye/modules/Launcher.java similarity index 100% rename from src/main/java/io/smallrye/modules/Launcher.java rename to runtime/src/main/java/io/smallrye/modules/Launcher.java diff --git a/src/main/java/io/smallrye/modules/LinkState.java b/runtime/src/main/java/io/smallrye/modules/LinkState.java similarity index 100% rename from src/main/java/io/smallrye/modules/LinkState.java rename to runtime/src/main/java/io/smallrye/modules/LinkState.java diff --git a/src/main/java/io/smallrye/modules/LoadedDependency.java b/runtime/src/main/java/io/smallrye/modules/LoadedDependency.java similarity index 100% rename from src/main/java/io/smallrye/modules/LoadedDependency.java rename to runtime/src/main/java/io/smallrye/modules/LoadedDependency.java diff --git a/src/main/java/io/smallrye/modules/LoadedModule.java b/runtime/src/main/java/io/smallrye/modules/LoadedModule.java similarity index 100% rename from src/main/java/io/smallrye/modules/LoadedModule.java rename to runtime/src/main/java/io/smallrye/modules/LoadedModule.java diff --git a/src/main/java/io/smallrye/modules/ModuleClassLoader.java b/runtime/src/main/java/io/smallrye/modules/ModuleClassLoader.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleClassLoader.java rename to runtime/src/main/java/io/smallrye/modules/ModuleClassLoader.java diff --git a/src/main/java/io/smallrye/modules/ModuleDescriptorLoader.java b/runtime/src/main/java/io/smallrye/modules/ModuleDescriptorLoader.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleDescriptorLoader.java rename to runtime/src/main/java/io/smallrye/modules/ModuleDescriptorLoader.java diff --git a/src/main/java/io/smallrye/modules/ModuleFinder.java b/runtime/src/main/java/io/smallrye/modules/ModuleFinder.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleFinder.java rename to runtime/src/main/java/io/smallrye/modules/ModuleFinder.java diff --git a/src/main/java/io/smallrye/modules/ModuleLoadException.java b/runtime/src/main/java/io/smallrye/modules/ModuleLoadException.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleLoadException.java rename to runtime/src/main/java/io/smallrye/modules/ModuleLoadException.java diff --git a/src/main/java/io/smallrye/modules/ModuleLoader.java b/runtime/src/main/java/io/smallrye/modules/ModuleLoader.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleLoader.java rename to runtime/src/main/java/io/smallrye/modules/ModuleLoader.java diff --git a/src/main/java/io/smallrye/modules/ModuleNotFoundException.java b/runtime/src/main/java/io/smallrye/modules/ModuleNotFoundException.java similarity index 100% rename from src/main/java/io/smallrye/modules/ModuleNotFoundException.java rename to runtime/src/main/java/io/smallrye/modules/ModuleNotFoundException.java diff --git a/src/main/java/io/smallrye/modules/ResourceLoaderOpener.java b/runtime/src/main/java/io/smallrye/modules/ResourceLoaderOpener.java similarity index 100% rename from src/main/java/io/smallrye/modules/ResourceLoaderOpener.java rename to runtime/src/main/java/io/smallrye/modules/ResourceLoaderOpener.java diff --git a/src/main/java/io/smallrye/modules/desc/Biterator.java b/runtime/src/main/java/io/smallrye/modules/desc/Biterator.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/Biterator.java rename to runtime/src/main/java/io/smallrye/modules/desc/Biterator.java diff --git a/src/main/java/io/smallrye/modules/desc/Dependency.java b/runtime/src/main/java/io/smallrye/modules/desc/Dependency.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/Dependency.java rename to runtime/src/main/java/io/smallrye/modules/desc/Dependency.java diff --git a/src/main/java/io/smallrye/modules/desc/ModifierFlag.java b/runtime/src/main/java/io/smallrye/modules/desc/ModifierFlag.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/ModifierFlag.java rename to runtime/src/main/java/io/smallrye/modules/desc/ModifierFlag.java diff --git a/src/main/java/io/smallrye/modules/desc/Modifiers.java b/runtime/src/main/java/io/smallrye/modules/desc/Modifiers.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/Modifiers.java rename to runtime/src/main/java/io/smallrye/modules/desc/Modifiers.java diff --git a/src/main/java/io/smallrye/modules/desc/ModuleDescriptor.java b/runtime/src/main/java/io/smallrye/modules/desc/ModuleDescriptor.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/ModuleDescriptor.java rename to runtime/src/main/java/io/smallrye/modules/desc/ModuleDescriptor.java diff --git a/src/main/java/io/smallrye/modules/desc/PackageAccess.java b/runtime/src/main/java/io/smallrye/modules/desc/PackageAccess.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/PackageAccess.java rename to runtime/src/main/java/io/smallrye/modules/desc/PackageAccess.java diff --git a/src/main/java/io/smallrye/modules/desc/PackageInfo.java b/runtime/src/main/java/io/smallrye/modules/desc/PackageInfo.java similarity index 100% rename from src/main/java/io/smallrye/modules/desc/PackageInfo.java rename to runtime/src/main/java/io/smallrye/modules/desc/PackageInfo.java diff --git a/src/main/java/io/smallrye/modules/impl/Access.java b/runtime/src/main/java/io/smallrye/modules/impl/Access.java similarity index 100% rename from src/main/java/io/smallrye/modules/impl/Access.java rename to runtime/src/main/java/io/smallrye/modules/impl/Access.java diff --git a/src/main/java/io/smallrye/modules/impl/TextIter.java b/runtime/src/main/java/io/smallrye/modules/impl/TextIter.java similarity index 100% rename from src/main/java/io/smallrye/modules/impl/TextIter.java rename to runtime/src/main/java/io/smallrye/modules/impl/TextIter.java diff --git a/src/main/java/io/smallrye/modules/impl/Util.java b/runtime/src/main/java/io/smallrye/modules/impl/Util.java similarity index 100% rename from src/main/java/io/smallrye/modules/impl/Util.java rename to runtime/src/main/java/io/smallrye/modules/impl/Util.java diff --git a/src/main/java/io/smallrye/modules/jfr/DefineDuplicateEvent.java b/runtime/src/main/java/io/smallrye/modules/jfr/DefineDuplicateEvent.java similarity index 100% rename from src/main/java/io/smallrye/modules/jfr/DefineDuplicateEvent.java rename to runtime/src/main/java/io/smallrye/modules/jfr/DefineDuplicateEvent.java diff --git a/src/main/java/io/smallrye/modules/jfr/DefineFailedEvent.java b/runtime/src/main/java/io/smallrye/modules/jfr/DefineFailedEvent.java similarity index 100% rename from src/main/java/io/smallrye/modules/jfr/DefineFailedEvent.java rename to runtime/src/main/java/io/smallrye/modules/jfr/DefineFailedEvent.java diff --git a/src/main/java/io/smallrye/modules/jfr/LinkEvent.java b/runtime/src/main/java/io/smallrye/modules/jfr/LinkEvent.java similarity index 100% rename from src/main/java/io/smallrye/modules/jfr/LinkEvent.java rename to runtime/src/main/java/io/smallrye/modules/jfr/LinkEvent.java diff --git a/src/main/java/module-info.java b/runtime/src/main/java/module-info.java similarity index 100% rename from src/main/java/module-info.java rename to runtime/src/main/java/module-info.java diff --git a/src/test/java/io/smallrye/modules/test/BasicTests.java b/runtime/src/test/java/io/smallrye/modules/test/BasicTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/BasicTests.java rename to runtime/src/test/java/io/smallrye/modules/test/BasicTests.java diff --git a/src/test/java/io/smallrye/modules/test/DelegatingModuleLoaderTests.java b/runtime/src/test/java/io/smallrye/modules/test/DelegatingModuleLoaderTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/DelegatingModuleLoaderTests.java rename to runtime/src/test/java/io/smallrye/modules/test/DelegatingModuleLoaderTests.java diff --git a/src/test/java/io/smallrye/modules/test/DependencyModifierTests.java b/runtime/src/test/java/io/smallrye/modules/test/DependencyModifierTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/DependencyModifierTests.java rename to runtime/src/test/java/io/smallrye/modules/test/DependencyModifierTests.java diff --git a/src/test/java/io/smallrye/modules/test/DependencyTests.java b/runtime/src/test/java/io/smallrye/modules/test/DependencyTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/DependencyTests.java rename to runtime/src/test/java/io/smallrye/modules/test/DependencyTests.java diff --git a/src/test/java/io/smallrye/modules/test/ExceptionTests.java b/runtime/src/test/java/io/smallrye/modules/test/ExceptionTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ExceptionTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ExceptionTests.java diff --git a/src/test/java/io/smallrye/modules/test/FoundModuleTests.java b/runtime/src/test/java/io/smallrye/modules/test/FoundModuleTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/FoundModuleTests.java rename to runtime/src/test/java/io/smallrye/modules/test/FoundModuleTests.java diff --git a/src/test/java/io/smallrye/modules/test/LoadedModuleTests.java b/runtime/src/test/java/io/smallrye/modules/test/LoadedModuleTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/LoadedModuleTests.java rename to runtime/src/test/java/io/smallrye/modules/test/LoadedModuleTests.java diff --git a/src/test/java/io/smallrye/modules/test/ModuleDescriptorBuilderTests.java b/runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorBuilderTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ModuleDescriptorBuilderTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorBuilderTests.java diff --git a/src/test/java/io/smallrye/modules/test/ModuleDescriptorManifestTests.java b/runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorManifestTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ModuleDescriptorManifestTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorManifestTests.java diff --git a/src/test/java/io/smallrye/modules/test/ModuleDescriptorModifierTests.java b/runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorModifierTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ModuleDescriptorModifierTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorModifierTests.java diff --git a/src/test/java/io/smallrye/modules/test/ModuleDescriptorXmlTests.java b/runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorXmlTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ModuleDescriptorXmlTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ModuleDescriptorXmlTests.java diff --git a/src/test/java/io/smallrye/modules/test/ModuleLoaderTests.java b/runtime/src/test/java/io/smallrye/modules/test/ModuleLoaderTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/ModuleLoaderTests.java rename to runtime/src/test/java/io/smallrye/modules/test/ModuleLoaderTests.java diff --git a/src/test/java/io/smallrye/modules/test/PackageAccessTests.java b/runtime/src/test/java/io/smallrye/modules/test/PackageAccessTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/PackageAccessTests.java rename to runtime/src/test/java/io/smallrye/modules/test/PackageAccessTests.java diff --git a/src/test/java/io/smallrye/modules/test/PackageInfoTests.java b/runtime/src/test/java/io/smallrye/modules/test/PackageInfoTests.java similarity index 100% rename from src/test/java/io/smallrye/modules/test/PackageInfoTests.java rename to runtime/src/test/java/io/smallrye/modules/test/PackageInfoTests.java diff --git a/src/test/java/module-info.java b/runtime/src/test/java/module-info.java similarity index 100% rename from src/test/java/module-info.java rename to runtime/src/test/java/module-info.java