how to avoid getRuntime.exec() to block when reading inputStream? - java

I call a class which is located somewhere in a jar file (using java -classpath path/file.jar classname) within my java code.
My problem is when the command genKOSCommand is invalid the call to input.readLine() will block the program. So I added input.ready() to hope avoiding blocking. When I debug the program it's ok. Seem to work. But when don't run it in debug the buffer is never ready.
// Execute a command with an argument that contains a space
String[] genKOSCommand = new String[] {
"java",
"-classpath",
Config.XDSI_TEST_KIT_HOME + "/xdsitest/lib/xdsitest.jar;"
+ Config.XDSI_TEST_KIT_HOME + "/xdsitest/classes",
"ca.etsmtl.ihe.xdsitest.docsource.SimplePublisher", "-k",
"C:/Softmedical/Viewer_Test/xdsi-testkit-2.0.4/xdsihome/usr/data/image14.dcm" };
Process child = Runtime.getRuntime().exec(genKOSCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(
child.getInputStream()), 13107200);
String line = null;
if (input.ready()) {
while ((line = input.readLine()) != null) {
System.out.println(line);
}
try {
child.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Any advice on how to detect problems with the executed command?
Thank you.

You need to wait in a loop for the BufferedReader to be ready.
while (input.ready() == false) { /* intentional empty space here */ }
while ((line = input.readLine()) != null) {
System.out.println(line);
}
/* rest of code follows */

Related

wkhtmltopdf called from java getting hanged

We are the using the following code to generate PDFs using wkhtmltopdf
public class SystemUtils{
public String executeCommand(String... command) {
Process process = null;
try {
// Using redirectErrorStream as true. Otherwise we have to read both process.getInputStream() and
// process.getErrorStream() in order to not exhaust the stream buffer.
process = new ProcessBuilder(command).redirectErrorStream(true).start();
process.waitFor();
StringBuilder outputBuilder = new StringBuilder();
try(BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = stdError.readLine()) != null) {
outputBuilder.append(line).append(StringConstants.CARRIAGE_RETURN);
}
}
return outputBuilder.toString();
} catch (IOException | InterruptedException e) {
String exceptionMsg = "Error while executing command '"+command+"' : ";
LOGGER.error(exceptionMsg, e);
throw new AppException(exceptionMsg, e);
} finally {
if(process != null){
process.destroy();
}
}
}
public static void main(String[] args){
SystemUtils systemUtils = new SystemUtils();
String[] array = {"wkhtmltopdf", "/home/pgullapalli/Desktop/testsimilar1.html", "/home/pgullapalli/Desktop/test.pdf"};
systemUtils.executeCommand(array);
}
}
This works absolutely fine for smaller size files. But when we try to process a larger file, it is indefinitely waiting without any response. I am not sure what is going wrong? Can someone please suggest?
I moved process.waitFor() before the return statement and it started working. This probably could be happening as the output buffer has filled and we are not reading from it. After moving the process.waitFor after the stream reading, things are working fine.

Joining a thread / process in Java after some time - Java

I have the following method, which executes a command as a process and returns the ouput:
public String execute(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return output.toString();
}
This code is great whenever the command returns, however for continuing running processes such as top this may never return. The code does not need to keep running continuously. It only needs to capture a snapshot, or it could time out after some time, such as 3 seconds. How can I accomplish that?
Process has a method waitFor. It can be used to force a timeout. For example:
if ((p = Runtime.getRuntime().exec(execPath)) != null) && !p.waitFor(TIMEOUT_CONSTANT, TimeUnit.SECONDS)) {
p.destroyForcibly();
}

java: parse output of execute command

i am running jdk on windows 7. I try to run a external software (pocketsphinx_continous.exe) within my java application. The software runs permanently (pocketsphinx_continous.exe) and prints some output to the console which i like to read by my java application.
if i run "pocketsphinx_continous.exe" with some params from the commandline all works well and i see the output from the software. After killing the process, i try to run it within my java application. But java print no output to the console.
This is my code:
public void start(){
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"D:/cmusphinx/pocketsphinx/bin/Release/x64/pocketsphinx_continuous.exe", "-hmm", "d:/cmusphinx/pocketsphinx/model/en-us/en-us", "-lm", "d:/cmusphinx/pocketsphinx/model/en-us/en-us.lm.bin", "-dict", "d:/cmusphinx/pocketsphinx/model/en-us/cmudict-en-us.dict", "-samprate", "16000/8000/48000", "-inmic", "yes"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Java will only print "Here is the standard output of the command:" and nothing more. But it wont crash, its still running without any errors. It seems to me java will wait until the executed command is finished until it prints anything. But the software will run permanently and print some times new results ...
Any ideas?
Best regards
Mike
I suggest you do the following:
Process p = null;
ProcessBuilder b = new ProcessBuilder("D:/cmusphinx/pocketsphinx/bin/Release/x64/pocketsphinx_continuous.exe -hmm d:/cmusphinx/pocketsphinx/model/en-us/en-us -lm d:/cmusphinx/pocketsphinx/model/en-us/en-us.lm.bin -dict d:/cmusphinx/pocketsphinx/model/en-us/cmudict-en-us.dict -samprate 16000/8000/48000 -inmic yes");
try {
p = b.start();
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader output = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
try {
while ( (line = output.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
Using ProcessBuilder you don't have to separate parameters. Just copy the whole command in a String.

Call Apache Cordova CLI from Java

I want the Apache Cordova CLI being called by a Java Process but unfortunatly the Java Process doesn't wait until it is finished.
This is, how i call it:
StringBuffer sb = null;
String cmd = "cd /location/generated && cordova create MyNewApp"
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
sb = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I've seen many solutions, that say "waitFor()" will do the trick but unfortunatly not for me. I've already tried to always read and compare the last line of code generated by the cordova cmd and finish afterwards, but this is not a good approach. Do you have any suggestions?
Resolved it:
Cmd looks like this "cordova create /path/to/generated/app/ Hello World"
Be aware, the path has to exist before the cmd is beeing called

how to get error message when excuting java command?

I call a class which is located somewhere in a jar file (using java -classpath path/file.jar classname) within my java code.
This work well but only if the command is well formed. If I make a mistake the getRuntime().exect(command) just doesn't say anything. Bellow I have the working command invocation. I would like to get the error message when the command doesn't work. If I make a mistake in a cmd (windows) I get a proper error and I can fix it. But not within my java application.
I left a 'if(input.ready())' since if I don't the program freezes when the command line is incorrect. This happens when executing 'input.readLine()'.
// Execute a command with an argument that contains a space
String[] genKOSCommand = new String[] {
"java",
"-classpath",
Config.XDSI_TEST_KIT_HOME + "/xdsitest/lib/xdsitest.jar;"
+ Config.XDSI_TEST_KIT_HOME + "/xdsitest/classes",
"ca.etsmtl.ihe.xdsitest.docsource.SimplePublisher", "-k",
"C:/Softmedical/Viewer_Test/xdsi-testkit-2.0.4/xdsihome/usr/data/image14.dcm" };
Process child = Runtime.getRuntime().exec(genKOSCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(
child.getInputStream()), 13107200);
String line = null;
if (input.ready()) {
while ((line = input.readLine()) != null) {
System.out.println(line);
}
try {
child.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Have any advice on how to get an error from the executed command?
Thank you
By using getErrorStream:
BufferedReader errinput = new BufferedReader(new InputStreamReader(
child.getErrorStream()));
When processing the input from the different streams, it is better to do it in a different thread (since those calls (readLine etc.) are blocking calls.
Here's a bit more complete piece of code to print out errors received upon running some command via Process/Runtime:
final String command = "/bin/bash -c cat foo.txt | some.app";
Process p;
try {
p = Runtime.getRuntime().exec(command);
} catch (final IOException e) {
e.printStackTrace();
}
//Wait to get exit value
try {
p.waitFor();
final int exitValue = p.waitFor();
if (exitValue == 0)
System.out.println("Successfully executed the command: " + command);
else {
System.out.println("Failed to execute the following command: " + command + " due to the following error(s):");
try (final BufferedReader b = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line;
if ((line = b.readLine()) != null)
System.out.println(line);
} catch (final IOException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Isn't Process.getErrorStream what you want?

Categories