Determine exit status within the java shutdown hook thread
Asked Answered
K

4

13

I would like to determine the exit status of the process during the shutdown hook runtime.

I want to have a logic which is based on the status code (0 or nonzero)

(ex: if zero do nothing else nonzero send an alert email)

Do you know how I can get this information?

Killigrew answered 28/9, 2009 at 11:58 Comment(0)
I
7

I tried to override the SecurityManager checkExit(int status) method - this works if System.exit(status) is called anywhere explicitly - however, it doesn't set the status when the application exits "normally" (no active threads), or an error kills the VM.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.Permission;


public class ExitChecker {

    public ExitChecker() {

        System.setSecurityManager(new ExitMonitorSecurityManager());

        Runtime.getRuntime().addShutdownHook(new Thread(new MyShutdownHook()));

        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        String line = "";
        while (!line.equalsIgnoreCase("Q")) {
            try {
                System.out.println("Press a number to exit with that status.");
                System.out.println("Press 'R' to generate a RuntimeException.");
                System.out.println("Press 'O' to generate an OutOfMemoryError.");
                System.out.println("Press 'Q' to exit normally.");
                line = input.readLine().trim();

                processInput(line);
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    private void processInput(String line) {
        if (line.equalsIgnoreCase("Q")) {
            // continue, will exit loop and exit normally
        } else if (line.equalsIgnoreCase("R")) {
            throwRuntimeException();
        } else if (line.equals("O")) {
            throwError();
        } else {
            // try to parse to number
            try {
                int status = Integer.parseInt(line);
                callExit(status);
            } catch(NumberFormatException x) {
                // not a number.. repeat question...
                System.out.println("\nUnrecognized input...\n\n");
            }
        }
    }

    public void callExit(int status) {
        System.exit(status);
    }

    public void throwError() {
        throw new OutOfMemoryError("OutOfMemoryError");
    }

    public void throwRuntimeException() {
        throw new RuntimeException("Runtime Exception");
    }

    public static void main(String[] args) {
        new ExitChecker();
    }

    private static class ExitMonitorSecurityManager extends SecurityManager {

        @Override
        public void checkPermission(Permission perm) {
            //System.out.println(perm.getName());
            //System.out.println(perm.getActions());
        }

        @Override
        public void checkPermission(Permission perm, Object context) {
            //System.out.println(perm.getName());
            //System.out.println(perm.getActions());
        }

        @Override
        public void checkExit(int status) {
            System.out.println("Setting exit value via security manager...");
            MyShutdownHook.EXIT_STATUS = status;
        }
    }

    private static class MyShutdownHook implements Runnable {

        public static Integer EXIT_STATUS;

        public void run() {

            System.out.println("In MyShutdownHook - exit status is " + EXIT_STATUS);
        }
    }

}
Incomprehension answered 28/9, 2009 at 13:45 Comment(0)
M
4

Here is some example code whereby a dedicated class is used to initiate a System.exit call via a call to doExit(int). The class also stores the exit status and subsequently acts as a shut-down hook.

public class ShutDownHook implements Runnable {
  private volatile Integer exitStatus;

  // Centralise all System.exit code under control of this class.
  public void doExit(int exitStatus) {
    this.exitStatus = exitStatus;
    System.exit(exitStatus); // Will invoke run.
  }

  public void run() {
    // Verify that an exit status has been supplied.
    // (Application could have called System.exit(int) directly.)
    if (this.exitStatus != null) {
      switch(exitStatus) {
        case 0: // Process based on exit status.
        // Yada yada ...
      }
    }
  }
}
Metaprotein answered 28/9, 2009 at 12:25 Comment(1)
Yes wrapping the exit method and using it accross the application code is one option but not the best! I was expecting a exitStatus property which is provided by the java sdk though it seems its not available.Killigrew
W
1

Why do this in the application itsellf? If your application is not sending a e-mails as part of normal operations, incorporating this kind of functionality is not a good idea, IMHO.

I would just trust to setting an appropriate return value from the JVM process and let a shell script or whatever take care of the conditional creation of the e-mail.

Shutdownhooks are supposed to run for a short time only, sending an e-mail could consume quite some time.

Wrathful answered 28/9, 2009 at 12:57 Comment(1)
I do agree. This condition should be out of the application codebase and something external could take care of the email alert. The application runs on a NT box as a service using tanuki wrapper community edition. The wrapper provide email notifications but only in its paid version. Are you aware of a free/open sourced configuration that could manage email notifications?Killigrew
M
-1

You must save the exit status in main into a global (public static) variable.

Marisamariscal answered 28/9, 2009 at 12:6 Comment(2)
Why specifically a public static variable in main? Couldn't the exit status be passed to the object acting as the shut-down hook prior to calling System.exit?Metaprotein
The global variable is just the most simple solution.Marisamariscal

© 2022 - 2024 — McMap. All rights reserved.