Wait for terminal result before proceeding code - java

I'm posting requests to a Servlet. In that Servlet, I have a code which executes terminal and running some commands there. I want my code to wait the terminal process before it response my requests. How can I manage it?
Below you can see my code:
Process send = Runtime.getRuntime().exec(new String[] {"sh", "-c", fileNameShort + ".jar /tmp/"+ fileNameShort +".class; /home/ubuntu/android-x86.rund.sh -cp /tmp/"+ fileNameShort +".jar " + fileNameShort});

You can use Process#waitFor():
System.out.println("Waiting for process...");
send.waitFor();

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Waiting for process completion..");
int exitValue = process.waitFor();
System.out.println("Process is done..");
Method is waitFor() enables you to wait for the process to complete.
ErrorStream and InoutStream enables to get the output & error of the execution respectively
exitValue indicates manner of completion of the process. exitValue 0 is for normal completion

Related

Get stdInput from a java Process before the process terminates

So I am trying to run a python script and want to obtain the stdInput from the script so I can use it. I have noticed the stdInput will hang until the process has finished.
Python script:
import time
counter = 1
while True:
print(f'{counter} hello')
counter += 1
time.sleep(1)
Java code:
public class Main {
public static void main(String[] args) throws IOException {
Runtime rt = Runtime.getRuntime();
String[] commands = {"python3", "/Users/nathanevans/Desktop/Education/Computing/Programming/Java/getting script output/src/python/main.py"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
System.out.println("stdOuput of the command");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("stdError of the command");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
}
Nothing is printed from the java application until the Process is terminated but in this case when I terminate the java application.
How would I obtain the stdInput as it is written by the script?
In order to get Python output immediately you'd need to turn off Python output buffering - that is covered here
This may fix your problem but you may run into second issue because you are reading STD IN / OUT in one thread. If STDERR buffer fills before you read to end of STDIN it will block the process. The solution then is to read STD/IN/ERR in separate threads or use ProcessBuilder which allows redirect to files or redirect STDERR to STDOUT:
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectOutput(outfile);
pb.redirectError(errfile);
//or
pb.redirectErrorStream(true);
Process p = pb.start();

Wait until a command ends

There's a command, that runs an exe, it makes an output and when this command ends, then I should run the upload(); method.
run.command(exe_path, txt_path);
run.start();
TimeUnit.SECONDS.sleep(20);
upload();
How can I replace the static sleep method?
Using a ProcessBuilder, you should be able to call Process.waitFor() to wait for the command to finish.
Process p = new ProcessBuilder("foo.exe", "arg1").start();
// handle any input and output
InputStream stdout = p.getInputStream();
OutputStream stdin = p.getOutputStream();
InputStream stderr = p.getErrorStream();
int ret = p.waitFor(); // <- wait for exit

How to check , if a service is running on linux machine using java code

I want to check the status of a service running on linux.
On machine i use the command "systemctl is-active service-name" to check the status of services.And it gives the output as active/inactive(when service is running/not running).
I want to get the status of the service in java. how i do that?
I tried this..
String SERVER_STATUS = new String[]{SUDO_COMMAND, "systemctl is-active vpnd.service"};
try {
final Process process = new ProcessBuilder(SERVER_STATUS).start();
process.waitFor();
InputStream in = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
System.out.println("status: " + br.readLine());
} catch (IOException | InterruptedException e) {}
But br.readLine() is coming as null.
Two things I found
Please split the command
Use absolute path of the command
Example
String SERVER_STATUS[] = new String[]{"sudo", "/usr/bin/systemctl", "is-active", "java-linux-sample.service"};
try {
final Process process = new ProcessBuilder(SERVER_STATUS).redirectErrorStream(true).start();
process.waitFor();
InputStream in = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//String line = null;
System.out.println("status: " + br.readLine());
} catch (Exception e)
{
e.printStackTrace();
}
I assume this is because there is an error running the application. Does your java process have permissions to run systemctl? Is it failing to find the service?
I would advise that you also check the exit value and then check the appropriate error stream.
For example on a Windows machine if I make a mistake in the cmd command
String[] SERVER_STATUS_COMMAND = {"cmd.exe", "/c", "echoo foobar"};
Your program will write
status: null
If we tweak the application slightly we can have the error stream redirected to the output:
final Process process = new ProcessBuilder(SERVER_STATUS_COMMAND)
.redirectErrorStream(true)
.start();
then the program would write:
status: 'echoo' is not recognized as an internal or external command,

Running Shell Script at the command line

I am running a Shell script using cygwin.
Process p;
InputStream in;
BufferedReader br;
String line;
String cmd;
cmd = "D:/cygwin/bin/bash -c '/bin/test/app.sh" +three_ltr_id+""+mon_code+""+year_code+""+part_no+""+version_no+" '";
System.out.println("EXECUTING: " + cmd);
p = Runtime.getRuntime().exec(cmd);
in = p.getInputStream();
p.waitFor();
br = new BufferedReader(new InputStreamReader(in));
System.out.println("OUT:");
while ((line = br.readLine()) != null) {
System.out.println(line);
System.out.println("SCRIPT EXECUTED PROPERLY");
This is showing EXECUTING and the commands that I passed to script.
If I go inside D:/cygwin/bin/test folder and run the same command it works.
When I run the same command at the command line it won't work.
You need to start reading the input from p.getInputStream() immediately, and keep reading it until there is no more. On Windows, there is little or no buffer in the pipe, and the process will hang once it is filled.
Same is true for the error stream. You could launch threads to read both streams, or there's an option in the way you launch processes to combine regular output and errors, and you can just read them from there.

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

Categories

Resources