How can a Java program detect that the MacOS machine is being shut down?

Viewed 325

I have a Java application that I want to be started on my Mac whenever I start the machine. The application should be shut down gracefully whenever the machine is shut down.

I added a shutdown hook in the main method:

Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(scheduler)));

ShutdownHook class looks like this:

public class ShutdownHook implements  Runnable {
    private final static Logger LOGGER = LoggerFactory.getLogger("Shutdown Hook");
    private final Scheduler scheduler;

    public ShutdownHook(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    @Override
    public void run() {
        LOGGER.debug("Starting to shot down the application");
        try {
            scheduler.shutdown();
        } catch (final SchedulerException e) {
           LOGGER.error("An error occurred while trying to shut down the scheduler", e);
        }
        LOGGER.info("Exiting the shutdown hook");
    }
}

Then I built the application into an executable JAR and added it to the list of "Login items".

"Users and Groups" window

The application is started when I log in.

However, the shutdown hook is not executed when the machine shuts down.

How can I make sure that when I shut down the machine using the menu item shown below, a running Java application detects that the machine is shutting down?

"Shutdown" menu item

Update 1:

As far as I understand, one way to fix the error is to use launchd to start the Java program. I wrote the plist file below.

The next question is how to make sure that launchd runs the application described in that plist file?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ExitTimeOut</key>
    <integer>300</integer>
    <key>StandardErrorPath</key>
    <string>/Users/XXXXXX/sw/wordcounter-daemon/error</string>
    <key>Label</key>
    <string>com.dpisarenko.wordcounterdaemon</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/java</string>
        <string>-jar</string>
        <string>/Users/XXXXXXX/sw/wordcounter-daemon/wordcounter-daemon-0.1-jar-with-dependencies.jar</string>
    </array>
</dict>
</plist>
1 Answers

Usually Unix-style systems will shutdown a daemon process in two steps:

  1. SIGTERM signal send to process

  2. SIGKILL signal send to process if the process still runs after X seconds after point 1

This answer explains how to configure ExitTimeOut value which controlls time between these two signals on MacOS.

The behaviour for non-daemon processes might be different and this might be the reason your process is not executing JVM shutdown hook. The JVM probably received SIGKILL and by design a user-space process can't handle this signal. Potentially you want to convert your process to a daemon.

Related