hlovdal
hlovdal

Reputation: 28180

Failure to start program from java (using ProcessBuilder)

I am trying to call cleartool from an java application, but cleartool hangs even for a simple "-version" argument. Running cleardiff instead of cleartool works fine, so apparently there is something specific with the cleartool program (which I assume is related to its interactive capabilities).

The following program

import java.io.*;
import java.util.*;

public class ExecTesting extends Thread {

    private List<String> command = new ArrayList<String>();

    public ExecTesting (List<String> command) {
        super();
        this.command = command;
    }

    private void print(String s) {
        System.out.println(s);
    }

    @Override
    public void run() {
        Process process;
        OutputStream stdin;
        InputStream stdout;
        InputStream stderr;
        String line;

        try {
            String commandString = joinList(command, " ");
            print("Executing: " + commandString);

            // runtime.exec has several issues (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1)
            // better to use ProcessBuilder (http://java.sun.com/developer/JDCTechTips/2005/tt0727.html#2)
            //process = Runtime.getRuntime().exec(commandString);
            process = new ProcessBuilder(command).start();
            // it fails in both cases though

            stdin  = process.getOutputStream();
            stdout = process.getInputStream();
            stderr = process.getErrorStream();

            BufferedReader bufferedStderr = new BufferedReader(new InputStreamReader(stderr));
            while ((line = bufferedStderr.readLine()) != null) {
                print("stderr: " + line);
            }
            bufferedStderr.close();

            BufferedReader bufferedStdout = new BufferedReader(new InputStreamReader(stdout));
            while ((line = bufferedStdout.readLine()) != null) {
                print("stdout: " + line);
            }
            bufferedStdout.close();

            stdin.close();
            stdout.close();
            stderr.close();

            process.waitFor();
            print("Execution finished, exit code " + process.exitValue());
            process.destroy();
        } catch (IOException e) {
            print("IOException: " +e.getStackTrace());
        } catch (InterruptedException e) {
            print("InterruptedException: " + e.getStackTrace());
        }

    }

    /* assumes a list with at least one element */
    private static String joinList(List<String> list, String glue) {
        Iterator<String> i = list.iterator();
        String ret = i.next();
        while (i.hasNext()) {
            ret += glue + i.next();
        }
        return ret;
    }

    public static void main(String[] args) {
        ArrayList<String> cmd1 = new ArrayList<String>();
        cmd1.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleardiff.exe");
        cmd1.add("-version");
        ExecTesting et1 = new ExecTesting(cmd1);
        et1.start();

        ArrayList<String> cmd2 = new ArrayList<String>();
        //cmd2.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleardiff.exe");
        cmd2.add("c:\\Program Files\\Rational\\ClearCase\\bin\\cleartool.exe");
        cmd2.add("-version");
        ExecTesting et2 = new ExecTesting(cmd2);
        et2.start();

        et1 = new ExecTesting(cmd1);
        et1.start();
    }
}

gives the following output

Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleartool.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0

hanging on the execution of the cleartool command. If instead cmd2 is changed to cleardiff the output is as expected

Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
Executing: [c:\Program Files\Rational\ClearCase\bin\cleardiff.exe, -version]
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0
stdout: cleardiff                         2003.06.10+ (Tue Jul 13 14:02:05  2004)
Execution finished, exit code 0

Question: Does anyone know why cleartool is hanging and how to fix?

Upvotes: 2

Views: 5073

Answers (2)

Brian Agnew
Brian Agnew

Reputation: 272217

You should consume the stdout and stderr in separate threads, otherwise you will experience blocking behaviour.

I suspect that's what's happening in this instance (and that it's unrelated to cleartool/cleardiff other than they're outputting stdout/err). See this answer for more information.

Upvotes: 3

akarnokd
akarnokd

Reputation: 69997

It seems you close the I/O streams BEFORE you start to wait for the termination. Also you read the stderr and stdout sequentially. However, the read to stderr blocks as there are no errors printed by the application and you don't move to the phase where you read the stdout. This deadlocks.

You could join the stderr and stdout via ProcessBuilder.redirectErrorStream() and then you need only to read stdout.

Your sample works in some cases because when you are blocked on the stderr, the application response on the stdout doesn't hit the size of the communication buffer. When the application quits, the stderr loop exits and the loop for stdout is able to retieve the contents of that buffer.

Upvotes: 3

Related Questions