Wait for process to finish before proceeding in Java - java

Essentially, I'm making a small program that's going to install some software, and then run some basic commands afterwards to prep that program. However, what is happening is that the program starts its install, and then immediately moves on to the following lines (registration, updates, etc). Of course, that can't happen until it's fully installed, so I'd like to find a way of waiting on the first process before running the second. For example,
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
//Wait here, I need to finish installing first!
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");

Call Process#waitFor(). Its Javadoc says:
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
Bonus: you get the exit value of the subprocess. So you can check whether it exited successfully with code 0, or whether an error occured (non-zero exit code).

you can use Process.waitFor() method
and the doc says
Causes the current thread to wait, if necessary, until the process
represented by this Process object has terminated. This method returns
immediately if the subprocess has already terminated. If the
subprocess has not yet terminated, the calling thread will be blocked
until the subprocess exits.

If you are running a system command that returns a very long response string, stdin buffer fills up and the process appears to hang. This happened to me with sqlldr. If that appears to be the case then just read from stdin as the process is running.
try {
ProcessBuilder pb = new ProcessBuilder("myCommand");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
StringBuffer response = new StringBuffer();
StringBuffer errorStr = new StringBuffer();
boolean alreadyWaited = false;
while (p.isAlive()) {
try {
if(alreadyWaited) {
// read the output from the command because
//if we don't then the buffers fill up and
//the command stops and doesn't return
String temp;
while ((temp = stdInput.readLine()) != null) {
response.append(temp);
}
String errTemp;
while ((errTemp = stdError.readLine()) != null) {
errorStr.append(errTemp);
}
}
Thread.sleep(1000);
alreadyWaited = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("Response is " + response);
logger.debug("Error is: " + errorStr);
}
} catch (IOException e) {
logger.error("Error running system command", e);
}

Include waitFor(). In your case, your code will look something like below.
Main.say("Installing...");
Process p1 = Runtime.getRuntime().exec(dir + "setup.exe /SILENT");
p1.waitFor()
Main.say("Registering...");
Process p2 = Runtime.getRuntime().exec(installDir + "program.exe /register aaaa-bbbb-cccc");
Main.say("Updating...");
Process p4 = Runtime.getRuntime().exec(installDir + "program.exe /update -silent");

Related

Why in order to execute an external code I have to re-run the main application? [duplicate]

I have the next code:
Process p = Runtime.getRuntime().exec(args);
and I want my program to wait for the Runtime.getRuntime().exec(args); to finish cause it last 2-3sec and then to continue.
Ideas?
use Process.waitFor():
Process p = Runtime.getRuntime().exec(args);
int status = p.waitFor();
From JavaDoc:
causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
Here is a sample code:
Process proc = Runtime.getRuntime().exec(ANonJava.exe#);
InputStream in = proc.getInputStream();
byte buff[] = new byte[1024];
int cbRead;
try {
while ((cbRead = in.read(buff)) != -1) {
// Use the output of the process...
}
} catch (IOException e) {
// Insert code to handle exceptions that occur
// when reading the process output
}
// No more output was available from the process, so...
// Ensure that the process completes
try {
proc.waitFor();
} catch (InterruptedException) {
// Handle exception that could occur when waiting
// for a spawned process to terminate
}
// Then examine the process exit code
if (proc.exitValue() == 1) {
// Use the exit value...
}
You can find more on this site: http://docs.rinet.ru/JWP/ch14.htm

Killing and reading the reply from Process performing Ping Comand

I'm creating a ping bot and have some problems reading data and kill a process when I make a infinite (-t) ping. The program dose what it is suppose to do. But it is still processing my pings in the background even when i close the program if the ping haven't completed.
This is the calculating part of an class that create a new window with a text area. It takes in the IP, Count of pings and Size.
if (countInput.equals("-1")){
countInput = "-t ";
} else {
countInput = "-n " + countInput;
}
String pingCmd = "ping " + countInput + " -l " + sizeInput + " " + ipInput;
Thread thread = new Thread(() -> {
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(pingCmd);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
final String outputLine = inputLine;
Platform.runLater(() -> textArea.appendText(outputLine + "\n"));
}
in.close();
} catch (IOException event) {
System.out.println(event);
}
});
thread.start();
}
I have tried to kill the Process and the Runtime with no luck.
I managed to add a button to the screen that i want to kill the ping command and return the result so i can print it to the Text-Area (like Ctrl-C in cmd).
Please tell me if you need any more of the program.
EDIT: What i have done:
I have tried to execute a thread/Runtime/Process killing when the stage is closed, also tried in a finally stage on the while loop. Nothing seemed to stop the ping it self.
I tried to create a BufferedWriter to the OutputStream() on the process and tried to send a "Ctrl-c"/killing command to the Cmd it self, with no luck.
So the best thing would be to modify the program to have a method for killing the CMD Process and return the end value (similar to use Ctrl-c in a CMD application ping), and be able to post that result in the text area.

Java Process getting stopped when run in background in linux

I have the below lines of code `
private String build(String command) {
ShellExecutable obj = new ShellExecutable();
String output = obj.executeCommand(command);
return output;
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
String[] cmdarray = { "bash", "-c", command };
try {
System.out.println("Before Command Execution in Bash..& command is: " + command);
p = Runtime.getRuntime().exec(cmdarray);
System.out.println("After Command execution in Bash & Before waitFor..");
p.waitFor();
System.out.println("After wait for: " + p.exitValue());
System.out.println("After wait for: " + p.isAlive());
System.out.println("After Command execution in Bash..");
if (p.getInputStream() != null) {
System.out.println("Input Stream is present");
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
}
if (p.getErrorStream() != null) {
System.out.println("Error Stream is present");
BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String errorLine = "";
while ((errorLine = errorReader.readLine()) != null) {
output.append(errorLine + "\n");
}
}
} catch (Exception e) {
System.out.println("Exception Occured:" + e.getLocalizedMessage() + "Message is:" + e.getMessage());
}
return output.toString();
}
`
I am trying to run this as a foreground process in Linux, it works brilliant. But, when I try to run the same as a background process using nohup the service is stopping. I found similar kind of issues on stack overflow but I couldn't't figure out the solution for this particular case.
For the above code the output I am getting is as follows:
Called listApps...
Before Command Execution in Bash..& command is: xxxxxxxx
After Command execution in Bash & Before waitFor..
[1]+ Stopped nohup java -jar ReadingShell-0.0.1-SNAPSHOT-jar-with-dependencies.jar
I am not getting any exception in the above code, its just stopping without displaying anything. But, when I try displaying p.exitValue() before p.waitFor(), I printed the stacktrace, it is as follows,
java.lang.IllegalThreadStateException: process hasn't exited
at java.lang.UNIXProcess.exitValue(UNIXProcess.java:424)
at org.monitoring.ReadingShell.ShellExecutable.executeCommand(ShellExecutable.java:101)
at org.monitoring.ReadingShell.ShellExecutable.build(ShellExecutable.java:82)
at org.monitoring.ReadingShell.ShellExecutable.getApplicationList(ShellExecutable.java:46)
at spark.RouteImpl$1.handle(RouteImpl.java:72)
at spark.http.matching.Routes.execute(Routes.java:61)
at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:130)
at spark.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:50)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1568)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:126)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
at java.lang.Thread.run(Thread.java:745)
You have to read the output streams before you wait for the end of the child process. Otherwise if the child writes more than a buffer's worth (512B? 4K?) to one of the streams, it will be made to wait until something reads and empties the buffer. But this won't happen since your parent process is already executing waitFor().
So, you have to create two threads to read these output streams, and start them before calling waitFor().
By reading the opendjk source code for UnixProcess we see the following
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
wait();
}
return exitcode;
}
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn't exited");
}
return exitcode;
}
hasExited is never reset in the file so logically exitValue() cannot throw after waitFor() is called. (Unless it is interrupted)
Something must be different when you run it than in the code your question has. A minimal complete example class displaying the issue so we can reproduce it would help.
I had a similar issue. The jar file would be fine if ran in the foreground, but stop when executed in nohup with the process/job going into Stopped.
Figured out that nohup will go into stopped if any of the inner scripts try to read from the terminal - see the post here
I used tmux to solve this as suggested by this thread

Run a process asynchronously and read from stdout and stderr

I have some code that runs a process and reads from the stdout and stderr asynchronously and then handles when the process completes. It looks something like this:
Process process = builder.start();
Thread outThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
// Read stream here
} catch (Exception e) {
}
});
Thread errThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
// Read stream here
} catch (Exception e) {
}
});
outThread.start();
errThread.start();
new Thread(() -> {
int exitCode = -1;
try {
exitCode = process.waitFor();
outThread.join();
errThread.join();
} catch (Exception e) {
}
// Process completed and read all stdout and stderr here
}).start();
My issue is with the fact that I am using 3 threads to achieve this asynchronous "run-and-get-output" task - I don't know why, but I feel it doesn't feel right using 3 threads. I could allocate the threads out of a thread pool, but that would still be blocking those threads.
Is there anything I can do, maybe with NIO, to reduce this to fewer (1?) thread? Anything I can think of will be constantly spinning a thread (unless I add a few sleeps), which I don't really want to do either...
NOTE: I do need to read as I go (rather than when the process has stopped) and I do need to separate stdin from stderr so can't do a redirect.
Since you've specified that you need to read the output as you go, there is no non-multi-threaded solution.
You can reduce the number of threads to one beyond your main thread though:
Process process = builder.start();
Thread errThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
// Read stream here
} catch (Exception e) {
}
});
errThread.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
// Read stream here
} catch (Exception e) {
}
// we got an end of file, so there can't be any more input. Now we need to wait for stderr/process exit.
int exitCode = -1;
try {
exitCode = process.waitFor();
errThread.join();
} catch (Exception e) {
}
// Process completed
If you truely don't need to deal with the error/output until after the process ends, you can simplify it a bit and only use your main thread like this:
File stderrFile = File.createTempFile("tmpErr", "out");
File stdoutFile = File.createTempFile("tmpStd", "out");
try {
ProcessBuilder builder = new ProcessBuilder("ls /tmp");
Process p = builder.start();
int exitCode = -1;
boolean done = false;
while (!done) {
try {
exitCode = p.waitFor();
done = true;
} catch (InterruptedException ie) {
System.out.println("Interrupted waiting for process to exit.");
}
}
BufferedReader err = new BufferedReader(new FileReader(stderrFile));
BufferedReader in = new BufferedReader(new FileReader(stdoutFile));
....
} finally {
stderrFile.delete();
stdoutFile.delete();
}
This is probably not a good idea if you generate a lot of output from the process you are calling as it could run out of disk space... but it'll likely be slightly faster since it doesn't have to spin up another Thread.
Assuming you don't mind the input and error streams to be merged, you could only use one thread with:
builder.redirectErrorStream(true); //merge input and error streams
Process process = builder.start();
Thread singleThread = new Thread(() -> {
int exitCode = -1;
//read from the merged stream
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
//read until the stream is exhausted, meaning the process has terminated
while ((line = reader.readLine()) != null) {
System.out.println(line); //use the output here
}
//get the exit code if required
exitCode = process.waitFor();
} catch (Exception e) { }
}).start();
Have a look at the ExecHelper from OstermillerUtils.
The idea is that the thread waiting for the process to complete, does not just wait but reads input from stdout and stderr if there is input available and regurarly checks if the process has finished.
If you do not do any heavy processing with the input from stdout and stderr, you might not need an extra thread to handle the input. Just copy ExecHelper and add some extra functions/methods to process any new input. I've done this before to show the process output while the process is running, it is not difficult to do (but I lost the source code).
If you do need a separate thread for processing the input, make sure to synchronize the output and error StringBuffers when these buffers are updated or read.
Another thing you might want to consider is adding an abort time-out. It is a little bit harder to implement but was very valuable to me: if a process takes too much time, the process gets destroyed which in turn ensures nothing remains hanging. You can find an old (outdated?) example this gist.
You'll have to compromise. Here are your options:
A. You can do it with 2 threads (instead of 3):
First thread:
read from stdout until readline returns null
call Process.waitFor()
join Thread#2
Second thread:
reads from stderr until readline returns null
B. Merge streams and use Debian's annotate-output to discriminate the 2 streams
http://manpages.debian.org/cgi-bin/man.cgi?query=annotate-output&sektion=1
C. If it's a short-living process just wait for the end of it
D. If it's a long-living process then you can spin between readers with some sleep in between.

Log4j hanging my application

Im trying to get console output from an external application in my application. When i call the externall app from my code it hangs with the message:
Configuring logging...
Configuring log4j from: C:\GPAT\log4j.cfg
and nothing happens. I searched through internet and it seems that it might be thread issue. But i cant modify this external application and i must go through log4j. I read the external app like this:
StringBuffer output = new StringBuffer();
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(GSATCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
System.out.println("Test running...");
String line = null;
while ((line = input.readLine()) != null) {
System.out.println(line); // Writes the test output to console
output.append(line); output.append("\n");
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
System.out.println("Test successfully executed");
} catch (Throwable t) {
t.printStackTrace();
}
Thanks for reading.
You need to consume both stdout and stderr from a spawned process in separate threads, to prevent blocking behaviour (your spawned process will write to buffers, and block if those buffers aren't being emptied by your consuming process).
See the 2nd paragraph of this answer for more details and a link to a suitable fix.

Categories

Resources