Jakarta ProjectのCommonsサブプロジェクトはさまざまな場面で活用できるライブラリを集めたプロジェクトです。今回から3回にわたってCommonsの代表的なコンポーネントについて使い方を説明していきたいと思います。
Commonsは多くのコンポーネントから構成されています。これらのうち正式に提供されていて安定して利用可能なものはThe Commons Properに属しており、実験的なコンポーネントについてはThe Sandboxに属しています。本原稿の執筆時点ではThe Commons Properには、次の17のコンポーネントが登録されています。
BeanUtils | JavaのリフレクションAPIとイントロスペクションAPI関連の利用しやすいラッパーを提供するコンポーネント |
---|---|
Betwixt | JavaBeansとXML文書のマッピングを行うためのコンポーネント |
Cactus | サーバサイドのJavaコードのためのテスティングフレームワーク。現在ではCactusはJakartaのトップレベルのプロジェクトに移動されている |
CLI | コマンドライン引数やオプションに関するシンプルなAPIを提供するコンポーネント |
Collections | Javaコレクションフレームワークを拡張するクラス群を提供するコンポーネント |
Discovery | さまざまなスキーマを用いてサービス名や参照名とリソース名を対応づけることによってリソース(クラスを含む)の場所を特定するためのツールを提供するコンポーネント |
Digester | XMLとJavaオブジェクトのマッピングユーティリティ。主にXMLで記述された設定ファイルをパースするために用いる |
DBCP | データベースのコネクションプーリングサービスを提供するコンポーネント |
FileUpload | ServletやWebアプリケーションにファイルアップロード機能を追加するためのコンポーネント |
HttpClient | クライアントサイドで動作するHTTPプロトコルのフレームワークを提供するコンポーネント |
JXPath | JavaBeansの命名規則に従うようなJavaのクラスをXPathの構文を用いて操作するためのユーティリティを提供するコンポーネント |
Lang | java.langパッケージに属するクラスにさらなる機能性を提供するようなユーティリティクラス群を提供するコンポーネント |
Latka | HTTP機能の自動テスティングのためのテストスイート |
Logging | さまざまなロギングAPIの実装をラップして利用するためのコンポーネント |
Modeler | JMX(Java Management Extensions)仕様と互換性のあるモデルMBeanを生成するためのメカニズムを提供するコンポーネント |
Pool | オブジェクトプーリング機能を提供するコンポーネント |
Validator | 受信データの妥当性を検証するメソッドと検証規則をXMLファイルで定義するためのシンプルで拡張可能なフレームワークを提供するコンポーネント |
今回から3回にわたって、これらのコンポーネントのうち比較的利用場面が多いと思われるDigester、DBCP、Pool、Collections、Langについてサンプルプログラムを使って説明していきたいと思います(なおLoggingについては別の回にご説明します)。初回である今回はDigesterの説明をします。
プログラムの設定ファイルといえばjava.util.Propertiesクラスで読み込むことのできる形式であるプロパティリスト(リスト1)がまず思い浮かぶと思います。この「キーと要素のペア」式のファイルは扱いが簡単であるため小規模のプログラムでは手軽に用いることができますが、その半面構造化されていないため複雑な設定を記述する必要のある大規模プログラムで利用するには不向きであるといえます。
リスト1 プロパティリストの例 |
data-source.driverClass=com.mysql.jdbc.Driver |
そこで、ある程度以上の規模のプログラムでは構造を持つデータ形式であるXML(Extensible Markup Language)を用いて設定ファイルを記述するのが一般的になっており、例えばTomcatやStrutsなどでも設定ファイルはXMLで記述されています。そこで今回取り上げるサンプルプログラムでもXMLで設定ファイルを記述することにします。リスト2は今回のサンプルプログラムのための設定ファイルであり、データベース接続のための設定情報が記述されています。
通常XMLで記述されたファイルを解釈するにはDOM(Document Object Model)やSAX(Simple API for XML Parsing)を用いますが、これらは機能が豊富であり汎用的なAPIで構成されているため、単純なことをしたい場合でもある程度以上の量のコードを記述する必要があります。これに対して今回取り上げるDigesterはいわば設定ファイルを読み込むことに特化しているため、SAXやDOMを生で使用する場合に比べて格段に少ないコード量で設定ファイルの読み込み機能を実装することができます。
DigesterはもともとはStrutsにおいてXMLで書かれた設定ファイルを読み込むために開発されたユーティリティクラスでしたが、現在ではJakarta Commonsのコンポーネントとして提供されています。
Digesterを利用すると、XMLファイルをJavaのオブジェクトツリーの形で読み込むことができます。XMLファイルからオブジェクトツリーを構築するための仕組みを知るには、Digesterが持つ次の2つの機能要素について知る必要があります。
Digesterを利用するには、対象となるXMLファイルのそれぞれの要素(タグ)とマッチするようなパターン文字列と、マッチしたときに何を行うかを表すプロセッシングルールの組をあらかじめ登録しておく必要があります。Digester#parse()メソッドが呼ばれると、Digesterは登録されているパターン文字列とXML要素を逐次照合します。そしてXML要素がパターン文字列にマッチした場合、パターン文字列に対応するプロセッシングルールを実行します。プロセッシングルールとしてはオブジェクトを生成したりオブジェクトのメソッドを呼び出したりするほか、オブジェクトスタックを操作するようなルールを指定できます。こうしてオブジェクトスタックをテンポラリバッファとして利用しつつオブジェクトツリーを構築していけるようになっています。
なお、よく利用するようなプロセッシングルールはあらかじめ用意されていますが、ユーザーが自由に作成することもできます。プロセッシングルールの作成方法やあらかじめ用意されているプロセッシングルールについてはJakartaのページで公開されているドキュメントを参照してください。
原稿執筆時のDigesterの最新バージョンは1.3(2003年3月現在)です。DigesterはJakarta Commonsのページからダウンロードしてください。また、このバージョンのDigesterを利用するにはほかに以下のCommonsコンポーネントが必要です。
またDigesterは内部でSAXパーサを利用していますので、JavaプラットフォームとしてJ2SEのバージョン1.3以前をお使いの場合は別途CrimsonやXercesなどのSAXパーサを用意する必要があります。
それではサンプルプログラム(ここから一連のソースファイルをダウンロードできます)を用いて具体的にDigesterの動作を見ていきましょう(リスト3)。
サンプルプログラムではDigesterを用いてリスト2の設定ファイルを読み込みます。読み込んだ結果、<sample>要素に対応するSampleConfigクラス(リスト4)のオブジェクトが<data-source>要素に対応するDataSourceConfigクラス(リスト5)のオブジェクトを子に持つオブジェクトツリーが生成されます。
サンプルプログラムをコンパイルしてクラスパスを適切に設定したうえでコマンドラインにて、
java net.skirnir.sample.Sample XMLファイル名
|
というコマンドを実行することで、生成したオブジェクトツリーが持つ設定値を表示させることができます。
ところで、Digesterを用いてXMLファイルを読み込むためのメソッドがSampleConfigの中のload()メソッドです(リスト6)。
リスト6 load()メソッド | ||||||||||||||||||||
public void load(File configFile)
"setDataSourceConfig",
"setProperty", 2);
0, "property");
1, "value");
} catch (IOException ex) { |
このメソッドの内容について、順を追って説明していきましょう。
(1)でorg.apache.commons.Digesterクラスのインスタンスを生成します。(2)では読み込むXMLファイルの検証を行わないことをDigesterに指示しています。検証を行う場合はDigester#setValidating(true)とします。(3)ではこのオブジェクト(SampleConfig)自身をオブジェクトスタックにプッシュしています。
これでDigesterの初期設定は完了です。次に(4)〜(8)の部分でプロセッシングルールを登録していきます。(4)ではsample/data-sourceというパターン文字列とオブジェクトを生成するためのプロセッシングルール(ObjectCreateRule)の組を登録しています。sample/data-sourceというパターン文字列はXMLファイル中の<sample>要素の中の<data-source>要素とマッチします。
またObjectCreateRuleは第2引数に指定したクラス名のクラスのインスタンスを生成してオブジェクトスタックにプッシュするようなルールです。従って、(4)の意味は「<sample>要素の中に<data-source>要素が見つかったらnet.skirnir.sample.DatasSourceConfigクラスのインスタンスを生成してオブジェクトスタックにプッシュせよ」ということになります。
引き続き(5)ではsample/data-sourceというパターン文字列とオブジェクトスタック上の2つのオブジェクトを関連付けるためのプロセッシングルール(SetNextRule)の組を登録しています。SetNextRuleはオブジェクトスタックの上から2番目(next)のオブジェクトについて第2引数に指定したメソッドを呼び出すようなルールです。呼び出されるメソッドは第3引数に指定したクラス名のクラスのインスタンスを引数として持つと仮定され、実際の引数としてはオブジェクトスタックの一番上にあるオブジェクトが渡されます。従って(5)の意味は「<sample>要素の中に<data-source>要素が見つかったらオブジェクトスタックの上から2番目のオブジェクトについてsetDataSourceConfig()メソッドを呼び出せ。このとき引数としてはオブジェクトスタックの一番上のオブジェクトを渡せ」ということになります。
最後のプロセッシングルールが(6)〜(8)のCallMethodRuleとCallParamRuleです。これら2つは組で働きます。意味はオブジェクトスタックの一番上のオブジェクトについてCallMethodRuleの第2引数で指定したメソッドを呼び出します。呼び出すメソッドの引数の個数は第3引数で指定した個数で、実際の引数としてはCallParamRuleの第3引数で指定した属性(パターンにマッチした要素の属性です)の値が渡されます。
何番目の引数として渡されるかは第2引数で指定されます。従って(6)〜(8)の意味は「<sample>要素の中の<data-source>要素の中に<set-property>要素が見つかったらオブジェクトスタックの一番上のオブジェクトについてsetProperty(<set-property>要素のproperty属性の値、<set-property>要素のvalue属性の値)メソッドを呼び出せ」ということになります。
以上でプロセッシングルールの登録は完了です。後は(9)のようにDigester#parse()メソッドを呼び出せばXMLファイルの読み込みが行われます。XMLファイルを読み込み、ファイルの先頭から順に要素が登録されているパターン文字列と一致するかチェックされ、一致している場合は対応するプロセッシングルールを呼び出します。
パターン照合とプロセッシングルールの実行機構によってオブジェクトスタックを操作することでXMLファイルからJavaのオブジェクトツリーを生成するDigesterの仕組みは、最初は複雑に思えるかもしれませんが、慣れるとどういうXMLファイルを読み込むにはどういうパターン文字列とプロセッシングルールを登録すべきかが思い浮かぶようになります。皆さんもぜひ実際にDigesterを用いてXMLファイルを読み込むプログラムを作成することでDigesterに慣れていってください。
次回はデータベースコネクションのプーリングを行うためのDBCPと汎用のオブジェクトプーリング機構を構築するためのPoolについて説明します。
横田健彦(よこた たけひこ)
東京工業大学卒業後、(株)東芝に入社。現在、知識メディアラボラトリーにてコミュニティベース情報共有システムの研究に従事。小学校のころからコンピュータに触れ、主にゲームプログラミングを通してBASIC、アセンブラをはじめとする多数の言語を学ぶ。JavaではJakartaプロジェクトの成果物を利用していく中で主にWebアプリケーションプログラミングの面白さに引かれ、Ja-Jakartaプロジェクトの活動に貢献する一方でオープンソースのJavaベースのWebコンテンツ管理システムであるKvasir/Soraの開発を行っている。
Copyright © ITmedia, Inc. All Rights Reserved.