従来ヒープ情報のようなリアルタイム更新するグラフを実装する場合、
- サーバサイドで画像を生成し、ブラウザへ送る
- サーバからデータを受け取って、ブラウザがアプレットでグラフを描画する
のどちらかだったと思います*1。
前者はサーバに負荷がかかるため、後者が一般的でしょう。けどアプレットって起動が結構重いので、イライラしますね。
そこへ第3の選択肢が現れました!Google ChartはサーバでもクライアントでもなくGoogleインフラが描画をやっちゃってくれます。早速作ってみました。
index.html
<html> <head> <meta http-equiv="content-type" content="text/html;charset=Shift_JIS"> <title>Simple Console</title> <script type="text/javascript" src="jquery-1.2.3.js"></script> <script> var NUM_OF_SAMPLES = 60; // 表示サンプル数 var timerId; var maxMemory = 0; var maxChd; var totalChd; var usedChd; function init() { // 同期でmaxMemoryを取得 jQuery.ajax({ async: false, url: "resource.jsp", data: "cmd=maxMemory", success: function(data){maxMemory = data} }); // 初期データ文字列を組み立て maxChd = "100"; totalChd = "0"; usedChd = "0"; for (i = 1; i < NUM_OF_SAMPLES; i++) { maxChd += ",100"; totalChd += ",0"; usedChd += ",0"; } // 周期呼び出し timerId = setInterval("loadChart()", $("#updatePeriod").attr("value") * 1000); } function loadChart() { // 非同期でヒープ情報を取得 jQuery.get("resource.jsp", "cmd=heap", function(dataStr){buildChart(dataStr)}); } function buildChart(dataStr) { var data = dataStr.split(","); // maxMemoryに対する比を0〜100で表現 totalChd += "," + Math.round(data[0] * 1000 / maxMemory) / 10; usedChd += "," + Math.round(data[1] * 1000 / maxMemory) / 10; // データ文字列をずらす totalChd = totalChd.substring(totalChd.indexOf(",") + 1); usedChd = usedChd.substring(usedChd.indexOf(",") + 1); // URL組み立て var url = "http://chart.apis.google.com/chart?" + "chs=480x320&cht=lc&chxt=x,y&chco=ff0000,00ff00,0000ff&chdl=Max|Total|Used&" + "chxl=0:||1:||" + Math.round(maxMemory / (1024 * 1024)) + "MB&" + "chd=t:" + maxChd + "|" + totalChd + "|" + usedChd; // srcを差し替える $("#heapChart").attr("src", url); // URLをデバッグ出力 $("#debug").html(url); } function changePeriod() { clearInterval(timerId); timerId = setInterval("loadChart()", $("#updatePeriod").attr("value") * 1000); } function gc() { // 非同期でGCを実行 jQuery.get("resource.jsp", "cmd=gc"); } </script> </head> <body onload="init()"> <img id="heapChart" src="" alt="heap chart"> <br> <form name="form1"> 更新周期<input type="text" id="updatePeriod" size="5" value="1">秒 <input type="button" value="周期変更" onclick="changePeriod()"> <br> <input type="button" value="GC" onclick="gc()"> <br><br> <div id="debug" style="width:480px;word-wrap:break-word;word-break:break-all;"></div> <br> </form> </body> </html>
resource.jsp
<%@page session="false" contentType="text/html; charset=Shift_JIS" %> <%@page import="java.util.*" %> <% response.setHeader("Expires", "-1"); response.setHeader("Pragma","no-cache"); response.setHeader("Cache-Control","no-cache"); String cmd = request.getParameter("cmd"); if (cmd.equals("maxMemory")) { Runtime runtime = Runtime.getRuntime(); out.print( runtime.maxMemory() ); } else if (cmd.equals("heap")) { Runtime runtime = Runtime.getRuntime(); out.print( runtime.totalMemory() + "," + (runtime.totalMemory() - runtime.freeMemory()) ); } else if (cmd.equals("gc")) { System.gc(); } %>
resource.jspは単純にヒープ情報のデータだけ返します。index.htmlは非同期でjspを呼び出し、Google ChartのURLを組み立て、imgタグのsrc属性を差し替えます。1秒間隔の更新でも全く問題ありません。さすがGoogle!
JavaScriptはまだまだビギナーなのでもっさいコードがあるかもしれません。jQueryを使ってみました。コードが少しはすっきりしたかな?
http://toshiyakobayashi.googlepages.com/scon.zip
からダウンロードできるようにしました。解凍し、Tomcatならwebapps/Rootの下に、JBossならdeploy/jboss-web.deployer/ROOT.warの下にsconディレクトリをコピーしたらOKです。
*1:どちらにしてもライブラリはJFreeChartあたり