2009-06-25 55 views
2

我想從java應用程序中調用cleartool,但即使對於簡單的「-version」參數,cleartool也會掛起。運行cleardiff而不是cleartool可以正常工作,顯然cleartool程序有一些特定的功能(我認爲它與它的交互功能有關)。未能從java啓動程序(使用ProcessBuilder)

以下程序

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(); 
    } 
} 

給出以下輸出

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 

掛在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 

問:有誰知道爲什麼cleartool懸掛,以及如何解決?

回答

2

您應該在單獨的線程中使用stdout和stderr,否則您將遇到阻塞行爲。

我懷疑在這種情況下發生了什麼(並且除了輸出stdout/err之外,它與cleartool/cleardiff無關)。有關更多信息,請參閱this answer

3

看來你關閉了I/O流之前你開始等待終止。你也可以順序閱讀stderr和stdout。但是,由於應用程序不打印錯誤,因此讀取到標準錯誤塊並且不會移至讀取stdout的階段。這個僵局。

您可以通過ProcessBuilder.redirectErrorStream()加入stderr和stdout,然後您只需要讀取stdout。

您的示例在某些情況下可用,因爲當您在stderr上被阻止時,stdout上的應用程序響應不會達到通信緩衝區的大小。當應用程序退出時,stderr循環退出,標準輸出的循環能夠恢復該緩衝區的內容。