Antで条件分岐する方法

今さらながら、Antを勉強中。

思った以上に、いろいろできるなあ。とりあえず、条件分岐できることが分かったので、開発環境と本番環境でデプロイ処理を変えるなんてことができそう。

OSで分岐するケース。Windowsで開発して、Linuxで本番稼動させるようなプロジェクトなら、こんな感じかしら。

<condition property="os" value="win">
    <os family="windows" />
</condition>
<condition property="os" value="unix">
    <os family="unix" />
</condition>

<target name="deploy"> <antcall target="${os}_deploy" /> </target>
<target name="win_deploy"> <!-- windowsの場合のデプロイ(略) --> </target>
<target name="unix_deploy"> <!-- unixの場合のデプロイ(略) --> </target>

他にも、ファイルの有無(available)やパラメータが指定の文字列を含むかどうか(contains)といった方法で判定ができる。すごい。

今まで条件に応じたターゲットを作ってきて、ターゲット名を覚えるのが面倒だったけど、この条件分岐で内部でごにょごにょしておけば、何も気にせず、ant deploy ってできるわけだ。これ、地味に良い収穫だったかも。

つーか、AntじゃなくてMavenやりたいんだけどさ。うん、まあ、オトナの事情があるんだ。そこんとこ、よろしくお願いします。

"Tenured Gen"と"PS Old Gen"

以前、JMXで書いたメモリ使用量の監視プログラムが、監視対象サーバを変えた途端、Exception を吐いて死亡。えええ。

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://myserver:1234/jmxrmi");
JMXConnector conn = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc = conn.getMBeanServerConnection();

MemoryPoolMXBean mpbean = (MemoryPoolMXBean) ManagementFactory.newPlatformMXBeanProxy(mbsc, "java.lang:type=MemoryPool,name=Tenured Gen", MemoryPoolMXBean.class);

んで、エラー。

Exception in thread "main" java.lang.IllegalArgumentException: java.lang:type=MemoryPool,name=Tenured Gen not found in the connection.
at java.lang.management.ManagementFactory.newPlatformMXBeanProxy(Unknown Source)
...

「そんな ObjectName のMBean はコネクションに無いよ」とか言っちゃっているので、どんなもんがリストされているか確認。

ObjectName oName;
Set names = mbsc.queryNames(null, null);
for (Iterator it = names.iterator(); it.hasNext();) {
    objectName = (ObjectName) it.next();
    System.out.println("ObjectName: " + objectName );
}

そして、暴かれた驚愕の事実。

...
ObjectName: java.lang:type=MemoryPool,name=PS Old Gen
...

Old領域を表す名前が、「Tenured Gen」じゃなくて、「PS Old Gen」になっている。書き直してコンパイルしたら、無事に動作してくれた。ふう。

どうやらJVMが採用するGC方式によって、ここの名前が変わるみたい。JVM1.5系だと、マルチプロセッサ環境では、パラレルGC方式に自動的にスイッチされる。賢い仕様なのだけど、こんなとこにも影響が出るとは。

ということで、環境に応じて適切なプール名称を指定する方法を考えねば…。

続きを読む ""Tenured Gen"と"PS Old Gen""

HttpUnitでもタイムアウトを実現する

先日、「HttpUnitはタイムアウトに未対応だって」で、HttpUnitがソケット通信中のタイムアウトをサポートしていないことについて、嘆き悲しんだわけです。

もはや HttpUnit に修正パッチ当てるしか無いのかなーなんて思っていたけど、裏技っぽいものを発見。Sun JVM 限定だけど、以下のコードでタイムアウト値が設定できた。

// コネクション確立時に使用するタイムアウト値
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");

// 入力ストリーム読み出し時に使用するタイムアウト値 System.setProperty("sun.net.client.defaultReadTimeout", "10000");

プログラムの先頭で、上記のようにプロパティを設定しちゃえば、それ以降の HttpUnit が使用する URLConnection がその値を参照して動いてくれる。もしタイムアウトになった場合は、SocketTimeoutException をスローする。

ただし、プロパティを設定すると JVM 単位でしか制御できなくなるはず。サーブレットコンテナ上で使う場合や、コネクションごとに値を変えたいケースでは、現実的じゃない。簡単なクライアントだったらOKだけれども。

こうなってくると、いよいよスレッドかなー。スレッドにしておくと、後々の利便性も高そうだし、やってみる価値はありそう。

NekoHTML+XPathで注意すべきこと

HTMLパーサの素敵ライブラリ NekoHTML のパース結果を、XPathAPI でごにょごにょしようとしたら、上手くノードが取れない。なぜ。

Document doc = parser.getDocument();
NodeList nodelist = XPathAPI.selectNodeList(doc, "//input");

試しに Xerces2 の DOMParser を使ってみると、上手く行く。まさか相性とかじゃないし、何だろうと思ってログを眺めていたら、タグ名が大文字になって返ってきてるわけ。えー。

ちゃんとFAQに書いてありました。

Element names are written in uppercase letters (e.g., BODY). Attribute names are written in lowercase letters (e.g., lang, onsubmit).

ということで、NekoHTML のパース結果に対してタグ名処理する場合は、大文字にしなくちゃいけない。

Document doc = parser.getDocument();
NodeList nodelist = XPathAPI.selectNodeList(doc, "//INPUT");

見事にハマりました。春だなあ。

HttpUnitはタイムアウトに未対応だって

Webページを自動巡回するのに、HttpUnitを使ったら便利かなーと思っていたけど、コネクションのタイムアウト設定がサポートされてないっぽい。今時、JDK1.3ベースなのか。うーん、惜しい。

やっぱりcommonsのHttpClientを使うのが良いかなー。さすがに自前でソケットをイジイジすんのは辛いからなあ。

FindBugsにヘコまされ

遅ればせながら、FindBugsを使ってみた。

ソースレビュー代わりに使えるかと思って、今のプロジェクトで試してみたら、1600個も問題点を指摘されてしまった。最初、160個だと思って、それでもビックリしたのに、よくよく見たら1600個って。しかも自分で書いたとこも、相当数を指摘されている…。ううう、これは結構ヘコむなー。

まあ、実行前にバグが分かるということで、これは開発時に各自が使うツールなんだろうなあ。XPの代わりってことにもならないし、開発効率向上ツールの域内かしらむ。結局、ソースレビューの目的とは、ちと次元が違うんだな。期待しすぎか。

結論、やっぱり人間はスゴイ。

奥さん、HttpClient が便利すぎます

4年ぶりにJavaでネットワークプログラミング。

はじめは java.net.Socket か java.net.HttpURLConnection クラスで実装しようと思っていたけど、commons にて HttpClient を発見。使ってみたら、スゲー便利。そうそう、こういうのを探してました!

Jakarta Commons - HTTP Client

ダウンロードするときは、パッケージ依存している commons-logging と commons-codecs もご一緒にどうぞ。

早速トライアルということで、POSTメソッドでIDとパスワードを送ってログインするプログラムを、Socket、HttpURLConnection、HttpClient の3つのバージョンで書いてみた。

続きを読む "奥さん、HttpClient が便利すぎます"

Appletで半角英数字も日本語フォントにするには

JREの設定がデフォルトのまま、Appletで半角英数字と日本語の、いわゆる和欧混植をやろうとすると、英数字だけ等幅フォントになってカッコ悪い。いじめカッコ悪い。

すべて日本語フォントを使用するように変えてみようと、設定ファイルであるところの、fontconfig.properties を適当にイジってみたら上手くいったみたい。おお。

sequence.allfonts=japanese-iso10646,latin-1
sequence.allfonts.UTF-8.ja.JP=japanese-iso10646,latin-1

こんな感じで、latin-1 より先に日本語フォントが使われるように、検索順序を指定してやれば良いっぽい。よく分かってないけど。完全に自分メモです、これは。

ただでさえ慣れないJavaのフォント設定を、さらにフォント周辺が分かりづらいLinuxで行っていると、だんだん頭がおかしくなってくる気がする。ううう。

Tilesフレームワークは誰のため?

新規にJavaでWebアプリケーションをこさえることになったので、いろいろと方針を画策中。

画面数が多いのが気になったので、Tilesフレームワークでちょっとはラクできないかと考えたんだけど、どうも都合が悪い。画面の共通要素をタイルとして切り出すことで、必要最小限の画面生成で済むと思ったんだけど、かなり中途半端な印象。

ほとんど共通なんだけど、数箇所だけ各ページで異なるような場合がとても面倒。ムリヤリ何とかできなくも無さそうだけど、そんな保守性の下がるようなことは、今回のラクしたいという目的と背反なので、完全にボツ。JSPファイルが増えたり、設定ファイルが複雑になるのは避けたい。

そもそもTilesフレームワークというのは、簡単なレイアウト機能を提供するもので、世のWebアプリをframesetから解放するための仕組みにしか過ぎないのかな。それなら、共通要素は各JSPでimportして、レイアウトはCSSで行った方が、全然スッキリしそうだ。

個人的には、DreamWeaverのテンプレート機能のようなフレームワークが欲しいんだけど、見つけられなかった。自前で作れそうだけど、そんな時間は無いもんなあ。むむぅ。

最近、VelocityやTapestryのように、ビューとロジックを分離して、デザイナーとプログラマーの仕事を分業する仕組みばかり育っているけど、そこを同時進行する人にとっては、どうでも良い話だったりして。もしかして、Javaを選択したのがマズかったか…。

まあ、ここはスッパリとフレームワークは諦めて、ゴリゴリとJSP書いていくことにしよう。あとは運用フレームワークでカバーだなあ。うん。

operator does not exist: integer !=- integer

久しぶりに NetBeans で開発してみようかと思って、Tomcatを起動して動かしてみたら、こんなエラーを吐いて落ちる。なんでじゃ。APサーバー上では動いているのに。

org.postgresql.util.PSQLException: ERROR: operator does not exist: integer !=- integer

コンパイルに失敗したかなーと思って、JDKを替えて再構築するも状況は変わらず。よくよくエラー部分を見ると、SQLのパースで落ちている。とは言え、「!=-」なんて意味不明な演算子なんぞ使った覚えないんですがねー。むむむ。

んで、該当のSQLを見てみると、こんな記述。

WHERE group_id!=?

どうやら PreparedStatement でパラメータに負数が入ると落ちるということらしい。そんなことあるのか。どんなパースだ。でもAPサーバーでは動いているということは、開発環境の問題なのかな。うーむ。

続きを読む "operator does not exist: integer !=- integer"

jmapでオブジェクトのメモリ使用量を知る

J2SE1.5から試験導入されたトラブルシューティングツールのひとつ、jmapを使用するとヒープダンプ情報を取得することができる。どのオブジェクトが今どのくらい生成されて、どのくらいのサイズを占有しているか、定量的に見ることができる優れもの。これがJDK標準装備というのは素敵ですよ、奥さん。

とりあえず、一番わかりやすいところで、ヒープのヒストグラムを表示。

# jps
497 Jps
19719 Bootstrap

# jmap -histo 19719 > heap_histo.txt

すると、「heap_histo.txt」にメモリの現状がどわーっと表示されます。

Object Histogram:
Size        Count        Class description
-------------------------------------------------------
65156376        461687   char[]
22587104        118976   * ConstMethodKlass
19391400        484785   java.lang.String
14393048        11237    * ConstantPoolKlass
12386464        118976  * MethodKlass
10034000        102739  java.lang.Object[]

どのクラスのオブジェクトがどれくらいメモリを食っているかを知りたい場合にも良いし、メモリリーク時の原因調査の足がかりとしても使えそう。まあ、メモリリーク対策をするなら NetBeans とかのプロファイラーを使った方が良いんだけど、実運用環境で使えるという点では jmap は有用じゃないかと。

ただし、1.5ではSolaris/LinuxのJDKのみ。Windowsでは6から使えるようになるらしいッス。

GCViewer

GCViewer

JVMが吐き出すガーベッジコレクションのログを視覚化するツール。WindowsでもLinuxでも使える。稼働中のGCログを監視して、ダイナミックにグラフ化することもできるので、チューニング時に重宝するツールというわけです。

使い方は、いたってシンプル。JVMの起動時に、以下のようにGCログの出力先を指定して、そのログファイルを噛ませるだけ。ちなみに、これはSunのJVMの場合。HP-UX JVMとかは、-XVerbosegcとかで行けます。まあ、HP-UXだったら、HPjtuneを使った方が良いけど。

java -Xloggc:/var/log/gc.log -XX:+PrintGCDetails 

「+XX:+PrintGCDetails」を指定することで、Young領域とOld領域の情報もグラフに表示できるようになる。まあ、男は黙って「+XX:+PrintGCDetails」で良いんです。

これだけの機能があってオープンソースというのは嬉しい。

jstatの使い方

J2SE1.5から導入されたJVMの統計データ監視ツール、jstatの使い方メモ。

jstatを使えば、稼働中のJVMのヒープメモリの状態、パーマネント領域の状態、クラスローダーの統計情報などを参照することができる。イメージとしては、topコマンドみたいな感じで、JVMのリソース情報を監視できる。障害時の調査ユーティリティツールのひとつとして威力を発揮します。

まあ、プロファイリングツールではないので、メモリリークの有無は読み取れるけど、リーク箇所までは特定できないんで、そこは使い分けが必要だけど。

ここでは例として、Linuxのローカルマシン上で動いているtomcatの統計データを監視するケースを取り上げます。ただ、Windowsでも、同じ手順でOKのはず。

続きを読む "jstatの使い方"

JAVA_OPTSとCATALINA_OPTSの使い分け

tomcat起動時にJVMのオプションを指定するために、JAVA_OPTSとCATALINA_OPTSという2つの環境変数が用意されている。何が違うんだろうと思って、catalina.shを開いてみたら、両方に同じ説明が書いてある。

#   CATALINA_OPTS   (Optional) Java runtime options used when the "start",
#                   "stop", or "run" command is executed.
# 
#   JAVA_OPTS       (Optional) Java runtime options used when the "start",
#                   "stop", or "run" command is executed.

評価としては、JAVA_OPTS の次に CATALINA_OPTS がオプションとして付与されるようだけど、それがどう影響するのかわからない。オプションの順番で処理が変わったりするんだっけかな?

とりあえずJMeterでも使ってみるか

世間は連休ということで、しばし通常業務のことは忘れて、かねてよりマスト事項だったアプリケーションの負荷試験でもやってみようかと。とりあえず、定番のJMeterを使ってみた。

JMeterについては、事前知識はほぼゼロ。「リクエストを手軽にたくさん発行できるんでしょ?」くらいのイメージだったんだけど、これがスゴイ高機能で驚いた。

  • HTTP、FTP、LDAPをはじめ、Webサービスなど多様なリクエストを測定可能
  • アサーションによるテスト結果の評価ができる
  • 分析結果は表やツリー、グラフなど様々な形態でビジュアル化
  • レスポンスをファイルに出力できる
  • テストの実行順序や実行回数の制御が可能
  • リクエストの実行間隔を制御するタイマ機能を実装している
  • リクエスト間でのパラメータの引継ぎが可能(セッションIDとか)
  • 分散クライアントによる試験が実施できる
  • HTTPプロキシ機能でテストプランの自動生成が可能
  • ユーザー定義変数を使用したパラメータの細かい制御ができる

UIの評判が悪いようだけど、思ったより直感的に操作できた。リスナーやタイマ、処理などをツリー管理するインタフェースは、オブジェクト指向的だなあ、と思った。慣れれば問題なさそう。

ただ、ちょっと触ってみた感想としては、機能がたくさんありすぎて分からない、ということ。「ユーザーパラメータ」と「HTTPユーザーパラメータ」の違いとか、よく分からない。使いこなすためには、マニュアルの精読が必須かなあ。うむむ。

まずは一度、ちゃんとシナリオを作って、一通りをやってみるのが勉強になりそう。

続きを読む "とりあえずJMeterでも使ってみるか"