3

I need to execute an external application which returns large data (takes more than 2 hours to complete ) nand which continuously outputs data.

What I need to do is execute this program asynchronously and capture the output in a file. I tried using java process builder, however it seems to hang and return output only when the program is exited or forcefully terminated.

I tried to use process builder and spwaned a new thread to capture the output, but still it did not help.

Then I read about apache commons exec and tried the same . however this also seems to be taking a long time and returns different error codes ( for the same input)

CommandLine cmdLine = new CommandLine("/opt/testsimulator");

    DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
    ByteArrayOutputStream stdout = new ByteArrayOutputStream();
    PumpStreamHandler psh = new PumpStreamHandler(stdout);
    ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000);
    Executor executor = new DefaultExecutor();
    executor.setStreamHandler(psh);
    executor.setWatchdog(watchdog);
    try {
        executor.execute(cmdLine);
    } catch (ExecuteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Any help or working examples whould be very helpful

Gray
  • 115,027
  • 24
  • 293
  • 354
coder
  • 95
  • 2
  • 13
  • Is running the program from Java a hard requirement? Seems to me you should just execute the command from the shell and pipe it's output to your target file. – Perception May 19 '12 at 12:35
  • I've done this using ProcessBuilder, taking care to handle the input stream and the error stream, and have had no problems. Perhaps you've got a bug in your program. – Hovercraft Full Of Eels May 19 '12 at 12:41
  • Remember to accept an answer below if it helped you. – Gray Mar 13 '15 at 13:04

1 Answers1

5

Huh. Using ProcessBuilder should work for your configuration. For example, the following pattern works for me:

ProcessBuilder pb = new ProcessBuilder("/tmp/x");
Process process = pb.start();
final InputStream is = process.getInputStream();
// the background thread watches the output from the process
new Thread(new Runnable() {
    public void run() {
        try {
            BufferedReader reader =
                new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            is.close();
        }
    }
}).start();
// the outer thread waits for the process to finish
process.waitFor();

The program that I'm running is just a script with a whole bunch of sleep 1 and echo lines:

#!/bin/sh
sleep 1
echo "Hello"
sleep 1
echo "Hello"
...

The thread reading from the process spits out a Hello every second or so.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Thanks, there was some problem with my external application and hence the process builder was hanging. The above code works perfectly fine. I had one more question. I want to execute the program asynchronously and still save the output to a file. If I do not use process.waitFor(); the program would terminate without saving the output. Is there any way of achieving this? – coder May 22 '12 at 03:59
  • You do not need to record the `Process` result. If you just ignore it once the process finishes it should just get GC'd. In my example, the thread is not marked as daemon. If the main program finishes then it will wait for the thread to complete. If you _don't_ want it to wait then you can do a thread = new Thread(...); thread.setDaemon(true); thread.start();` pattern. – Gray May 22 '12 at 14:15