2009-09-28 10 views

Respuesta

6

Me trataron de anular el método SecurityManagercheckExit(int status) - esto funciona si System.exit(status) se llama explícitamente en cualquier lugar - sin embargo, no establece el estado cuando se cierra la aplicación "normalmente" (sin hilos activos), o mata a un error de la máquina virtual .

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

} 
0

Debe guardar el estado de salida en main en una variable global (public static).

+1

¿Por qué específicamente una variable estática pública en main? ¿No se pudo pasar el estado de salida al objeto que actúa como el gancho de apagado antes de llamar a System.exit? – Adamski

+0

La variable global es simplemente la solución más simple. –

2

Aquí hay un código de ejemplo mediante el cual se utiliza una clase dedicada para iniciar una llamada System.exit a través de una llamada al doExit(int). La clase también almacena el estado de salida y posteriormente actúa como un gancho de apagado.

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 ... 
     } 
    } 
    } 
} 
+0

Sí, enrollar el método de salida y usarlo a través del código de la aplicación es una opción, ¡pero no la mejor! Esperaba una propiedad exitStatus que proporciona Java SDK, aunque parece que no está disponible. – Kostas

1

¿Por qué hacer esto en la aplicación itsellf? Si su aplicación no envía correos electrónicos como parte de las operaciones normales, la incorporación de este tipo de funcionalidad no es una buena idea, en mi humilde opinión.

Confío en establecer un valor de retorno apropiado del proceso de JVM y dejar que un script de shell o lo que sea me ocupe de la creación condicional del correo electrónico.

Shutdownhooks se supone que se ejecutan por un tiempo corto, el envío de un correo electrónico podría consumir bastante tiempo.

+0

Estoy de acuerdo. Esta condición debe estar fuera de la base del código de la aplicación y algo externo podría encargarse de la alerta del correo electrónico. La aplicación se ejecuta en una caja NT como un servicio que usa la edición de comunidad de envoltura de tanuki. El contenedor proporciona notificaciones por correo electrónico, pero solo en su versión paga. ¿Conoces una configuración de fuente abierta/gratuita que podría administrar las notificaciones por correo electrónico? – Kostas

Cuestiones relacionadas