Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

exitされたくない

外部のクラスのmain()を呼んだりしてみたところ、System.exit()されて後続の処理をキャンセルされてしまいました。それでは困るので、セキュリティマネージャーの力を借りてみました。

// 現在のセキュリティマネージャを取得
final SecurityManager originalManager = System.getSecurityManager();

// 新しいセキュリティマネージャを作る
System.setSecurityManager(new SecurityManager() {
    // exitされたくない
    public void checkExit(int code){
        throw new MyExitException(code, "can not exit.");
    }
    // 他の操作は元のセキュリティマネージャにお願い
    public void checkPermission(Permission perm){
        if(originalManager != null) 
            originalManager.checkPermission(perm);
    }
    // 他の操作は元のセキュリティマネージャにお願い
    public void checkPermission(Permission perm, Object obj) {
        if(originalManager != null) 
              originalManager.checkPermission(perm, obj);
    }
});

Exception occured = null;
try{
    // 外部のメインルーチンを呼ぶ
    Outerclass.main(new String[] {"arg1", "arg2"});
}catch(MyExitException mee){
    // exitされた
    if(mee.getCode() != 0) occured = mee;
    // exitの戻り値が正常終了( = 0 )ならNOP
}catch(Exception e){
    // 例外が投げられた
    occured = e;
}finally{
    // セキュリティマネージャを戻す
    System.setSecurityManager(originalManager);
}

if(occured != null){
    /* 思う存分エラー処理 */
    ...
}

checkPermission()しか上書きしてない辺りがひじょーに自信ないので、クリティカルな場面ではjavaのセキュリティについてよく調べてから使ったほうが吉です。後、SecurityManagerの上書きができない状態になってることもあるので、そのときは諦めましょうorz。*1

いらないと思うけど、内部クラスのMyExitExceptionも載せときます。

    static private class MyExitException extends RuntimeException{
        private final int code;

        MyExitException(int code){
            this(code, null);
        }

        MyExitException(int code, String message){
            this(code, message, null);
        }

        MyExitException(int code, String message, Throwable th){
            super(message, th);
            this.code = code;
        };

        int getCode(){
            return code;
        }
    }

*1:後、Errorは潔く諦めてますが、それもなんとかしたければThrowableで。