Search code examples
javaprocessbufferedreaderprocessbuilder

Get BufferedReader.readLine() to wait for input


I have a Python server that I start with a Java ProcessBuilder thread. The Java program should wait until the server is ready before proceeding. When the server is ready, it outputs a "Server-ready" message, which I assume is picked up by the Process object's InputStream.

START_SERVER_COMMAND = TAGGERFLOW_HOME + "server.py";
server = new ProcessBuilder().inheritIO().command("python", START_SERVER_COMMAND, "" + portNum,
        config.featOrderName(), config.childOrderName(), "" + maxBeta).start();
System.out.println("Hypertagger server started");
LOGGER.log(Level.INFO, "Hypertagger server started");

String line = null;
while(line == null) {
    line = new BufferedReader(new InputStreamReader(server.getInputStream())).readLine();
    if(line == null)
        Thread.sleep(5000);
}
System.out.println("Exit loop");

However, line is always null, and so Java never exits the loop. That most likely indicates that my assumption about the InputStream picking up the "Server-ready" message is wrong, but I don't know why that would be the case.

I'm looking for either a way to pick up the "Server-ready" message or a better way to detect when the server is ready. Any help would be appreciated.

EDIT

Before this, I tried initializing the BufferedReader before the loop. It had the same behavior.


Solution

  • TL;DR: If you want your Java program to capture the output, don't redirect the output elsewhere, i.e. don't call inheritIO(), though you might want to call redirectErrorStream(true).


    What do you think inheritIO() does?

    Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.

    This is a convenience method. An invocation of the form

    pb.inheritIO()
    

    behaves in exactly the same way as the invocation

    pb.redirectInput(Redirect.INHERIT)
      .redirectOutput(Redirect.INHERIT)
      .redirectError(Redirect.INHERIT)
    

    When I/O is redirected, what do you think getInputStream() does?

    Returns the input stream connected to the normal output of the subprocess. The stream obtains data piped from the standard output of the process represented by this Process object.

    If the standard output of the subprocess has been redirected using ProcessBuilder.redirectOutput then this method will return a null input stream.

    Should be obvious, but what is a null input stream?

    a destination for standard output and standard error. By default, the subprocess writes standard output and standard error to pipes. Java code can access these pipes via the input streams returned by Process.getInputStream() and Process.getErrorStream(). However, standard output and standard error may be redirected to other destinations using redirectOutput and redirectError. In this case, Process.getInputStream() and/or Process.getErrorStream() will return a null input stream, for which:

    • the read methods always return -1
    • the available method always returns 0
    • the close method does nothing