design for a wrapper around command-line utilities

Posted by hatchetman82 on Stack Overflow See other posts from Stack Overflow or by hatchetman82
Published on 2010-03-17T15:19:23Z Indexed on 2010/03/17 15:21 UTC
Read the original article Hit count: 365

Filed under:
|
|

im trying to come up with a design for a wrapper for use when invoking command line utilities in java. the trouble with runtime.exec() is that you need to keep reading from the process' out and err streams or it hangs when it fills its buffers. this has led me to the following design:

public class CommandLineInterface {
    private final Thread stdOutThread;
    private final Thread stdErrThread;
    private final OutputStreamWriter stdin;
    private final History history;

public CommandLineInterface(String command) throws IOException {
    this.history = new History();
    this.history.addEntry(new HistoryEntry(EntryTypeEnum.INPUT, command));
    Process process = Runtime.getRuntime().exec(command);
    stdin = new OutputStreamWriter(process.getOutputStream());
    stdOutThread = new Thread(new Leech(process.getInputStream(), history, EntryTypeEnum.OUTPUT));
    stdOutThread.setDaemon(true);
    stdOutThread.start();
    stdErrThread = new Thread(new Leech(process.getErrorStream(), history, EntryTypeEnum.ERROR));
    stdErrThread.setDaemon(true);
    stdErrThread.start();
}

public void write(String input) throws IOException {
    this.history.addEntry(new HistoryEntry(EntryTypeEnum.INPUT, input));
    stdin.write(input);
    stdin.write("\n");
    stdin.flush();
}

}

public class Leech implements Runnable{ private final InputStream stream; private final History history; private final EntryTypeEnum type; private volatile boolean alive = true;

public Leech(InputStream stream, History history, EntryTypeEnum type) {
    this.stream = stream;
    this.history = history;
    this.type = type;
}

public void run() {
    BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
    String line;
    try {
        while(alive) {
            line = reader.readLine();
            if (line==null) break;
            history.addEntry(new HistoryEntry(type, line));
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

my issue is with the Leech class (used to "leech" the process' out and err streams and feed them into history - which acts like a log file) - on the one hand reading whole lines is nice and easy (and what im currently doing), but it means i miss the last line (usually the prompt line). i only see the prompt line when executing the next command (because there's no line break until that point). on the other hand, if i read characters myself, how can i tell when the process is "done" ? (either complete or waiting for input) has anyone tried something like waiting 100 millis since the last output from the process and declaring it "done" ?

any better ideas on how i can implement a nice wrapper around things like runtime.exec("cmd.exe") ?

© Stack Overflow or respective owner

Related posts about java

Related posts about runtime.exec