I am creating Processes using ProcessBuilder in my Java Application. The created process executes some FFMPEG commands which actually copy the RTSP streams in specified destination media file.
ProcessBuilder builder = new ProcessBuilder("ffmpeg", "-i", RTSP_URL, "-f", fileFormat, destFilePath);
Process processToExecute = builder.start();
I want to close the process before it completes its execution. So, If I run this FFMPEG command directly in windows CMD and then press 'CTRL+C' after 5 seconds then process get terminates with status '2'. And I can play the media file created so far.
So, If I do the same operation in my Java Application using:
process.destroy(); //I call this method after 5 sec
I get the status code '1' which means abnormal termination. I get the status by the following way:
processToExecute.destroy();
processToExecute.exitValue(); //This return me status '1'
And I can't play the media file and I think this is due to the abnormal termination of the process.
So how I can terminate the process created using ProcessBuilder in the same way we do in CMD with (CTRL+C) so that I may play the created media file ?
I want to terminate process (created using ProcessBuilder) in Java Application with status code of '2' that I get when I terminate process using CMD.
EDIT#01: --- Sharing Findings
So, when I try to delete that file once app terminates, I get the following error:
The Action Can't be Performed Because File is Opened in FFMPEG.exe
Which means that process is not terminating the command it is executing. That command still has occupied this file that's why I am not getting able to play it. Process gets terminate when I call:
processToExecute.destroy();
But, the task it is performing (that is execution of a command) is still active. Strange!!!!
EDIT#02: Sharing Ultimate Reason
Actually If I directly press 'CTRL+C' or 'q' in cmd when process is running then it terminates the process successfully and this process is no more visible in the currently executing processes lists.
And Programatically when I call method:
cmd> processToExecute.destroy();
It terminates the process but when I see the list of currently executing processes I can still see them over there.
And same scenario exists If I try to terminate this process using 'taskkill' or 'kill' command in another CMD by specifying their's name or pid that still process terminates abnormally.
P.S. I use the following command to see the running processes:
tasklist
So from this it proves that destroy() method from Application and 'taskkill or kill' command from another CMD is not terminating the process normally that pressing 'CTRL+C' and 'q' does.
Maybe try...
builder.inheritIO();
System.exit(2);
Or you could try to write to the stdin of the process...
process.getInputStream().write(exitCode);
Related
I am trying to write a shell script that records the exit status of a Java program. The script should simple launch a Java app, and if the Java app doesn't run for some reason, the shell script should detect this and take mitigating measures.
The following is my script:
#!/bin/bash
APPNAME="app"
APPFOLDER=$APPNAME
BACKUP=$APPFOLDER"-backup"
LOGFOLDER=$APPNAME"-log"
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
wait
STATUS=$?
if [ $STATUS -eq 0 ]
then
echo "Deployment successful" $?
else
echo "Deployment failed: ... derp" $?
fi
I have written a simple Swing GUI that runs fine. However, I packaged it as a jar without specifying an entry point. Hence, I should get the error:
Exception in thread "main" java.lang.NoClassDefFoundError: Demo$1
and the script should detect that the application failed to start.
All of this works FINE until I try to launch the Java app in the background using &. Whenever I do this:
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
the script always returns a 0 for $?, indicating it passed.
What am I doing wrong? Is there a better way to go about detecting if the app failed to launch?
Thanks!
Wait! you are recording the exit status of wait!
This is why you see unexpected result with your script. Look at the man page for bash (wait is a bash built-in so you need to read the bash manual):
wait [-n] [n ...]
Wait for each specified child process and return its termination status. Each n may be a process ID... If n is not given, all currently active child processes are waited for, and the return status is zero(!). If n specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process ... waited for.
Since you have not specified the n (child pid to wait for) the return status is zero as per spec.
Another question is: do you really need a wait.
If you don't need to run your app in the background then just do this:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log"
STATUS=$?
the only difference is that i removed unnecessary wait.
If for some reason you need to run your app in the background and read exit status later, then you need wait for that pid. To find out the pid of the last background process use special variable $!:
echo "Starting new app"
java -jar $APPFOLDER/$APPNAME*.jar > $LOGFOLDER/$APPNAME"_$(date+%Y.%m.%d.%s).log" &
CHILDPID=$!
wait "${CHILDPID}"
STATUS=$?
Here's short example of how it works:
user#s:~$ (sleep 10 && exit 42)&
[1] 27792
user#s:~$ wait "$!"
[1]+ Exit 42 ( sleep 10 && exit 42 )
user#s:~$ echo $?
42
What I want to know is if the app fails on startup or not. In the case of the former, my script would bag up the app and role out the previous version.
This purpose is too vague. Are you only interested in missing dependencies?
I don't think there is an easy way to distinguish between JRE non-zero exit code and you java application non-zero exit-code.
I can imagine lots of other reasons to unroll deployment many of which do not lead to non-zero exit code.
I created a java library which elevates a java application run from a JAR with administrator privileges. On linux this works fine, and if I exit the application by hitting CTRL-C in linux the elevated application started with sudo stops as expected. On windows this is not the behavior. When I exit with CTRL-C the administrator process keeps running and I need to manually stop it from the task manager.
See the code # https://github.com/rritoch/super-user-application/blob/master/src/main/java/com/vnetpublishing/java/suapp/WinSudo.java
How can I get the process which was created using JPA/ShellExecuteEx to automatically terminate if the calling process dies, such as when the user exits by typing CTRL-C?
As a temporary solution to this problem I have added a shutdown hook to end the child process. This is not an ideal solution because if the parent process is forcibly exited the shutdownHook won't be run and the child process continues running, but this does handle the CTRL-C initiated exit.
final HANDLE childProcess = execInfo.hProcess;
Thread shutdownHook = new Thread() {
#Override
public void run() {
System.out.println("Terminating child process");
Kernel32.INSTANCE.TerminateProcess(childProcess, 0);
Kernel32X.INSTANCE.CloseHandle(childProcess);
Kernel32X.INSTANCE.CloseHandle(hJob);
}
};
Runtime.getRuntime().addShutdownHook(shutdownHook);
When a tool developed in Java is launched, it creates temporary files in a folder. If terminated properly those files are getting deleted , but if terminated with kill or pkill commands those files are not getting deleted. Is there any way to send a signal to java process to delete those files before terminating the process?
Please help me to solve this issue.
Thanks in Advance
It seems like File.deleteOnExit() is fragile when it comes to process termination. In contrast, using the NIO API with the StandardOpenOption.DELETE_ON_CLOSE seems to be more reliable even though it’s specification only says: “If the close method is not invoked then a best effort attempt is made to delete the file when the Java virtual machine terminates”
E.g. when running the following program:
File f1=File.createTempFile("deleteOnExit", ".tmp");
f1.deleteOnExit();
final Path f2 = Files.createTempFile("deleteOnClose", ".tmp");
FileChannel ch = FileChannel.open(f2, StandardOpenOption.DELETE_ON_CLOSE);
System.out.println(f1);
System.out.println(f2);
LockSupport.parkNanos(Long.MAX_VALUE);
// the following statement is never reached, but it’s here to avoid
// early cleanup of the channel by garbage collector
ch.close();
and killing the process while it hangs at parkNanos, the JVM leaves the deleteOnExit tmp file while correctly deleting the deleteOnClose file on my machine.
You can add shutdown hook and clean everything you need explicitly.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
//put your shutdown code here
}
});
This is actually the same what java.io.File#deleteOnExit does for you.
I'm calling a batch that calls another "jar" that send messages to a server and write a report in the end, the time of execution varies from day to day, and the size of the input used in the batch influences to.
I would like to monitor when the batch auto-closes so I can make my original jar to read the log...
I'm calling it like this
Process prog = Runtime.getRuntime().exec("cmd /c start C:\\chamados\\corretorRota\\VerificarNumero.bat");
and the batch:
cd C:\chamados\corretorRota
java -jar BatchDispatcher.jar brux0043 5873 gcpn-rota.txt > resultado.txt
exit
(FYI brux0043 = server, 5873 = port gcpn-rota = input file writed previously)
(the batch keeps open util the end of the called jar)
You can write a log with the timestamp whenever the batch file was executed.
put this line in your batch file
echo. |time |find "current" >> log
this will then write the timestamp when the batch file was run to the log. Also, there should be a file called log before executing the batch file.
Now your java program can monitor the log and know how many times and when the batch file was executed.
You should use
prog.waitFor()
to wait for the process to finish execution.
I am using the following code to execute a batch file:
java.lang.Runtime rt = java.lang.Runtime.getRuntime();
Process pr = rt.exec("MyBatch.bat");
My batch file takes some time to execute. I want my servlet process to wait till the batch file execution completes. I would like to close the command prompt after executing the batch file. How can I do this?
Use Process.waitFor() to have your thread wait for the completion of the batch file's execution.
java.lang.Runtime rt = java.lang.Runtime.getRuntime();
Process pr = rt.exec("MyBatch.bat");
pr.waitFor();
You may also want to look at using ProcessBuilder instead of Runtime.getRuntime().exec() if you need access to the console's output and/or input.
The most straightforward way would be to use the .waitFor() method of the process object you created: pr.waitFor();
This is a blocking call, meaning that no other code will be executed before this call returns.
As others have said, you can use Process.waitFor(). However, before doing this you must start another thread that continually reads the contents of the process's output and error streams; otherwise if there is an error that causes lots of output your application will hang.
Alternatively you can have your batch file redirect output and errors to a file.
Look at the documentation for the Process class.
You can trace the InputStreamReader from your process.
and trace for the lines inside bat file.
When you are EOF then exit from command line
see the Example or full source code.
click here