Java Runtime.exec()
I can run this command from the command line without any problem (the validation script executes):
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
and from java if I leave off the URL parameter and just do:
String[] args1 = {"c:/Python27/python", "../feedvalidator/feedvalidator/src/demo.py" };
Runtime r = Runtime.getRuntime();
Process p = r.exec(args1);
it works fine. If I use certain URLs for a parameter such as:
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"};
it also works fine.
But if I use this particular URL https://das.dynalias.org:8080/das_core/das/2.16.840.1.113883.4.349/1012581676V377802/otherAdminData/careCoordinators, then the script just hangs (java waits for the process to finish). I’m not sure why it works from the command line for that URL but not from a java program. I tried adding quotes to surround the URL parameter but that didn’t work either. I don’t see any character in the URL that I think need to be escaped.
Full Code:
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!");
}
}
You need to drain the output and error streams of the process, or else it will block when the executed program produces output.
From the Process documentation:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
Read (and close) p.getInputStream()
and p.getErrorStream()
.
For example:
// com.google.common.io.CharStreams
CharStreams.toString(new InputStreamReader(p.getInputStream()));
CharStreams.toString(new InputStreamReader(p.getErrorStream()));
People usually got caught by exec routine hangs in Java. I was cought by that once too. The problem is that the process you are trying to execute may (depending on lot of things) either first write to stdOut or stdErr. If you handle them in wrong order exec will hang. To handle this properly always you must create 2 threads to read stdErr and stdOut simulteneously. Sth like:
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();