2

I have a jar file which keeps waiting for user input, process and print out result (in multiple lines) like this

>Input sentence 1
Result 1
Result 2
>Input sentence 2
Result 1
Result 2
Result 3
>

The only way to exit this jar program is by pressing Ctrl + C.

Now, I want to invoke this jar file from my java program. My code looks like this:

processBuilder = new ProcessBuilder(PATH_TO_BIN);
Process process = processBuilder.start();
writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

writer.write(inputSentence);
writer.newLine();
writer.flush();
String line;
while ((line = reader.readLine()) != null){ //<<<< it hangs here
    System.out.println(line);
}

My program can successfully print out the result returned by "jar" program, but it keep hanging at the next reader.readLine() and I can not provide the next input to "jar" program.

Is there any way to fix this issue?

Thanks in advance!

The Lazy Log
  • 3,564
  • 2
  • 20
  • 27
  • You are not writing anything to the jar in your `while` loop. It waits for input and you are waiting for its output. Add some `write` after the `System.out.println – AhmadWabbi Feb 20 '17 at 08:36
  • @AhmadWabbi maybe I did not say very clearly in my question, but the JAR file might yield multiple lines of results, not just a single line, that's why I need to read all the result lines using `while` loop as you can see – The Lazy Log Feb 20 '17 at 12:59
  • It wasn't even clear in your example. In this case, it is impossible to distinguish between your program waiting for the next result and waiting forever because the jar finished producing results and waits for Ctrl- C. Even `peek` won't distinguish. I don't see a solution other than sending Ctrl-C using a thread after a sufficient timeout. – AhmadWabbi Feb 21 '17 at 08:31

3 Answers3

1

You could use one Thread to read and other to write, then it wouldn't block on read, like this:

    ProcessBuilder processBuilder = new ProcessBuilder(PATH_TO_BIN);
    Process process = processBuilder.start();
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

      
    new Thread () {
      public void run() {
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = null;
        do {             
          line = reader.readLine();
          System.out.println(line);
        } while (line != null); // <<<< it waits here for next line of input 
      }
    }.start();
       

    // and here you can write something to the process InputSteram...
    writer.write(inputSentence);
    writer.newLine();
    writer.flush();
Krzysztof Cichocki
  • 6,294
  • 1
  • 16
  • 32
  • My apologies for not specifying clearly enough, the result might have multiple lines, not just a single line as in my initial example. I updated my question. – The Lazy Log Feb 20 '17 at 13:01
  • It doesn't 'wait here for next line of input' where 'here' is the `do/while` condition. It waits at `readLine()`. – user207421 Mar 03 '17 at 09:40
0

Method ready() from BufferedReader -Tells whether this stream is ready to be read.

You can use this method to check if stream is ready to be read and if yes you can do your work,

while (reader.ready()){
//Do the processing
}

See if this works.

iswan
  • 71
  • 5
0

I'm going to base off of @Krzystof's answer, however I'm assuming you're going to be using Java 7 or 8 (+).

In which case, you should be using Try-With-Resources, as follows:

public static void main (String[] args) throws java.lang.Exception {

    ProcessBuilder prBuilder = new ProcessBuilder("/path/to/bin");
    Process process = prBuilder.start();
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())) | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()))) {

        String line;

        while ((line = reader.readLine()) != null) {
            // Process input
        }

    } catch (IOException ex) {
        // Process IOException
    } finally {
        process.kill();
    }
}
SimonC
  • 1,547
  • 1
  • 19
  • 43
  • Thanks for sharing this. However, this code still hangs at `line = reader.readLine()`, right? I also updated my question for additional details – The Lazy Log Feb 20 '17 at 13:21
  • You could use the following condition: `while (reader.peek() != -1)` I'm sure of the exact behaviour, but I'm not aware that it "hangs". In any case though, it's good that the application waits for the next input. Otherwise you'd be passing possibly incomplete data. What reason do you have for needing continuous in-/output? – SimonC Feb 20 '17 at 13:23
  • 1
    I don't see `peek()` method on BufferedReader object, perhaps it is for Java 6. I'm using Java 8. The JAR file is provided by a third-party, I have no control over it. What I want is to ask user to provide an input, pass it to JAR program and get the output. JAR file needs to initialize bunch of models every time it starts. – The Lazy Log Feb 20 '17 at 14:27
  • Even when using `peek()`, it still hangs after reading the last line from the results. It seems like my program does not know whether or not it has finished reading all the output from JAR file and it keeps waiting – The Lazy Log Feb 20 '17 at 14:40