protected Context doCreate()

in impl/maven-executor/src/main/java/org/apache/maven/cling/executor/embedded/EmbeddedMavenExecutor.java [202:336]


    protected Context doCreate(Path mavenHome, ExecutorRequest executorRequest) {
        if (!Files.isDirectory(mavenHome)) {
            throw new IllegalArgumentException("Installation directory must point to existing directory: " + mavenHome);
        }
        if (!MVN4_MAIN_CLASSES.containsKey(executorRequest.command())) {
            throw new IllegalArgumentException(
                    getClass().getSimpleName() + " does not support command " + executorRequest.command());
        }
        if (executorRequest.environmentVariables().isPresent()) {
            throw new IllegalArgumentException(getClass().getSimpleName() + " does not support environment variables");
        }
        if (executorRequest.jvmArguments().isPresent()) {
            throw new IllegalArgumentException(getClass().getSimpleName() + " does not support jvmArguments");
        }
        Path boot = mavenHome.resolve("boot");
        Path m2conf = mavenHome.resolve("bin/m2.conf");
        if (!Files.isDirectory(boot) || !Files.isRegularFile(m2conf)) {
            throw new IllegalArgumentException(
                    "Installation directory does not point to Maven installation: " + mavenHome);
        }

        ArrayList<String> mavenArgs = new ArrayList<>();
        String mavenArgsEnv = System.getenv("MAVEN_ARGS");
        if (useMavenArgsEnv && mavenArgsEnv != null && !mavenArgsEnv.isEmpty()) {
            Arrays.stream(mavenArgsEnv.split(" "))
                    .filter(s -> !s.trim().isEmpty())
                    .forEach(s -> mavenArgs.add(0, s));
        }

        Properties properties = prepareProperties(executorRequest);
        // set ahead of time, if the mavenHome points to Maven4, as ClassWorld Launcher needs this property
        properties.setProperty(
                "maven.mainClass", requireNonNull(MVN4_MAIN_CLASSES.get(ExecutorRequest.MVN), "mainClass"));
        System.setProperties(properties);
        URLClassLoader bootClassLoader = createMavenBootClassLoader(boot, Collections.emptyList());
        Thread.currentThread().setContextClassLoader(bootClassLoader);
        try {
            Class<?> launcherClass = bootClassLoader.loadClass("org.codehaus.plexus.classworlds.launcher.Launcher");
            Object launcher = launcherClass.getDeclaredConstructor().newInstance();
            Method configure = launcherClass.getMethod("configure", InputStream.class);
            try (InputStream inputStream = Files.newInputStream(m2conf)) {
                configure.invoke(launcher, inputStream);
            }
            Object classWorld = launcherClass.getMethod("getWorld").invoke(launcher);
            Set<String> originalClassRealmIds = new HashSet<>();

            // collect pre-created (in m2.conf) class realms as "original ones"; the rest are created at runtime
            Method getRealms = classWorld.getClass().getMethod("getRealms");
            List<Object> realms = (List<Object>) getRealms.invoke(classWorld);
            for (Object realm : realms) {
                Method realmGetId = realm.getClass().getMethod("getId");
                originalClassRealmIds.add((String) realmGetId.invoke(realm));
            }

            Class<?> cliClass =
                    (Class<?>) launcherClass.getMethod("getMainClass").invoke(launcher);
            String version = getMavenVersion(cliClass);
            Map<String, Function<ExecutorRequest, Integer>> commands = new HashMap<>();
            ArrayList<Object> keepAlive = new ArrayList<>();

            if (version.startsWith("3.")) {
                // 3.x
                if (!ExecutorRequest.MVN.equals(executorRequest.command())) {
                    throw new IllegalArgumentException(getClass().getSimpleName() + " w/ mvn3 does not support command "
                            + executorRequest.command());
                }
                keepAlive.add(cliClass.getClassLoader().loadClass("org.fusesource.jansi.internal.JansiLoader"));
                Constructor<?> newMavenCli = cliClass.getConstructor(classWorld.getClass());
                Object mavenCli = newMavenCli.newInstance(classWorld);
                Class<?>[] parameterTypes = {String[].class, String.class, PrintStream.class, PrintStream.class};
                Method doMain = cliClass.getMethod("doMain", parameterTypes);
                commands.put(ExecutorRequest.MVN, r -> {
                    System.setProperties(prepareProperties(r));
                    try {
                        ArrayList<String> args = new ArrayList<>(mavenArgs);
                        args.addAll(r.arguments());
                        PrintStream stdout = r.stdOut().isEmpty()
                                ? null
                                : new PrintStream(r.stdOut().orElseThrow(), true);
                        PrintStream stderr = r.stdErr().isEmpty()
                                ? null
                                : new PrintStream(r.stdErr().orElseThrow(), true);
                        return (int) doMain.invoke(mavenCli, new Object[] {
                            args.toArray(new String[0]), r.cwd().toString(), stdout, stderr
                        });
                    } catch (Exception e) {
                        throw new ExecutorException("Failed to execute", e);
                    }
                });
            } else {
                // assume 4.x
                keepAlive.add(cliClass.getClassLoader().loadClass("org.jline.nativ.JLineNativeLoader"));
                for (Map.Entry<String, String> cmdEntry : MVN4_MAIN_CLASSES.entrySet()) {
                    Class<?> cmdClass = cliClass.getClassLoader().loadClass(cmdEntry.getValue());
                    Method mainMethod = cmdClass.getMethod(
                            "main",
                            String[].class,
                            classWorld.getClass(),
                            InputStream.class,
                            OutputStream.class,
                            OutputStream.class);
                    commands.put(cmdEntry.getKey(), r -> {
                        System.setProperties(prepareProperties(r));
                        try {
                            ArrayList<String> args = new ArrayList<>(mavenArgs);
                            args.addAll(r.arguments());
                            return (int) mainMethod.invoke(
                                    null,
                                    args.toArray(new String[0]),
                                    classWorld,
                                    r.stdIn().orElse(null),
                                    r.stdOut().orElse(null),
                                    r.stdErr().orElse(null));
                        } catch (Exception e) {
                            throw new ExecutorException("Failed to execute", e);
                        }
                    });
                }
            }

            return new Context(
                    bootClassLoader,
                    version,
                    classWorld,
                    originalClassRealmIds,
                    cliClass.getClassLoader(),
                    commands,
                    keepAlive);
        } catch (Exception e) {
            throw new ExecutorException("Failed to create executor", e);
        } finally {
            Thread.currentThread().setContextClassLoader(originalClassLoader);
            System.setProperties(originalProperties);
        }
    }