无法从java启动程序(使用ProcessBuilder)

时间:2022-11-14 20:47:58

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).

我试图从一个java应用程序调用cleartool,但是cleartool甚至挂起了一个简单的“-version”参数。运行cleardiff而不是cleartool工作正常,因此显然有一些特定于cleartool程序的东西(我假设它与其交互功能有关)。

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

挂在执行cleartool命令上。如果将cmd2更改为cleardiff,则输出符合预期

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?

问题:有谁知道为什么cleartool会挂起以及如何修复?

2 个解决方案

#1


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

您应该在单独的线程中使用stdout和stderr,否则您将遇到阻塞行为。

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.

我怀疑这是在这种情况下发生的事情(除了他们输出stdout / err之外,它与cleartool / cleardiff无关)。有关更多信息,请参阅此答案。

#2


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.

在您开始等待终止之前,您似乎关闭了I / O流。你还要按顺序读取stderr和stdout。但是,读取到stderr会阻止应用程序打印的错误,并且您不会移动到读取标准输出的阶段。这种僵局。

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

您可以通过ProcessBuilder.redirectErrorStream()加入stderr和stdout,然后您只需要读取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.

您的示例在某些情况下有效,因为当您在stderr上被阻止时,stdout上的应用程序响应不会达到通信缓冲区的大小。当应用程序退出时,stderr循环退出,stdout的循环能够撤消该缓冲区的内容。

#1


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

您应该在单独的线程中使用stdout和stderr,否则您将遇到阻塞行为。

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.

我怀疑这是在这种情况下发生的事情(除了他们输出stdout / err之外,它与cleartool / cleardiff无关)。有关更多信息,请参阅此答案。

#2


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.

在您开始等待终止之前,您似乎关闭了I / O流。你还要按顺序读取stderr和stdout。但是,读取到stderr会阻止应用程序打印的错误,并且您不会移动到读取标准输出的阶段。这种僵局。

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

您可以通过ProcessBuilder.redirectErrorStream()加入stderr和stdout,然后您只需要读取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.

您的示例在某些情况下有效,因为当您在stderr上被阻止时,stdout上的应用程序响应不会达到通信缓冲区的大小。当应用程序退出时,stderr循环退出,stdout的循环能够撤消该缓冲区的内容。