public void execute()

in src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java [138:319]


    public void execute() throws MojoExecutionException, MojoFailureException {

        try {
            // the feature launcher before version 1.1.28 used a single jar, while versions
            //  after that provide an assembly per SLING-10956
            VersionRange beforeAssemblyRange = VersionRange.createFromVersionSpec("(,1.1.26]");
            boolean useAssembly = !beforeAssemblyRange.containsVersion(new DefaultArtifactVersion(featureLauncherVersion));

            RepositorySystemSession repositorySession = mavenSession.getRepositorySession();
            File workDir = new File(outputDirectory, "launchers");
            workDir.mkdirs();

            File launcher;
            if (useAssembly) {
                // fetch the assembly artifact
                Artifact launcherAssemblyArtifact = new DefaultArtifact("org.apache.sling:org.apache.sling.feature.launcher:tar.gz:" + featureLauncherVersion);
                File assemblyArchive = resolver
                        .resolveArtifact(repositorySession, new ArtifactRequest(launcherAssemblyArtifact, remoteRepos, null))
                        .getArtifact()
                        .getFile();

                // unpack the file
                UnArchiver unArchiver = archiverManager.getUnArchiver( assemblyArchive );
                unArchiver.setSourceFile(assemblyArchive);
                unArchiver.setDestFile(workDir);
                unArchiver.extract();

                // system property
                Path relPath = Paths.get(launcherAssemblyArtifact.getArtifactId() + "-" + launcherAssemblyArtifact.getVersion(), "bin");
                if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                    relPath = relPath.resolve("launcher.bat");
                } else {
                    relPath = relPath.resolve("launcher");
                }
                launcher = workDir.toPath().resolve(relPath).toFile();
            } else {
                Artifact launcherArtifact = new DefaultArtifact("org.apache.sling:org.apache.sling.feature.launcher:" + featureLauncherVersion);
                launcher = resolver
                        .resolveArtifact(repositorySession, new ArtifactRequest(launcherArtifact, remoteRepos, null))
                        .getArtifact()
                        .getFile();
            }
            
            for ( Launch launch : launches ) {
                if (launch.isSkip()) {
                    getLog().info("Skipping starting launch with id " + launch.getId());
                    continue; // skip it
                }

                launch.validate();

                Artifact artifact = toArtifact(launch.getFeature());
                
                ArtifactResult result = resolver.resolveArtifact(repositorySession, new ArtifactRequest(artifact, remoteRepos, null));
                File featureFile = result.getArtifact().getFile();

                String javahome = System.getenv(JAVA_HOME);
                if (javahome == null || javahome.isEmpty()) {
                    // SLING-9843 fallback to java.home system property if JAVA_HOME env variable is not set
                    getLog().warn("The JAVA_HOME env variable was not set, falling back to the java.home system property");
                    javahome = System.getProperty("java.home");
                }
                List<String> args = new ArrayList<>();
                if (useAssembly) {
                    // use the post v1.1.28 launcher script

                    Map<String, String> newEnv = new HashMap<>(launch.getEnvironmentVariables());
                    newEnv.put(JAVA_HOME, javahome);

                    // SLING-9994 - if any extra vm options were supplied, apply them here
                    StringBuilder javaOptsBuilder = null;
                    String[] vmOptions = launch.getLauncherArguments().getVmOptions();
                    for (String vmOption : vmOptions) {
                        if (vmOption != null && !vmOption.isEmpty()) {
                            if (javaOptsBuilder == null) {
                                javaOptsBuilder = new StringBuilder();
                            } else {
                                javaOptsBuilder.append(" ");
                            }
                            javaOptsBuilder.append(vmOption);
                        }
                    }
                    if (javaOptsBuilder != null) {
                        // pass vmOptions through JAVA_OPTS environment variable?
                        if (newEnv.containsKey(JAVA_OPTS)) {
                            // if the original value existed append it to our buffer
                            javaOptsBuilder.append(" ").append(newEnv.get(JAVA_OPTS));
                        }
                        newEnv.put(JAVA_OPTS, javaOptsBuilder.toString());
                    }

                    args.add(launcher.getAbsolutePath());

                    launch.setEnvironmentVariables(newEnv);
                } else {
                    // use the pre v1.1.28 single jar technique

                    args.add(javahome + File.separatorChar + "bin" + File.separatorChar + "java");
                    // SLING-9994 - if any extra vm options were supplied, apply them here
                    String[] vmOptions = launch.getLauncherArguments().getVmOptions();
                    for (String vmOption : vmOptions) {
                        if (vmOption != null && !vmOption.isEmpty()) {
                            args.add(vmOption);
                        }
                    }
                    args.add("-jar");
                    args.add(launcher.getAbsolutePath());
                }
                if ( launch.getRepositoryUrls() != null && !launch.getRepositoryUrls().isEmpty() ) {
                    args.add("-u");
                    StringJoiner joiner = new StringJoiner(",");
                    launch.getRepositoryUrls().forEach( joiner::add );
                    args.add(joiner.toString());
                }
                args.add("-f");
                args.add(featureFile.getAbsolutePath());
                args.add("-p");
                args.add(launch.getId());
                
                for ( Map.Entry<String, String> frameworkProperty : launch.getLauncherArguments().getFrameworkProperties().entrySet() ) {
                    args.add("-D");
                    args.add(frameworkProperty.getKey()+"="+frameworkProperty.getValue());
                }
                
                for ( Map.Entry<String, String> variable : launch.getLauncherArguments().getVariables().entrySet() ) {
                    args.add("-V");
                    args.add(variable.getKey()+"="+variable.getValue());
                }

                // TODO - add support for all arguments supported by the feature launcher
                ProcessBuilder pb = new ProcessBuilder(args);
                pb.redirectOutput(Redirect.INHERIT);
                pb.redirectInput(Redirect.INHERIT);
                pb.directory(workDir);
                launch.getEnvironmentVariables().entrySet()
                    .forEach( e -> {
                            getLog().info("Setting environment variable '" + e.getKey() + "' to '" + e.getValue() + "'");
                            pb.environment().put(e.getKey(), e.getValue());
                        } );
                
                getLog().info("Starting launch with id '" + launch.getId() + "', args=" + args);
                
                CountDownLatch latch = new CountDownLatch(1);
                
                Process process = pb.start();
                
                Thread monitor = new Thread("launch-monitor-" + launch.getId()) {
                    @Override
                    public void run() {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                        String line;
                        try {
                            while ( (line = reader.readLine()) != null ) {
                                System.out.println(line); // NOSONAR - we pass through the subprocess stderr
                                if ( line.contains("Framework started")) {
                                    latch.countDown();
                                    break;
                                }
                            }
                        } catch (IOException e) {
                            getLog().warn(e.getMessage(), e);
                        }
                    }
                };
                monitor.start();
                getLog().info("Waiting for " + launch.getId() + " to start");
                boolean started = latch.await(launch.getStartTimeoutSeconds(), TimeUnit.SECONDS);
                if ( !started ) {
                    ProcessTracker.stop(process);
                    throw new MojoExecutionException("Launch " + launch.getId() + " failed to start in " + launch.getStartTimeoutSeconds() + " seconds.");
                }
                
                processes.startTracking(launch.getId(), process);
            }

        } catch (NoSuchArchiverException | InvalidVersionSpecificationException | ArtifactResolutionException | IOException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        } catch ( InterruptedException e ) {
            Thread.currentThread().interrupt();
            throw new MojoExecutionException("Execution interrupted", e);
        }
    }