I’m trying to call a command-line application (let’s call it SomeTerminalApp) from Java, more precisely, the following should happen.
- Java boots up SomeTerminalApp
- SomeTerminalApp asks for user input, which Java provides
- SomeTerminalApp processes the input, and after a while shows the output and asks new user input.
- Java detects this, processes SomeTerminalApp’s output and insers new user input, possibly based on the previous output.
- Steps 3-4 are repeated any number of times (until a stop condition in Java is met, depending on the outputs)
- We are done: Java closes the SomeTerminalApp and minds its own business again.
How should I best do this? Currently, I got very naive process handling
Process p = Runtime.getRuntime().exec("/path/SomeTerminalApp -q"); //run in quiet mode
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
with a function that inserts input and reads a fixed number of output lines immediately.
public ArrayList<String> exec (ArrayList<String> input, int nrOfOutputLines) {
for (int i=0; i<input.size(); i++) bw.write(input.get(i)+"\n");
bw.flush();
ArrayList<String> output = new ArrayList<String>();
for (int i=0; i<nrOfOutputLines; i++) output.add(br.readLine());
return output;
}
Alas, I often don’t know how many lines I’d have to read (as the output is unknown and is automatically split over many lines), and it also happens that the output doesn’t come immediately (it can take from milliseconds to days for the output to appear).
How should I treat such a process properly, i.e. listen to when the process has finished processing (not just putting a fixed timer or no timer) and read all the produced output as a response to the latest command (not just the last N lines for a fixed number N)?
You’ve got the right idea. There is no easy way to know when the subprocess is done. It either has to print something recognizable as its last action before going idle (“done” or something), or it needs to exit (which you can detect as EOF on your input).