Shell Class

package javaxt.io;
import java.io.*;

//******************************************************************************
//**  Shell Class
//******************************************************************************
/**
 *   Used to execute command line applications and return the corresponding
 *   output streams (standard output and error output streams).
 *
 ******************************************************************************/

public class Shell {

    private java.io.File executable;
    private String[] inputs;
    private java.util.List<String> output = new java.util.LinkedList<String>();
    private java.util.List<String> errors = new java.util.LinkedList<String>();
    private long startTime;
    private long ellapsedTime;
    private Process process;

  //**************************************************************************
  //** Constructor
  //**************************************************************************
  /** Creates a new instance of Shell.
   *  @param executable Path to the executable to run
   *  @param parameters Command line args passed to the executable
   */
    public Shell(java.io.File executable, String[] parameters) {

        this.executable = executable;
        this.ellapsedTime = -1;

        if (parameters==null){
            parameters = new String[0];
        }

        inputs = new String[parameters.length+1];
        inputs[0] = executable.toString();
        for (int i=0; i<parameters.length; i++){
            inputs[i+1] = parameters[i];
        }
    }

  //**************************************************************************
  //** Constructor
  //**************************************************************************
  /** Creates a new instance of Shell.
   *  @param executable Path to the executable to run
   *  @param parameters Command line args passed to the executable
   */
    public Shell(javaxt.io.File executable, String[] parameters) {
        this(executable.toFile(), parameters);
    }

  //**************************************************************************
  //** Constructor
  //**************************************************************************
  /** Creates a new instance of Shell.
   *  @param cmd Command to execute. Example: "cmd /c dir C:\\temp"
   */
    public Shell(String cmd){

        this.executable = null;
        this.ellapsedTime = -1;

        String arr[] = cmd.trim().split(" ");
        java.util.Vector<String> parameters = new java.util.Vector<String>();
        for (int i=0; i<arr.length; i++){
            String str = arr[i].trim();
            if (str.length()>0) parameters.add(str);
        }
        inputs = new String[parameters.size()];
        for (int i=0; i<parameters.size(); i++){
            inputs[i] = parameters.get(i);
        }
        java.io.File file = new java.io.File(inputs[0]);
        if (file.exists() && file.isFile()){
            executable = file;
        }
    }

  //**************************************************************************
  //** Constructor
  //**************************************************************************
  /** Creates a new instance of Shell.
   *  @param cmdarray Command to execute, along with the command line args in a
   *  String array.
   */
    public Shell(String[] cmdarray){
        this.executable = null;
        this.ellapsedTime = -1;
        inputs = cmdarray;
        java.io.File file = new java.io.File(inputs[0]);
        if (file.exists() && file.isFile()){
            executable = file;
        }
    }


  //**************************************************************************
  //** getOutput
  //**************************************************************************
  /** Used to retrieve the standard output stream. Returns a List that can be
   *  parsed while the executable is still running or after is has been run.
   *  The difference lies in when the run method is invoked. The following is
   *  an example of how to process the output stream while the app is running.
   *  The getOutput() is called BEFORE the run() method is invoked.
   <pre>
    File exe = new File("C:\\Program Files\\PostgreSQL\\8.4\\bin\\shp2pgsql.exe");
    String[] options = new String[]{"-W", "UTF-8", "-s", "4326", "C:\country.shp", "t_country"};

    javaxt.io.Shell cmd = new javaxt.io.Shell(exe, options);
    java.util.List<String> output = cmd.getOutput();
    cmd.run();

    String line;
    while (true){
        synchronized (output) {
            while (output.isEmpty()) {
              try {
                  output.wait();
              }
              catch (InterruptedException e) {
              }
            }
            line = output.remove(0);
        }

        if (line!=null){
            System.out.println(line);
        }
        else{
            break;
        }
    }
   </pre>
   * If you want to get the entire output all at once, just call the getOutput()
   * AFTER the run() method. Example:
   <pre>
    javaxt.io.Shell cmd = new javaxt.io.Shell(exe, options);
    cmd.run();
    java.util.List<String> output = cmd.getOutput();
    for (int i=0; i<output.size(); i++){
        System.out.println(output.get(i));
    }
   </pre>
   *
   */
    public java.util.List getOutput(){ return output; }


  //**************************************************************************
  //** getErrors
  //**************************************************************************
  /** Used to retrieve the error output stream. Returns a List that can be
   *  parsed while the executable is still running or after is has been run.
   */
    public java.util.List getErrors(){ return errors; }



  //**************************************************************************
  //** run
  //**************************************************************************
  /** Used to execute the process specified in the constructor and populate
   *  the output streams.
   */
    public void run() {

        ellapsedTime = -1;
        startTime = System.currentTimeMillis();

        try {

          //Run executable via Command Line and pick up the output stream
            Runtime runtime = Runtime.getRuntime();
            if (executable!=null){
                process = runtime.exec(inputs, null, executable.getParentFile());
            }
            else{
                process = runtime.exec(inputs);
            }


            StreamReader s1 = new StreamReader(output, process.getInputStream());
            StreamReader s2 = new StreamReader(errors, process.getErrorStream());
            s1.start();
            s2.start();
            process.waitFor();
            s1.join();
            s2.join();


          //Clean up!
            cleanUp();

        }
        catch(IOException e){
            throw new RuntimeException(e);
        }
        catch(InterruptedException e){
            throw new RuntimeException(e);
        }

        ellapsedTime = System.currentTimeMillis()-startTime;
    }


  //**************************************************************************
  //** stop
  //**************************************************************************
  /** Used to stop the current process. Note that this method does not stop
   *  or kill process grandchildren. This is a limitation of Java, not this
   *  class per se. See Sun bug 4770092 for more details.
   */
    public void stop(){
        if (process!=null){
            process.destroy();
            cleanUp();
            ellapsedTime = System.currentTimeMillis()-startTime;
        }
    }


  //**************************************************************************
  //** cleanUp
  //**************************************************************************
  /** Used to clean up system resources after a process has been terminated.
   *  Based on recommendations found in "Five Common java.lang.Process Pitfalls"
   *  by Kyle Cartmell (http://kylecartmell.com/?p=9).
   */
    private void cleanUp(){

      //Explicitly clean up every instance of Process by calling close on each stream
        try{process.getInputStream().close();} catch(Exception ex){}
        try{process.getErrorStream().close();} catch(Exception ex){}
        try{process.getOutputStream().close();} catch(Exception ex){}

      //Explicitly destroy the process even if the process is already terminated
        try{process.destroy();} catch(Exception ex){}

        process = null;
    }


  //**************************************************************************
  //** getEllapsedTime
  //**************************************************************************
  /** Used to return the total time (milliseconds) it took to execute the
   *  process.
   */
    public long getEllapsedTime(){
        return ellapsedTime;
    }


    /*
    public void run(byte[] b){

        try{

          //Run executable via Command Line and pick up the output stream
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(inputs, null, executable.getParentFile());

            //process.getOutputStream().write(b);

            System.out.println(b.length);

            BufferedOutputStream commandsStdIn = new BufferedOutputStream(process.getOutputStream());
            commandsStdIn.write(b);
            commandsStdIn.flush();
            commandsStdIn.close();



            StreamReader s1 = new StreamReader(output, process.getInputStream());
            StreamReader s2 = new StreamReader(errors, process.getErrorStream());
            s1.start();
            s2.start();
            process.waitFor();

        }
        catch(Exception e){
            e.printStackTrace();
        }

    }
    */

  //**************************************************************************
  //** StreamReader Class
  //**************************************************************************
  /** Thread used to read the standard input and output streams. */

    private class StreamReader implements Runnable {

        java.util.List list;
        InputStream is;
        Thread thread;


        public StreamReader (java.util.List list, InputStream is){
            this.list = list;
            this.is = is;
        }

        public void start () {
            thread = new Thread(this);
            thread.start();
        }

        public void run () {
            try {
                InputStreamReader isr = new InputStreamReader (is);
                BufferedReader br = new BufferedReader (isr);

                while (true) {
                    String s = br.readLine();
                    if (s == null) break;
                    //System.out.println(s);
                    if (list!=null) list.add(s);
                }

                list.add(null);
                is.close();

            }
            catch (Exception ex) {
                //System.out.println ("Problem reading stream... :" + ex);
                ex.printStackTrace ();
            }
        }

        public void join() throws InterruptedException {
            thread.join();
        }

    } //End StreamReader Class

}