ファイヤープロジェクト
JFreeChartで生成したグラフを一時ファイルに保存してServletで出してみる(JFreechart 0.9.16)
2004-06-26T23:00+09:00   matsu
JFreeChartでグラフを生成するのは非常に高価である.同じグラフを表示するのであれば,何度もJFreeChartオブジェクトを生成して画像データに変換して出力するということはしたくない.JFreeChartではこういった問題に対処するためのユーティリティクラスなどがあるようなので試してみた.
同じJFreeChartを何度も生成して画像データに変換して出力したくはない場合,画像データを一時ファイルとして保存し,それを出力するという方針が考えられる.JFreeChartで提供されている部品をこの方針にそって(私なりに)解釈すると,以下の三つの機能が含まれていることがわかる.
  1. 一時ファイルを読み出してクライアントに返す.
  2. グラフを一時ファイルとして保存する.
  3. 一時ファイルの管理(アクセス権管理と削除).
本頁のサンプルのためのweb.xmlを以下にしめす.
二つのサーブレットがあり,matsu.sample.TmpFileChartServletはJFreeChartを生成,グラフ画像を一時ファイルとして保存する.org.jfree.chart.servlet.DisplayChartはJFreeChartで用意されているサーブレットで,そのJavaDocにあるとおり,web.xmlを記述するだけで一時画像ファイルを読み出してクライアントに返す.
DisplayChartはJFreeChartで用意されているサーブレットで,web.xmlを記述だけで一時画像ファイルを読み出してクライアントに返してくれるが,JavaDocには説明がないので,仕様がよくわからない.ソースに目を通した所,大体以下のような機能がある.
一時画像ファイルの読みだし
読み出す一時画像ファイルは以下で特定される
  • request.getParameter("filename")で取得した値を一時ファイルファイル名とする.
  • 一時ファイルのあるパスはSystem.getProperty("java.io.tmpdir")で返る文字列(※)であらわされる.
そしてユーティリティクラスorg.jfree.chart.servlet.ServletUtilitiesを使用して画像をクライアントに返す.
ServletUtilities.sendTempFile(file, response);
一時画像ファイルのアクセス権確認
一時ファイルにアクセスするには,以下のいずれかを満たす必要がある.
  • 同じセッション上で以下の方法で保存した画像である.
    ServletUtilities.saveChartAsPNG(chart, width, height, session)
    
  • 一時ファイル名が"public"で始まる.
DisplayChartでは異常があった場合,基本的にJSPExceptionを投げてしまうので,実際のシステムではそのまま使うのではなく,拡張するとか,参考にして作成しなおす方がよいと思う.
※ 私はDebian GNU/Linux WoodyでTomcat4をapt-getしたのだが,System.getProperty("java.io.tmpdir")の値は
/usr/share/tomcat4/temp
で,
# ls -l /usr/share/tomcat4/temp
lrwxrwxrwx ...... /usr/share/tomcat4/temp -> /var/cache/tomcat4/_temp
だった.
DisplayChartで一時ファイルに保存されたグラフを読み出すには,まずグラフを一時ファイルに保存しておく必要がある.これを行う私が作成したサンプルを以下に示す.
サンプルのサーブレットはリクエスト(GET)のクエリ(任意)にpublicを取る.public=trueなら,一時ファイル名をpublicで始まるものにする.すなわちグラフを作成したセッションとは別のセッションからでも一時ファイル名が分かればDisplayChartで表示されるようになる.サンプルファイルのプレフィクスは以下で設定できる.
ServletUtilities.setTempFilePrefix(prefix);
念のためにプレフィクスの取得も.
ServletUtilities.getTempFilePrefix();
サンプルはセッション上にグラフの一時ファイル名の文字列がなければ,JFreeChartオブジェクトを生成してグラフ画像を保存し,一時ファイル名をセッションに格納する.
if (savedFileName == null) {
    try {
        // 棒グラフのJFreeChartを作成
        JFreeChart chart = createChart();

... 省略 ...

        // グラフをPNG形式でファイル保存
        savedFileName = ServletUtilities.saveChartAsPNG(chart, width, height, session);
        System.err.println("savedFileName = " + savedFileName);
        session.setAttribute(CHART_FILENAME_KEY, savedFileName);

... 省略 ...

    } catch (IOException e) {
        e.printStackTrace();
    }
}
サンプルでは一時ファイルのプレフィクスが切り替わった時には,セッションから一時ファイル名を削除するようにした.
session.removeAttribute(CHART_FILENAME_KEY);
今回のサンプルのポイントはorg.jfree.chart.servlet.ChartDeleterである.これはHttpSessionBindingListenerを実装しており,セッションに登録される際と削除された際にそれぞれ自分自身の持つvalueBound,valueUnboundが呼び出される.valueBoundは何もしない.valueUnboundは自分自身に登録されている一時ファイルを削除する.これを踏まえてServletUtilities.saveChartAsPNGの動きを追ってみる.
  1. 一時ファイル名を生成
  2. ChartUtilities.saveChartAsPNGでJFreeChartをPNGとして保存.
  3. session上にChartDeleterがキー"JFreeChart_Deleter"で登録されていなければ,作成してキー"JFreeChart_Deleter"登録
  4. chartDeleter.addChartでChartDeleterオブジェクトに先程作成したグラフの一時ファイルを登録(キーはファイル名).
上はPNG版だが,例によってJPEG版もある.で,セッションタイムアウトやsession.removeAttributeなどでセッションからChartDeleterオブジェクトが削除される際にChartDeleterのvalueUnboundが呼び出され,その内部でaddChartによって登録された一時ファイルが削除される.以上の動きを利用して,一時ファイルがサーバ上に溜って行かないようになっている. また,DisplayChartがリクエストパラメータfilenameを読み込み可能かどうかをチェックする際には実際には
chartDeleter.isChartAvailable(filename)
でチェックしている.これにより同じセッション上で
ServletUtilities.saveChartAsPNG(chart, width, height, session)
で保存した画像かどうかを確認している.
サンプルのソースを置いておく.これ.JFreeChartとJCommonのjarファイルを展開したディレクトリの下のlibの下に置いて
ant war
などとすれば作成できる.で,このサンプルはシステムプロパティやファイル作成などを行うので,セキュリティ関連の設定が必要である.catalina.policyで以下を追記した.
grant codeBase "file:/home/tomcat/webapps/tmp_file_servlet/WEB-INF/lib/-" {
  permission java.util.PropertyPermission "java.io.tmpdir", "read";
  permission java.io.FilePermission "/usr/share/tomcat4/temp", "read,write";
  permission java.io.FilePermission "/usr/share/tomcat4/temp/*", "read,write,del
ete";
};
※ Debian GNU/Linux WoodyでTomcat4をapt-get installしたら,/etc/tomcat/catalina.policyは読み込み専用になっていて,/etc/policy.d/に4つに分解されていた.
$ ls /etc/tomcat4/policy.d/
01system.policy  02debian.policy  03catalina.policy  04webapps.policy
ので,/etc/tomcat/catalina.policyではなく,/etc/policy.d/下のファイルを編集する必要がある./etc/init.d/tomcat4 startを実行すると,/etc/policy.d/下のファイルは以下で一つに結合される.
cat /etc/tomcat4/policy.d/*.policy >/var/lib/tomcat4/catalina.policy
今回のサンプルで私が実際に編集したのは
/etc/tomcat4/policy.d/04webapps.policy 
である.
matsu(C)
Since 2002
Mail to matsu