- PR -

Runtime.getRuntime().exec(commands)の実行時で動作がとまる。

1
投稿者投稿内容
PAL
ベテラン
会議室デビュー日: 2002/11/14
投稿数: 63
投稿日時: 2005-10-30 18:34
以下のようなソースで外部シェルをlinux上で実行しています。
コード:
/** コマンドを実行した結果を保持したList(Error) */
private ArrayList _commandOutputErrorList = new ArrayList();
/** コマンドを実行した結果を保持したList */
private ArrayList _commandOutputList = new ArrayList();

Process _process = Runtime.getRuntime().exec(commands);
// 標準出力、エラー出力をそれぞれ保持
BufferedReader _inputStream = new BufferedReader(new InputStreamReader(_process.getInputStream()));
BufferedReader _errorStream = new BufferedReader(new InputStreamReader(_process.getErrorStream()));
String _commandOutput;
while ((_commandOutput = _inputStream.readLine()) != null) {
	this.getCommandOutputList().add(_commandOutput);
}
while ((_commandOutput = _errorStream.readLine()) != null) {
	this.getCommandOutputErrorList().add(_commandOutput);
}
// プロセスの終了を待ちます。
 _process.waitFor();
// 終了コードの保持
this.setExitValue(_process.exitValue());


しかしながら、一部の外部コマンドを実行すると、その外部コマンドがエラーになる場合、上記ソースでは_inputStreamのWhileの部分で処理が停止してしまいます。
ソースを改変し、_errorStreamのWhileのみにするとエラーメッセージがArrayListに追加されて終了します。
ちなみに、その外部コマンドとは
if ( ! xmllint --noout --catalogs --valid ${OUT_FOLDER}/${WORDML_FILE_NAME}_m.xml ); then
exit 2
fi
 です。(xmllintはxalanかsaxonについていたXMLチェックプログラムです)

この事から、一部の外部コマンドはエラーの場合、_process.getInputStream()に値を返却せずに、_process.getErrorStream()に値を返却するため、_process.getInputStream()の部分でハングアップするのではないかと予想しています。

上記予想は正しいでしょうか?

また、正しい場合対処方法はどのようなものになるのでしょうか?

今は、『シェルに目印を入れて、その目印のエコーが返却されたら、Javaでストリームを切り替える。』でしのいでいますが、とても良い方法とは思えません。

よろしくお願いします。
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2005-10-30 19:25
Runtime#exec()で実行した外部コマンドが動いていないようです。外部コマンド実行でのリダイレクトについて より)や、
Apache AntExecタスクのソース が参考になると思います。
PAL
ベテラン
会議室デビュー日: 2002/11/14
投稿数: 63
投稿日時: 2005-11-01 22:43
引用:

ちいにぃさんの書き込み (2005-10-30 19:25) より:
Runtime#exec()で実行した外部コマンドが動いていないようです。外部コマンド実行でのリダイレクトについて より)や、
Apache AntExecタスクのソース が参考になると思います。


ありがとうございました。
仰るとおりでした。
以下のようになりました。(でも、サンプルソースが元々この形だったら・・・とは思いました^^)

コード:
public StreamPumper(final InputStream is, final int messageLevel) {
	this._pumpStreamReader = new BufferedReader(new InputStreamReader(is));
	this._messageLevel = messageLevel;
}
/**
 * 外部コマンドの標準出力を受け取ります。
 * @throws IOException IOException
 */
public void pumpStream() throws IOException {
	if (!_endOfStream) {
		String _line = _pumpStreamReader.readLine();
		if (_line != null) {
			outputLog(_line, _messageLevel);
		} else {
			_endOfStream = true;
		}
	}
}
public void run() {
	try {
		try {
			while (!_endOfStream) {
				pumpStream();
				sleep(SLEEP_TIME);
			}
		} catch (InterruptedException _ie) {
			//ignore
			log.error("Catch The Exception", _ie);
		}
		_pumpStreamReader.close();
	} catch (IOException _ioe) {
		// ignore
		log.error("Catch The Exception", _ioe);
	}
}

try {
	Process _process = Runtime.getRuntime().exec(commands);
	// 標準出力、エラー出力をそれぞれ保持
	StreamPumper _inputPumper = new StreamPumper(_process
			.getInputStream(), Project.MSG_INFO);
	StreamPumper _errorPumper = new StreamPumper(_process
			.getErrorStream(), Project.MSG_WARN);
	// starts pumping away the generated output/error
	_inputPumper.start();
	_errorPumper.start();
	// Wait for everything to finish
	_process.waitFor();
	// 外部コマンドのプロセスの終了を待ちます。
	_process.waitFor();
	// 標準出力を受け取っているスレッドの終了を待ち合わせます。
	_inputPumper.join();
	_errorPumper.join();
	// 外部コマンドのプロセスを破棄します。
	_process.destroy();
	// close the output file if required
	// 終了コードの保持
	this.setExitValue(_process.exitValue());
} catch (Exception _ex) {
	log.error("Catch The Exception", _ex);
}


1

スキルアップ/キャリアアップ(JOB@IT)