views:

792

answers:

4

Hi,

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?

A: 

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

Aaron Digulla
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?
Adamski
The global variable is just the most simple solution.
Aaron Digulla
+2  A: 

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 ...
      }
    }
  }
}
Adamski
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.
Kostas
+1  A: 

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.

Jeroen van Bergen
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?
Kostas
+2  A: 

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

}
Nate