2007年07月20日

●jstat + visualgc でリモートホストを監視

2007年04月09日「jvmstatでTomcat(JVM)の監視」の記事について、
コメント欄でも触れましたが、若干内容に誤りがありました。
jvmstatは、jstatと名前を変えてJ2SE5.0に組み込まれました。
同時に、jvmstatに関連するツール群もJ2SE5.0に組み込まれました。
ただしvisualgcのみ組み込まれなかったため、利用したい場合は
別途jstatを入手して、visualgcのみ使用する、といった形になります。

jvmstatツールでの名称 J2SE5.0での名称
jvmstat jstat
jvmps jps
perfagent jstatd
visualgc (対応無し)

それではjstatとvisualgcを使って、リモートホストのTOMCATを監視してみましょう。
まずは「監視される側(TOMCATの動作する側)」のホストの準備をおこないます。

visualgcへ監視内容を通知するデーモンプログラム(エージェント)「jstatd」を
実行します。jstatdを起動するには「ポリシーファイル」が必要です。
ポリシーファイルでは厳密なセキュリティポリシーを定義することができますが、
今回は簡単に全てを許可するポリシーとします。
(外部公開ホスト等では絶対にこの設定ではダメです)

grant {
    permission java.security.AllPermission;
};
ファイル名は仮に「all.policy」とでもして、適当な所に保存します。 保存したらjstatdを起動します。プロンプトからポリシーファイルを保存したパスに 移動して以下のコマンドを実行します。
jstatd -J-Djava.security.policy=all.policy
エージェントなので、実行すると終了するまで(Ctrl + Cキーを押すまで) プロンプトはそのままとなります。

では次に「監視する側」のホストの準備をおこないましょう。

visualgcを使うので、まだjvmstatツール群をインストールしていない場合は、
2007年04月09日の記事の要領で、ダウンロード・展開・
環境変数パスの設定を行ってください。

次にリモートホストで起動しているTOMCATのプロセスIDを調べましょう。 (事前にリモートホストでjstatdが起動している必要があります)
jps -l <リモートホストアドレス>

TOMCATは「Bootstrap」が含まれる行でしたね。
リモートホストに対してjpsを実行するとパッケージ名も表示されますね。

あとはプロセスIDとリモートホストアドレスを指定してvisualgcを実行するだけです。
visualgc <プロセスID>@<リモートホストアドレス>

2007年04月09日

●jvmstatでTomcat(JVM)の監視

jvmstatというツールでTomcat状況を監視してみましょう。
jvmstatはSUN Microより公開されているJVMのパフォーマンス情報(主にGC関連)をリアルタイムにモニタリングできるツールです。
さらに付属のvisualgcというツールでは、動作中のJavaVM のヒープメモリの状況をグラフィカルに表示することができます。
リモートホストの監視も付属のperfagentツールで可能だそうですが、今回はローカルマシンのTomcatの監視方法のみ説明します。

公開サイトより「jvmstat-3_0.zip」をダウンロードします。
展開すると「jvmstat」というディレクトリができるのでお好みの場所に移動します。
(スペースを含むパスではないほうがいいみたいです)

環境変数で<<jvmstatディレクトリの移動先>>\batにパスを通します。

準備はこれでOK。

visualgcの表示手順は以下のようにします。
1.Tomcatを起動する
2.コマンドプロンプトで「jps」と入力しEnterキーを押す
3.「Bootstrap」の行と、その数字(プロセスID)を見る
4.「visualgc プロセスID」と入力しEnterキーを押す

プロセスIDはWindowsの場合、タスクマネージャでも確認できますが、複数のJVMが立ち上がっている場合判別できません。eclipseもTomcatも「イメージ名」は「java.exe」とか「javaw.exe」になってしまいます。

jpsコマンドでは、プロセスIDとともに起動クラス名が表示されるので、Tomcatの起動クラス、つまり「Bootstrap」が判別できます。
それとjpsコマンドはjvmstatに含まれるツールではなく、J2SE5.0に含まれるツールです。

visualgcが起動できれば以下のように3つのウィンドウが表示されるはずです。

左上のウィンドウは「Visual GC Window」です。JVMのヒープ空間をEden、Survivor0 (S0)、Survivor1 (S1)、Old に分けて表示してくれます。

右上のウィンドウは「Graph Window」です。時系列に沿った Eden、S0、S1、Old、Perm の使用済みメモリサイズの グラフが表示されます。
他にGC が Java の実行を停止していた時間と、 GC の回数なども表示されます。

下のウィンドウは「Survivor Age Histogram Window」です。オブジェクトの年齢・寿命を測る目安らしいですが・・・よくわからん。

世代別GC」とかでググって勉強しませう。

●jconsoleでTomcat(JVM)の監視

今回はJavaの監視ツールで、Tomcat利用時の状況表示をおこなってみようと思います。
J2SE 5.0には、アプリケーションの状態などを監視/管理する(monitoring and management)ための
ツールが含まれています。

そのうちのひとつがjconsoleです。J2SE5.0は監視する側、される側双方のマシンに必要です。
(1台のマシンで完結する場合は当然そのマシンにJ2SE5.0がインストールされていればいいです)

まず監視される側のJavaアプリケーションの起動引数に以下の設定をします。

-Dcom.sun.management.jmxremote.port=ポート番号
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

リモート監視ではjconsoleから接続する際にポート番号の指定が必要になるため、
上記のようにポート番号を指定します。wellknownポートでなければなんでも良いと思います。
また、デフォルトでSSLとパスワード認証が有効になっているため、これを無効にします。

eclipse+Sysdeo Tomcatプラグイン環境がある場合は以下のように指定・起動します。
1.一度Sysdeo TomcatプラグインでTomcatを起動する
2.すぐにTomcatを終了する
3.eclipseのメニュー[実行]-[構成および実行]を選択してダイアログを開く
4.左側ツリーの[Javaアプリケーション]-[Tomcat 5.x]を選択する
5.右側の「引数」タブを開く
6.「VM引数」の末尾に上記引数3行を追加する。
7.「実行」ボタンを押してTomcatを起動する

これで監視される側の準備はOKです。

次に監視する側の操作です。
1.コマンドプロンプトで「jconsole」と入力してEnterキーを押す
(JAVA_HOME\binにパスは通っていますね?)
2.「リモート」タブを開く
3.「ホストまたはIP」に対象マシンのアドレスを入力する
4.「ポート」は上記で設定したポート番号を入力する
5.「ユーザー名」「パスワード」は入力無し
6.「接続」ボタンを押す

監視対象がローカルマシンの場合、「ホストまたはIP」を「127.0.0.1」としてもいいでしょう。

わりとおおざっぱな監視内容ではありますが、J2SEに含まれているツールとしては
十分ではないでしょうか。

2007年03月30日

●Javaでのわかち書き - senライブラリ

お次はJavaでわかち書きをする方法を説明します。

わかち書きにはSenというライブラリを利用します。
Sen は、Java で実装された形態素解析器で、工藤拓さんによりオープンソース(LGPL)で開発されている形態素解析器MecabをJavaへポーティングしたライブラリ、だそうです。

Sen配布ページから「sen-1.2.2.1.zip」をダウンロードして解凍します。

この中にはわかち書きのための辞書は含まれておらず、自分で作成する必要があります。
辞書の作成のためには「Apache Ant」と「Active Perl」が必要です。

AntはApacheAntプロジェクトサイトから「apache-ant-1.7.0-bin.zip」をダウンロードします。
Active PerlはActiveStateサイトから「ActivePerl-5.8.8.820-MSWin32-x86-274739.msi」をダウンロードします。

Antはダウンロードしたファイルを解凍して、<<Antの解凍先>>\apache-ant-1.7.0\bin にパスを通しておきます。
Active PerlはMSI形式のインストーラーなので、普通にインストールできます。

また、辞書データはネットから自動的にダウンロードされるため、インターネット接続環境が必要です。プロキシの指定が必要な場合、<<senの解凍先>>\dic ディレクトリの「build.xml」を事前に編集しておきます。 build.xmlをエディタで開き、ファイル先頭辺り、 <property name="***" value="***" /> が連なっている末行に
<property name="proxy.host" value="プロキシサーバーのアドレス" />
を記述します。

準備ができたらプロンプトを立ち上げ、カレントディレクトリが<<senの解凍先>>\dic となるように移動します。

D:\sen-1.2.2.1\dic> ant -Dperl.bin=<<Perlのインストール先>>\bin\perl.exe
上記コマンドを実行すると辞書が作成されます。

さてさてようやっとJavaプログラムです。
eclipseでプロジェクトを作成し、「sen.jar」と「commons-logging.jar」にクラスパスを設定します。
また「icu4j_3_4_4.jar」にもクラスパスを設定します。(cu4jはIBMが提供しているJavaライブラリで、配布サイトで入手できます。)

package sen;

import java.io.IOException;
import java.util.ArrayList;

import com.ibm.icu.text.Normalizer;

import net.java.sen.StringTagger;
import net.java.sen.Token;

public class SenTest {

    public static void main(String[] args) throws IllegalArgumentException, IOException{
        System.setProperty("sen.home", "D:/sen-1.2.2.1");
        
        StringTagger tagger = StringTagger.getInstance();
        String str = args[0];
        Token[] token = tagger.analyze(str);
        String convToken = "";
        
        ArrayList wakati = new ArrayList();
        
        for (int i = 0; i < token.length; i++) {
//            System.out.println(token[i].getBasicString() + "("
//                    + token[i].getTermInfo() + ")");

            convToken = Normalizer.normalize(token[i].getBasicString().toUpperCase(), Normalizer.NFKC);
            if (!wakati.contains(convToken))
                wakati.add(convToken);
        }
        
        for (String result : wakati){
            System.out.println(result);
        }
    }
}

実行引数の文字列をわかち書きして、コンソールに出力するプログラムです。
System.setPropertyでsenの展開先を指定します。
tagger.analyzeでわかち書きされたTokenオブジェクト配列が返されます。
token[要素].getBasicString()でわかち書きされた文字を取得できます。
Normalizer.normalizeはicu4jのメソッドで、文字の「ゆれ」を統一します。
ここではtoUpperCase()と組み合わせることで、「英数字は大文字半角・カタカナは全角」となるようにしています。全文検索キーワードに収めるキーワードの「ゆれ」を統一しておくことで、検索時に全角・半角・大文字・小文字いずれでも検索できるようにするためです。
重複したキーワードを取得しないように、!wakati.containsでチェックしています。

このサンプルではコンソール出力していますが、実際は「
DB更新時のキーワード列に収めるデータ」と「検索時に検索条件をわかち書きするため」に使用することになります。

2006年03月17日

●Tomcat アプリケーションの日本語化

今回は日本語をプロジェクトで扱えるようにしてみます。
strutsのAction Formはブラウザからのリクエストデータを格納する際、何もエンコード処理をしてくれませんので、何らかの方策をとらないと日本語がAction Formに文字化けして格納されてしまいます。


Servlet2.3から、Filter機能が実装されましたのでこれを利用しましょう。Tomcat5.0はServlet2.3に対応しています。Filterはリクエストデータがサーブレット(strutsの場合はAction Servlet)に届く前に処理される機能なので、ここでエンコード処理をほどこしていれば、Action以降のプログラムでいちいちエンコード用のプログラミングをする必要がなくなるわけです。(Filter機能がもしなかったら、Action Formのresetメソッドなりgetterなりで全部エンコードプログラミングしなきゃならないわけで…うぇ〜)


Filterとして登録するエンコード用クラスは、Tomcatでサンプルアプリケーションをインストールしていれば、<tomcatインストール先>webapps/examples/WEB-INF/classes/filters にSetCharacterEncodingFilter.javaがあるそうなのでそれを使います。ない場合は、ここからダウンロードしてください。


「filters」というパッケージを作成して、そこにSetCharacterEncodingFilter.javaを配置しましょう。


次に配置したフィルタがコンテナに使用されるように、web.xmlを編集します。WEB-INF/web.xmlをエディタで開いて、
<web-app>のすぐ下あたりに以下の記述をします。


  <!-- Jananese Encoding Filter Setting -->

  <filter>

    <filter-name>encodingFilter</filter-name>

    <filter-class>filters.SetCharacterEncodingFilter</filter-class>

    <init-param>

      <param-name>encoding</param-name>

      <param-value>Windows-31J</param-value>

    </init-param>

  </filter>



  <filter-mapping>

    <filter-name>encodingFilter</filter-name>

    <servlet-name>action</servlet-name>

  </filter-mapping>


また、struts-blankのコピーからアプリケーションを作成している場合、web.xmlのdtd定義が
古いです。Filterが利用できるよう、以下のようにヘッダーを編集しましょう。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">


他にもいくつか約束事が。


1.作成するJSPファイルは全てエンコード「MS932」で保存してください。(eclipseのデフォルト・テキストファイル・エンコード)

2.JSPファイルの1行目には必ず以下の内容を記述してください。


<%@ page contentType="text/html; charset=Windows-31J" language="java"%>

3.<head>タグの中に以下のタグを記述してください。


<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">

これで準備完了。日本語文字をPOSTしてみてください。機種依存文字もかなりいけるはずです。(まるいち、とか、
かっこかぶ、とか)


…じゃGETは?というと、ここまでの対処じゃまだ化けてしまいます。

まずtomcatにGETリクエストの場合でもFilterを経由するように設定しなければなりません。
<tomcatインストール先>conf/server.xmlをエディタで開き、
「<Connector port="8009"…」で始まる箇所を探します。
「protocol="AJP/1.3"」の後ろ辺りに、


useBodyEncodingForURI="true"

を付加してください。(/>の前)


さらに、先ほど配置したSetCharacterEncodingFilterクラスを編集します。doFilterメソッドを以下のように書き換えてください。


public void doFilter(ServletRequest request, ServletResponse response,

    FilterChain chain) throws IOException, ServletException {



  // Conditionally select and set the character encoding to be used

  if (ignore || (request.getCharacterEncoding() == null)) {

    // リクエストがGETメソッドなら、UTF-8エンコーディングを使用

    if (request instanceof HttpServletRequest

        && "GET".equalsIgnoreCase(((HttpServletRequest) request)

            .getMethod())) {

      request.setCharacterEncoding("UTF-8");

    // リクエストがPOSTメソッドなら、web.xmlに指定した文字エンコーディングを使用

    } else {

      String encoding = selectEncoding(request);

      if (encoding != null)

        request.setCharacterEncoding(encoding);

    }

  }



  // Pass control on to the next filter

  chain.doFilter(request, response);



}


おまけ:
ブラウザからのリクエストデータを、データベースに格納する際、以下の注意が必要です。
・データベースがPostgreSQLでかつ、データ文字コードがEUC-JP
  =>問題無し

・データベースがOracleでかつ、データ文字コードがJA16SJIS、またはJA16EUCの場合
  =>「〜」が化ける


詳細は、翔泳社のDBマガジン2006年2月号の特集記事を参照ください。
で、Oracleの「〜」が化け対処方法は、
・データ文字コードJA16SJISTILDEにするか、JA16EUCTILDEにすることです。


一度作成したデータベースの文字コードは変更できませんので、expユーティリティでデータ退避の上再作成しかないですね…

2006年01月30日

●J2SE SDKのインストール

Tomcat&Eclipseの開発のためにまず、J2SE(Java 2 Platform, Standard Edition)をインストールします。
Eclipseにはオリジナルのコンパイラが内臓されているため、不要といえば不要ですがJavaAPIのソースを参照したいケースもままあるため、ここでは開発キットであるJ2SE SDKをインストールします。

(※注 以下の説明文でパスの区切り文字が「\(バックスラッシュ)」で表記されていますが、「¥」に読み替えてください。


sunのダウンロードサイトにアクセスし、「Download J2SE SDK」リンクをクリックします。


上の方にある「license agreement」に同意(Accept)のチェックを入れます。


「Windows Platform - Java(TM) 2 SDK, Standard Edition 1.4.2_*」表の「Windows Offline Installation, Multi-language」リンクをクリックします。


ダウンロード先を指定して(どこでも)、「j2sdk-1_4_2_*-windows-i586-p.exe」を保存します。


保存したインストーラーを実行します。


使用許諾契約条項に同意します。


インストールする機能と、インストール先を選択します。

デモはいらないので外します。インストール先は、「E:\j2sdk1.4\」のようにリビジョン番号をフォルダ名から外すと、新しいバージョンに入れ直すときに環境変数の変更がいらなくなるので便利。(さすがにメジャー・マイナーバージョンくらいは入れておいたほうが…)


IEとの関連付け。お好みでチェックON・OFFを選択。


インストール開始。しばらく待ちます。


インストール完了。


再起動を促すダイアログが出たら従います。


環境変数を設定します。(Windows2000の場合)
コントロールパネル - システム - 詳細タブ - 環境変数ボタン と進み、「システム環境変数」(下段の方)に以下の環境変数を追加します。もし同名の変数が既に存在する場合は、編集ボタンで開いてから「変数値」の末尾に「;」で繋げて値を追加してください。


変数名:JAVA_HOME
変数値:J2SE SDKでインストール先に指定したディレクトリパス(例:E:\J2sdk1.4)

変数名:CLASSPATH
変数値:.;%JAVA_HOME%\jre\lib;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar

変数名:Path
変数値:%JAVA_HOME%\bin;


設定できたら、コマンドプロンプトから「set」コマンドで現在の環境変数内容を確認してください。OS・環境によっては再起動しないと反映しない場合があります。(俺のマシンぽ…(´・ω・`)
その場合は再起動してからもう一度確認しましょう。


最後にコマンドプロンプトから「java -version」と入力して、インストールしたJ2SEのバージョンが表示されれば完了です。