Package za.co.enerweb.toolbox.io

Source Code of za.co.enerweb.toolbox.io.CommandUtils

package za.co.enerweb.toolbox.io;

import static za.co.enerweb.toolbox.string.StringUtils.nullString2EmptyString;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.io.FileUtils;

import za.co.enerweb.toolbox.io.internal.OutputWaiter;
import za.co.enerweb.toolbox.string.StringUtils;
import za.co.enerweb.toolbox.timing.Stopwatch;

// leaving the following there for future reference
// if( systemCommandMode.equals(SystemCommandMode.ONELINE )){
// cl.runCommandLine(cmd);
// }else if( systemCommandMode.equals(SystemCommandMode.BASH )){
// cl.runCommandLine("bash");
// cl.writelnToStdIn(cmd);
// cl.writelnToStdIn("exit");
// }else if( systemCommandMode.equals(SystemCommandMode.COMMAND )){
// cl.runCommandLine("command");
// cl.writelnToStdIn(cmd);
// cl.writelnToStdIn("exit");
// }
// rather do "cmd /c" or "bash -c"
/**
* Utility for running commands. Suitable defaults are used for handling output,
* the working dir etc. XXX: We can later provide another form that can pass in
* input.
*/
@Slf4j
public class CommandUtils {
    private static final int MILLISECONDS_TO_WAIT_FOR_OUTPUT = 300;

    protected OutputHandler stdoutHandler;
    private OutputHandler stderrHandler;
    protected Writer stdin;
    protected Process process;
    protected OutputWaiter stdoutWaiter;
    private OutputWaiter stderrWaiter;
    private String[] commandAndArgs;
    private boolean deleteWorkDirWhenDone = false;

    protected String command;
    private String commandInPath = null;
    private String[] args;
    private File workingDir;
    private boolean checkExitCode = true;
    private String[] environment = new String[0];
    private boolean cacheOutput = true;

    private static CommandUtils simpleExecute;

    public static String simpleExecute(String... commandAndArgs)
        throws IOException {
        return simpleExecute(null, commandAndArgs);
    }

    public static String simpleExecute(File workdir, String... commandAndArgs)
        throws IOException {
        if (simpleExecute == null) {
            synchronized (CommandUtils.class) {
                if (simpleExecute == null) {
                    simpleExecute = new CommandUtils();
                }
            }
        }
        simpleExecute.setWorkingDir(workdir);
        simpleExecute.setCommandAndArgs(commandAndArgs);
        simpleExecute.excecute();
        return simpleExecute.getStdOutOutput();
    }

    public CommandUtils() {
    }

    public CommandUtils(final String command) {
        this.command = command;
    }

    public CommandUtils(final String command, final String... args) {
        this.command = command;
        this.args = args;
    }

    public CommandUtils command(final String command) {
        this.command = command;
        commandInPath = null;
        return this;
    }

    public void setArgs(final String... args) {
        this.args = args;
    }

    public CommandUtils args(final String... args) {
        this.args = args;
        return this;
    }

    public void setCommandAndArgs(final String... commandAndArgs) {
        command(commandAndArgs[0]);
        args = new String[commandAndArgs.length - 1];
        System.arraycopy(commandAndArgs, 1, args, 0, args.length);
    }

    public void mustCopyEnvironmentToSubprocess() {
        setEnvironment(null);
    }

    /**
     * (Resets output handlers)
     */
    public void setCacheOutput(boolean cacheOutput) {
        this.cacheOutput = cacheOutput;
        stdoutHandler = null;
        stderrHandler = null;
    }

    /**
     * Will use string builder output handlers.
     * (Resets output handlers)
     */
    public void cacheOutput() {
        setCacheOutput(true);
    }

    /**
     * Just log the output.
     * (Resets output handlers)
     */
    public void logOutput() {
        setCacheOutput(false);
    }

    public String getStdOutOutput() {
        return getOutput(stdoutHandler);
    }

    public String getStdErrOutput() {
        return getOutput(stderrHandler);
    }

    private String getOutput(final OutputHandler outputHandler) {
        if (outputHandler instanceof StringBuilderOutputHandler) {
            return ((StringBuilderOutputHandler) outputHandler).toString();
        }
        throw new IllegalStateException("The output was not cached.");
    }

    protected void start() throws IOException {
        validateNotStarted();
        validateSetup();

        if (commandInPath == null) {
            commandInPath = findFileInPath(workingDir, command)
                .getAbsolutePath();
        }
        commandAndArgs = new String[args.length + 1];
        commandAndArgs[0] = commandInPath;
        System.arraycopy(args, 0, commandAndArgs, 1, args.length);
        workingDir.mkdirs();
        log.debug("Executing:\n{}\n(In {})", toString(),
            workingDir.getAbsolutePath());
        process = Runtime.getRuntime().exec(commandAndArgs, environment,
            workingDir);

        stdin = new OutputStreamWriter(new BufferedOutputStream(process
            .getOutputStream()));

        stdoutWaiter = new OutputWaiter(process.getInputStream(),
            stdoutHandler);

        stderrWaiter = new OutputWaiter(process.getErrorStream(),
            stderrHandler);

        stdoutWaiter.start();
        stderrWaiter.start();
    }

    public void stop() {
        if (process != null) {
            process.destroy();
        }
    }

    protected void validateStarted() {
        if (process == null) {
            throw new IllegalStateException("Process not started");
        }
    }

    protected void validateNotStarted() {
        if (process != null) {
            throw new IllegalStateException("Process started already.");
        }
    }

    protected void validateSetup() {
        if (command == null) {
            throw new IllegalStateException("No command specified");
        }
        // use suitable defaults if they are not provided
        if (args == null) {
            args = new String[0];
        }
        if (stdoutHandler == null) {
            if (cacheOutput) {
                setStdoutHandler(new StringBuilderOutputHandler());
            } else {
                stdoutHandler = new LogOutputHandler();
            }
        } else {
            stdoutHandler.clear();
        }
        if (stderrHandler == null) {
            if (cacheOutput) {
                setStderrHandler(new StringBuilderOutputHandler());
            } else {
                stderrHandler = new LogOutputHandler();
            }
        } else {
            stderrHandler.clear();
        }
        if (workingDir == null) {
            workingDir = TempDir.createTempDir();
            deleteWorkDirWhenDone = true;
        } else {
            deleteWorkDirWhenDone = false;
        }
    }

    @Override
    public String toString() {
        return StringUtils.join(commandAndArgs, " ");
    }

    /**
     * If we get interrupted, the external process will be killed.
     *
     * @return
     * @throws IOException
     */
    public int excecute() throws IOException {
        start();
        int exitValue = -1;
        boolean interrupted = false;
        try {
            exitValue = process.waitFor();
        } catch (InterruptedException e) {
            log.info("Interrupted while running " + toString()
                + ", killing it now.", e);
            process.destroy();
            interrupted = true;
        }
        if (!interrupted) {
            // wait a little for the output, if we were not interrupted.
            try {
                stdoutWaiter.join(MILLISECONDS_TO_WAIT_FOR_OUTPUT);
                stderrWaiter.join(MILLISECONDS_TO_WAIT_FOR_OUTPUT);
            } catch (InterruptedException e) {
                log.debug("Interrupted while waiting for output.", e);
            }
        } else {
            stdoutWaiter.interrupt();
            stderrWaiter.interrupt();
        }

        if (deleteWorkDirWhenDone) {
            FileUtils.deleteQuietly(workingDir);
            workingDir = null;
        }
        process = null;
        if (checkExitCode) {
            checkExitCode(exitValue);
        }
        return exitValue;
    }

    private void checkExitCode(final int exitValue) {
        if (exitValue != 0) {
            throw new RuntimeException("Non-zero exit value " + exitValue
                + " while executing:\n" + toString()
                + "\n(with working dir: " + workingDir.getAbsolutePath() + ")");
        }
    }

    /**
     * look for the file in the working dir, the check if its absolute then look
     * for it in the system $PATH TODO: look for .exe, .com, .bat, .cmd on
     * windows too
     *
     * @param workingDir
     * @param fileName
     * @return
     * @throws FileNotFoundException
     */
    public static File findFileInPath(final File workingDir,
        final String fileName) throws FileNotFoundException {
        // see if its in the working dir
        File ret = new File(workingDir, fileName);
        if (ret.isFile()) {
            return ret;
        }
        // see if its absolute
        ret = new File(fileName);
        if (ret.isFile()) {
            return ret;
        }

        // look for it on the path
        String systemPath = nullString2EmptyString(System.getenv("PATH"));
        String[] pathDirs = systemPath.split(File.pathSeparator);
        for (String pathDir : pathDirs) {
            ret = new File(pathDir, fileName);
            if (ret.isFile()) {
                return ret;
            }
        }
        throw new FileNotFoundException("The file '" + fileName
            + "' could not be found in the workingdir, it is not absolute "
            + "and it is not in the system path (" + systemPath + ").");
    }

    // this is useful for manually testing this on different platforms
    public static void main(final String[] args) {
        if (args.length < 1) {
            log.error("USAGE: java za.co.enerweb.toolbox.io.CommandUtils "
                + "sping localhost -c 12");
            System.exit(1);
        }
        CommandUtils cu = new CommandUtils();
        cu.setCommandAndArgs(args);
        Stopwatch sw = new Stopwatch();
        try {
            cu.excecute();
        } catch (IOException e) {
            log.error("Error while executing " + args[0], e);
        } finally {
            log.debug("Execution time: {}", sw.getDelta());
        }
    }

    public void setStdoutHandler(final OutputHandler stdoutHandler) {
        if (stdoutWaiter != null) {
            stdoutWaiter.setOutputHandler(stdoutHandler);
        }
        this.stdoutHandler = stdoutHandler;
    }

    public void setStderrHandler(final OutputHandler stderrHandler) {
        if (stderrWaiter != null) {
            stderrWaiter.setOutputHandler(stderrHandler);
        }
        this.stderrHandler = stderrHandler;
    }

    public String getCommand() {
        return command;
    }

    public void setCommand(final String command) {
        this.command = command;
    }

    public File getWorkingDir() {
        return workingDir;
    }

    public void setWorkingDir(final File workingDir) {
        this.workingDir = workingDir;
    }

    public boolean isCheckExitCode() {
        return checkExitCode;
    }

    public void setCheckExitCode(final boolean checkExitCode) {
        this.checkExitCode = checkExitCode;
    }

    public String[] getArgs() {
        return args;
    }

    public String[] getEnvironment() {
        return environment;
    }

    public void setEnvironment(final String[] environment) {
        this.environment = environment;
    }
}
TOP

Related Classes of za.co.enerweb.toolbox.io.CommandUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.