無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

クローズ忘れの検出

InputStreamなどのclose忘れを検出できるようにしてみます。

戦略

  • クローズしないといけないモノを生成したら、タイマーを起動。一定時間内にクローズされなかった場合、エラーを報告する。
  • ファイナライズされた場合も同様。
  • どこで作られたかわかるようにするため、例外を利用する。

実装:

import java.io.Closeable;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * {@link java.io.Closeable} にclose忘れ検出機能を付加する。
 */
public class ForgottenDetector
implements Closeable {
    
    /** 猶予期間 (秒) */
    private static final int MORATORIUM = 10;
	
    /**移譲先{@link Closeable}*/
    private final Closeable delegate;
    /**作成された場所を特定するための例外。*/
    private final RuntimeException ex;
    /**タイマー*/
    private Timer timer;

    /**
     * コンストラクタ
     * @param delegate 移譲先{@link Closeable}
     */
    public ForgottenDetector ( Closeable delegate ){
        this.delegate = delegate;
        this.ex = new RuntimeException("resource not closed.");
        this.timer = new Timer("ForgottenDetector", true);
        this.timer.schedule( new TimerTask() {
            public void run() {
            	report();
            }
        }, 1000 * MORATORIUM );
    }

    /* 継承元クラスのJavaDocを参照 */
    public void close () throws IOException {
        try {
            delegate.close();
        } finally {
            if ( this.timer  != null ) {
                this.timer .cancel();
                this.timer  = null;
            }
        }
    }

    /* 継承元クラスのJavaDocを参照 */
    protected void finalize () throws Throwable {
        try {
            super.finalize();
        } finally {
        	report();
        }
    }
    /**
     * close忘れを報告する。
     */
    private final void report() {
        if ( this.timer  != null ) {
            this.timer.cancel();
            ex.printStackTrace(); // 標準エラーに出力。
            this.timer = null;
        }
    }
}

使い方:

Closeable closeable = new ByteArrayInputStream( new byte[0] );
closeable = new ForgottenDetector(closeable ); // 検知器を設定する。

Thread.sleep(1000*12); // 猶予期間を超えるまで待つ。 

出力:

java.lang.RuntimeException: resource not closed.
	at ForgottenDetector.<init>(ForgottenDetector.java:31)
	....

ただし、これだと検知器適用後はclose()しか実行できません。InputStreamであればread()などのAPIも委譲しないと使えない・・。orz。汎用的にするのであれば、Aspectで実装するのがスマートかも。