Java Runtime.exec()
Я могу запустить эту команду из командной строки без каких-либо проблем (выполняется проверка script):
c:/Python27/python ../feedvalidator/feedvalidator/src/demo.py https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators
и из java, если я оставил параметр URL и просто сделаю:
String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" };
Runtime r = Runtime.getRuntime();
Process p = r.exec(args1);
он отлично работает. Если я использую определенные URL-адреса для параметра, например:
String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" , "http://www.intertwingly.net/blog/index.atom"};
// or
String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" , "http://www.cnn.com"};
он отлично работает.
Но если я использую этот конкретный URL https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators, тогда script просто зависает (java ждет завершения процесса). Я не уверен, почему он работает из командной строки для этого URL-адреса, но не из java-программы. Я попытался добавить цитаты, чтобы окружить параметр URL, но это тоже не сработало. Я не вижу ни одного символа в URL-адресе, который, как мне кажется, должен быть экранирован.
Полный код:
String urlToValidate = "https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators";
String[] args1 = {"c:/Python27/python", "C:/Documents and Settings/vhaiswcaldej/DAS_Workspace/feedvalidator/feedvalidator/src/demo.py", urlToValidate };
System.out.println(args1[0] + " " + args1[1] + " " + args1[2]);
Runtime r = Runtime.getRuntime();
Process p = r.exec(args1);
BufferedReader br = new BufferedReader(new InputStreamReader(
p.getInputStream()));
int returnCode = p.waitFor();
System.out.println("Python Script or OS Return Code: " + Integer.toString(returnCode));
if (returnCode >= 2) {
.out.println("OS Error: Unable to Find File or other OS error.");
}
String line = "";
while (br.ready()) {
String str = br.readLine();
System.out.println(str);
if (str.startsWith("line")) {
//TODO: Report this error back to test tool.
//System.out.println("Error!");
}
}
Ответы
Ответ 1
Вам нужно слить выходные и потоки ошибок процесса, иначе он будет блокироваться, когда исполняемая программа выдает вывод.
Из Документация по процессам:
Поскольку некоторые собственные платформы предоставляют ограниченный размер буфера для стандартных потоков ввода и вывода, неспособность оперативно записать входной поток или прочитать выходной поток подпроцесса, может привести к блокировке подпроцесса и даже к взаимоблокировке.
Ответ 2
Считать (и закрыть) p.getInputStream()
и p.getErrorStream()
.
Например:
// com.google.common.io.CharStreams
CharStreams.toString(new InputStreamReader(p.getInputStream()));
CharStreams.toString(new InputStreamReader(p.getErrorStream()));
Ответ 3
Люди обычно попадают под обычную процедуру exec на Java. Я тоже это сообразил. Проблема в том, что процесс, который вы пытаетесь выполнить, может (в зависимости от множества вещей) сначала записывать в stdOut или stdErr. Если вы справитесь с ними в неправильном порядке, exec зависает. Чтобы правильно справляться с этим, вы должны создать 2 потока для чтения stdErr и stdOut одновременно. Sth вроде:
Process proc = Runtime.getRuntime().exec( cmd );
// handle process' stdout stream
Thread out = new StreamHandlerThread( stdOut, proc.getInputStream() );
out.start();
// handle process' stderr stream
Thread err = new StreamHandlerThread( stdErr, proc.getErrorStream() );
err.start();
exitVal = proc.waitFor(); // InterruptedException
...
out.join();
err.join();