0

Goal: to initialise a JVM(2) from a separate JVM(1) using ProcessBuilder, capturing the resulting output from JVM(2) and displaying the result within a JTextArea in JVM(1).

Situation: able to launch JVM(2) from within JVM(1) and capture the resulting output from JVM(2) to a JTextArea within the JVM(1).

Problem: the JVM(2) will not respond to input until JVM(1) is terminated.

Thread inside VJM(1) that starts JVM(2):

 Runnable runnable = () -> { 

     try {
         JVMBooter.startSecondJVM();
     } catch (Exception ex) {
        Logger.getLogger(MyMenu.class.getName()).log(Level.SEVERE, null, ex);
     }

 };
 Thread t = new Thread(runnable);
 t.start();

JVMBooter source code:

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;


public class JVMBooter {

    public static void startSecondJVM() throws Exception {

        ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "startscript.bat");
        File dir = new File("D:/Server");
        pb.directory(dir);
        Process p = pb.start();

        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line = null;

        ( (line = reader.readLine()) != null && ! line.trim().equals("--EOF--")) {

            OutputFrame.textArea.append(line + "\n");
        }

    }

}

The JVM(2) is started within the startscript.bat file with:

java -jar server.jar
Yahwho
  • 55
  • 6
  • Hi @Yahwho From the Close Queue guidance : "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers." See: https://stackoverflow.com/help/mcve – Rob Kielty Feb 07 '19 at 12:04
  • @RobKielty Thank you Rob, I will rework my question. – Yahwho Feb 07 '19 at 12:05
  • No worries, you're not far off. State the problem explicitly and place it at the top off the question. – Rob Kielty Feb 07 '19 at 12:08
  • btw. My answer should also help debugging your actual situation in case it doesn't solve it directly. Start with my example and see if it goes (it should). Then slowly change one thing at a time. First the Caller to you server call. (I expect that to work as well) Then the System.out to your GUI (I expect there to be your actual problem) – Angelo Fuchs Feb 08 '19 at 08:40
  • I resolved this issue. [capturing-the-system-out-messages-from-another-process](https://stackoverflow.com/questions/54598131/capturing-the-system-out-messages-from-another-process) – Yahwho Feb 08 '19 at 21:08
  • Possible duplicate of [Capturing the system.out messages from another process](https://stackoverflow.com/questions/54598131/capturing-the-system-out-messages-from-another-process) – Angelo Fuchs Feb 11 '19 at 14:02

1 Answers1

2

Depending on the situation it may be necessary to read the error stream instead of the input stream, e.G. if your second java call is -version or the program you call only writes to stderr instead of stdout getting the Error Stream is the correct approach.

I wrote this MCVE:

import java.io.*;

public class Starter {
    public static void main(String[] args) throws IOException {
        ProcessBuilder pb = new ProcessBuilder("./dosomething.sh");
        File dir = new File(new File(File.listRoots()[0], "tmp"), "2jvm");
        pb.directory(dir);
        Process p = pb.start();

        BufferedReader read = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        String line;
        while ( (line = read.readLine() ) != null) {
            System.out.println("line: " + line);
        }
    }
}

and in 'dosomething.sh' this:

echo before
java -version
echo after

when I use p.getInputStream I would get the 'before' and 'after'. When I use p.getErrorStream I get the Java Version Information. That might be true for you too. I suggest you add echo lines in your batch file to see if they get printed out.

I also wrote a simple hello world and when I called that from dosomething.sh it got printed to the input stream as expected. It is a weird quirk of -version to write to stderr.

For completeness here is the Hello World I used (it has waits to simulate a longrunning server process):

public class Caller {
  public static void main(String[] args) {
    synchronized(Caller.class) {
      for(int ii = 0; ii < 10; ii++) {
        try {
          Caller.class.wait(1000);
        } catch (Exception ex) {
          ex.printStackTrace();
        }
        System.out.println("Hello world! " + ii);
      }
    }
  }
}
Angelo Fuchs
  • 9,825
  • 1
  • 35
  • 72
  • The problem I have, using your example as reference is that Caller will not accept input - output is fine. The same behaviours are present whether I use getInputStream or getErrorStream – Yahwho Feb 08 '19 at 08:53
  • @Yahwho I don't quite understand: Your (initial) question was about the InputStream of a called program. That means the OUTPUT of the called program (server in your case) is fed into the INPUT of the calling program. Your initial code does not handle the other direction at all. If you struggle there as well, please do post a new question. – Angelo Fuchs Feb 08 '19 at 08:55