From dfbb6e507ae348fa183a9e5d30c1bab121382628 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Sat, 23 Dec 2023 12:18:10 +0700 Subject: [PATCH] [REFACTOR] Using Java 17 --- LauncherAPI/build.gradle | 23 +- LauncherClient/build.gradle | 4 +- LauncherCore/build.gradle | 22 +- .../pro/gravit/utils/helper/JVMHelper.java | 29 +- .../pro/gravit/utils/launch/ModuleHacks.java | 0 .../pro/gravit/utils/launch/ModuleLaunch.java | 316 ++++++++++++++++- .../pro/gravit/utils/helper/JVMHelper.java | 213 ------------ .../pro/gravit/utils/launch/ModuleLaunch.java | 323 ------------------ LauncherStart/build.gradle | 4 +- ServerWrapper/build.gradle | 24 +- 10 files changed, 324 insertions(+), 634 deletions(-) rename LauncherCore/src/main/{java11 => java}/pro/gravit/utils/launch/ModuleHacks.java (100%) delete mode 100644 LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java delete mode 100644 LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleLaunch.java diff --git a/LauncherAPI/build.gradle b/LauncherAPI/build.gradle index 8a418fc6..d50a567e 100644 --- a/LauncherAPI/build.gradle +++ b/LauncherAPI/build.gradle @@ -1,5 +1,5 @@ -sourceCompatibility = '1.8' -targetCompatibility = '1.8' +sourceCompatibility = '17' +targetCompatibility = '17' dependencies { api project(':LauncherCore') @@ -14,29 +14,10 @@ api project(':LauncherCore') } } -sourceSets { - java11 { - java { - srcDirs = ['src/main/java11'] - } - dependencies { - java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava } - } - } -} - jar { - into('META-INF/versions/11') { - from sourceSets.java11.output - } archiveClassifier.set('clean') } -compileJava11Java { - sourceCompatibility = 11 - targetCompatibility = 11 -} - tasks.register('sourcesJar', Jar) { from sourceSets.main.allJava archiveClassifier.set('sources') diff --git a/LauncherClient/build.gradle b/LauncherClient/build.gradle index 5c62ac48..9a59ce29 100644 --- a/LauncherClient/build.gradle +++ b/LauncherClient/build.gradle @@ -8,8 +8,8 @@ url "https://repo.spring.io/plugins-release/" } } -sourceCompatibility = '1.8' -targetCompatibility = '1.8' +sourceCompatibility = '17' +targetCompatibility = '17' jar { archiveClassifier.set('clean') diff --git a/LauncherCore/build.gradle b/LauncherCore/build.gradle index 86420ba1..efd55c0a 100644 --- a/LauncherCore/build.gradle +++ b/LauncherCore/build.gradle @@ -1,5 +1,5 @@ -sourceCompatibility = '1.8' -targetCompatibility = '1.8' +sourceCompatibility = '17' +targetCompatibility = '17' dependencies { compileOnly group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi'] @@ -21,28 +21,10 @@ events "passed", "skipped", "failed" } } -sourceSets { - java11 { - java { - srcDirs = ['src/main/java11'] - } - dependencies { - java11Implementation group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson'] - java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava } - } - } -} jar { - into('META-INF/versions/11') { - from sourceSets.java11.output - } archiveClassifier.set('clean') manifest.attributes("Multi-Release": "true") } -compileJava11Java { - sourceCompatibility = 11 - targetCompatibility = 11 -} tasks.register('sourcesJar', Jar) { from sourceSets.main.allJava diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java index e691aacb..d2779207 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java @@ -53,35 +53,12 @@ public static ARCH getArch(String arch) { } public static int getVersion() { - String version = System.getProperty("java.version"); - if (version.startsWith("1.")) { - version = version.substring(2, 3); - } else { - int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - } - return Integer.parseInt(version); + //System.out.println("[DEBUG] JVMHelper 11 version"); + return Runtime.version().feature(); } public static int getBuild() { - String version = System.getProperty("java.version"); - int dot; - if (version.startsWith("1.")) { - dot = version.indexOf("_"); - } else { - dot = version.lastIndexOf("."); - } - if (dot != -1) { - version = version.substring(dot + 1); - } - try { - return Integer.parseInt(version); - } catch (NumberFormatException exception) { - return 0; - } - + return Runtime.version().update(); } public static String getNativeExtension(JVMHelper.OS OS_TYPE) { diff --git a/LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleHacks.java b/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleHacks.java similarity index 100% rename from LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleHacks.java rename to LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleHacks.java diff --git a/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java b/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java index 0301ad02..ab4d829d 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java @@ -1,17 +1,323 @@ package pro.gravit.utils.launch; +import pro.gravit.utils.helper.HackHelper; +import pro.gravit.utils.helper.IOHelper; +import pro.gravit.utils.helper.JVMHelper; +import pro.gravit.utils.helper.LogHelper; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.file.Path; -import java.util.Collection; -import java.util.List; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public class ModuleLaunch implements Launch { + private ModuleClassLoader moduleClassLoader; + private Configuration configuration; + private ModuleLayer.Controller controller; + private ModuleFinder moduleFinder; + private ModuleLayer layer; + private MethodHandles.Lookup hackLookup; + private boolean disablePackageDelegateSupport; @Override public ClassLoaderControl init(List files, String nativePath, LaunchOptions options) { - throw new UnsupportedOperationException("Please use Multi-Release JAR"); + this.disablePackageDelegateSupport = options.disablePackageDelegateSupport; + moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> { + try { + return e.toUri().toURL(); + } catch (MalformedURLException ex) { + throw new RuntimeException(ex); + } + }).toArray(URL[]::new), ClassLoader.getPlatformClassLoader()); + moduleClassLoader.nativePath = nativePath; + { + if(options.enableHacks) { + hackLookup = HackHelper.createHackLookup(ModuleLaunch.class); + } + if(options.moduleConf != null) { + // Create Module Layer + moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).map(Path::toAbsolutePath).toArray(Path[]::new)); + ModuleLayer bootLayer = ModuleLayer.boot(); + if(options.moduleConf.modules.contains("ALL-MODULE-PATH")) { + var set = moduleFinder.findAll(); + if(LogHelper.isDevEnabled()) { + for(var m : set) { + LogHelper.dev("Found module %s in %s", m.descriptor().name(), m.location().map(URI::toString).orElse("unknown")); + } + LogHelper.dev("Found %d modules", set.size()); + } + for(var m : set) { + options.moduleConf.modules.add(m.descriptor().name()); + } + options.moduleConf.modules.remove("ALL-MODULE-PATH"); + } + configuration = bootLayer.configuration() + .resolveAndBind(moduleFinder, ModuleFinder.of(), options.moduleConf.modules); + controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader); + layer = controller.layer(); + // Configure exports / opens + for(var e : options.moduleConf.exports.entrySet()) { + String[] split = e.getKey().split("/"); + String moduleName = split[0]; + String pkg = split[1]; + LogHelper.dev("Export module: %s package: %s to %s", moduleName, pkg, e.getValue()); + Module source = layer.findModule(split[0]).orElse(null); + if(source == null) { + throw new RuntimeException(String.format("Module %s not found", moduleName)); + } + Module target = layer.findModule(e.getValue()).orElse(null); + if(target == null) { + throw new RuntimeException(String.format("Module %s not found", e.getValue())); + } + if(options.enableHacks && source.getLayer() != layer) { + ModuleHacks.createController(hackLookup, source.getLayer()).addExports(source, pkg, target); + } else { + controller.addExports(source, pkg, target); + } + } + for(var e : options.moduleConf.opens.entrySet()) { + String[] split = e.getKey().split("/"); + String moduleName = split[0]; + String pkg = split[1]; + LogHelper.dev("Open module: %s package: %s to %s", moduleName, pkg, e.getValue()); + Module source = layer.findModule(split[0]).orElse(null); + if(source == null) { + throw new RuntimeException(String.format("Module %s not found", moduleName)); + } + Module target = layer.findModule(e.getValue()).orElse(null); + if(target == null) { + throw new RuntimeException(String.format("Module %s not found", e.getValue())); + } + if(options.enableHacks && source.getLayer() != layer) { + ModuleHacks.createController(hackLookup, source.getLayer()).addOpens(source, pkg, target); + } else { + controller.addOpens(source, pkg, target); + } + } + for(var e : options.moduleConf.reads.entrySet()) { + LogHelper.dev("Read module %s to %s", e.getKey(), e.getValue()); + Module source = layer.findModule(e.getKey()).orElse(null); + if(source == null) { + throw new RuntimeException(String.format("Module %s not found", e.getKey())); + } + Module target = layer.findModule(e.getValue()).orElse(null); + if(target == null) { + throw new RuntimeException(String.format("Module %s not found", e.getValue())); + } + if(options.enableHacks && source.getLayer() != layer) { + ModuleHacks.createController(hackLookup, source.getLayer()).addReads(source, target); + } else { + controller.addReads(source, target); + } + } + moduleClassLoader.initializeWithLayer(layer); + } + } + return moduleClassLoader.makeControl(); } @Override - public void launch(String mainClass, String mainModule, Collection args) throws Throwable { - throw new UnsupportedOperationException("Please use Multi-Release JAR"); + public void launch(String mainClass, String mainModuleName, Collection args) throws Throwable { + Thread.currentThread().setContextClassLoader(moduleClassLoader); + if(mainModuleName == null) { + Class mainClazz = Class.forName(mainClass, true, moduleClassLoader); + MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity(); + JVMHelper.fullGC(); + mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0])); + return; + } + Module mainModule = layer.findModule(mainModuleName).orElseThrow(); + Module unnamed = ModuleLaunch.class.getClassLoader().getUnnamedModule(); + if(unnamed != null) { + controller.addOpens(mainModule, getPackageFromClass(mainClass), unnamed); + } + // Start main class + ClassLoader loader = mainModule.getClassLoader(); + Class mainClazz = Class.forName(mainClass, true, loader); + MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)); + mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0])); + } + + private static String getPackageFromClass(String clazz) { + int index = clazz.lastIndexOf("."); + if(index >= 0) { + return clazz.substring(0, index); + } + return clazz; + } + + private class ModuleClassLoader extends URLClassLoader { + private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader(); + private final List transformers = new ArrayList<>(); + private final Map> classMap = new ConcurrentHashMap<>(); + private final Map packageToModule = new HashMap<>(); + private String nativePath; + + private final List packages = new ArrayList<>(); + public ModuleClassLoader(URL[] urls, ClassLoader parent) { + super("LAUNCHER", urls, parent); + packages.add("pro.gravit.launcher."); + packages.add("pro.gravit.utils."); + } + + private void initializeWithLayer(ModuleLayer layer) { + for(var m : layer.modules()) { + for(var p : m.getPackages()) { + packageToModule.put(p, m); + } + } + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if(name != null && !disablePackageDelegateSupport) { + for(String pkg : packages) { + if(name.startsWith(pkg)) { + return SYSTEM_CLASS_LOADER.loadClass(name); + } + } + } + return super.loadClass(name, resolve); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + var clazz = findClass(null, name); + if(clazz == null) { + throw new ClassNotFoundException(name); + } + return clazz; + } + + @Override + protected Class findClass(String moduleName, String name) { + Class clazz; + { + clazz = classMap.get(name); + if(clazz != null) { + return clazz; + } + } + if(name != null && !transformers.isEmpty()) { + boolean needTransform = false; + for(ClassLoaderControl.ClassTransformer t : transformers) { + if(t.filter(moduleName, name)) { + needTransform = true; + break; + } + } + if(needTransform) { + String rawClassName = name.replace(".", "/").concat(".class"); + try(InputStream input = getResourceAsStream(rawClassName)) { + byte[] bytes = IOHelper.read(input); + for(ClassLoaderControl.ClassTransformer t : transformers) { + bytes = t.transform(moduleName, name, null, bytes); + } + clazz = defineClass(name, bytes, 0, bytes.length); + } catch (IOException e) { + return null; + } + } + } + if(clazz == null && layer != null && name != null) { + var pkg = getPackageFromClass(name); + var module = packageToModule.get(pkg); + if(module != null) { + try { + clazz = module.getClassLoader().loadClass(name); + } catch (ClassNotFoundException e) { + return null; + } + } + } + if(clazz == null) { + try { + clazz = super.findClass(name); + } catch (ClassNotFoundException e) { + return null; + } + } + if(clazz != null) { + classMap.put(name, clazz); + return clazz; + } else { + return null; + } + } + + @Override + public String findLibrary(String name) { + return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION); + } + + public void addAllowedPackage(String pkg) { + packages.add(pkg); + } + + private ModuleClassLoaderControl makeControl() { + return new ModuleClassLoaderControl(); + } + + private class ModuleClassLoaderControl implements ClassLoaderControl { + + @Override + public void addLauncherPackage(String prefix) { + addAllowedPackage(prefix); + } + + @Override + public void addTransformer(ClassTransformer transformer) { + transformers.add(transformer); + } + + @Override + public void addURL(URL url) { + ModuleClassLoader.this.addURL(url); + } + + @Override + public void addJar(Path path) { + try { + ModuleClassLoader.this.addURL(path.toUri().toURL()); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + @Override + public URL[] getURLs() { + return ModuleClassLoader.this.getURLs(); + } + + @Override + public Class getClass(String name) throws ClassNotFoundException { + return Class.forName(name, false, ModuleClassLoader.this); + } + + @Override + public ClassLoader getClassLoader() { + return ModuleClassLoader.this; + } + + @Override + public Object getJava9ModuleController() { + return controller; + } + + @Override + public MethodHandles.Lookup getHackLookup() { + return hackLookup; + } + } } } diff --git a/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java deleted file mode 100644 index d2779207..00000000 --- a/LauncherCore/src/main/java11/pro/gravit/utils/helper/JVMHelper.java +++ /dev/null @@ -1,213 +0,0 @@ -package pro.gravit.utils.helper; - -import java.io.File; -import java.lang.invoke.MethodHandles; -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; -import java.lang.management.RuntimeMXBean; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collection; -import java.util.Locale; -import java.util.Map; - -public final class JVMHelper { - - // MXBeans exports - public static final RuntimeMXBean RUNTIME_MXBEAN = ManagementFactory.getRuntimeMXBean(); - public static final OperatingSystemMXBean OPERATING_SYSTEM_MXBEAN = - ManagementFactory.getOperatingSystemMXBean(); - public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName()); - public static final int OS_BITS = getCorrectOSArch(); - // System properties - public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion(); - public static final ARCH ARCH_TYPE = getArch(System.getProperty("os.arch")); - public static final String NATIVE_EXTENSION = getNativeExtension(OS_TYPE); - public static final String NATIVE_PREFIX = getNativePrefix(OS_TYPE); - public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model")); - // Public static fields - public static final Runtime RUNTIME = Runtime.getRuntime(); - public static final ClassLoader LOADER = ClassLoader.getSystemClassLoader(); - public static final int JVM_VERSION = getVersion(); - public static final int JVM_BUILD = getBuild(); - - static { - try { - MethodHandles.publicLookup(); // Just to initialize class - } catch (Throwable exc) { - throw new InternalError(exc); - } - } - - private JVMHelper() { - } - - public static ARCH getArch(String arch) { - if (arch.equals("amd64") || arch.equals("x86-64") || arch.equals("x86_64")) return ARCH.X86_64; - if (arch.equals("i386") || arch.equals("i686") || arch.equals("x86")) return ARCH.X86; - if (arch.startsWith("armv8") || arch.startsWith("aarch64")) return ARCH.ARM64; - if (arch.startsWith("arm") || arch.startsWith("aarch32")) return ARCH.ARM32; - throw new InternalError(String.format("Unsupported arch '%s'", arch)); - } - - public static int getVersion() { - //System.out.println("[DEBUG] JVMHelper 11 version"); - return Runtime.version().feature(); - } - - public static int getBuild() { - return Runtime.version().update(); - } - - public static String getNativeExtension(JVMHelper.OS OS_TYPE) { - switch (OS_TYPE) { - case MUSTDIE: - return ".dll"; - case LINUX: - return ".so"; - case MACOSX: - return ".dylib"; - default: - throw new InternalError(String.format("Unsupported OS TYPE '%s'", OS_TYPE)); - } - } - - public static String getNativePrefix(JVMHelper.OS OS_TYPE) { - switch (OS_TYPE) { - case LINUX: - case MACOSX: - return "lib"; - default: - return ""; - } - } - - public static void appendVars(ProcessBuilder builder, Map vars) { - builder.environment().putAll(vars); - } - - public static Class firstClass(String... names) throws ClassNotFoundException { - for (String name : names) - try { - return Class.forName(name, false, LOADER); - } catch (ClassNotFoundException ignored) { - // Expected - } - throw new ClassNotFoundException(Arrays.toString(names)); - } - - public static void fullGC() { - RUNTIME.gc(); - LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20); - } - - public static String[] getClassPath() { - return System.getProperty("java.class.path").split(File.pathSeparator); - } - - public static URL[] getClassPathURL() { - String[] cp = System.getProperty("java.class.path").split(File.pathSeparator); - URL[] list = new URL[cp.length]; - - for (int i = 0; i < cp.length; i++) { - URL url = null; - try { - url = new URL(cp[i]); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - list[i] = url; - } - return list; - } - - public static X509Certificate[] getCertificates(Class clazz) { - Object[] signers = clazz.getSigners(); - if (signers == null) return null; - return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new); - } - - public static void checkStackTrace(Class mainClass) { - LogHelper.debug("Testing stacktrace"); - Exception e = new Exception("Testing stacktrace"); - StackTraceElement[] list = e.getStackTrace(); - if (!list[list.length - 1].getClassName().equals(mainClass.getName())) { - throw new SecurityException(String.format("Invalid StackTraceElement: %s", list[list.length - 1].getClassName())); - } - } - - private static int getCorrectOSArch() { - // As always, mustdie must die - if (OS_TYPE == OS.MUSTDIE) - return System.getenv("ProgramFiles(x86)") == null ? 32 : 64; - - // Or trust system property (maybe incorrect) - return System.getProperty("os.arch").contains("64") ? 64 : 32; - } - - public static String getEnvPropertyCaseSensitive(String name) { - return System.getenv().get(name); - } - - public static boolean isJVMMatchesSystemArch() { - return JVM_BITS == OS_BITS; - } - - public static String jvmProperty(String name, String value) { - return String.format("-D%s=%s", name, value); - } - - public static String systemToJvmProperty(String name) { - return String.format("-D%s=%s", name, System.getProperties().getProperty(name)); - } - - public static void addSystemPropertyToArgs(Collection args, String name) { - String property = System.getProperty(name); - if (property != null) - args.add(String.format("-D%s=%s", name, property)); - } - - public static void verifySystemProperties(Class mainClass, boolean requireSystem) { - Locale.setDefault(Locale.US); - // Verify class loader - LogHelper.debug("Verifying class loader"); - if (requireSystem && !mainClass.getClassLoader().equals(LOADER)) - throw new SecurityException("ClassLoader should be system"); - - // Verify system and java architecture - LogHelper.debug("Verifying JVM architecture"); - } - - public enum ARCH { - X86("x86"), X86_64("x86-64"), ARM64("arm64"), ARM32("arm32"); - - public final String name; - - ARCH(String name) { - this.name = name; - } - } - - public enum OS { - MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx"); - - public final String name; - - OS(String name) { - this.name = name; - } - - public static OS byName(String name) { - if (name.startsWith("Windows")) - return MUSTDIE; - if (name.startsWith("Linux")) - return LINUX; - if (name.startsWith("Mac OS X")) - return MACOSX; - throw new RuntimeException(String.format("This shit is not yet supported: '%s'", name)); - } - } - -} diff --git a/LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleLaunch.java b/LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleLaunch.java deleted file mode 100644 index ab4d829d..00000000 --- a/LauncherCore/src/main/java11/pro/gravit/utils/launch/ModuleLaunch.java +++ /dev/null @@ -1,323 +0,0 @@ -package pro.gravit.utils.launch; - -import pro.gravit.utils.helper.HackHelper; -import pro.gravit.utils.helper.IOHelper; -import pro.gravit.utils.helper.JVMHelper; -import pro.gravit.utils.helper.LogHelper; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.module.Configuration; -import java.lang.module.ModuleFinder; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class ModuleLaunch implements Launch { - private ModuleClassLoader moduleClassLoader; - private Configuration configuration; - private ModuleLayer.Controller controller; - private ModuleFinder moduleFinder; - private ModuleLayer layer; - private MethodHandles.Lookup hackLookup; - private boolean disablePackageDelegateSupport; - @Override - public ClassLoaderControl init(List files, String nativePath, LaunchOptions options) { - this.disablePackageDelegateSupport = options.disablePackageDelegateSupport; - moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> { - try { - return e.toUri().toURL(); - } catch (MalformedURLException ex) { - throw new RuntimeException(ex); - } - }).toArray(URL[]::new), ClassLoader.getPlatformClassLoader()); - moduleClassLoader.nativePath = nativePath; - { - if(options.enableHacks) { - hackLookup = HackHelper.createHackLookup(ModuleLaunch.class); - } - if(options.moduleConf != null) { - // Create Module Layer - moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).map(Path::toAbsolutePath).toArray(Path[]::new)); - ModuleLayer bootLayer = ModuleLayer.boot(); - if(options.moduleConf.modules.contains("ALL-MODULE-PATH")) { - var set = moduleFinder.findAll(); - if(LogHelper.isDevEnabled()) { - for(var m : set) { - LogHelper.dev("Found module %s in %s", m.descriptor().name(), m.location().map(URI::toString).orElse("unknown")); - } - LogHelper.dev("Found %d modules", set.size()); - } - for(var m : set) { - options.moduleConf.modules.add(m.descriptor().name()); - } - options.moduleConf.modules.remove("ALL-MODULE-PATH"); - } - configuration = bootLayer.configuration() - .resolveAndBind(moduleFinder, ModuleFinder.of(), options.moduleConf.modules); - controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader); - layer = controller.layer(); - // Configure exports / opens - for(var e : options.moduleConf.exports.entrySet()) { - String[] split = e.getKey().split("/"); - String moduleName = split[0]; - String pkg = split[1]; - LogHelper.dev("Export module: %s package: %s to %s", moduleName, pkg, e.getValue()); - Module source = layer.findModule(split[0]).orElse(null); - if(source == null) { - throw new RuntimeException(String.format("Module %s not found", moduleName)); - } - Module target = layer.findModule(e.getValue()).orElse(null); - if(target == null) { - throw new RuntimeException(String.format("Module %s not found", e.getValue())); - } - if(options.enableHacks && source.getLayer() != layer) { - ModuleHacks.createController(hackLookup, source.getLayer()).addExports(source, pkg, target); - } else { - controller.addExports(source, pkg, target); - } - } - for(var e : options.moduleConf.opens.entrySet()) { - String[] split = e.getKey().split("/"); - String moduleName = split[0]; - String pkg = split[1]; - LogHelper.dev("Open module: %s package: %s to %s", moduleName, pkg, e.getValue()); - Module source = layer.findModule(split[0]).orElse(null); - if(source == null) { - throw new RuntimeException(String.format("Module %s not found", moduleName)); - } - Module target = layer.findModule(e.getValue()).orElse(null); - if(target == null) { - throw new RuntimeException(String.format("Module %s not found", e.getValue())); - } - if(options.enableHacks && source.getLayer() != layer) { - ModuleHacks.createController(hackLookup, source.getLayer()).addOpens(source, pkg, target); - } else { - controller.addOpens(source, pkg, target); - } - } - for(var e : options.moduleConf.reads.entrySet()) { - LogHelper.dev("Read module %s to %s", e.getKey(), e.getValue()); - Module source = layer.findModule(e.getKey()).orElse(null); - if(source == null) { - throw new RuntimeException(String.format("Module %s not found", e.getKey())); - } - Module target = layer.findModule(e.getValue()).orElse(null); - if(target == null) { - throw new RuntimeException(String.format("Module %s not found", e.getValue())); - } - if(options.enableHacks && source.getLayer() != layer) { - ModuleHacks.createController(hackLookup, source.getLayer()).addReads(source, target); - } else { - controller.addReads(source, target); - } - } - moduleClassLoader.initializeWithLayer(layer); - } - } - return moduleClassLoader.makeControl(); - } - - @Override - public void launch(String mainClass, String mainModuleName, Collection args) throws Throwable { - Thread.currentThread().setContextClassLoader(moduleClassLoader); - if(mainModuleName == null) { - Class mainClazz = Class.forName(mainClass, true, moduleClassLoader); - MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity(); - JVMHelper.fullGC(); - mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0])); - return; - } - Module mainModule = layer.findModule(mainModuleName).orElseThrow(); - Module unnamed = ModuleLaunch.class.getClassLoader().getUnnamedModule(); - if(unnamed != null) { - controller.addOpens(mainModule, getPackageFromClass(mainClass), unnamed); - } - // Start main class - ClassLoader loader = mainModule.getClassLoader(); - Class mainClazz = Class.forName(mainClass, true, loader); - MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)); - mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0])); - } - - private static String getPackageFromClass(String clazz) { - int index = clazz.lastIndexOf("."); - if(index >= 0) { - return clazz.substring(0, index); - } - return clazz; - } - - private class ModuleClassLoader extends URLClassLoader { - private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader(); - private final List transformers = new ArrayList<>(); - private final Map> classMap = new ConcurrentHashMap<>(); - private final Map packageToModule = new HashMap<>(); - private String nativePath; - - private final List packages = new ArrayList<>(); - public ModuleClassLoader(URL[] urls, ClassLoader parent) { - super("LAUNCHER", urls, parent); - packages.add("pro.gravit.launcher."); - packages.add("pro.gravit.utils."); - } - - private void initializeWithLayer(ModuleLayer layer) { - for(var m : layer.modules()) { - for(var p : m.getPackages()) { - packageToModule.put(p, m); - } - } - } - - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if(name != null && !disablePackageDelegateSupport) { - for(String pkg : packages) { - if(name.startsWith(pkg)) { - return SYSTEM_CLASS_LOADER.loadClass(name); - } - } - } - return super.loadClass(name, resolve); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - var clazz = findClass(null, name); - if(clazz == null) { - throw new ClassNotFoundException(name); - } - return clazz; - } - - @Override - protected Class findClass(String moduleName, String name) { - Class clazz; - { - clazz = classMap.get(name); - if(clazz != null) { - return clazz; - } - } - if(name != null && !transformers.isEmpty()) { - boolean needTransform = false; - for(ClassLoaderControl.ClassTransformer t : transformers) { - if(t.filter(moduleName, name)) { - needTransform = true; - break; - } - } - if(needTransform) { - String rawClassName = name.replace(".", "/").concat(".class"); - try(InputStream input = getResourceAsStream(rawClassName)) { - byte[] bytes = IOHelper.read(input); - for(ClassLoaderControl.ClassTransformer t : transformers) { - bytes = t.transform(moduleName, name, null, bytes); - } - clazz = defineClass(name, bytes, 0, bytes.length); - } catch (IOException e) { - return null; - } - } - } - if(clazz == null && layer != null && name != null) { - var pkg = getPackageFromClass(name); - var module = packageToModule.get(pkg); - if(module != null) { - try { - clazz = module.getClassLoader().loadClass(name); - } catch (ClassNotFoundException e) { - return null; - } - } - } - if(clazz == null) { - try { - clazz = super.findClass(name); - } catch (ClassNotFoundException e) { - return null; - } - } - if(clazz != null) { - classMap.put(name, clazz); - return clazz; - } else { - return null; - } - } - - @Override - public String findLibrary(String name) { - return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION); - } - - public void addAllowedPackage(String pkg) { - packages.add(pkg); - } - - private ModuleClassLoaderControl makeControl() { - return new ModuleClassLoaderControl(); - } - - private class ModuleClassLoaderControl implements ClassLoaderControl { - - @Override - public void addLauncherPackage(String prefix) { - addAllowedPackage(prefix); - } - - @Override - public void addTransformer(ClassTransformer transformer) { - transformers.add(transformer); - } - - @Override - public void addURL(URL url) { - ModuleClassLoader.this.addURL(url); - } - - @Override - public void addJar(Path path) { - try { - ModuleClassLoader.this.addURL(path.toUri().toURL()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - - @Override - public URL[] getURLs() { - return ModuleClassLoader.this.getURLs(); - } - - @Override - public Class getClass(String name) throws ClassNotFoundException { - return Class.forName(name, false, ModuleClassLoader.this); - } - - @Override - public ClassLoader getClassLoader() { - return ModuleClassLoader.this; - } - - @Override - public Object getJava9ModuleController() { - return controller; - } - - @Override - public MethodHandles.Lookup getHackLookup() { - return hackLookup; - } - } - } -} diff --git a/LauncherStart/build.gradle b/LauncherStart/build.gradle index bdc73a50..225658f7 100644 --- a/LauncherStart/build.gradle +++ b/LauncherStart/build.gradle @@ -8,8 +8,8 @@ url "https://repo.spring.io/plugins-release/" } } -sourceCompatibility = '1.8' -targetCompatibility = '1.8' +sourceCompatibility = '17' +targetCompatibility = '17' jar { archiveClassifier.set('clean') diff --git a/ServerWrapper/build.gradle b/ServerWrapper/build.gradle index 66520bef..9937f08f 100644 --- a/ServerWrapper/build.gradle +++ b/ServerWrapper/build.gradle @@ -14,30 +14,10 @@ } } -sourceSets { - java11 { - java { - srcDirs = ['src/main/java11'] - } - dependencies { - java11Implementation project(':LauncherAPI') - java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava } - } - } -} - -sourceCompatibility = '1.8' -targetCompatibility = '1.8' - -compileJava11Java { - sourceCompatibility = 11 - targetCompatibility = 11 -} +sourceCompatibility = '17' +targetCompatibility = '17' jar { - into('META-INF/versions/11') { - from sourceSets.java11.output - } archiveClassifier.set('clean') manifest.attributes("Main-Class": mainClassName, "Premain-Class": mainAgentName,