Shutdown hook doesn't work in Eclipse [duplicate] - java

This question already has answers here:
How to get shutdown hook to execute on a process launched from Eclipse
(7 answers)
Closed 5 years ago.
I have added a shutdown hook via:
Runtime.getRuntime().addShutdownHook(myShutdownHook);
It works fine normally, but not when I click the red stop button in Eclipse. Is there a way to make the shutdown hook be called in Eclipse?

The red stop button forcibly kills the application, i.e. not gracefully, so the JVM doesn't know that the application is exiting, therefore the shutdown hooks are not invoked.
Unfortunately, there is no way (in Windows, at least) to provide a mechanism that ensures that the hook is always invoked. It's just something that may be invoked, but there is no guarantee.

I made a hack by replacing JavaProcess with decorated one:
IProcess p = launch.getProcesses()[0];
launch.addProcess(new JavaProcessDecorator(p));
launch.removeProcess(p);
And decorator is overriding terminate function.
public class JavaProcessDecorator implements IProcess {
private IProcess p;
public JavaProcessDecorator(IProcess p) {
this.p = p;
}
private boolean sigkill = false;
#SuppressWarnings("rawtypes")
#Override public Object getAdapter(Class arg) { return p.getAdapter(arg); }
...
#Override public ILaunch getLaunch() { return p.getLaunch(); }
#Override public IStreamsProxy getStreamsProxy() { return p.getStreamsProxy(); }
#Override public void setAttribute(String s1, String s2) { p.setAttribute(s1, s2); }
#Override public void terminate() throws DebugException {
if(!sigkill) {
try {
IDebugIService cs = DirmiServer.INSTANCE.getRemote("main", IDebugIService.class);
if(cs != null) cs.modelEvent(new TerminateRequest());
} catch (RemoteException e) { }
this.sigkill = true;
} else p.terminate();
}}
At first click on red button, I send a message to application asking for gently termination. If it is not working, second click on red button will kill it.

I know I'm a bit late to the party, but I found this thread seeking for help and so will probably others.
We had the same issue and solved it with an Eclipse plugin (on Linux) which provides additional stop buttons now.
I hope this serves all of you as well as it did help us :)

Red stop button just terminates the application and according to eclipse devs they can't do anything about it see this issue in eclipse bug tracker.

#Pacerier - From the Javadoc: In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.

If you just want to test if the hook is working or not, throw new RuntimeException() from the trigger point. This should call the shutdown hook even from Eclipse.

Related

Process.exitValue() and Process.destroy() features

I have been experimenting with Process and ProcessBuilder and come with this SSCCE.
import java.io.IOException;
public class TestProcess {
public static void main(String[] args) {
Process process = null;
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
try {
process = pb.start();
} catch (IOException e) {e.printStackTrace();}
//have some time to close notepad
try {
Thread.sleep(10*1000);
} catch (InterruptedException ignored) {}
try {
System.out.println(process.exitValue());
} catch (IllegalThreadStateException e) {
System.out.println(e);
}
if (process != null)
process.destroy();
/*try {
Thread.sleep(0, 1);
} catch (InterruptedException ignored) {}*/
System.out.println(process.exitValue());
}
}
If I run this code and close notepad before 10s timeout. destroy() call does not show any problem on attempt to stop already terminated process. Why?
If run this code and don't close notepad at all (with commented second sleep)
It seems that destroy is asynchronous call (just sending a signal?) which results in exception in second exitValue()
java.lang.IllegalThreadStateException: process has not exited
Exception in thread "main" java.lang.IllegalThreadStateException: process has not exited
at java.lang.ProcessImpl.exitValue(ProcessImpl.java:246)
at TestProcess.main(TestProcess.java:30)
If I run this code and don't close notepad at all (with uncommented second sleep) then second exitValue never throws Exception, even though sleep value is just 1ms. Is it because of sleep() overhead itself?
Second exitValue would return 1.
PS. I run it from Windows 7 and Eclipse.
ProcessImpl.java on destroy method call native function terminateProcess:
public void destroy() { terminateProcess(handle); }
private static native void terminateProcess(long handle);
terminateProcess is platform dependent and for Windows you can find sources here. It's just call Windows TerminateProcess function (link to this function was in previously answer or you can google it) with uExitCode=1 - thats why exit code of destroyed process is 1.
In linux looks like is used something similar to this. And as proof next code return 143 in ubuntu, that correspond to SIGTERM (https://stackoverflow.com/a/4192488/3181901):
public static void main(final String[] args) throws IOException, InterruptedException {
final Process process = Runtime.getRuntime().exec(args[0]);
process.destroy();
Thread.sleep(1000);
System.out.println(process.exitValue());
}
Why would it show a problem? You're trying to destroy a process that was already destroyed. The specification of Process.destroy() doesn't say what happens if there was nothing to destroy, so it is logical (I suppose) to assume that if there's nothing to destroy, then there's nothing to complain about. Compare with Thread.join(), which doesn't just die if the thread has already ended.
The only way to kill a process is to send it a signal. On some OS's, there are other, more "violent" ways (on some platforms, for example, it is possible to simply remove the process from the OS's list of running processes. Results are undefined and it usually ends ugly), but at least with platforms that I know of, it's really all about sending signals.
Possible, indeed, that it's because it takes time to invoke Thread.sleep(). Try increasing the timeout value.
I'm expecting that the destroy() method is calling the native windows function TerminateProcess.
Looking at MSDN, I found this:
TerminateProcess is asynchronous; it initiates termination and returns immediately. If you need to be sure the process has terminated, call the WaitForSingleObject function with a handle to the process.
So I think it explain that destroy is indeed asynchronous.
Another extract from the same source:
The TerminateProcess function is used to unconditionally cause a process to exit.
I guess that "unconditionnally" can explain why the call of destroy() on a terminate process don't fail.
Hope this help. (really interesting question !)

Regarding shutdownhook understanding

I was going through shutdown hook feature of java , My analysis was ..shutdownhook allows to register a thread that will be created immediatly but started only when the JVM ends ! So it is some kind of "global jvm finalizer", and you can make useful stuff in this thread (for example shutting down java ressources like an embedded hsqldb server). This works with System.exit(), or with CTRL-C / kill -15 (but not with kill -9 on unix, of course).
Please advise more practical uses and please also if possibe an small example will help to make understanding more clear..!
When a shutdown hook is added to a Runtime instance, it is added to a list of Threads to start upon clean termination of the JVM.
Example: Using shutdown hook to ensure that a java.awt.TrayIcon is removed from the system tray.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
if (SystemTray.isSupported()) {
SystemTray.getSystemTray().remove(yourTrayIcon);
}
} catch (Exception e) {
// failed to remove
e.printStackTrace();
}
}
});
More can be read in the offical documentation.

Call a method when java applcation force close

I want to call a method when I terminating my Java application forcefully. I need to release resource I used in my application.
Please help me.
Thanks
It depends a bit on what you mean by "forcefully", but I expect you want to add a Shutdown hook.
Shutdown hooks are small threads which are called whenever Java attempts to shut down. You can add one using the Runtime API, like so:
Runtime.getRuntime().addShutdownHook(Thread hook)
Of course, if you really force a shutdown (by turning the machine off, or running kill -9 on it,) the operating system will shut down Java without giving it a chance to clean up anything. In that case, you won't be able to do anything about it.
This'll be what you want:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
// release your resource
}
});
You need to use Shutdownhook: Here is example:
Runtime.getRuntime ().addShutdownHook (
new Thread () {
#Override
public void run () {
System.out.println ( "Shutdown hook" );
}
} );

How to stop a java application?

I have made a java application and have packed it into an executable jar file. Now a user can start that program from either of the following two ways:
Start if from command prompt by executing the following command on the command prompt:
java -jar "MyJar.jar"
By double clicking on that jar file.
I want that my client would adopt second approach as it is much easier than the first approach. But the problem with second approach is how to stop application before it has finished?
It is a command-line application.
And no command prompt window appears when a user double clicks on the jar file. So in this case, Will Ctrl + c work?
Stopping (exiting) the application should be inside the application. Whether it is command line or GUI based, the application developer should write code to exit it (For eg., in a command line application you might have something like Press 5 to exit, Press Esc to Exit etc) and in an application with a GUI, you will have to write code to exit when the window is closed, or an EXIT button (or others, depending on your application)
Ctrl + C is KILL the application. This is not a Normal exit. For apps with a GUI, the user would typically (in Windows) go to task manager and end the process (similar ways in other operating systems)
But these are abnormal exits - when the user wants to kill the app when, for instance, the application is no longer responding. Normal exits should be provided by the application (and therefore by the programmer - you)
I've had a similar problem. I have some Java programs that are basically long-running daemon processes. It's nice to be able to stop them and bounce (restart) them.
I've used two approaches. Both have advantages and disadvantages. One is to set up a signal handler, by putting a function like this in some class of your program (in mine, it's in the class with the main method).
import sun.misc.Signal;
import sun.misc.SignalHandler;
...
private static boolean stopNow = false;
private static boolean restartNow = false;
...
private static void handleSignals() {
try {
Signal.handle(new Signal("TERM"), new SignalHandler() {
// Signal handler method for CTRL-C and simple kill command.
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGTERM handling in this instance.");
}
try {
Signal.handle(new Signal("INT"), new SignalHandler() {
// Signal handler method for kill -INT command
public void handle(Signal signal) {
MyClass.stopNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.debug("No SIGINT handling in this instance.");
}
try {
Signal.handle(new Signal("HUP"), new SignalHandler() {
// Signal handler method for kill -HUP command
public void handle(Signal signal) {
MyClass.restartNow = true;
}
});
}
catch (final IllegalArgumentException e) {
logger.warn("No SIGHUP handling in this instance.");
}
}
This has worked robustly for us in production. You need a genuine Sun JRE for this to work; the one shipped with a typical Linux distro doesn't have the Signal stuff in it. It works OK on Windows too, but you don't get the HUP signal. You do need a shortcut or shellscript to launch this thing.
Also, keep in mind that signal handling is a big fat botch. Don't try to do very much inside your signal handler. You can see that my sample code simply sets static flags. Other parts of my program detect that the flag changed, and shut down. I could have experimented with more complex code inside the signal handler, but I didn't feel like taking on the QA burden.
The other approach is to structure your program as a Servlet. You'll write a class that extends HttpServlet in this case. Override Servlet.init with a method that starts your worker thread. Likewise, Override Servlet.destroy with a method that shuts yourself down.
Then you can use a Java EE container server like Tomcat to manage your starting and stopping.
If your program is a console mode program and it's doing output, Ctrl-C should be able to kill it.
If it's a GUI program, you'll want to give it a button to exit, or at least setting EXIT_ON_CLOSE as the defaultCloseOperation of your main JFrame.
ctrl+alt+suppr -> kill the javaw.exe ? :p
Or you would have to present a user interface with a stop button (see swing etc)
It depends on the User Interface. If its a Swing application then you can setDefaulCloseOperation(JFrame.EXIT_ON_CLOSE) on your main Frame. If its a console app and the user is interacting with it then you ask the user to enter a value that indicates to you that they want to stop the app. If yoy are not interacting with the user at all then ctrl-c will have to work.
Is it a GUI application or commandline.
In first case just handle the window closing event. In second case handle e.g. CTRL + C
that depends on what kind of application is it?
Is it a swing application? If so, then your app should handle when user clicks the 'close' button. There is a behavior for that. JFrame.close()
If it isnt a swing app then ctrl+c will work.
"It is a command-line application" you say.. Well you could do it so that when the user hit a button (say esc) he can write short commands to exit, restart etc..
You can do this with KeyListener. When ESC is hit (say that is the button you want the user to hit), you use Scanner on System.in, and you will do a System.exit(0); if the input is "exit".
I've used socket connection to enable kill of running instance.
//send kill signal to running instance, if any
try {
new Socket("localhost", 4000).getInputStream().read(); //block until its done
} catch (Exception e) { //if no one is listening, we're the only instance
}
//start kill listener for self
new Thread() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(4000);
serverSocket.accept();
//do cleanup here
serverSocket.close();
} catch (Exception e) {
}
System.exit(0);
}
}.start();
You can use this one: exit()
It's possible to predefine all the action before virtual machine is totally stoppeed thus you can save your data and performa all actions to prevent the data loss.
I'm not sure it's a good way, because I've just started Java study, but it seems working.

How can I interrupt IMAP's IDLE?

I am using the Javamail API connecting to my IMAP server. Everything is working great with the javax.mail.Folder.idle() method. My listener gets called when a new mail comes in. However the problem is idle blocks forever, how do I interrupt it? How do I actually stop the listening without killing my Java program?
I've tried calling Thread.interrupt() on the idle'd thread. Nothing happens. I am running out of ideas.
Performing any operation on that folder (from another thread) will cause idle() method to return immediately. So if you want to forcefully interrupt it, just call close() from a new thread.
If you read the documentation properly, and read the source code, you'll realise that you have to create a new thread for calling .idle().
Allocate that thread to a variable, and whenever you want call the interrupt() on that thread, or just ignore notifications!
If you need to get idle() going again, just rerun the thread!
I created something similar, so you might wanna check it out.
https://github.com/mofirouz/JavaPushMail/blob/master/src/main/java/com/mofirouz/javapushmail/JavaPushMailAccount.java
Good luck
A proper way to abort IDLE command is the following snippet. Note that the Folder instance should be the same as the one used to start idling. I've tested the other solutions proposed on this thread but they didn't work in my case.
IMAPFolder folder = store.getFolder("INBOX");
try {
folder.doOptionalCommand("Abort IDLE error mesage", new IMAPFolder.ProtocolCommand() {
#Override
public Object doCommand(IMAPProtocol p) throws ProtocolException {
p.idleAbort();
return Boolean.TRUE;
}
});
} catch (MessagingException e) {
e.printStackTrace();
}

Categories