ninja.build.RunClassInSeparateJvmMachine.java Source code

Java tutorial

Introduction

Here is the source code for ninja.build.RunClassInSeparateJvmMachine.java

Source

/**
 * Copyright (C) 2012-2015 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<String> jvmArguments;
    // basedir of project this plugin run in
    private final File mavenBaseDir;

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

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

    }

    public RunClassInSeparateJvmMachine(String name, String classNameWithMainToRun, String classpath,
            List<String> 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<String> 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);
    }

}