com.tc.process.Exec.java Source code

Java tutorial

Introduction

Here is the source code for com.tc.process.Exec.java

Source

/*
 *
 *  The contents of this file are subject to the Terracotta Public 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://terracotta.org/legal/terracotta-public-license.
 *
 *  Software distributed under the License is distributed on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 *  the specific language governing rights and limitations under the License.
 *
 *  The Covered Software is Terracotta Core.
 *
 *  The Initial Developer of the Covered Software is
 *  Terracotta, Inc., a Software AG company
 *
 */
package com.tc.process;

import org.apache.commons.io.IOUtils;

import com.tc.util.ThreadUtil;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;

public class Exec {

    public static final long NO_TIMEOUT = -1;

    public static String getJavaExecutable() {
        String javaHome = System.getProperty("java.home");
        if (javaHome == null) {
            throw new IllegalStateException("java.home system property not set");
        }

        File home = new File(javaHome);
        ensureDir(home);

        File bin = new File(home, "bin");
        ensureDir(bin);

        File java = new File(bin, "java" + (System.getProperty("os.name").contains("win") ? ".exe" : ""));
        if (java.exists() && java.canRead()) {
            return java.getAbsolutePath();
        }

        throw new AssertionError(java.getAbsolutePath() + " cannot be read or does not exist");
    }

    public static Result execute(String cmd[]) throws Exception {
        return execute(cmd, null, null, null);
    }

    public static Result execute(String cmd[], long timeout) throws Exception {
        return execute(cmd, null, null, null, timeout);
    }

    public static Result execute(String cmd[], String outputLog) throws Exception {
        return execute(cmd, outputLog, null, null);
    }

    public static Result execute(String cmd[], String outputLog, byte[] input) throws Exception {
        return execute(cmd, outputLog, input, null);
    }

    public static Result execute(String cmd[], String outputLog, byte[] input, File workingDir) throws Exception {
        return execute(cmd, outputLog, input, workingDir, NO_TIMEOUT);
    }

    public static Result execute(String cmd[], String outputLog, byte[] input, File workingDir, long timeout)
            throws Exception {
        Process process = Runtime.getRuntime().exec(cmd, null, workingDir);
        return execute(process, cmd, outputLog, input, workingDir, timeout);
    }

    public static Result execute(Process process, String cmd[], String outputLog, byte[] input, File workingDir)
            throws Exception {
        return execute(process, cmd, outputLog, input, workingDir, NO_TIMEOUT);
    }

    @SuppressWarnings("resource")
    public static Result execute(final Process process, String cmd[], String outputLog, byte[] input,
            File workingDir, final long timeout) throws Exception {
        final AtomicBoolean processFinished = new AtomicBoolean();
        if (timeout > 0) {
            Thread timeoutThread = new Thread() {
                @Override
                public void run() {
                    ThreadUtil.reallySleep(timeout);
                    if (!processFinished.get()) {
                        process.destroy();
                    }
                }
            };
            timeoutThread.start();
        }

        Thread inputThread = new InputPumper(input == null ? new byte[] {} : input, process.getOutputStream());

        StreamCollector stderr = null;
        StreamCollector stdout = null;

        FileOutputStream fileOutput = null;
        StreamAppender outputLogger = null;

        String errString = null;
        String outString = null;

        try {
            if (outputLog != null) {
                errString = "stderr output redirected to file " + outputLog;
                outString = "stdout output redirected to file " + outputLog;
                fileOutput = new FileOutputStream(outputLog);
                outputLogger = new StreamAppender(fileOutput);
                outputLogger.writeInput(process.getErrorStream(), process.getInputStream());
            } else {
                stderr = new StreamCollector(process.getErrorStream());
                stdout = new StreamCollector(process.getInputStream());
                stderr.start();
                stdout.start();
            }

            inputThread.start();

            final int exitCode = process.waitFor();
            processFinished.set(true);

            inputThread.join();

            if (outputLogger != null) {
                outputLogger.finish();
            }

            if (stderr != null) {
                stderr.join();
                errString = stderr.toString();
            }

            if (stdout != null) {
                stdout.join();
                outString = stdout.toString();
            }

            return new Result(cmd, outString, errString, exitCode);
        } finally {
            closeQuietly(fileOutput);
        }
    }

    private static void closeQuietly(OutputStream output) {
        if (output != null) {
            try {
                output.close();
            } catch (IOException ioe) {
                // quiet
            }
        }
    }

    private static void ensureDir(File dir) {
        if (!dir.exists()) {
            throw new AssertionError(dir + " does not exist");
        }
        if (!dir.isDirectory()) {
            throw new AssertionError(dir + " is not a directory");
        }
        if (!dir.canRead()) {
            throw new AssertionError(dir + " is not readable");
        }
    }

    private static class InputPumper extends Thread {
        private final InputStream data;
        private final OutputStream output;

        InputPumper(byte[] input, OutputStream output) {
            this.output = output;
            this.data = new ByteArrayInputStream(input);
        }

        @Override
        public void run() {
            try {
                IOUtils.copy(data, output);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                closeQuietly(output);
            }
        }
    }

    public static class Result {
        private final String stderr;
        private final String stdout;
        private final int exitCode;
        private final String[] cmd;

        private Result(String[] cmd, String stdout, String stderr, int exitCode) {
            this.cmd = cmd;
            this.stdout = stdout;
            this.stderr = stderr;
            this.exitCode = exitCode;
        }

        public String getStderr() {
            return stderr;
        }

        public String getStdout() {
            return stdout;
        }

        public int getExitCode() {
            return exitCode;
        }

        @Override
        public String toString() {
            return "Command: " + Arrays.asList(cmd) + "\n" + "exit code: " + exitCode + "\n" + "stdout: " + stdout
                    + "\n" + "stderr: " + stderr + "\n";
        }

    }

}