Stop JVM windows process if caller of ShellExecuteEx dies - java

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

Related

Restart Tomcat with Java

I need to restart the tomcat from Java code.
For eg, if a query is not executed for a certain time Period then it will restart the tomcat automatically.
I have tried the following shutdown and startup code, but when we shutdown the tomcat then the java code will not run and tomcat not started.
Note :- I am running this code from a application and restarting the same tomact which the same application is using.
Following the code
try {
PreparedStatement.setQueryTimeout(10);
rs = PreparedStatement.executeQuery();
} catch (SQLException ex) {
System.out.println("IN CATCH BLOCK FOR THE REFRESH INVOICE");
String shutcommand = "killall java";
Process shutchild = Runtime.getRuntime().exec(shutcommand);
System.out.println("JAVA PROCESS KILLED");
String locationCommand = "cd /root/cluster/tomcat6/bin";
Process locationChild = Runtime.getRuntime().exec(locationCommand);
String strtcommand = "./startup.sh";
Process strtchild = Runtime.getRuntime().exec(strtcommand);
}
Killing tomcat after SQLException this is not good idea to handle this exception. Probably the problem is on database site.
But if you are sure, that it is what you need you can kill this java proces in this section, but to run tomcat you should use for example bash and cron. Why? Beacues after killing your executing code will stop, so you don't achieve the line to start tomcat.
How to check tomcat: Is Tomcat running?
TL;DR
File binaryDir = new File(System.getProperty("catalina.home") + File.separator + "bin");
String restartCommand = "\"shutdown.bat & ping 0.0.0.0 -n 4 & C:\\WINDOWS\\system32\\net start Tomcat8\"";
new ProcessBuilder("cmd", "/c", restartCommand).directory(binaryDir).start();
Survive
Creating new process will survive JVM shutdown. If you combine commands in one line
it should work fine according to my tests and this.
shutdown.bat
You need to use shutdown.bat instead stopping windows service because it often fails on Windows with message Cannot stop service Apache Tomcat...
ping 0.0.0.0 -n 4
You need to wait some time after shutdown otherwise you will get Service is already starting. Try again later error message. Also note I use ping instead timeout because it causes problems on some systems.
C:\WINDOWS\system32\net start Tomcat8
I'm starting windows service because invoking startup.bat won't work for me. Also remember to replace Tomcat8 if you using different tomcat or custom service name for example Tomcat7
Redirect I/O
Don't redirect input or output of process instance or command will shutdown with JVM, and Tomcat won't start.
You can execute this native command using java
String command = "c:\program files\tomcat\bin\startup.bat";//for linux use .sh
Process child = Runtime.getRuntime().exec(command);
You should consider using ProcessBuilder instead of Runtime exec. Also, you should split all the arguments when you want to execute a command.
I suggest this :
ProcessBuilder shutcommand = new ProcessBuilder("killall", "java");
Process shutchild = shutcommand.start();
System.out.println("JAVA PROCESS KILLED");
ProcessBuilder strtcommand = new ProcessBuilder("/root/cluster/tomcat6/bin/startup.sh", "java");
Process strtchild = strtcommand.start();

Install4j silent upgrade without closing running application

With Install4j I am trying to do a silent upgrade without shutting down the app it is upgrading. I am receiving the following error "The application is running. Please close all instances and run this installer again." Is there any way around this. I am calling the installer from my code with the following code
String [] args = new String[1];
args[0] = "-q";
ApplicationLauncher.launchApplicationInProcess("6661", args, new ApplicationLauncher.Callback() {
#Override
public void exited(int i) {
logger.info("The installer exited");
}
#Override
public void prepareShutdown() {
logger.info("Calling the prepareShutowon fuction");
}
}, ApplicationLauncher.WindowMode.DIALOG, null);
This does not seem to work. The upgrade only works if I close the application which I do not want do.
With Install4j I am trying to do a silent upgrade without shutting down the app it is upgrading.
That is not possible, on Windows JAR files and executables cannot be overwritten if they are in use by a running executable.
In the updater, you need a "Shut down calling launcher" action just before the new installer is started. You have probably removed that action from the default configuration. The new installer can then restart the application automatically with an "Execute launcher" action on the "Finish" screen.

How to Terminate a Process Normally Created using ProcessBuilder

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

Java process when terminated abnormally with Kill or pkill unix comamnds doesnot delete temporary files

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.

Silk Test Open Agent locks trace file

We have testing java application.
This application performs different types of testing. On one step it starts Silk Test.
This application writes a lot of traces using System.out.println.
We redirect this traces to file app.trace in our cmd file.
Something like:
java com.test.app > app.trace
When this testing application stops it is not possible to remove app.trace file because it is locked by Silk Test Open Agent.
I do not understand how this application can lock our trace file.
We do not start this application directly from our code.
We use Silk4J lib to start Silk Test.
As far as I know this library connects to Silk Test windows service which starts Silk Test Open Agent.
Does anyone can explain me - why and how Silk Test Open Agent locks our trace file?
The cause of this is because Open Agent does not close down when the test finishes. I just kill Open Agent when my suite is done.
public class ProcessKill {
public void killOpenAgent () {
kill ("openAgent.exe");
}
public void kill (String processName) {
String command = "cmd /c taskkill";
String parameter = " /F /IM " + processName;
System.out.println("Killing process: " + processName);
try {
Runtime.getRuntime().exec(command + parameter);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am using TestNG to control my tests, so I just call this from the #AfterSuite method to always make sure that Open Agent is killed after each run. This also helps to release the licence.
The reason is that child processes inherit the open files of their parents, in this case the redirected output stream to the file. This makes sense, as is allows you to also capture the output of those child processes.
However, otherwise than David Genrich suggested in his answer, I would not forcefully kill the agent as it may then fail to release some resources and clean up properly. This might lead to follow-up problems.
I suggest separately starting the OpenAgent before you run your tests so it's not a child process of the test runner.

Categories