Velocity

Velocityについて

コミュニティ

ドキュメント

比較

ツール

日本語訳について

目次

  1. はじめに
  2. リソース
  3. Velocity の動作原理
  4. Singletonにすべきか否か…
  5. コンテキスト
  6. Servlet で Velocity を使う
  7. 一般的なアプリケーションで Velocity を使う
  8. EventCartridge とイベントハンドラ
  9. Velocity 設定キーと値
  10. ログシステム設定
  11. リソースローダの設定
  12. 国際化のためのテンプレートエンコーディング
  13. Velocity と XML
  14. FAQ (よく聞かれる質問)
  15. まとめ
  16. 追記 1:サンプル Servlet の配備


はじめに

Velocity は、Java ベースのテンプレートエンジンであり、 データをフォーマット・表示する文書を簡単に作成・提供するための単純で強力な開発ツールです。 このガイドでは、 Velocity の主な用途である以下の2つの領域に焦点を当てながら、 Velocity を使用した開発の基本概要について説明したいと思います。 :

  • Servlet ベースの WWW 開発
  • 一般的なアプリケーションでの使用

両者は本質的には違いはないことが分かると思います。あえて違いがあるとすれば、 Servlet 開発では基本クラスとして我々の提供する Velocity Servlet を使うと簡単になるのと、 アプリケーション開発で役立つユーティリティクラスを提供していることぐらいでしょう。

導入

この情報は Velocity サイト上や文書内の他の場所にもありますが、 念のために、ここでも記述しています。 Velocity をあなたのコンピュータで動かすのは、非常に簡単です。 なお、全てのディレクトリの参照は、 Velocity 配布のルートディレクトリを基準にしていますのでご注意ください。

  1. Velocity 配布を入手します。 リリース版や、夜間スナップショットとしても入手できますし、直接 CVS コードリポジトリからも入手可能です。 どれでも構いませんが、最新の機能なら、夜間スナップショットがおそらく一番良いでしょう。 詳細情報は、こちらを参照してください。
  2. Java 構築ツールの Jakarta Ant を まだインストールしていない場合には、まずそれをインストールしてください。 Velocity を使用するには必要ありませんが、Velocity を構築するのに必要です。
  3. 配布の build ディレクトリに移動します。
  4. ant <build target> とタイプします。<build target> は以下のうちのどれかです。
    • jar bin ディレクトリに Velocity の完全版の jar ファイルを構築します。jar ファイルは、'velocity-X.jar' という名前で、 「X」は、現在のバージョン番号です。このjarファイルにはVelocity で必要なコンポーネントは含まれていません。このターゲットを使う場合は、 Jakarta Commons から Collections コンポーネントを入手し、クラスパス (あるいは WEB-INF/lib)に追加する必要があります。 ビルドインされたログ機能やテンプレート変換機能を使いたい場合は、 クラスパス か webapps の WEB-INF/lib に jar ファイルを適宜含めなければなりません。 便宜上、ORO、Logkit、Commons Collections を含めた jar ファイルを構築できる jar-dep タスクを使うこともできます。
    • jar-dep bin ディレクトリに Velocity の完全版の jar ファイルを構築します。この jar ファイルには、 Jakarta Avalon Logkit パッケージによるロギングに必要なサポートや、 Jakarta Commons による重要な設定のサポートや、 Jakarta ORO パッケージを使った WebMacro テンプレート変換に必要なサポートが含まれています。
    • jar-core bin ディレクトリにサイズの小さな「velocity-core-X.jar」という 名前のVelocity JAR ファイルを構築します。この JAR ファイルには、Velocity 機能のコアが含まれていますが、サンプルや、Anakia、Texen 、VelocityServer をサポートする基本クラスといったユーティリティは含まれていません。
    • jar-util bin ディレクトリに「velocity-util-X.jar」という名前の ユーティリティ Velocity JAR ファイルを 構築します。この JAR ファイルには、 Anakia、Texen 、 WebMacro テンプレート変換ユーティリティといった、 ユーティリティのコードが入っています。通常の jar ターゲットと同様の外部依存が必要です。
    • jar-servlet bin ディレクトリに「velocity-servlet-X.jar」という名前の ユーティリティ Velocity jar ファイルを構築します。この jar ファイルには、 servlet プログラマ向けのユーティリティのコードがあります。 通常の jar ターゲットと同様の外部依存が必要です。
    • jar-j2ee 「jar」ターゲットと同様に、 J2EE サポートを必要とするすべてのコンポーネントが含まれている、 完全な jar を構築します。現在のところ、 org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader だけしか含まれません。他のものと同様に、「velocity-j2ee-X.jar」という名前で、 bin ディレクトリに置かれます。注意: この構築ターゲットを使用したいときには、build/lib ディレクトリに j2ee.jar のコピー(またはリンク)を置かなければなりません。我々は、 配布の一部としてそれを提供していません。取得元としては、 http://java.sun.com/ が良いしょう。通常の jar ターゲットと同様の外部依存が必要です。
    • jar-J2EE-dep J2EE をサポートする完全な jar ファイルを構築し、Jakarta Avalon Logkit によるロギングサポートや、Jakarta ORO パッケージによる正規表現サポートが含まれています。上記の jar-dep ターゲットでの注意もご覧下さい。
    • examples examples ディレクトリにあるプログラムサンプルのコードを構築します。 このターゲットは forumdemo プロジェクトも構築します。
    • forumdemo examples/forumdemo ディレクトリにサンプル Web アプリケーションを 構築します。
    • docs Velocity の Anakia XML 変換ツールを使用して 今ご覧のドキュメントを docs ディレクトリに構築します。 スタイルシートの代わりに Velocity テンプレートを使うことができます。 -- 一度お試しください! 注意:このターゲットでは、 jakarta-site2 プロジェクトのディレクトリが jakarta-velocity 配布ディレクトリと同じディレクトリの下にある必要があります。 このターゲットについての詳細は build.xml ファイルをご覧ください。
    • jar-src 全ての Velocity ソースコードを一つの jar にまとめ、 bin ディレクトリに置きます。
    • javadocs docs/api ディレクトリに Javadoc クラスドキュメントを構築します。
    • test (jar タスクのあとで) テストルーチンの testbed スイートに対して Velocity のテストを行います。
    • help 利用できる構築ターゲットの一覧を表示します。
  5. ビルドのテストは、必要ではありませんが、するに越したことはないでしょう。 上記の test ターゲットを使ってください。
  6. これで、 Velocity を、使用する準備ができました。JAR ファイルを、 クラスパスなどの適切な場所( Servlet で使うのなら、webappの lib ディレクトリとか)に置きます
  7. サンプルを試してみたいという場合(はじめての場合には特に推奨します)には、 ant examples でサンプルを構築してください。

依存関係

Velocity は汎用的な機能に関していくつかのパッケージに依存しています。 これらのパッケージは便宜上、build/lib に入っています。 しかし、デフォルトのビルドターゲット(上述)には入っていません。 デフォルトのビルドターゲットを使う場合は、 クラスパスにこの依存関係を加えなければなりません。

  • Jakarta Commons Collections -- 必須です。
  • Jakarta Avalon Logkit -- オプションですが、非常に一般的です。 Velocityで、デフォルトのファイルベースのロギングを使う場合に必要です。
  • Jakarta ORO -- オプションです。org.apache.velocity.convert.WebMacro テンプレート変換ユーティリティを使う場合に必要です。


リソース

かなりの数のリソースやサンプルをプログラマは利用できます。 サンプルやドキュメント、できればソースコードもチェックすることをお勧めします。 素晴らしいソースのいくつかを紹介しましょう。

  • ユーザコミュニティと開発者コミュニティ : メーリングリスト から参加してください。
  • メーリングリストアーカイブ : http://www.mail-archive.com は、そのひとつです。 velocity-user、 velocity-devの両方のアーカイブを見るには、検索フィールドに 'velocity' と入力してください。
  • ソースコード : src/java/… : Velocity プロジェクトのすべてのソースコードがあります。
  • アプリケーションサンプル 1 : examples/app_example1 : アプリケーションプログラムでの Velocity の使い方を示した簡単なサンプル。
  • アプリケーションサンプル 2 : examples/app_example2 : Velocity アプリケーションユーティリティクラスを使用したアプリケーション プログラムの簡単なサンプル。
  • Servlet サンプル : examples/servlet_example1 : Servlet での Velocity の使い方を示した簡単なサンプル。
  • ロガーサンプル : examples/logger_example : カスタムロギングクラスを作成し、全てのログメッセージを受信できるように Velocity に登録する方法を示す簡単なサンプル。
  • XML サンプル : examples/xmlapp_example : JDOM を使って、Velocity テンプレート内から XML ドキュメントデータを読み込んでアクセスする方法を示す簡単なサンプル。 ドキュメントツリーを探索するための再帰的な Velocimacro デモも含まれています。
  • イベントサンプル : examples/event_example : Velocity 1.1 の イベントハンドリングAPIを使い方をデモするサンプル。
  • Anakia アプリケーション : examples/anakia : Velocityを使って、XML データを処理するスタイルシートを作る方法 を示すサンプルアプリケーション。
  • フォーラムデモ Web アプリ : examples/forumdemo : 単純なServletベースのフォーラムアプリケーションの動作サンプル。
  • ドキュメンテーション : docs : html で生成されたVelocityプロジェクトの全てのドキュメント。
  • API ドキュメント : docs/api : 生成された、Velocity プロジェクトの Javadoc ドキュメント
  • 各種テンプレート : test/templates : testbed ディレクトリ内には、テンプレートサンプルがたくさん入っています。 VTL (Velocity Template Language) の使い方についてのすばらしい情報源となるでしょう。
  • コンテキストサンプル : examples/context_example : Velocity コンテキストの拡張方法を示した2つのサンプルがあります。 上級者向け。

上記の全てのディレクトリは、配布ルートディレクトリからの相対パスとなっています。


Velocity の動作原理

「基本パターン」

アプリケーションプログラムや Servlet で Velocity を使う場合 (実際のところ、何で使う場合も)、通常は以下のことを行う必要があります。

  1. Velocity を初期化します。 これは、Singleton と、「分離実行時インスタンス」(詳細については下記参照) というVelocity の利用パターンの両方に適用され、一度だけ行う必要があります。
  2. Context オブジェクトを生成します (詳細は後述)。
  3. データオブジェクトを Context に追加します。
  4. テンプレートを選択します。
  5. 出力を生成するためにデータとテンプレートを「マージ」します。

org.apache.velocity.app.Velocity クラスから Singleton パターンを使用する場合、 コードではこんな風になります。

import java.io.StringWriter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ResourceNotFoundException; 
import org.apache.velocity.exception.ParseErrorException; 
import org.apache.velocity.exception.MethodInvocationException; 

Velocity.init();

VelocityContext context = new VelocityContext();

context.put( "name", new String("Velocity") );

Template template = null;

try
{
   template = Velocity.getTemplate("mytemplate.vm");
}
catch( ResourceNotFoundException rnfe )
{
   // テンプレートが見つからない
}
catch( ParseErrorException pee )
{
  // 構文エラー : テンプレートの解析時に問題発生
}
catch( MethodInvocationException mie ) 
{ 
  // テンプレートのどこかで例外が投げられた
} 
catch( Exception e )
{}

StringWriter sw = new StringWriter();

template.merge( context, sw );

これが、基本的なパターンです。とっても単純ですよね? これが、 テンプレート処理で Velocity を使うときに通常行うことです。 たぶん、ここまで厳密にコードを書くことにはならないでしょう -- Servlet プログラマとアプリケーションプログラマの両方に対して、 より簡単にするためのいくつかのツールを用意しています。 このガイドの後の方で、 Servlet と一般的なアプリケーションの両方での Velocity の使い方について説明し、 より簡単にするために我々が提供するツールについて説明します。 しかし、どちらの場合でも上記のような処理が、 表立って、あるいは舞台裏で行われているのです。


Singletonにすべきか否か…

Velocity 1.2 からは、Velocity エンジンを使うにあたって、開発者には Singleton モデルと分離インスタンスモデルの 2 つの選択肢があります。 どちらの方法でも同じコアの Velocity コードを使用し、どちらの方法でも Velocity を簡単に Java アプリケーションに統合できます。

Singleton モデル

これは従来のパターンで、JVM (場合によっては Webアプリケーション) 内にただ一つの Velocity エンジンのインスタンスがあり、これを全てで共有します。 設定をローカライズしたり、リソースを共有することができるので、とても便利です。 例えば、このパターンは Servlet 2.2 以降に準拠した Web アプリケーションで使用するのに適切なモデルです。なぜなら、 各 Web アプリケーションが独自の Velocity のインスタンスを持つため、 Web アプリケーションの Servlet は、テンプレート、ロガーといったリソースを共有できるからです。 Singleton は、org.apache.velocity.app.Velocity クラスからアクセス でき、以下の例のように使用します。

 

import org.apache.velocity.app.Velocity; 
import org.apache.velocity.Template; 

(中略) 
/* 
 *  エンジンの設定 -- サンプルとして、このクラスそのものを
 *  ロガーとして使っています -- ロギングサンプルを参照
 */ 
Velocity.setProperty( Velocity.RUNTIME_LOG_LOGSYSTEM, this); 
/* 
 *  ここで、エンジンを初期化します
 */ 
Velocity.init(); 

(中略) 

Template t = Velocity.getTemplate("foo.vm"); 

Singleton モデルは、 org.apache.velocity.servlet.VelocityServlet というベースクラスでも使われていることに注意してください。 このクラスは Servlet を簡単に作成するためにこの配布で提供されている ユーティリティクラスです。 このクラスを拡張するのが、Velocity を使った Servlet を開発する際に最も一般的で便利な方法ですが、 何か別のものが必要ならばこのクラスを使わないことも可能です。

分離インスタンス

バージョン 1.2 から、分離インスタンスによって、同一のJVM (または Web アプリケーション) 内で Velocity インスタンスを欲しいだけ生成し、設定し、使用することができます。 テンプレートディレクトリやロガーなどのように、同じアプリケーションで 別々の構成をサポートしたいときに役に立ちます。分離インスタンスを使用するには、 org.apache.velocity.app.VelocityEngine クラスを使用します。 上記の Singleton の例と似たような例があります。

 
    
import org.apache.velocity.app.VelocityEngine; 
import org.apache.velocity.Template; 

(中略) 

/*
 * 新たなエンジンのインスタンスを生成
 */

VelocityEngine ve = new VelocityEngine(); 

/*
 * エンジンの設定。この場合、このクラスそのものを、
 * ロガーとして使用しています(ロギングサンプルを参照)。
 */

ve.setProperty( VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this); 

/*
 * エンジンを初期化
 */

ve.init(); 
 
(中略) 

Template t = ve.getTemplate("foo.vm"); 

ごらんのように、これはとても単純でストレートです。 幾つかの単純な文法の変更を除いて、 Singleton にせよ分離インスタンスにせよ、 Velocity を使う時にアプリケーションやテンプレートの高レベルの構造を 変更する必要はありません

もしプログラミングする場合に Velocity 内とやり取りするのに使うクラスは、 Singleton モデルを使用する場合には org.apache.velocity.app.Velocity で、 Singleton でないモデル(「分離インスタンス」)を使用する場合には org.apache.velocity.app.VelocityEngine です。

アプリケーションでは、org.apache.velocity.runtime パッケージの RuntimeRuntimeConstantsRuntimeSingletonRuntimeInstance の各クラスは絶対に使わないでください。 これらは内部使用のみを想定しており、いつか変更される可能性があります。 上で説明したとおり、使うべきクラスは org.apache.velocity.app パッケージにある、Velocity クラスと VelocityEngine クラスです。これらのクラスに何かが抜けていたり何かが必要ならば、 ためらわずに変更点を提案して下さい。 -- これらのクラスはアプリケーション開発者向けのものです。


コンテキスト
基本

『コンテキスト』の概念は、Velocity の核となるもので、システムの各部分の間で、 データのコンテナ(入れ物)をやり取りするのに一般的なテクニックです。 つまり、コンテキストは、 Java レイヤ (あるいはプログラマ) とテンプレートレイヤ (あるいはデザイナ) の間でのデータの「運び屋」だということです。 プログラマは、アプリケーションで必要な色々なタイプのオブジェクトを集めて、 コンテキストに設定します。デザイナの方では、これらのオブジェクト、 あるいはそのメソッドやプロパティは、リファレンス と呼ばれるテンプレート要素でアクセスできます。 一般的に、プログラマはデザイナと一緒にアプリケーションでのデータ要件を決めます。 ある意味ではこの要件が、デザイナがテンプレートでアクセスできるデータセットを生成する 「API」となります。ですから、開発プロセスのこのフェーズではある程度時間を割いて 慎重な分析を行うだけの意味があります。

Velocityを使うと、特別な要件やテクニック (例えばLDAPサーバに直接アクセスする コンテキストとか) をサポートする自分用のコンテキストクラスを作ることもできますが、 配布の一部として、VelocityContext という良く出来た基本的な実装クラスが用意されています。

VelocityContext はあらゆる汎用的な用途に適しており、使用を強く推奨します。 自分用のコンテキスト実装を拡張または作成する必要があるのは例外的で高度な場合のみです。

VelocityContext の使い方は、通常の Java の Hashtable クラスを使用するのと 同じくらい単純です。このインタフェースには便利なメソッドがいろいろありますが、 主に使うメソッドは以下の2つです。

public Object put(String key, Object value);
public Object get(String key);

HashTable と同様に、値は java.lang.Object から派生しており、null は禁止されています。 int や float といった基本タイプは適宜ラッパクラスでラップしなければなりません。

基本的なコンテキストの操作方法は本当にこれで全てです。詳細については配布に含まれている APIドキュメントをご覧下さい。

#foreach() での繰り返しオブジェクトのサポート

プログラマであれば、コンテキストへのオブジェクトの設定を極めて自由に行えます。 しかし、他の大部分の自由と同様に、この自由にも少しですが責任がついてきます。 そのためには、 Velocity のサポート対象とそれによって起こる問題を理解する必要があります。 Velocity は VTL の #foreach() 指示子で使うのに適した、 何種類かのコレクションタイプをサポートしています。

  • Object[] 通常のオブジェクト配列。特に説明の必要はないでしょう。 Velocity 内部では、Iterator インタフェースを備えたクラスで配列をラップしますが、 それはプログラマまたはテンプレート作者であれば気にする必要はありません。
  • java.util.Collection Velocity ではループで使う Iterator を 取得するのに iterator() メソッドを使用します。 したがってオブジェクトで Collection インタフェースを実装する場合は iterator() が正しく動作する Iterator を返すことを確認してください。
  • java.util.Map この場合、Velocity は、ループで Iterator を取り出すために呼ばれる iterator() メソッドを持っている Collection インタフェースを取得するのに、インタフェースメソッドの values() を使います。
  • java.util.Iterator 使用上の注意: 今のところ条件つきでのみサポートされています -- 懸念されるのは Iterator が 「リセット不可」であることです。もし Iterator が「裸のまま」で [訳注:他の型を経由せずに] コンテキストに設定されて #foreach() で2回以上使われる場合、 Iterator はリセットされないので、2回目以降の #foreach() ブロックでは失敗します。
  • java.util.Enumeration 使用上の注意: java.util.Iterator と同様に、今のところ条件つきでサポートされています -- 懸念されるのは Enumeration が「リセット不可」であることです。もし Enumeration が「裸のまま」でコンテキストに設定されて #foreach() で2回以上使われる場合、 Enumerationはリセットされないので、2回目以降の #foreach() ブロックでは失敗します。

IteratorEnumeration の場合、 どうしても必要な時のみコンテキストに設定することをお勧めします。 使用に関して問題がなく、かつ使用可能ならば、再利用可能な繰り返しインタフェースを Velocity が使えるようにするべきです。

直接 java.util.Iterator インタフェースを使用するのが適切な場合もあります (例えば、JDBC 経由の大きなデータセット)。しかし、もし避けられるのであれば、 他のものを使う方がよいでしょう。「直接」というのは以下のような場合をさします。

Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");

context.put("words", v.iterator() );

この場合、Iterator そのものがコンテキストに設定されます。 代わりに単純に以下のようにしたとしましょう。

context.put("words", v );

これですべて丸く収まります。Velocity は Vector が (List 経由で) Collection を実装していることを理解するので、iterator() メソッドを見つけられますし、このメソッドを使って、必要に応じて毎回「新鮮な」 Iterator を取得します。Iterator をそのまま使った場合(二つのコード例の最初の方)、 Velocityが #foreach() で一度使うと、次の #foreach() で使う場合に、新しいオブジェクトを取得できません。その結果、 このリファレンスを使った2回目以降の #foreach() ブロックは何も出力できません。

以上の説明で Velocity ではコレクションを使った繰り返し処理は、慎重に、かつよく考えて 使う必要があると言いたいわけではありません。むしろ通常は逆なのです。コンテキストに Iterator [訳注:Enumerationも同様です] を設定する時だけ気をつければいいのです。

コンテキスト連鎖

Velocity でのコンテキストの設計で革新的な機能は、コンテキスト連鎖 という概念です。時には コンテキストラッピング と呼ばれることもある、 この先進的な機能を使うと、別々のコンテキストをくっつけて、テンプレートからは、 「連続した」コンテキストであるように見えるようにできます。

具体的に例を示すのが一番でしょう。

VelocityContext context1 = new VelocityContext();

context1.put("name","Velocity");
context1.put("project", "Jakarta");
context1.put("duplicate", "I am in context1");

VelocityContext context2 = new VelocityContext( context1 );

context2.put("lang", "Java" );
context2.put("duplicate", "I am in context2");

template.merge( context2, writer );

上記のコードでは、 context2 が context1 に連鎖するように context2 を設定しました。 つまり、テンプレートでは二つの VelocityContext オブジェクトのどちらに設定した項目でも、 オブジェクトを加えるのに使うキーが重複しない限りはアクセスできるということです。 この場合は、「duplicate」というキーについては連鎖の最後のコンテキストに格納された オブジェクトが利用できます。上記の例でいえば、オブジェクトとして返されるのは、 「I am in context2」という文字列となります。

コンテキストの項目に関するこのような重複、あるいは「被覆」 (covering) で、下のオブジェクトに害を及ぼしたり変更したりはできないことに注意して下さい。 したがって上記の例では、「I am in context1」は無事ですし、context1.get("duplicate") でアクセスできます。しかし、テンプレート内では「$duplicate」というリファレンスの値は 「I am in context2」となり、覆われた「I am in context1」という文字列に、 テンプレートはアクセスできません。

同様に、テンプレート処理をした後で検証するコンテキストに、 情報を追加するテンプレートを使っている場合は注意が必要です。テンプレート内の #set() ステートメント経由でコンテキストに変更を加えても、 外側の [訳注:連鎖の後方の] コンテキストにしか影響しません。したがって、 テンプレートからのデータが内部のコンテキストに設定されていると思って、 外側のコンテキストを廃棄したりしないように気をつけてください。

この機能はいろんな使い方ができますが、その中でも特に一般的なのは、 階層化したデータアクセスやツールセットの提供でしょう。

先に述べたとおり、Velocity コンテキストの仕組も拡張できるのですが、それについては、 今のところ、このガイドの範囲外です。もし興味があるのでしたら、コンテキストがどのように まとめられるかを理解するために org.apache.velocity.context パッケージの各クラスのソースコードをご覧下さい。さらに、配布の examples/context_example ディレクトリにあるいくつかのサンプルでは、 代替的な実装を示しており、その中にはバックアップ先としてデータベースを使う 「あまり賢くない」 サンプルもあります。 [訳注:context_exampleのことだと思われます。]

これらのサンプルはあくまでデモや教育のためのものであり、サポートはされませんので、 ご注意ください。

テンプレートで生成されたオブジェクト

テンプレート内で実行時に生成されたオブジェクトを Java コードが扱わざるを得ない 状況としてよくあるのは次の2種類でしょう。

テンプレート作者が Java コードがコンテキストに設定したオブジェクトのメソッドを 呼び出すとき。

#set($myarr = ["a","b","c"] )
$foo.bar( $myarr )

テンプレートがオブジェクトをコンテキストに加えるとき。この場合、 マージ処理が完了した後で、Java コードはこれらのオブジェクトにアクセスできます。

#set($myarr = ["a","b","c"] )
#set( $foo = 1 )
#set( $bar = "bar")

こういうケースを扱う場合、とても単純な場合でも、以下の事柄だけは知っておくべきです。

  • VTLのRangeOperator [ 1..10 ] や ObjectArray ["a","b"] は、 コンテキストに設定される場合や、メソッドに渡される場合は、 java.util.ArrayList オブジェクトとなります。したがって、 テンプレート内で生成された配列を受け取るメソッドを作成する時は、 このことを考慮する必要があります。
  • コンテキスト内では数字は Integer になり、文字列はもちろん String になります。
  • Velocityはメソッド呼び出しにおいて引数を適切に「狭く」します。したがって、 #set() を通してコンテキストに設定された int データを引数に setFoo( int i ) を呼び出しても正しく動作します。
その他のコンテキストの課題

VelocityContext(および AbstractContext から派生するすべてのコンテキスト)で提供される 機能の1つに、ノード単位イントロスペクションキャッシングがあります。通常の場合、 開発者であっても、 VelocityContext をコンテキストとして使う限りは、 この機能を気にする必要はありません。しかし、この機能を意識しなければならない 既知の使い方のパターンが現在一つだけあります。

VelocityContext ではテンプレート内の構文ノードに関する、 イントロスペクション情報を、ノードを処理する(訪れる)ごとに蓄積していきます。 したがって、

  • 同じ VelocityContext を使って、同じテンプレート上で繰り返し処理を行っている
  • Template キャッシュがオフである
  • 繰り返しごとに getTemplate() で Template を要求している

という条件が重なると、VelocityContext が「メモリリーク」しているように見える ことがあります(実際には、さらなるイントロスペクション情報を集めているだけです)。 この場合、処理する(訪れる)テンプレートごとに、テンプレートノードのイントロスペクション 情報が蓄積され、テンプレートのキャッシュがオフであるため、 VelocityContext は、 毎回新しいテンプレートを処理していると思ってしまいます。そのため、他の場合に比べて、 より多くのイントロスペクション情報を集めることになり、消費メモリが多くなるのです。 この場合、以下の対応のうち最低でも一つは行うことを強く推奨します。

  • テンプレート処理プロセスによる解析毎に新しい VelocityContext を生成します。 これによって、イントロスペクションキャッシュデータの蓄積を防げます。 データやオブジェクトをロードしているため VelocityContext を再利用したい場合は、 ロードした VelocityContext をラップする[連鎖させる]だけで、「外側の」コンテキストが イントロスペクション情報を蓄積し、そうした情報は廃棄できます。例) VelocityContext useThis = new VelocityContext( populatedVC ); これで問題ないのは、外側のコンテキストがイントロスペクションのキャッシュデータを 保存しながら、内側のコンテキストから要求されたデータを取得できるからです (内側のコンテキストデータは空なので)。ただし気をつけるべきことがあります -- テンプレートでデータをコンテキストに設定し、 次の繰り返しでそれが使われることがわかっている場合は、 他の対応策を取る必要があります。 なぜなら、テンプレートで #set() メソッドを使う場合、 一番外側のコンテキストに保存されてしまうからです。詳しくは、 コンテキスト連鎖 の説明をご覧下さい。
  • テンプレートキャッシュをオンにします。これにより、繰り返しのたびにテンプレートが 解析されることが防げるため、イントロスペクションのキャッシュ情報の追加が避けられる のみならず、キャッシュ情報を使うことで性能向上につながります。
  • ループによる繰り返しの間はテンプレートオブジェクトを再利用します。そうすれば、 キャッシュがオフであっても、 Velocity は同じテンプレートを何度も読み込んだり、 何度も解析したりしなくなるので、 VelocityContext は毎回新しいイントロスペクション 情報を集めなくなります。


ServletでVelocityを使う
Servletのプログラミング

Velocity の最も代表的な利用領域は WWW 向けの Java Servlet プログラミングの領域です。 Velocity がこの領域で最適な理由はたくさんありますが、主要な理由のひとつに、 Velocity ではコード層からプレゼンテーション層(またはビュー) を強制的に分離できることが挙げられます。 このことに関しては多くのリソースがありますが、例えば こういうものがあります。

Servlet 環境で Velocity を使う基本テクニックは、非常に単純なものです。 念のために説明すると、やるべきことは提供されている VelocityServlet ベースクラスを 拡張して、ひとつのメソッド(handleRequest())を実装するだけです。 Servlet 開発で Velocity を使うのに必要なのは本当にこれだけなのです。

Velocity 1.1 では、以下の2つの handleRequest() メソッドがあります。

public Template handleRequest( Context )

これは、2つのメソッドの古い方です。このメソッドでは有効なテンプレートオブジェクトを 返す必要があります。有効でなかったり、null だったりすると、 エラーと見なされ、その結果、 error() エラーハンドリングメソッドが呼び出されます。必要なら error() をオーバーライドできます。null を返す可能性がある場合 (例えば、リクエストをリダイレクトさせたい場合)は、 次に説明する新しいメソッドを使用することが推奨されます。
public Template handleRequest( HttpServletRequest, HttpServletResponse, Context )
これは2つの handleRequest() メソッドの新しい方で、バージョン 1.1 において実装されました。上のメソッドとの違いは、このメソッドでは、Context に加えて、 HttpServletRequestHttpServletResponse オブジェクトがメソッドに対する引数として渡されるということです。もう一つの違いは、 このメソッドでは全ての処理をメソッドが行ったことを明示するために null を返せることと、全ての処理をメソッドが行った場合、Velocity は requestCleanup() 以外は何もしてはいけないということです。例えば、 要求をリダイレクトしたい場合には極めて役に立ちます。
当然のことながら、確実で最新の注意事項については、Javadoc API ドキュメンテーションを参照してください。

以下のコードは、配布のサンプルディレクトリに入っている SampleServlet.java クラスと 同じ物です。

public class SampleServlet extends VelocityServlet
{
    public Template handleRequest( HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   Context context )
    {

        String p1 = "Jakarta";
        String p2 = "Velocity";

        Vector vec = new Vector();
        vec.addElement( p1 );
        vec.addElement( p2 );

        context.put("list", vec );

        Template template = null;

        try
        {
            template =  getTemplate("sample.vm");
        }
        catch( ResourceNotFoundException rnfe )
        {
          // テンプレートを見つけられなかった
        } 
        catch( ParseErrorException pee )
        {
          // 構文エラー:テンプレート解析で問題あり
        }
        catch( Exception e )
        {}

        return template;
    }
}

見覚えがありますか? VelocityServlet ベースクラスが代わりに行う、 コンテキストオブジェクトの生成と merge() ステップを除いて、 このガイドの初めの方に説明した基本的なコードパターンと同じです。 この場合は、コンテキストを取得し、アプリケーションデータを追加し、 テンプレートを返します。

handleRequest()メソッドに渡されるデフォルトの Context オブジェクトには、現在のHttpServletRequestHttpServletResponseオブジェクトの両方が含まれています。 これらは、定数 VelocityServlet.REQUEST (値は「req」) と VelocityServlet.RESPONSE (値は「res」) を使って、 コンテキストに設定されます。Java コードでこれらのオブジェクトにアクセスするには、 以下のようにします。

public Template handleRequest(  Context context )
{
    HttpServletRequest request =  (HttpServletRequest) context.get( REQUEST );
    HttpServletResponse response =  (HttpServletResponse) context.get( RESPONSE );

   ...

そしてテンプレートでは以下のようにアクセスします。

#set($name = $req.getParameter('name') )

より高度な使い方として、 VelocityServlet ベースクラスは、 リクエスト処理のハンドリングの一部をオーバーライドできます。 オーバーライドできるのは以下の各メソッドです。

Properties loadConfiguration( ServletConfig )

通常の設定メカニズムをオーバーライドし、設定プロパティの追加や変更ができます。 実行時に Webアプリケーションのルートに絶対パスを設定するために、 テンプレートやログのパスをオーバーライドしたり増やしたりするのに役立ちます。
Context createContext(HttpServletRequest, HttpServletResponse )
自分でコンテキストオブジェクトを生成できます。これによってより高度なテクニック、 例えば、例えばコンテキストの連鎖や、ツールやデータでの事前ロードを行えます。 デフォルトの実装では、内部で設定されたリクエストおよびレスポンスオブジェクトを 含む VelocityContext オブジェクトを返します。 リクエストおよびレスポンスオブジェクトは、Servlet コンテナの実装によっては発生する かもしれない、イントロスペクションでの問題を回避するために単純なラッパクラスで ラップされています。リクエストおよびレスポンスオブジェクトは通常どおり使用できますし、 テンプレートからもどちらのメソッドにもアクセスできます。 人によっては重要かも知れないので、念のため注記しておくと、これらのクラスは、 厳密的には javax.servlet.XXXX クラスではありません。
void setContentType( HttpServletRequest,HttpServletResponse )
リクエストをチェックして、リクエストやクライアントに応じて独自のコンテントタイプを 設定できます。デフォルトの実装ではコンテントタイプは velocity.properties に指定した値か、指定されていなければデフォルトで「text/html」が設定されます。
void mergeTemplate( Template, Context, HttpServletResponse )
出力ストリームを生成できます。 VelocityServlet は非常に効率的な Writer クラスのプールを使いますので、通常は特別な状況においてのみオーバーライドされます。
void requestCleanup( HttpServletRequest, HttpServletResponse , Context )
リクエスト処理の最後に、クリーンアップやリソース再利用といった処理ができます。 デフォルトでは、何もしません。
protected void error( HttpServletRequest, HttpServletResponse, Exception )
リクエスト処理での例外発生時に呼ばれるエラーハンドラ。 デフォルトの実装では、ユーザへスタックトレースと例外情報とともに単純な HTML メッセージを送ります。クライアントメッセージをカスタマイズしたり、 より高度にエラーを扱うためにオーバーライドします。
詳細情報は、Javadoc の API ドキュメント をご覧下さい。

配備

Velocity ベースの Servlet を配備する場合、プロパティファイルが Velocity ランタイムを設定するのに使われているかどうか確認したいことがあるかと思います。 Tomcat でこの目的を達成するためには、Web アプリのルートディレクトリ(webapps/appname) に velocity.properties ファイルを置き、以下の内容を WEB-INF/web.xml ファイルに追加するという方法があります。

<servlet>
  <servlet-name>MyServlet</servlet-name>
  <servlet-class>com.foo.bar.MyServlet</servlet-class>
  <init-param>
      <param-name>properties</param-name>
      <param-value>/velocity.properties</param-value>
  </init-param>
</servlet>

記述が全て正しければ、MyServlet がロードされるとき、内部のデフォルトに依存せずに、 MyServlet自身を初期化するために velocity.properties ファイルを確実に使用します。

注意: Velocity は中心となるコアの Runtime クラスで Singleton モデルを使うので、 確実に Web アプリのクラスローダが自分の Runtime インスタンスを管理できるように、 velocity-XX.jar は CLASSPATH や Servlet コンテナのトップレベルの lib ディレクトリに置くのではなく、Velocity を使用するすべての Web アプリケーションの WEB-INF/lib ディレクトリに置くのがよいでしょう。

この配備方法なら、異なる Web アプリケーションでの Velocity 設定での衝突を確実に防げます。


一般的なアプリケーションで Velocity を使う

Velocity は汎用ツールとして設計されたので、一般的なアプリケーションプログラムでも、 Servlet で使う場合と同様に役に立ちます。 通常はこのガイドの初めに説明したのと同じプログラミングパターンを使うことができますが、 Servlet プログラミングで簡単に使える VelocityServlet ベースクラスを提供したのと同様に、アプリケーション用に、いくつかのユーティリティメソッドが用意されています。 アプリケーションプログラマとして追加で行う必要があるのは Velocity ランタイムエンジンを初期化することだけで、しかもそれは簡単です。

Velocity ヘルパクラス

Velocity には、Velocity(org.apache.velocity.app.Velocity) と呼ばれるアプリケーションユーティリティクラスがあります。 このクラスの目的は、Velocity の初期化で必要なメソッドや Velocity を使いやすくするのに役に立つユーティリティルーチンを提供することです。 このクラスはプロジェクトの Javadoc で文書化されていますので、より確実な詳細については、 そちらを参照してください。このドキュメンテーションは、本来チュートリアルであるため、 完璧な API 情報については、Javadoc が最も信頼できる情報源です。

Velocity ランタイムエンジンは、同じ JVM で実行される全ての Velocity ユーザに対してリソース、ロギングなどのサービスを提供する Singleton インスタンスです。 したがって、ランタイムエンジンは一度だけ初期化されます。Velocity の初期化は何度でも試せますが、適用されるのは最初の初期化のみで、他のものは無視されます。 Velocity ユーティリティクラスは、現在ランタイムエンジンの設定で使用される 5つのメソッドを提供します。

設定メソッドは以下の通りです。

  • setProperty( String key, Object o )
    プロパティ key に値 o を設定します。 値は通常は String ですが、特殊なケースとして、 値のコンマ区切りのリスト ("foo, bar, woogie" といった、 String) の可能性もありますし、他のケースも将来出てくるかもしれません。
  • Object getProperty( String key )
    プロパティキーの値を返します。 注意: String 以外もありうるので、あなたは戻り値のタイプを 把握していなければなりません。
  • init()
    配布で提供されるデフォルトの各プロパティでランタイムを初期化します。 (プロパティに関連するセクション (後述) にデフォルト値の一覧があります。)
  • init( Properties p )
    引数として渡される java.util.Properties オブジェクトに含まれる各プロパティでランタイムを初期化します。
  • init( String filename )
    filename で示されるプロパティファイルにある各プロパティでランタイムを初期化します。

注意: それぞれの場合、デフォルトプロパティは、基本設定として使用され、 アプリケーションで指定された追加のプロパティはデフォルトのプロパティを上書きします。 オーバーライトされないデフォルトプロパティは全て有効となります。この方法には、 プロパティ全てでなく変更したい部分だけ指定できるという利点があります。

もう一点、注意事項として、 init() の呼び出しは、 アプリケーションに悪影響を与えずに複数回行われるかもしれません。 しかし、エンジンの設定は、最初のinit() メソッドの呼び出しで セットされた設定プロパティによって行われ、 それ以降の設定変更や init() 呼び出しは無視されます。

最も一般的な Velocity の初期化の方法は以下の通りです。

  1. 設定したい値を org/apache/velocity/runtime/defaults/velocity.properties(デフォルトのセット)と同じフォーマットのファイル、または java.util.Properties で設定し、その上で init( filename ) または init( Properties ) を呼び出します。
  2. setProperty() を使って設定値を別々にセットし、それからinit() を呼びます。この方法は通常、すでに設定管理システムを持つ、 より高度なアプリケーションで使われます -- この方法を使えば、 例えば実行時に生成する値に基づいてアプリケーションで Velocity を設定できます。

一度ランタイムが初期化されたら、ランタイムでやりたいことができます。 その際に行うことのほとんどは、テンプレートを処理して出力ストリームに送ることであり、 Velocity ユーティリティクラスで簡単に行うことができます。 現状でのメソッドと処理概要の一覧は以下の通りです。

  • evaluate( Context context, Writer out, String logTag, String instring )
    evaluate( Context context, Writer writer, String logTag, InputStream instream )
    この2つのメソッドは、String あるいは InputStream 形式の入力を、 指定した Context を使って処理し、出力 Writer に送ります。 文字列のトークンの置換に使うとか、データベースなどファイルでないストレージに VTL を含んだ内容の「テンプレート」を保持したり同様のデータを動的に作成したりする場合に、 非常に便利なメソッドです。
  • invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer )
    Velocimacro (VM) に直接アクセスできます。やろうと思えば、上記の evaluate() メソッドでも行えます。このメソッドの場合は、 VMに好きな名前をつけ、VMへの引数となる配列やデータのコンテキスト、 それに出力先のWriterを生成します。注意: VM の引数は、 引数として使う文字列データではなく、Context 内のデータオブジェクトの「キー」 でなければなりません。これは将来変更される可能性があります。
  • mergeTemplate( String templateName, Context context, Writer writer )
    Velocity の通常のテンプレート処理サービスに簡単にアクセスできます。このメソッドは、 テンプレートの取得と処理を担当します。このメソッドには、ファイルリソースローダ向けの プロパティ設定にしたがってテンプレートをロードできるという利点があり、それによって Velocity が提供するファイルテンプレートおよび解析済みテンプレートのキャッシュ化という 利点が得られます。この方法はテンプレートにアクセスするのに最も効率的な方法であり、 特に必要がない限りはこの方法をお勧めします。
  • boolean templateExists( String name )
    name で指定されたテンプレートが現在設定されているリソースローダで 見つけられるかどうか判定します。

一度これらの基本ヘルパを理解すれば、Velocity を使った Java プログラムを書くのは簡単です。 こんな感じです。

import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;

public class Example2
{
    public static void main( String args[] )
    {
        /* まず実行時エンジンを初期化する。デフォルトでよい。 */

        Velocity.init();

        /* Context を作成して、データを入れる */

        VelocityContext context = new VelocityContext();

        context.put("name", "Velocity");
        context.put("project", "Jakarta");

        /* テンプレートを処理する */

        StringWriter w = new StringWriter();

        Velocity.mergeTemplate("testtemplate.vm", context, w );
        System.out.println(" template : " + w );

        /* 処理する文字列を作成する */

        String s = "We are using $project $name to render this.";
        w = new StringWriter();
        Velocity.evaluate( context, w, "mystring", s );
        System.out.println(" string : " + w );
    }
}

このプログラムを実行し、プログラムと同じディレクトリにtesttemplate.vm というテンプレートを置きます (デフォルトの設定プロパティを使ったため、 テンプレートをロードするデフォルトの場所は現在のディレクトリになります)。 その結果、出力は以下のようになります。

template : Hi!  This Velocity from the Jakarta project.

string : We are using Jakarta Velocity to render this.

この際に使用したテンプレート(testtemplate.vm)は以下のとおりです。

Hi!  This $name from the $project project.

これで完了です! プログラムで mergeTemplate()evaluate() の両方を使う必要はなかったことにご注意ください。両方入れたのはデモのためです。 恐らくどちらか1つだけを使うことになりますが、 アプリケーションの要件に応じて好きな処理を行えます。

これはこのガイドの最初の方で説明した「基本パターン」と少し違うように見えますが、 実は同じパターンなのです。まず、コンテキストを作り、必要なデータで埋めています。 この例との違いですが、最初の例では、mergeTemplate() を使っている箇所で、 mergeTemplate() が Runtime クラスの低レベルの呼び出しを利用して、 テンプレートの取得とマージを行っています。第二の例では、 処理の「テンプレート選択」の部分に対応させるように、 String 経由で動的にテンプレートを生成し、低レベル呼び出しを行う代わりに evaluate() メソッドでマージを行っています。

このように、上記の例では Velocity テンプレートエンジンを使用する際の 単純なパターンに合わせたわけですが、この他にも各ユーティリティメソッドは、 退屈な繰り返し作業を行ったり、 テンプレートファイル以外のテンプレート生成手段を提供したりします。

例外

Velocity が、解析/マージのサイクルで投げる例外は3種類あります。これらの例外は、 I/O の問題などによる例外に追加するものです。org.apache.velocity.exception パッケージにあるこれらの例外を以下に示します。

  1. ResourceNotFoundException
    リソース管理システムが要求されたリソース (テンプレート) を見つけられない時に投げられます。
  2. ParseErrorException
    リソース (テンプレート) を解析するとき、VTL 構文エラーが見つかった時に投げられます。
  3. MethodInvocationException
    処理時にコンテキスト内のオブジェクトのメソッドで例外が投げられた場合に投げられます。 この例外は投げられた例外をラップしてアプリケーションに伝搬するためのものです。 これを使えば固有のオブジェクトで実行時に起こった問題を扱うことができます。

それぞれの場合にメッセージはランタイムログに入ります。 詳細は、Javadoc API ドキュメンテーションをご覧下さい。

その他雑記

上記の例ではデフォルトのプロパティが使われていましたが、 固有のプロパティ設定はとても簡単です。どこかにプロパティファイルを作り、 そのファイル名を Velocity ユーティリティクラスの init(String) メソッドに渡す方法と、java.util.Properties オブジェクトを作り、 好きなプロパティと値を加え、それを init(Properties) メソッドに渡す方法があります。後者の方法の方が便利です。 というのは、load() メソッドを使って、 別々のプロパティファイルから直接設定したり、 もっといい方法として、実行時にアプリケーション/フレームワークの プロパティセットから動的に設定することができるからです。 これによって、自分のアプリのプロパティ全てを、 1つのプロパティファイルにまとめることができるのです。

テンプレートをロードするのにカレントディレクトリ以外のディレクトリを使いたい場合には、 以下のようにもできます。

 ...

import java.util.Properties;
 ...

public static void main( String args[] )
{
    /* まずは、実行エンジンを初期化する  */

    Properties p = new Properties();
    p.setProperty("file.resource.loader.path", "/opt/templates");
    Velocity.init( p );

    /* Contextを作ってデータを入れる */

 ...

ディレクトリ /opt/templates があり、そこにテンプレート testtemplate.vm がある場合に、これはうまく動きます。 これを試して問題があるなら、情報を得るために velocity.log をチェックして下さい -- エラーメッセージは何がおかしいか理解するためにかなり役立ちます。


EventCartridge とイベントハンドラ

バージョン 1.1 から、Velocity にきめの細かいイベントハンドリングシステムが追加されました。 EventCartridge はイベントハンドラを登録するためのクラスで、さらに、 必要ならば、マージ時に登録したイベントハンドラにアクセスするための デリバリエージェントとしても動作します。 現在、ハンドルできるイベントは3つで、すべて org.apache.velocity.app.event パッケージにあります。

org.apache.velocity.app.event.NullSetEventHandler

#set() で null が代入された場合、通常はログに記録されます。 NullSetEventHandler を使うと、こうした場合にロギングを「拒否」できます。
public interface NullSetEventHandler extends EventHandler
{
    public boolean shouldLogOnNullSet( String lhs, String rhs );
}   
org.apache.velocity.app.event.ReferenceInsertionEventHandler
ReferenceInsertionEventHandler を使うと、リファレンス ($foo) の値の 出力ストリームへの書き出しに割り込んで、出力内容を変更できます。
public interface  ReferenceInsertionEventHandler extends EventHandler
{
    public Object referenceInsert( String reference, Object value  );
}
org.apache.velocity.app.event.MethodExceptionEventHandler
ユーザが作成したメソッドから例外が投げられた時に、 MethodExceptionEventHandler が、関連する Class やメソッド名、 投げられた例外とともに起動します。このハンドラは、メソッド呼び出しの返り値 として使われる使われる有効なオブジェクトを返すか、 引数として渡された例外、あるいは新しい例外を投げます。新しい例外の場合は、 MethodInvocationException としてラップされてユーザに伝搬されます。
public interface MethodExceptionEventHandler extends EventHandler
{
    public Object methodException( Class claz, String method, Exception e )
         throws Exception;
}

EventCartridge の使い方

EventCartridge の使い方はとても簡単です。 以下の例は、org.apache.velocity.test.misc.Test から抜粋したものです。

 ...

import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
import org.apache.velocity.app.event.MethodExceptionEventHandler;
import org.apache.velocity.app.event.NullSetEventHandler;

 ...

public class Test implements ReferenceInsertionEventHandler, 
                             NullSetEventHandler,
                             MethodExceptionEventHandler
{
    public void myTest()
    {
        ....

        /*
         * ここでは、Test クラスは、イベントハンドラインタフェースを
         * サポートするように正しいメソッドを実装していると仮定します。
         * これらを使うにはまず、カートリッジを新しく作ります。
         */
        EventCartridge ec = new EventCartridge();
         
        /*
         * そして、このクラスをハンドラに収容するように登録します
         */
        ec.addEventHandler(this);
           
        /*
         * 最後に コンテキストにカートリッジそのものを追加します。
         */
        ec.attachToContext( context );

        /*
         * あとは、いつものようにコンテキストをテンプレートにマージします。
         */

        ....
    }
      
    /*
     *  ここで、イベントハンドラの実装を行います。
     */
    public Object referenceInsert( String reference, Object value  )
    {
        /*  リファレンスを使ってなにかします */
        return value;
    }

    public boolean shouldLogOnNullSet( String lhs, String rhs )
    {
        if ( /* 何らかのルール */ )
            return false;
        
        return true;
    }

    public Object methodException( Class claz, String method, Exception e )
         throws Exception
    {
        if ( /* 何らかのルール */ )
           return "I should have thrown";

        throw e;
    }
}


Velocity 設定キーと値

Velocity の実行時構成は、以下の一覧にある各設定キーで制御します。 通常、これらのキーは String の値、あるいは CSV (Comma Separated Value) と呼ばれるコンマ区切りの String のリストの値を持ちます。

各デフォルト値は Velocity の JAR ファイルに含まれており、ソースとしては /src/Java/org/apache/velocity/runtime/defaults/velocity.defaults にあり、 Velocity はこれらを設定のベースラインとして使います。 これにより、 Velocity の起動時に設定キーに常に「正しい」値が入っていることが 保証されますが、それはあなたが求めている値だとは限りません。

init() の実行前に値を指定すると、デフォルトの値を置き換えられます。 したがって、Velocity では変更が必要なキーの値だけを設定すればよくて、それ以外は 気にする必要はありません。さらに、設定関連を含めて多くの機能が追加されても、 それに合わせて設定ファイルを変更する必要はありません -- Velocity エンジンは、 常にデフォルト値を持っているからです。

設定 API についての詳細は上のセクション 一般的なアプリケーションで Velocity を使う を参照してください。

Velocity の動作を制御する設定キーの一覧は以下の通りです。 各キーはカテゴリ別に分類され、「=」記号の後に現在のデフォルト値を示しています。

Runtime Log

runtime.log = velocity.log
エラー、警告、情報に関するメッセージのためのログファイルのフルパスと名前。 格納場所は、絶対パスでなければ、「カレントディレクトリ」の相対パスとなります。

runtime.log.logsystem
このプロパティには、デフォルトの値がありません。このキーは Velocity でロギングクラス のインスタンスを使うのに使用します。ロギングクラスは org.apache.velocity.runtime.log.LogSystem インタフェースをサポートします。 このインタフェースを使えば、 Velocity のログメッセージと アプリケーションのログメッセージを同じログに入れることができます。詳細は、 一般的なアプリケーションで Velocity を使う のセクションをご覧ください。

runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem
Velocity がインスタンス化したログシステムで使用されるクラスです。

runtime.log.error.stacktrace = false
runtime.log.warn.stacktrace = false
runtime.log.info.stacktrace = false
true にすると、これらのエラーカテゴリーのスタックトレースを有効にします。 これは大量のログを生成します。

runtime.log.invalid.references = true
false にすると、リファレンスが無効な場合もログ出力されません。 本番環境では false にすると良いのですが、 デバッグ時には [trueにしておくと] とても役立ちます。

runtime.log.logsystem.avalon.logger = name
これを使うと、ユーザは Avalon 階層内の既存のロガーを LogSystem インタフェースで ラップしなくても name で指定できます。 注意: デフォルトのログシステムは変更される可能性があるため、この設定とともに runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem と指定しなければ なりません。また Avalon ログシステムが将来もデフォルトのログシステムであることは 保証されていません

文字エンコーディング

input.encoding = ISO-8859-1
入力 (テンプレート) の文字エンコーディングを指定します。 これを使うと、テンプレートで UTF-8 といった別のエンコーディングを使用できます。

output.encoding = ISO-8859-1
VelocityServlet と Anakia からの出力ストリームのための文字エンコーディング

#foreach() 指示子

directive.foreach.counter.name = velocityCount
#foreach() 指示子で使用され、ループカウントのためのコンテキストキー として使用される文字列を定義します。テンプレートでは、このループカウントに $velocityCount でアクセスできます。

directive.foreach.initial.value = 1
#foreach() ループでのループカウンタリファレンスのためのデフォルトの開始値

#include() と #parse() 指示子

directive.include.output.errormsg.start = <!-- include error :
directive.include.output.errormsg.end = see error log -->
#include() 指示子で問題が起こった場合の、入力ストリームのエラーメッセージ用に 開始タグと終了タグを定義します。.start と .end の両方でタグが定義されていれば、 エラーメッセージは、「.start msg .end」という形式 (この形式では .start と .end でプロパティの値を参照します) で、 ストリームに出力されます。 .start と .end の両方で(次の)タグが定義されていても、 テンプレート処理ストリームへの出力が行われるだけです。

directive.parse.maxdepth = 10
テンプレート解析の深度を定義します。 テンプレートは、別のテンプレートを #parse() するかも知れませんし、 解析されるテンプレートにも #parse() 指示子があるかもしれません。 この値は、#parse() 再帰の無限ループを防ぎます。

リソース管理

resource.manager.logwhenfound = true
リソースマネージャからの「リソース発見」メッセージの ロギングの制御を切り替えます。最初にリソースが見つかったときに、 リソース名とリソースを見つけたローダのクラス名が ランタイムログに通知されます。

resource.loader = <name> (default = File)
複数値のキーで、値として CSV 形式を受け入れます。 リソースローダのパブリック名が使用されます。このパブリック名は、 このリソースローダに固有のプロパティを指定するのに使用されます。 注意: 複数値のキーでは、"file, class" (引用符なし) といった値を渡すことが可能で、 上記の値の場合、2つのローダの設定値が後に続くことを示しています。

<name>.loader.description = Velocity File Resource Loader
当該ローダの説明文字列。

<name>.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
このローダのクラスの実装名。デフォルトのローダはファイルローダです。

<name>.resource.loader.path = .
複数値のキーで、値として CSV 形式を受け入れます。 ローダによるテンプレートの読み込み元のルートを示します。テンプレートは このルートのサブディレクトリに存在しているかもしれません。 例) homesite/index.vm。この設定キーは、現在のところ FileResourceLoader と JarResourceLoader に適用されます。

<name>.resource.loader.cache = false
ローダでのテンプレートのキャッシュ制御。 配備とデバッグを簡単にするために、デフォルトは false となっています。 本番環境への配備の際に true にすべきです。 「true」の場合は modificationCheckInterval プロパティが適用されます。 これによって、キャッシュを効率的に行い、リロード制御を簡単に行えます -- これは、テンプレートは頻繁に変更されるけれども、アプリケーションや Servlet エンジンの 再起動はしたくない、あるいは許可されていないようなホスティング環境や ISP 環境 で役に立ちます。

<name>.resource.loader.modificationCheckInterval = 2
キャッシュが有効な場合の変更チェックの間隔の秒数です。 この数字が 0 より大きい整数の場合、テンプレートが変更されたかどうかを チェックする間隔の秒数を示します。最後のチェック以降にテンプレートが 変更されていれば、再ロード・再解析されます。そうでなければ、何もしません。 0 以下の場合は修正チェックは行われませんし、 (上記の) cache プロパティ が true の場合、テンプレートが最初の使用時に一度ロード・解析されたら、 アプリケーションや Servlet エンジンが再起動するまでチェック・リロードは行われません。

具体例として、デフォルトの Velocity プロパティで FileResourceLoader のセットアップ がどのように管理されているかを示します。

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2

Velocimacro

velocimacro.library = VM_global_library.vm
複数値のキーで、値としてCSV形式を受け入れます。 Velocity Runtime エンジンが起動したときにロードされる Velocimacro ライブラリのファイル名(複数指定可)です。これらの Velocimacro は、 すべてのテンプレートからアクセスできます。このファイルでは ファイルローダリソースパスのルートからの相対パスを想定しています。

velocimacro.permissions.allow.inline = true
テンブレート内で #macro() 指示子による新しい Velocimacro の定義を許可するかどうか を決定します。デフォルト値は true で、どんなテンプレートでも新しいVelocimacro の定義・使用が可能であることを意味します。 注意: 他のプロパティの設定によっては、これらの #macro() ステートメントが グローバルな定義を置き換えることも可能です。

velocimacro.permissions.allow.inline.to.replace.global = false
テンプレート内で「インライン」定義された Velocimacro が、起動時にロードされた ライブラリ内の Velocimacro 定義を置換できるかどうか制御します。

velocimacro.permissions.allow.inline.local.scope = false
Velocimacro の「プライベートな」テンプレートのネームスペースを制御します。 true のとき、テンプレート内の #macro() 指示子で作成した Velocimacro は、 定義を行ったテンプレートからのみアクセスできます。つまり、起動時にロードされる グローバル/ローカルのライブラリ以外の Velocimacro は共有できないことを意味します (上記参照)。また、テンプレートが相互干渉できないことも意味します。 このプロパティを使うと、グローバル/ローカルのライブラリに「デフォルト」の Velocimacro 定義があり、テンプレート内の使用時にその実装を「オーバーライド」するという テクニックが可能です。こうしたことが可能なのは、このプロパティが true の場合、 Velocimacro でのテンプレートのネームスペースの検索がグローバルネームスペースより 先に行われ、オーバーライドを行うことが可能となるためです。

velocimacro.context.localscope = false
Velocimacro 内のリファレンスへのアクセス (set/get) でコンテキストを変更できるようにするか、 それとも、アクセスはその Velocimacro のローカルスコープに限定するかを決めます。

velocimacro.library.autoreload = false
Velocimacro ライブラリの自動ロードを制御します。 trueにセットすると、起動された Velocimacro のライブラリソースについて 変更をチェックし、必要であればリロードされます。 これにより、まさに通常のテンプレートと同じように、 アプリケーションや Servlet コンテナを再起動せずに Velocimacro ライブラリの変更・テストができるようになります。 これは、リソースローダのキャッシュが off (例えば file.resource.loader.cache = false ) の場合のみ動作します。 この機能は開発用であり本番環境用ではありません。

文字列展開

runtime.interpolate.string.literals = true
VTL String リテラルの展開の仕組みを制御します。注意: VTL String リテラルは厳密に言えば二重引用符で囲まれた文字列で、 #set() ステートメント内、リファレンスのメソッド呼び出し、VM へのパラメータで使われたり、 VTL 指示子への引数として一般的に使われたりします。 詳細は VTL リファレンスを見てください。

ランタイム設定

parser.pool.size = 20
このプロパティでは、Velocity が起動時に作成して、プールに保持する パーサの数を設定します。 デフォルトのパーサ数は20ですが、たいていの用途では十分なはずです。 Velocity がパーサを使い果たすと、ログに記録され、必要に応じて動的に 作成されます。ただし、それらはプールに加えられないことに注意してください。 通常のパーサのプールと比較して動作が遅くなりますが、 これは例外的な状態だと考えられます。ログにメッセージが出た場合には、 このプロパティの数字を増やしてください。


ログシステム設定

Velocity には、シンプルかつ柔軟な、優れたロギング機能がいくつかあります。 特に設定をしなくても、Velocity はファイルベースのロガーをセットアップします。 このロガーはすべてのログメッセージを Velocity が起動した「カレントディレクトリ」 に velocity.log という名前のファイルで出力します。 より高度な使い方をするユーザのために、既存のロギング機能と Velocity を統合し、 全てのログメッセージを既存のロガーに出力することも可能です。

以下の選択肢があります。

  • デフォルト設定
    デフォルトでは、Velocity はファイルベースのログをカレントディレクトリに作成します。
  • カスタムのスタンドアロンのロガー
    カスタムロギングクラスを作成することもできます -- org.apache.velocity.runtime.log.LogSystem インタフェースを実装し、 設定プロパティ runtime.log.logsystem.class にクラス名を設定するだけでよく、 そうすれば Velocity は 初期化時にそのクラスのインスタンスを生成します。 他のプロパティも指定するのと同様に、別のクラス名の指定もできます。 詳細については、Velocity ヘルパクラスVelocity 設定キーと値 を参照してください。
  • 統合ロギング
    org.apache.velocity.runtime.log.LogSystem インタフェースを実装するだけで、 Velocity のロギング機能をあなたのアプリケーションの既存のロギングシステムと 統合できます。そして、 init() を呼ぶ前に runtime.log.logsystem 設定キーを 使って Velocity にロギングクラスのインスタンスを渡せば、 Velocity はアプリケーションの ロガーにメッセージを送るようになります。詳細は、 Velocity ヘルパクラスVelocity 設定キーと値 を参照してください。

とても単純ですが、カスタムのロガーを作ってみましょう。 以下のコードは、あなた自身のアプリケーションで行うかもしれない内容の単純なスケッチです。

カスタムロガーの単純な例

これは、あなた自身のアプリケーションに Velocity のロギングシステムを統合する 方法の簡単な例です。

import org.apache.velocity.runtime.log.LogSystem;

...

public class MyClass implements LogSystem
{

...

    public MyClass()
    {
        ...

        try
        {
            /*
             *  このクラスをロガーとして登録。
             */
            Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, this );
            Velocity.init();
        }
        catch (Exception e)
        {
            /*
             *  なにか行う。
             */
        }             
    }

    /**
     *  Velocity がログメッセージを引数に呼び出すメソッドで、これを実装します。
     */
    public void logVelocityMessage(int level, String message)
    {
        /*  なにかする */
    }
...
}            


リソースローダの設定

Velocity で基本的かつ重要なものとして、 リソース管理システムとリソースローダがあげられます。管理対象が「テンプレート」 でなく、「リソース」となっているのは、リソース管理システムがテンプレート以外のリソース、 特に #include() 指示子によってロードされるようなものも扱っているからです。

リソースローダシステムは非常に柔軟であり、複数のリソースローダを同時に 動作させられます。このおかげで設定やリソース管理が著しく柔軟になっていますし、 さらに、ユーザが特別な要件に基づく独自のリソースローダを書くことができます。

現在、Velocity には以下で説明される4種類のリソースローダがあります。 注意: このサンプル設定プロパティでは、ローダの一般名が示されます( 例:「file」はfile.resource.loader.pathを指します)。 この「一般名」だと、あなたの設定では動かないかもしれません。 このシステムがどのように動作するかについて理解するには、 リソース設定プロパティに関するセクションを参照してください。 また、各ローダは org.apache.velocity.runtime.resource.loader パッケージにあります。

  • FileResourceLoader : このローダはファイルシステムからリソースを取得します。 設定プロパティは以下の通りです。
    • file.resource.loader.path = <テンプレートのルートパス>
    • file.resource.loader.cache = true/false
    • file.resource.loader.modificationCheckInterval = <チェック間隔 (秒) >
    これはデフォルトのローダで、「カレントディレクトリ」からデフォルトでテンプレートを 取得する設定になっています。 Servlet で Velocity を使う場合、 Servlet エンジンを 起動するディレクトリにテンプレートを置きたくない時に、問題が発生する可能性があります。 詳細は Velocity で Servlet 開発のセクションを見てください。
  • JarResourceLoader : このローダは、特定の JAR ファイルからリソースを取得します。 JAR ファイルにテンプレートをまとめられることを除いて、 FileResourceLoader とほぼ同じです。プロパティについても、jar.resource.loader.path 以外は 同じです。このプロパティでリソースをロードしたい JAR ファイル (複数可) のフルパスを 指定します。この loader.path で JAR ファイルを指定するには、 java.net.JarURLConnection の標準の JAR URL 構文を使います。
  • ClasspathResourceLoader : このローダは、クラスローダからリソースを取得します。たいていの場合は、 ClasspathResourceLoader が、クラスパス内 (例えば、JARファイル内) のテンプレートを ロードするということです。クラスパスは多くの場合大きな悩みの種ですが、 Servlet 仕様 2.2 以降に対応した Servlet コンテナを動かす時には、 非常に役に立つ仕組みです。 Tomcat は、こうした Servlet コンテナの一例です。このローダを効果的に使うには、 テンプレートを JAR ファイルに入れて、Webアプリの WEB-INF/lib ディレクトリに 置けば十分です。設定オプションを気にする必要はありませんし、JAR リソースローダや File リソースローダで起こりうる絶対パス/相対パスの問題も起こりません。 繰り返しますが、ClasspathResourceLoader は、 Servlet コンテナだけでなく、 どのアプリケーションコンテキストでも使用できることに注意して下さい。
  • DataSourceResourceLoader : このローダは、データベースなどの DataSource からリソースをロードします。 J2EE サポートが必要なので、標準ビルドでは、このローダはビルドされません。 このローダをビルドするためには、J2EE 配布をダウンロードし、 j2ee.jar を build/lib ディレクトリに移動して、 jar-j2ee というビルドターゲットを使用して VelocityのJARファイルを 新たにビルドします。 このローダの詳細については、 org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader クラスの Javadoc をご覧下さい。
設定例

Velocity でのリソースローダの設定は簡単です。 さらに詳細を知りたい場合は、 リソース設定 セクションにある、制御のためのプロパティの一覧を参照してください。

一つ以上のリソースローダを設定する場合、最初のステップとして Velocity に対してリソースローダを名前で「宣言」します。 プロパティ resource.loader を使い、一つ以上のローダ名を [コンマ区切りの]リストで指定します。どんな名前でもかまいません -- これらの名前は、該当するローダを設定プロパティに関連づけるために使われます。

resource.loader = file

このエントリでは、「file」として知られているリソースローダを 使うと宣言しています。次に行うのは、重要なプロパティをセットすることです。 ここで一番大事なのは、ローダとして使用するクラスを宣言することです。

file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader

この場合、「file」というリソースローダを設定し、それが org.apache.velocity.runtime.resource.loader.FileResourceLoader クラスを使用することを Velocity に伝えます。 次に、このローダにとって重要なプロパティを設定します。

file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2

ここで3つの設定を行っています。ます、テンプレートを見つけるためのパスとして /opt/templates を設定しています。次に、テンプレートまたは静的ファイルが 読まれた後、メモリにキャッシュされるように、キャッシュをオンにしています。 最後に、新しいテンプレートの更新チェック間隔を2秒にセットしています。

基本的な設定は以上です。他の設定例もいくつか挙げましょう。

何もしないデフォルト設定 : その名のとおり、デフォルト設定を取得するのに何もする必要はありません。 この設定ではデフォルトのリソースパスとしてカレントディレクトリで FileResourceLoader を 使い、キャッシュはオフです。プロパティは以下のようになります。

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0

複数テンプレートパス設定 : テンプレートの検索パスの「ノード」として複数のディレクトリが指定された FileResourceLoader を使用するように設定します。また、キャッシュを使い、 テンプレートの変更を10秒間隔でチェックします。プロパティは以下のようになります。

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = /opt/directory1, /opt/directory2
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 10

複数ローダ設定 : この設定は、FileResourceLoader、ClasspathResourceLoader、JarResourceLoader という 3つのローダを同時に動かすようにセットアップします。 ローダは、最初に FileResourceLoader、次に ClasspathResourceLoader、 最後に JarResourceLoader が参照されます。こうすれば、クラスパス上にあるテンプレートを 置き換える際に、ファイルテンプレートの領域に入れるだけでよく、JAR ファイルを 再ビルドする必要はありません。

#
# 使用する3つのリソースローダを指定
#
resource.loader = file, class, jar

#
# 'file'と名づけたローダでは、使用するクラスとして FileResourceLoader をセットして
# キャッシュを off にして、 テンプレート用に3つのディレクトリを使用する
#
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = templatedirectory1, anotherdirectory, foo/bar
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0

#
# 'class'と名づけたローダでは、ClasspathResourceLoader を使用する
#
class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader

#
# 最後に、'jar'と名づけたローダでは、JarResourceLoader を使用し、
# 2つの JAR ファイルから読み込む
#
jar.resource.loader.description = Velocity Jar  Resource Loader
jar.resource.loader.class = org.apache.velocity.runtime.resource.loader.JarResourceLoader
jar.resource.loader.path = jar:file:/myjarplace/myjar.jar, jar:file:/myjarplace/myjar2.jar

「file」、「class」、「jar」という名前はあくまで都合と分類のためのものであることに 注意してください。これらは好きな名前でかまいません -- プロパティと関連づけるために、 使われるだけだからです。とはいえ、機能のヒントとなる名前を使用することをお勧めします。

適切に動作させるのに必要な設定情報は3つともごくわずかですが、 ClasspathResourceLoader はその中でも最も単純です。


国際化のためのテンプレートエンコーディング

バージョン1.1現在、テンプレートごとにテンプレートリソースの文字エンコーディングを 指定できます。通常のリソース API は、エンコーディングを引数として渡せるように 拡張されています。

org.apache.velocity.servlet.VelocityServlet :

public Template getTemplate( String template, String encoding )

org.apache.velocity.app.Velocity :

public static Template getTemplate(String name, String encoding)

public static boolean mergeTemplate( String templateName, String encoding, Context context, Writer writer )

encoding引数の値は JVM でサポートされる通常のエンコーディング仕様 (例:「UTF-8」、「ISO-8859-1」) です。 文字セットの公式名称は、 こちらを参照してください。

これはテンプレート自身のエンコーディングにのみ適用されます -- 出力エンコーディングはアプリケーション固有の問題です。


Velocity と XML

Velocity は柔軟で単純なテンプレート言語であるため、 XML データを利用するのに 理想的な環境となっています。Anakia は、 XML からの出力処理で XSL を置き換えるのに Velocity を利用する例です。 このドキュメンテーションを含む Velocity サイトは、Anakia を使って、 XML ソースから生成しています。 Jakarta サイトもまた Anakia を使用して処理されています。

一般的に、Velocity で XML を扱う場合、 XML を Java でアクセスしやすいデータ構造に変換するのに JDOM か何かを使うというパターンがあります。 次に、XML ドキュメントから (JDOM ツリー経由で) 直接データアクセスするテンプレートを生成します。例として、次の XML 文書を使ってみましょう。

<?xml version="1.0"?>

<document>
 <properties>
  <title>Developer's Guide</title>
  <author email="geirm@apache.org">Velocity Documentation Team</author>
 </properties>
</document>

ここで、以下のようなコードを含む小さな Java プログラムを作成します。

...

SAXBuilder builder;
Document root = null;

try 
{
    builder = new SAXBuilder(  "org.apache.xerces.parsers.SAXParser" );
    root = builder.build("test.xml");
}
catch( Exception ee)
{}

VelocityContext vc = new VelocityContext();
vc.put("root", root );

...

(このやり方についての詳細は、配布のexamplesディレクトリにある Anakia サンプルを参照してください。) 次に、通常の Velocity テンプレートを作成します。

<html>
  <body>
    The document title is 
    $root.getChild("document").getChild("properties").getChild("title").getText()
  </body>
</html>

そして、通常行うように、JDOM ツリーを含む Context に使って、テンプレートを処理します。 もちろん、この例がすべてではありませんが、 Velocity テンプレートから簡単に XMLデータに 直接アクセスする基本的な方法を示しています。

Velocity で XML データのスタイルを決める大きな利点の一つは、アプリケーションが用意する 他のオブジェクトやデータにアクセスできるということです。 その XML 文書にあるデータに限定されないのです。出力に関する追加情報を提供するために、 何でも追加できますし、XML データを使いやすくするツールも提供できます。 Bob McWhirter の Werken Xpath はこの種の便利なツールの一つです -- Anakia での使い方の例は org.apache.velocity.anakia.XPathTool にあります。

XML と Velocity で起こる問題の1つに、XML エンティティをどう扱うかというものがあります。 テクニックの一つとして、エンティティを処理して出力ストリームに送る際に、 Velocimacro と組み合わせて使うという方法があります。

## まず、Velocimacro をどこかで定義します

#macro( xenc $sometext )$tools.escapeEntities($sometext)#end

## そして以下のように使用します

#set( $sometext = " < " )
<text>#xenc($sometext)</text>

ここで escapeEntities() メソッドはカプセル化を行います。もう一つのテクニックは コンストラクタの引数でコンテキストを取得し、以下のメソッドだけを実装する エンコードユーティリティを作成するという方法です。

public String get(String key)
{
    Object obj = context.get(key)
    return (obj != null) ? Escape.getText( obj.toString() ) : "";
}

コンテキストには "xenc" というキーで設定します。そして以下のように使用します。

<text>$xenc.sometext</text>

この方法だと Velocity のイントロスペクション プロセスが使えるという利点があります -- このコードではコンテキスト内の $xenc オブジェクトの get("sometext") を呼び出そうと します -- そして xenc オブジェクトは、Context から値を取得、エンコードして返すことが できます。

別の方法として、Velocity がカスタムのコンテキストオブジェクトを簡単に実装できることを 利用して、返り値の文字列すべてにエンコーディングを常に適用する独自のコンテキストを 実装するというのも「あり」でしょう。その場合、メソッド呼び出しの出力は直接処理しない ように気をつけてください。メソッド呼び出しではオブジェクトまたは文字列 (エンコーディングが必要かもしれません) を返す可能性があるからです。 #set() 指示子で コンテキストに設定ししてから使うようにしましょう。以下に例を挙げます。

#set( $sometext = $jdomElement.getText() )
<text>$sometext</text>

XML エンティティを扱う前者の方法は、Christoph Reck (Velocityコミュニティの アクティブな参加者です) のアイデアを元にしています。 この文書への彼の (知られざる) 貢献に、非常に感謝しています。彼のアイデアは それほどめちゃめちゃにはなってないと思います :)


FAQ (よく聞かれる質問)

Velocity を使う開発者から繰り返し上がってくる質問とその回答を紹介します (順不同) 。 もしさらに増えるようでしたら、別の文書にしようと思います。

VTL のクラスメンバやコンスタントにアクセスできないんだけど、どうして?

簡単に言えば、フィールドについてはイントロスペクションを行っていないからです。 その理由はデータオブジェクトの生データは隠すという考え方を推進したいからです。 この問題の解決法は2通りあります。一つは公開したいデータ要素へのアクセッサを書く ことです。もちろん、ソースのないインスタンスは動作しませんし、すごくめんどくさいです。 もう一つの解決法のために、クラスをイントロスペクションして、テンプレートから 簡単にアクセスできるようにパブリックで静的なフィールドを公開する org.apache.velocity.app.FieldMethodizer というクラスがあります。 例えばこんなクラスがあるとしましょう。

    public class Foo
    {
        public static String PATH_ROOT = "/foo/bar";
     
        ....
    }
  

これを利用するコードで Foo を以下のようにコンテキストに設定します。

      context.put("myfoo", new FieldMethodizer( new Foo() ) );
  

テンプレートでこのフィールドにアクセスするには、Java と同じやり方で 簡単にアクセスできます。

       $myfoo.PATH_ROOT
  

もし、パブリックで静的でないメンバにアクセスせざるを得ない壊滅的な状況 (あるいは、プライベートメンバにアクセスしなければならないような破滅間際の状況) なら、FieldMethodizer クラスを自分で継承あるいは修正する必要が あります。(もちろん、それでもなおアクセッサを用意することをお勧めしますが……)

Velocity はテンプレートをどこで探すの?

デフォルト、つまり何も自分で設定していない場合は、Velocity は カレントディレクトリ (あるいは「foo/bar.vm」のようにテンプレート へのパスを設定している場合はカレントディレクトリ基準の相対パス) にあるファイルをテンプレートとして探します。

Velocity でそのようにしているのは、インストール直後でもできるだけそのまま使える ようにするためです。「ルート」ディレクトリから探すべきだという意見もありましたが、 その場合、複数のルートを持つ (「C:\」「D:\」……のように) ファイルシステムでの 対応方法がはっきりしていません。 [そのため採用していません。]

詳細については、 リソースローダに関するセクションや、 設定キー、値、デフォルト値に関するセクションを見てください。


まとめ

詳しくはありませんが、このガイドが Java プロジェクトで Velocity を使うのに役に立つ 紹介となることを望みます。また、Velocity に興味をもっていただいたことを感謝します。 このドキュメンテーションについて、あるいは Velocity テンプレートエンジンそのものに 関するコメントは何でも歓迎します。

フィードバックをしていただくには、 メーリングリスト に参加していただく必要があります。また、よく考えた上で、詳細かつ建設的な内容で お願いします。


追記1:サンプル Servlet の配備

初心者の Servlet ユーザが挫折することが多いのは、全てをまとめた上で動かす時です。 Tomcat や Resin といった Servlet エンジンの使い方は初めて使う人には分かりづらいのです (そして、慣れたユーザでさえも……)。 SampleServlet サンプルを動かすための基本的な手順を以下で説明します (できるだけ分かりやすくしたつもりです)。注意事項として、 サンプルテンプレートである sample.vm と、 Servlet コードそのものである SampleServlet.java は、 examples/servlet_example ディレクトリにあります。 Servlet エンジンによっては(例えば Resin など)、 Servlet を自動的にコンパイルしてくれますが、動かす前にサンプルをコンパイル するに越したことはないでしょう。コンパイルする方法については、 Velocity のビルドに関する説明 を見ていただいた上で、 examples をお使い下さい。

Jakarta Tomcat

Jakarta Tomcat での設定はわりと簡単です。 Tomcat は「webapps」ディレクトリで 「Web アプリ」を探すので、そこでセットアップすればいいのです。

  1. まず、Tomcat の webapps ディレクトリに velexample という名前でディレクトリを作成して新しい「Web アプリ」を作り、 以下のようなディレクトリ構造にします。
    velexample
    velexample/WEB-INF
    velexample/WEB-INF/lib
    velexample/WEB-INF/classes
  2. velocity-1.2.jar を velexample/WEB-INF/lib ディレクトリに置きます。
  3. SampleServlet.class を velexample/WEB-INF/classes ディレクトリに置きます。
  4. sample.vm テンプレートを velexample ディレクトリに置きます。SampleServlet は、 テンプレートのソースディレクトリとして Web アプリのルートディレクトリを使うので、 それ以外の設定は不要です。
  5. これで Tomcat を起動(または再起動)すればServletにアクセスできるはずです。
  6. Servlet にアクセスするには、Web ブラウザで以下のアドレスを指定します。
    http://localhost:8080/velexample/servlet/SampleServlet
    もし、うまく動かなければ、以下のアドレスを指定してみてください。
    http://<あなたのコンピュータのIPアドレス>:8080/velexample/servlet/SampleServlet
    [訳注: Tomcat 4.1以降ではセキュリティの観点からこのアドレス指定方法では動作しないようになったため、Web アプリの web.xml で Servlet の設定をした上で別のアドレス指定をする必要があります。詳しくは Tomcat のドキュメントをご覧下さい。]
  7. サンプル出力が表示されるはずです。

Caucho Technology の Resin

Caucho Technology の Resin Servlet エンジンでサンプル Servlet を動かすのもとても簡単です。 以下の手順はVersion 1.2.5リリースでテストしました。 すでに、ディストリビューションを ZIP か TAR で解凍済みで、Servlet エンジンの起動方法(Unix なら bin/httpd.sh とか)がわかっており、 doc ディレクトリ(ディストリビューションのルート)がどこにあるか わかっていることを前提にしています。

  1. SampleServlet.class ファイルを doc/WEB-INF/classes ディレクトリにコピーします。
  2. sample.vm テンプレートファイルを doc/ ディレクトリにコピーします。
  3. velocity-1.1.jar を doc/WEB-INF/lib ディレクトリにコピーします。
  4. Resin を起動します。
  5. Servlet にアクセスするには、Web ブラウザで以下のアドレスを指定します。
    http://localhost:8080/servlet/SampleServlet
    もし、うまく動かなければ、以下のアドレスを指定してみてください。
    http://<あなたのコンピュータのIPアドレス>:8080/servlet/SampleServlet
    サンプル出力が表示されるはずです。

こちらの方が設定が単純なように見えます -- Tomcat サンプルの場合は 別々の完全な Web アプリを新たに設定するのに対して、Resinの場合はその必要が ないからです -- しかし、どちらの場合も Velocity と一緒に動かすためには十分な設定が 必要であることに注意して下さい。

注意:残念ながら、Servlet エンジンに関するご質問にはお答えできません。 Servlet エンジンの提供元にお問い合わせ下さい。



このドキュメントは、 熊坂祐二 、 高橋達男 が訳しました。
コメントがある場合は、 report@jajakarta.org までお願いします。
オリジナル英文 Copyright © 1999-2003, The Apache Software Foundation