Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: replaced Windows CS with CS that redirects err to out

...

This noncompliant code example properly drains the input stream from the process, thereby preventing the input stream buffer from becoming full and blocking. However, it ignores the error stream, which can also fill and cause the process to block.

Code Block
bgColor#ccccff#ffcccc
public class Exec {
  public static void main(String args[]) throws IOException, InterruptedException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("notemaker");
    InputStream is = proc.getInputStream();
    int c;
    while ((c = is.read()) != -1)
      System.out.print((char) c);
    int exitVal = proc.waitFor();   
  }
}

Compliant Solution (redirectErrorStream())

This compliant solution redirects the process's error stream to its input stream. Thus, the program can drain the single output stream without fear of blockage.

Code Block
bgColor#ffcccc

public class Exec {
  public static void main(String args[]) throws IOException, InterruptedException {
    ProcessBuilder pb = new ProcessBuilder("notemaker");
    pb = pb.redirectErrorStream(true);
    Process proc = pb.start();
    InputStream is = proc.getInputStream();
    int c;
    while ((c = is.read()) != -1)
      System.out.print((char) c);
    int exitVal = proc.waitFor();   
  }
}

...

Code Block
bgColor#ccccff
class StreamGobbler extends Thread {
  InputStream is;
  PrintStream os;

  StreamGobbler(InputStream is, PrintStream os) {
    this.is = is;
    this.os = os;
  }

  public void run() {
    try {
    int c;
    while ((c = is.read()) != -1)
      os.print((char) c);
    } catch (IOException x) {
      // handle error
    }
  }
}
	
public class Exec {
  public static void main(String[] args) throws IOException, InterruptedException {
	
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("notemaker");

    // Any error message?
    StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), System.err);
	
    // Any output?
    StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), System.out);
	
    errorGobbler.start();
    outputGobbler.start();
	
    // Any error?
    int exitVal = proc.waitFor();
    errorGobbler.join();   // Handle condition where the
    outputGobbler.join();  // process ends before the threads finish 
  }
}

Compliant Solution (Windows)

This compliant solution uses a ProcessBuilder to simplify the handling mechanism by merging the error and output streams. The readToPrompt() method reads the output of the invoked process; details of its implementation necessarily depend on the exact formatting of the command prompt used by the platform's command interpreter.

Code Block
bgColor#ccccff

public class Exec {
  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;
      }
    }
  }
}

Exceptions

FIO10-EX0: A process that does not read input from its input stream need not have data supplied there. Likewise a process that does not send output to its output stream need not have its output stream emptied. And a proces that does not send output to its error stream need not have its error stream emptied.

...