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

org.enhydra.xml.xmlc.misc.ProcessRunner Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * 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 terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: ProcessRunner.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.misc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import org.enhydra.xml.io.ErrorReporter;
import org.enhydra.xml.xmlc.XMLCException;

/**
 * Run a process, optionally collecting stdout/stderr.
 */
public class ProcessRunner {
    /**
     * Options to enable passing or collecting of output.
     */
    public static final int PASS_STDOUT = 0x01;
    public static final int PASS_STDERR = 0x02;
    public static final int COLLECT_STDOUT = 0x04;
    public static final int COLLECT_STDERR = 0x08;
    public static final int STDERR_TO_REPORTER = 0x10;
    public static final int DUMP_STDERR_ON_FAIL = 0x20;
    public static final int NO_EXCEPTION_ON_ERR_EXIT = 0x40;

    /*
     * Output streams; maybe null.
     */
    private OutputStream stdoutStream;
    private OutputStream stderrStream;

    /*
     * Collection buffers; maybe null.
     */
    private StringBuffer stdoutBuf;
    private StringBuffer stderrBuf;

    /**
     * Options.
     */
    private int options;
    
    /**
     * Exit code of last process.
     */
    int exitCode;

    /**
     * Output monitoring thread.
     */
    private class OutputMonitorThread extends Thread {
        private BufferedReader input;
        private PrintWriter output;
        private StringBuffer outputBuf;
        private IOException ioException = null;
        private boolean terminateRequested;

        /**
         * Construct an output monitor thread object.
         * @param in Stream to read from.
         * @param out Stream to write to.  If null, don't copy to an
         *               output stream.
         * @param outBuf Buffer to collect output in. If null, don't collect.
         */
        OutputMonitorThread(InputStream in,
                            OutputStream out,
                            StringBuffer outBuf) {
            input = new BufferedReader(new InputStreamReader(in));
            if (out != null) {
                output = new PrintWriter(new OutputStreamWriter(out), true);
            }
            outputBuf = outBuf;
        }
        
        /**
         * Terminate the monitor thread.
         */ 
        public void terminate() {
            interrupt();
            terminateRequested = true;
        }

        /**
         * Get an exception, if one terminated the thread, otherwise
         * null indicates no errors.
         */
        public IOException getException() {
            return ioException;
        }


        /**
         * Copy the stream until eof.
         */
        private void copyStream() throws IOException {
            String line;
            while ((line = input.readLine()) != null) {
                if (output != null) {
                    output.println(line);
                }
                if (outputBuf != null) {
                    outputBuf.append(line);
                    outputBuf.append('\n');
                }
            }
        }

        /**
         * Run the copy thread.
         */
        public void run() {
            try {
                copyStream();
            } catch (IOException except) {
                ioException = except;
            }
            if (output != null) {
                output.flush();
            }
        }
    }

    /**
     * Constructor.
     */
    public ProcessRunner(int opts) {
        setOptions(opts);
    }

    /**
     * Set the options
     */
    public void setOptions(int opts) {
        options = opts;
        if ((options & PASS_STDOUT) != 0) {
            stdoutStream = System.out;
        } else {
            stdoutStream = null;
        }
        if ((options & PASS_STDERR) != 0) {
            stderrStream = System.err;
        } else {
            stderrStream = null;
        }
        if ((options & DUMP_STDERR_ON_FAIL) != 0) {
            options |= COLLECT_STDERR;
        }
    }

    /**
     * Get the options
     */
    public int getOptions() {
        return options;
    }

    /*
     * Get exit code of process.
     */
    public int getExitCode() {
        return exitCode;
    }

    /*
     * Dump stderr if requested on a failure.
     */
    private void dumpStderr(ErrorReporter errorReporter) {
        if ((options & DUMP_STDERR_ON_FAIL) != 0) {
            errorReporter.error(stderrBuf.toString());
        }
    }

    /**
     * Monitor the running process.
     */
    private void monProc(Process proc) 
        throws IOException, InterruptedException {

        // Don't wipe out old buffer in case it was saved.
        if ((options & COLLECT_STDOUT) != 0) {
            stdoutBuf = new StringBuffer();
        } else {
            stdoutBuf = null;
        }
        if ((options & COLLECT_STDERR) != 0) {
            stderrBuf = new StringBuffer();
        } else {
            stderrBuf = null;
        }

        OutputMonitorThread outMon =
            new OutputMonitorThread(proc.getInputStream(),
                                    stdoutStream,
                                    stdoutBuf);
        OutputMonitorThread errMon =
            new OutputMonitorThread(proc.getErrorStream(),
                                    stderrStream,
                                    stderrBuf);
        try {
            outMon.start();
            errMon.start();
            proc.waitFor();
        } catch (InterruptedException except) {
            try {
                // Last ditch effort to clean up proc
                proc.destroy();
                proc.waitFor();
            } catch (InterruptedException drop) {
                // Already have an error...
            }
            outMon.terminate();
            errMon.terminate();
        } finally {
            outMon.join();
            errMon.join();
        }
        if (outMon.getException() != null) {
            throw outMon.getException();
        }
        if (errMon.getException() != null) {
            throw errMon.getException();
        }
    }

    /**
     * Run a process.  Stdout/stderr are optionally copied to the standard
     * descriptors and/or collected.
     *
     * @param cmd Program to run and arguments.
     * @param verboseOut Write verbose message to this file if not null.
     * @param failMsg Message to use in exception if process fails.
     */
    public void run(String[] cmd,
                    ErrorReporter errorReporter,
                    PrintWriter verboseOut,
                    String failMsg) throws XMLCException {
        if (verboseOut != null) {
            for (int i = 0; i < cmd.length; i++) {
                if (i > 0) {
                    verboseOut.print(" ");
                }
                verboseOut.print(cmd[i]);
            }
            verboseOut.println();
        }
        
        Process proc;
        exitCode = 0;
        try {
            proc = Runtime.getRuntime().exec(cmd);
            monProc(proc);
        } catch (IOException except) {
            dumpStderr(errorReporter);
            throw new XMLCException(except);
        } catch (InterruptedException except) {
            dumpStderr(errorReporter);
            throw new XMLCException(except);
        }
        exitCode = proc.exitValue();
        if (exitCode != 0) {
            dumpStderr(errorReporter);
            if ((options & NO_EXCEPTION_ON_ERR_EXIT) == 0) {
                throw new XMLCException(failMsg);
            }
        }
    }

    /**
     * Get accumulated stdout, or null if it was not collected.
     */
    public String getStdout() {
        return stdoutBuf.toString();
    }

    /**
     * Get accumulated stderr, or null if it was not collected.
     */
    public String getStderr() {
        return stderrBuf.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy