
import java.util.logging.Logger;
import java.util.*;
import java.io.*;


class StreamGobbler extends Thread
{
   public static final Logger LOGGER = Logger.getLogger(StreamGobbler.class.getName());

   InputStream is;
   String type;
   OutputStream os;

   StreamGobbler(InputStream is, String type)
   {
      this(is, type, null);
   }

   StreamGobbler(InputStream is, String type, OutputStream redirect)
   {
      LOGGER.fine("trace");
      this.is = is;
      this.type = type;
      this.os = redirect;
   }


   public void run()
   {
      LOGGER.fine("trace");

      try
      {
         BufferedOutputStream bos = null;
         if(os != null)
            bos = new BufferedOutputStream(os);

         BufferedInputStream bis = new BufferedInputStream(is);

         byte[] buffer = new byte[2048];
         int nread = 0;
         while ( (nread = bis.read(buffer)) != -1)
         {
            if (bos != null)
            {
               bos.write(buffer, 0, nread);
            }
            else
            {
               LOGGER.finest(type + ">" + new String(buffer, 0, nread, "utf-8"));
            }
         }

         if(bos !=null)
            bos.flush();

      } catch (IOException ioe)
      {
         ioe.printStackTrace();  
      }
   }
}


class ExecCmd
{
   public static final Logger LOGGER = Logger.getLogger(ExecCmd.class.getName());

   public int exitValue;

   public void doRun(OutputStream outputStream, String[] cmd)
      throws IOException, InterruptedException
   {
      LOGGER.fine("trace CMD: " + Arrays.toString(cmd));

      // Assert outputStream != null

      long start_nsec = System.nanoTime();

      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec(cmd);

      // any error message?
      StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");

      // any output?
      StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", outputStream);

      long meas1_nsec = System.nanoTime();

      // kick them off
      outputGobbler.start();
      errorGobbler.start();

      outputGobbler.join();
      errorGobbler.join();

      long meas2_nsec = System.nanoTime();

      exitValue = proc.waitFor();

      long meas3_nsec = System.nanoTime();

      outputStream.flush();

      long meas4_nsec = System.nanoTime();

      LOGGER.finer("RUNTIME[nsec] ExecCmd::doRun(): "
            +       String.valueOf((long)Math.round( (meas1_nsec - start_nsec)/1.0e6 ))
            + " " + String.valueOf((long)Math.round( (meas2_nsec - start_nsec)/1.0e6 ))
            + " " + String.valueOf((long)Math.round( (meas3_nsec - start_nsec)/1.0e6 ))
            + " " + String.valueOf((long)Math.round( (meas4_nsec - start_nsec)/1.0e6 )));
   }


}

