All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ninja.build.RunClassInSeparateJvmMachine Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
/**
 * Copyright (C) 2012-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ninja.build;

import java.io.File;
import java.io.IOException;
import java.util.List;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;
import org.zeroturnaround.exec.StartedProcess;
import org.zeroturnaround.exec.listener.ProcessListener;

public class RunClassInSeparateJvmMachine {
    static private final Logger log = LoggerFactory.getLogger(RunClassInSeparateJvmMachine.class);

    private final String name;
    private OutputStream output;
    StartedProcess activeProcess;
    private final AtomicBoolean restarting;
    // Main class that will be used to load...
    private final String classNameWithMainToRun;
    private final String classpath;
    private final List jvmArguments;
    // basedir of project this plugin run in
    private final File mavenBaseDir;

    public RunClassInSeparateJvmMachine(
            String name,
            String classNameWithMainToRun,
            List classpath, 
            List jvmArguments,
            File mavenBaseDir) {

        this(name,
            classNameWithMainToRun,
            StringUtils.join(classpath, File.pathSeparator),
            jvmArguments,
            mavenBaseDir);

    }
    
    public RunClassInSeparateJvmMachine(
            String name,
            String classNameWithMainToRun,
            String classpath, 
            List jvmArguments,
            File mavenBaseDir) {

        this.name = name;
        this.output = System.out;
        this.classNameWithMainToRun = classNameWithMainToRun;
        this.classpath = classpath;
        this.jvmArguments = jvmArguments;
        this.mavenBaseDir = mavenBaseDir;
        this.restarting = new AtomicBoolean(false);

    }

    public OutputStream getOutput() {
        return output;
    }

    public void setOutput(OutputStream output) {
        this.output = output;
    }

    public StartedProcess getActiveProcess() {
        return activeProcess;
    }

    public void setActiveProcess(StartedProcess activeProcess) {
        this.activeProcess = activeProcess;
    }

    public synchronized void restart() {
        restarting.set(true);
        try {
        
            if (this.activeProcess != null) {
                
                log.debug("Attempting to destroy previous {} process", name);
                this.activeProcess.getProcess().destroy();
                
                log.debug("Waiting for previous {} process to terminate", name);
                ProcessResult result =
                    this.activeProcess.getFuture().get();
                
            }
            
            log.debug("Starting new {}", name);
            this.activeProcess = startProcess();
            
        } catch (ExecutionException | InterruptedException | IOException e) {
            log.error("Something fishy happenend. Unable to cleanly restart {}!", name, e);
            log.error("You'll probably need to restart maven?");
        } finally {
            restarting.set(false);
        }
    }

    StartedProcess startProcess() throws IOException {
        ProcessExecutor processExecutor
            = buildProcessExecutor();
    
        return processExecutor.start();
    }

    ProcessExecutor buildProcessExecutor() {
        
        List commandLine = new ArrayList<>();

        String javaHome = System.getProperty("java.home");
        String javaBin = javaHome + File.separator + "bin" + File.separator
                + "java";
        
        commandLine.add(javaBin);

        commandLine.addAll(jvmArguments);

        commandLine.add("-cp");
        commandLine.add(classpath);
        commandLine.add(classNameWithMainToRun);
        
        // not redirecting error stream used for unit tests
        return new ProcessExecutor(commandLine)
            .directory(mavenBaseDir)
            .destroyOnExit()
            .addListener(new ProcessListener() {
                @Override
                public void afterStop(Process process) {
                    if (!restarting.get()) {
                        log.error("JVM process for {} terminated (next file change will attempt to restart it)", name);
                    }
                }
            })
            .redirectErrorStream(true)
            .redirectOutput(this.output);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy