|
7 | 7 | import org.intellij.lang.annotations.Language;
|
8 | 8 | import org.jetbrains.annotations.NotNull;
|
9 | 9 |
|
| 10 | +import java.io.File; |
| 11 | +import java.io.FileInputStream; |
| 12 | +import java.io.IOException; |
| 13 | +import java.io.InputStream; |
10 | 14 | import java.lang.reflect.InvocationTargetException;
|
11 | 15 | import java.lang.reflect.Method;
|
12 | 16 | import java.lang.reflect.Modifier;
|
| 17 | +import java.net.JarURLConnection; |
| 18 | +import java.net.MalformedURLException; |
| 19 | +import java.net.URL; |
| 20 | +import java.net.URLClassLoader; |
| 21 | +import java.nio.file.Files; |
| 22 | +import java.nio.file.Path; |
| 23 | +import java.nio.file.Paths; |
| 24 | +import java.nio.file.StandardOpenOption; |
| 25 | +import java.util.Arrays; |
13 | 26 | import java.util.concurrent.CompletableFuture;
|
14 | 27 | import java.util.concurrent.ExecutionException;
|
15 | 28 | import java.util.concurrent.Executor;
|
16 | 29 | import java.util.concurrent.LinkedBlockingDeque;
|
17 | 30 | import java.util.function.Supplier;
|
| 31 | +import java.util.jar.JarInputStream; |
18 | 32 |
|
19 | 33 | /**
|
20 | 34 | * Provides an interface to the NodeJS runtime for Java developers. You can only access the NodeJS world
|
@@ -44,27 +58,72 @@ private static class Linkage {
|
44 | 58 | // Called from the boot.js file as part of NodeJVM startup, do not call.
|
45 | 59 | @SuppressWarnings("unused")
|
46 | 60 | @Deprecated
|
47 |
| - public static void boot(String entryPointName, |
48 |
| - LinkedBlockingDeque<Runnable> taskQueue, |
| 61 | + public static void boot(LinkedBlockingDeque<Runnable> taskQueue, |
49 | 62 | Value evalFunction,
|
50 |
| - String[] args) { |
| 63 | + String[] args) throws ClassNotFoundException, IOException { |
| 64 | + try { |
| 65 | + boot1(taskQueue, evalFunction, args); |
| 66 | + } catch (Throwable e) { |
| 67 | + e.printStackTrace(); |
| 68 | + System.exit(1); |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + private static void boot1(LinkedBlockingDeque<Runnable> taskQueue, Value evalFunction, String[] args) throws ClassNotFoundException, IOException { |
51 | 73 | assert linkage == null : "Don't call this function directly. Already started!";
|
52 | 74 | assert evalFunction.canExecute();
|
53 | 75 | NodeJS.linkage = new Linkage(taskQueue, evalFunction);
|
54 | 76 | Thread.currentThread().setName("NodeJS main thread");
|
| 77 | + |
| 78 | + if (args.length == 0) { |
| 79 | + System.err.println("You must specify at least a class name, or -jar jarname.jar"); |
| 80 | + System.exit(1); |
| 81 | + } else if (!args[0].equals("-jar")) { |
| 82 | + Class<?> entryPoint = Class.forName(args[0]); |
| 83 | + startJavaThread(entryPoint, Arrays.copyOfRange(args, 1, args.length)); |
| 84 | + } else { |
| 85 | + File myJar = new File(args[1]); |
| 86 | + final URL url = myJar.toURI().toURL(); |
| 87 | + String mainClassName = ""; |
| 88 | + try (InputStream stream = Files.newInputStream(Paths.get(args[1]), StandardOpenOption.READ)) { |
| 89 | + JarInputStream jis = new JarInputStream(stream); |
| 90 | + mainClassName = jis.getManifest().getMainAttributes().getValue("Main-Class"); |
| 91 | + } |
| 92 | + |
| 93 | + if (mainClassName == null) { |
| 94 | + System.err.println("JAR file does not have a Main-Class attribute, is not executable."); |
| 95 | + System.exit(1); |
| 96 | + } |
| 97 | + // Use the parent classloader to forcibly toss out this version of the interop JAR, to avoid confusion |
| 98 | + // later when there are two classloaders in play, BUT, holepunch this specific class and inner classes |
| 99 | + // through so the state linked up from the bootstrap script is still here. In other words, this class is |
| 100 | + // special, so don't give it dependencies outside the JDK. |
| 101 | + ClassLoader thisClassLoader = NodeJS.class.getClassLoader(); |
| 102 | + URLClassLoader child = new URLClassLoader(new URL[] {url}, thisClassLoader.getParent()) { |
| 103 | + @Override |
| 104 | + protected Class<?> findClass(String name) throws ClassNotFoundException { |
| 105 | + if (name.startsWith(NodeJS.class.getName())) { |
| 106 | + return thisClassLoader.loadClass(name); |
| 107 | + } else |
| 108 | + return super.findClass(name); |
| 109 | + } |
| 110 | + }; |
| 111 | + Class<?> entryPoint = Class.forName(mainClassName, true, child); |
| 112 | + startJavaThread(entryPoint, Arrays.copyOfRange(args, 2, args.length)); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + private static void startJavaThread(Class<?> entryPoint, String[] args) { |
55 | 117 | Thread javaThread = new Thread(() -> {
|
56 | 118 | try {
|
57 |
| - Class<?> entryPoint = Class.forName(entryPointName); |
58 | 119 | Method main = entryPoint.getMethod("main", String[].class);
|
59 | 120 | assert Modifier.isStatic(main.getModifiers());
|
60 | 121 | main.invoke(null, new Object[] { args });
|
61 | 122 | System.exit(0);
|
62 | 123 | } catch (NoSuchMethodException e) {
|
63 |
| - System.err.println("No main method found in " + entryPointName); |
| 124 | + System.err.println("No main method found in " + entryPoint.getName()); |
64 | 125 | } catch (InvocationTargetException e) {
|
65 | 126 | e.getCause().printStackTrace();
|
66 |
| - } catch (ClassNotFoundException e) { |
67 |
| - System.err.println(String.format("Main class with name '%s' not found.", entryPointName)); |
68 | 127 | } catch (Throwable e) {
|
69 | 128 | e.printStackTrace();
|
70 | 129 | }
|
|
0 commit comments