Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFcccc
public class Exec {
  public static void main(String args[]) {
throws IOException   try {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      int exitVal = proc.exitValue();
    } catch (Throwable t) { t.printStackTrace();}
  }
}

Noncompliant Code Example

In this noncompliant code example, the waitFor() method blocks the calling thread until the invoked process terminates. This howeverHowever, this also has a shortcoming ; in that, the program may remain blocked for a long time because of the limited buffer size available for the standard output streams on many platforms. The output from the external prgram program may exhaust the buffer, causing this condition.

Code Block
bgColor#FFcccc
public class Exec {
  public static void main(String args[]) {
    trythrows IOException {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      int exitVal = proc.waitFor();
    } catch (Throwable t) { t.printStackTrace();}
  }
}

Compliant Solution (1)

An inefficient solution is to exhaust the output and the stderr streams before beginning to wait for the process. A better option is to empty both the stderr and output streams. The code below This compliant solution shows this but is not the best solution as it does not process any arguments passed to the external program (notemaker) and exits with an OS-specific non-zero exit code.

Code Block
bgColor#ccccff
public class Exec {
  public static void main(String args[]) {
throws IOException, InterruptedException  try {
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");
      InputStream is = proc.getInputStream();
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
    
    String line;

      while ( (line = br.readLine()) != null)   
        System.out.println(line);  // printsPrints the error lines

      int exitVal = proc.waitFor();
    } catch (Throwable t) { t.printStackTrace(); }
  }
}

Compliant Solution (2)

...

Code Block
bgColor#ccccff
class Exec extends Thread  {
  InputStream is;
  String type;
  OutputStream os;

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

  Exec(InputStream is, String type, OutputStream redirect) {
    this.is = is;
    this.type = type;
    this.os = redirect;
  }

  public void run() {
    try {
      PrintWriter pw = null;
      if (os != null) {
        pw = new PrintWriter(os);
      }  
     
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line = null;
 
      while ( (line = br.readLine()) != null) {
        if (pw != null) {
          pw.println(line);
          pw.flush();
        }
 
        System.out.println(type + ">" + line);
      }
 
      if (pw != null)
        pw.flush();
    } catch (IOException ioe) { /* Forward to handler */ }
  }
}
	
public class ExecMe {
  public static void main(String[] args) {
    // ... perform command argument check  ...
	
    try {
      FileOutputStream fos = new FileOutputStream("c:\\output.txt");
      Runtime rt = Runtime.getRuntime();
      Process proc = rt.exec("notemaker");

      // anyAny error message?
      Exec errorGobbler = new Exec(proc.getErrorStream(), "ERROR");
	
      // anyAny output?
      Exec outputGobbler = new Exec(proc.getInputStream(), "OUTPUT", fos);
	
      errorGobbler.start();
      outputGobbler.start();
	
      // anyAny error?
      int exitVal = proc.waitFor();
      errorGobbler.join();     // handle condition where the
      outputGobbler.join();    // process ends before the threads finish 

      fos.flush();
      fos.close();
    } catch (Throwable t) { /* forward to handler */ }
  }
}

...

Compliant Solution (3) (Windows)

This complint compliant solution (based on the Sun forums query Runtime.exec hangs even If I drain output), uses the ProcessBuilder to merge the error and output streams to simplify the handling mechanism. The readToPrompt() method interacts with the command prompt and reads the output of the invoked process.

Code Block
bgColor#ccccff
public class Cmd {
  public static void main(String[] args) throws IOException {
    ProcessBuilder pb = new ProcessBuilder("cmd");
    pb = pb.redirectErrorStream(true);
    Process p = pb.start();
    InputStream is = p.getInputStream();
    OutputStream os = p.getOutputStream();

    PrintWriter pw = new PrintWriter(os, true);
    readToPrompt(is);
    
    pw.println("dir");
    readToPrompt(is);    
  }
 
  private static void readToPrompt(InputStream is) throws IOException {
    String s = "";
    for (;;) {
      int i = is.read();
      
      if (i < 0) {
        System.out.println();
        System.out.println("EOF");
        System.exit(0);
      }
 
      char c = (char)i; // Safe
      s += c;
  
      if (s.endsWith("\r\n") {
        System.out.print(s);
        s = "";
      }
      
      // detects prompt, to break out
      if (c == '>' && s.length() > 2 && s.charAt(1) == ':') {
        System.out.print(s);
        break;
      }
    }
  }
}

...