天天看點

Velocity 開発者ガイド

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

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

導入

この情報は 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)に追加する必要があります。 ビルドインされたログ機能やテンプレート変換機能を使いたい場合は、 クラスパスか Web アプリケーションの 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、VelocityServlet をサポートする基本クラスといったユーティリティは含まれていません。
    • jar-util

      bin

      ディレクトリに「velocity-util X.jar」という名前の ユーティリティ Velocity JAR ファイルを 構築します。この JAR ファイルには、 Anakia、Texen 、 WebMacro テンプレート変換ユーティリティといった、 ユーティリティのコードが入っています。通常の

      jar

      ターゲットと同様の外部依存が必要です。
    • jar-servlet

      bin

      ディレクトリに「velocity-servlet X.jar」という名前の ユーティリティ Velocity jar ファイルを構築します。この jar ファイルには、 サーブレットプログラマ向けのユーティリティのコードがあります。 通常の

      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 ファイルを、 クラスパスなどの適切な場所(サーブレットで使うのなら、 Webアプリケーションの lib ディレクトリとか)に置きます
  7. サンプルを試してみたいという場合(はじめての場合には特に推奨します)には、

    ant examples

    でサンプルを構築してください。

依存関係

Velocity ではコレクションなど Java 2 API を使っているので、ビルドには Java 2 Standard Edition SDK (Software Development Kit) が必要です。 Velocity を実行するには、Java 2 Standard Edition RTE (Run Time Environment) (もちろん SDK でも可) が必要です。

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 アプリケーション ユーティリティクラスを使用したアプリケーション プログラムの簡単なサンプル。
  • サーブレットサンプル :

    examples/servlet_example1

    : サーブレットでの 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

    : 単純なサーブレットベースのフォーラムアプリケーションの動作サンプル。
  • ドキュメンテーション :

    docs

    : html で生成されたVelocityプロジェクトの全てのドキュメント。
  • API ドキュメント :

    docs/api

    : 生成された、Velocity プロジェクトの Javadoc ドキュメント
  • 各種テンプレート :

    test/templates

    : testbed ディレクトリ内には、テンプレートサンプルがたくさん入っています。 VTL (Velocity Template Language) の使い方についてのすばらしい情報源となるでしょう。
  • コンテキストサンプル :

    examples/context_example

    : Velocity コンテキストの拡張方法を示した2つのサンプルがあります。 上級者向け。
上記の全てのディレクトリは、配布ルートディレクトリからの相対パスとなっています。
Velocity の動作原理

「基本パターン」

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

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

org.apache.velocity.app.Velocity

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

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

Singleton モデル

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

org.apache.velocity.app.Velocity

クラスからアクセスでき、以下の例のように使用します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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"); 
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Singleton モデルは、

org.apache.velocity.servlet.VelocityServlet

という基本クラスでも使われていることに注意してください。 このクラスはサーブレットを簡単に作成するためにこの配布で提供されている ユーティリティクラスです。 このクラスを拡張するのが、Velocity を使ったサーブレットを開発する際に最も一般的で便利な方法ですが、 何か別のものが必要ならばこのクラスを使わないことも可能です。

分離インスタンス

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

org.apache.velocity.app.VelocityEngine

クラスを使用します。 上記の Singleton の例と似たような例があります。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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"); 
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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

プログラミングの際に Velocity 内部と情報をやり取りするのに使うクラスは、 Singleton モデルを使用するなら

org.apache.velocity.app.Velocity

で、 Singleton でないモデル(「分離インスタンス」)を使用するなら

org.apache.velocity.app.VelocityEngine

です。

アプリケーションでは、

org.apache.velocity.runtime

パッケージの

Runtime

RuntimeConstants

RuntimeSingleton

RuntimeInstance

の各クラスは絶対に使わないでください。これらは内部使用のみを想定しており、いつか変更される可能性があります。上で説明したとおり、使うべきクラスは

org.apache.velocity.app

パッケージにある、

Velocity

クラスと

VelocityEngine

クラスです。これらのクラスに何かが抜けていたり何かが必要ならば、ためらわずに変更點を提案して下さい ─ これらのクラスはアプリケーション開発者向けのものです。
コンテキスト

基本

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

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

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

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public Object put(String key, Object value);
public Object get(String key);
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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 は、インタフェースメソッドの

    values()

    を使います。これは、ループで Iterator を取り出すために呼ばれる

    iterator()

    メソッドを持つ

    Collection

    インタフェースを取得するためです。
  • java.util.Iterator

    使用上の注意:今のところ條件つきでのみサポートされています ─ 懸念されるのは Iterator が「リセット不可」であることです。もし Iterator が「何も着けずに」 [訳注:他の型を経由せずに] コンテキストに設定されて #foreach() で2回以上使われる場合、 Iterator はリセットされないので、2回目以降の #foreach() ブロックでは失敗します。
  • java.util.Enumeration

    使用上の注意:

    java.util.Iterator

    と同様に、今のところ條件つきでサポートされています ─ 懸念されるのは Enumeration が「リセット不可」であることです。もし Enumeration が「何も着けずに」コンテキストに設定されて #foreach() で2回以上使われる場合、 Enumerationはリセットされないので、2回目以降の #foreach() ブロックでは失敗します。

Iterator

Enumeration

については、どうしても必要な時のみコンテキストに設定することをお勧めします。それが可能で問題がないのなら、再利用可能な繰り返しインタフェースを Velocity が見つけるという形にすべきです。

直接

java.util.Iterator

インタフェースを使用するのが適切な場合もあります (例えば、JDBC 経由の大きなデータセット)。しかし、もし避けられるのであれば、他のものを使う方がよいでしょう。「直接」とは以下のようなやり方のことです。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");

context.put("words", v.iterator() );
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
この場合、Iterator そのものがコンテキストに設定されます。代わりに単純に以下のようにしたとしましょう。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
context.put("words", v );
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
これですべて丸く収まります。Velocity は Vector が (List 経由で) Collection を実裝していることを了解するので、

iterator()

メソッドを見つけられますし、このメソッドを使って、必要に応じて毎回「新鮮な」 Iterator を取得します。Iterator をそのまま使った場合(二つのコード例の最初の方)、 Velocityが

#foreach()

で一度使うと、次の

#foreach()

で使う場合に、新しいオブジェクトを取得できません。その結果、このリファレンスを使った2回目以降の

#foreach()

ブロックは何も出力できません。

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

コンテキスト連鎖

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

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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 );
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

上記のコードでは、 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 コードがコンテキストに設定したオブジェクトのメソッドを呼び出すとき。

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
#set($myarr = ["a","b","c"] )
$foo.bar( $myarr )
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
テンプレートでオブジェクトをコンテキストに加えるとき。この場合、マージ処理が完了した後で、Java コードはこれらのオブジェクトにアクセスできます。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
#set($myarr = ["a","b","c"] )
#set( $foo = 1 )
#set( $bar = "bar")
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
こういうケースを扱う場合、とても単純な場合でも、以下の事柄だけは知っておくべきです。
  • 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 は毎回新しいイントロスペクション情報を集めなくなります。
サーブレットでVelocityを使う

サーブレットのプログラミング

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

サーブレット環境で Velocity を使う基本テクニックは、非常に単純なものです。念のために説明すると、やるべきことは提供されている VelocityServlet 基本クラスを拡張して、ひとつのメソッド(

handleRequest()

)を実裝するだけです。サーブレット開発で 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

に加えて、

HttpServletRequest

HttpServletResponse

オブジェクトがメソッドに対する引數として渡されるということです。もう一つの違いは、このメソッドでは全ての処理をメソッドが行ったことを明示するために

null

を返すことができることです。この場合 Velocity は

requestCleanup()

以外は何もしません。これは、例えば要求をリダイレクトしたい場合に極めて便利です。

當然のことながら、最も確実で最新の注意事項については、Javadoc API ドキュメンテーションを參照してください。

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

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

handleRequest()

メソッドに渡されるデフォルトの

Context

オブジェクトには、現在の

HttpServletRequest

HttpServletResponse

オブジェクトの両方が含まれています。これらは、定數

VelocityServlet.REQUEST

(値は「req」) と

VelocityServlet.RESPONSE

(値は「res」) を使って、コンテキストに設定されます。Java コードでこれらのオブジェクトにアクセスするには、以下のようにします。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public Template handleRequest(  Context context )
{
    HttpServletRequest request =  (HttpServletRequest) context.get( REQUEST );
    HttpServletResponse response =  (HttpServletResponse) context.get( RESPONSE );

   ...
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
そしてテンプレートでは以下のようにアクセスします。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
#set($name = $req.getParameter('name') )
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
より高度な使い方として、 VelocityServlet 基本クラスは、リクエスト処理のハンドリングの一部をオーバーライドできます。オーバーライドできるのは以下の各メソッドです。

Properties loadConfiguration( ServletConfig )

通常の設定メカニズムをオーバーライドし、設定プロパティの追加や変更ができます。実行時に Webアプリケーションのルートに絶対パスを設定するために、テンプレートやログのパスをオーバーライドしたり増やしたりするのに役立ちます。

Context createContext(HttpServletRequest, HttpServletResponse )

自分でコンテキストオブジェクトを生成できます。これによってより高度なテクニック、例えば、例えばコンテキストの連鎖や、ツールやデータでの事前ロードを行なえます。デフォルトの実裝では、内部で設定されたリクエストおよびレスポンスオブジェクトを含む VelocityContext オブジェクトを返します。リクエストおよびレスポンスオブジェクトは、サーブレットコンテナの実裝によっては発生するかもしれない、イントロスペクションでの問題を回避するために単純なラッパクラスでラップされています。リクエストおよびレスポンスオブジェクトは通常どおり使用できますし、テンプレートからもどちらのメソッドにもアクセスできます。人によっては重要かも知れないので、念のため注記しておくと、これらのクラスは、厳密には 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 ベースのサーブレットを配備する場合、プロパティファイルが Velocity ランタイムを設定するのに使われているかどうか確認したいことがあるかと思います。 Tomcat でこの目的を達成するためには、Web アプリケーションのルートディレクトリ(webapps/appname)に velocity.properties ファイルを置き、以下の内容を WEB-INF/web.xml ファイルに追加するという方法があります。

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
<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>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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

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

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

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

Velocity は汎用ツールとして設計されたので、一般的なアプリケーションプログラムでも、サーブレットで使う場合と同様に役に立ちます。通常はこのガイドの初めに説明したのと同じプログラミングパターンを使うことができますが、サーブレットプログラミングで簡単に使える 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 プログラムを書くのは簡単です。こんな感じです。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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 );
    }
}
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
このプログラムを実行し、プログラムと同じディレクトリに

testtemplate.vm

というテンプレートを置きます (デフォルトの設定プロパティを使ったため、テンプレートをロードするデフォルトの場所は現在のディレクトリになります)。その結果、出力は以下のようになります。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
template : Hi!  This Velocity from the Jakarta project.

string : We are using Jakarta Velocity to render this.
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
この際に使用したテンプレート(testtemplate.vm)は以下のとおりです。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Hi!  This $name from the $project project.
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
これで完了です! プログラムで

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つのプロパティファイルにまとめることができるのです。

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
...

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を作ってデータを入れる */

 ...
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
ディレクトリ

/opt/templates

があり、そこにテンプレート

testtemplate.vm

がある場合に、これはうまく動きます。これを試して問題があるなら、情報を得るために velocity.log をチェックして下さい ─ エラーメッセージは何がおかしいか了解するためにかなり役立ちます。
アプリケーション屬性
アプリケーション屬性 は、(

VelocityEngine

Velocity

Singleton のどちらかを経由して) RuntimeInstance に関連付けられる名前と値のペアです。RuntimeInstance にアクセスできる VeclocityEngine のどの部分からでもアクセスできます。

この機能は、アプリケーションレイヤと Velocity エンジンのカスタムの部分 (ロガー、リソースローダ、リソースマネージャなど) の間でのデータの受け渡しが必要なアプリケーションのために用意しました。

アプリケーション屬性 API は非常に単純です。アプリケーションからアクセスするメソッドとしては、

VelocityEngine

Velocity

クラスに以下のメソッドがあります。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public void setApplicationAttribute( Object key, Object value );

      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

このメソッドを使うと、アプリケーション (または内部コンポーネント) 固有のキーで Object を儲存できます。キーや値に制限はありません。キーの値はいつでも設定できます ─ init() が呼ばれる前に設定する必要はありません。

内部コンポーネントが

RuntimeServices

インタフェース経由でオブジェクトにアクセスする場合は、以下のメソッドを使って、キーと値のペアにアクセスできます。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public Object getApplicationAttribute( Object key );

      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
内部コンポーネントではキーの値の取得はできても、設定はできないことに注意して下さい。内部コンポーネントがアプリケーションと情報の受け渡しをしなければならない場合は、値として渡される Object 経由でなければなりません。
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

から抜粋したものです。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
...

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 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 設定キーと値

Velocity の実行時構成は、以下の一覧にある各設定キーで制禦します。通常、これらのキーは String の値、あるいは CSV (Comma Separated Values) と呼ばれるコンマ區切りの 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

プロパティが適用されます。これによって、キャッシュを効率的に行ない、リロード制禦を簡単に行なえます ── これは、テンプレートは頻繁に変更されるけれども、アプリケーションやサーブレットエンジンの再起動はしたくない、あるいは許可されていないようなホスティング環境や ISP 環境で役に立ちます。

<name>.resource.loader.modificationCheckInterval = 2

キャッシュが有効な場合の変更チェックの間隔の秒數です。この數字が 0 より大きい整數の場合、テンプレートが変更されたかどうかをチェックする間隔の秒數を示します。最後のチェック以降にテンプレートが変更されていれば、再ロード・再解析されます。そうでなければ、何もしません。 0 以下の場合は修正チェックは行われませんし、 (上記の)

cache

プロパティが true の場合、テンプレートが最初の使用時に一度ロード・解析されたら、アプリケーションやサーブレットエンジンが再起動するまでチェック・リロードは行れません。

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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 のライブラリソースについて変更をチェックし、必要であればリロードされます。これにより、まさに通常のテンプレートと同じように、アプリケーションやサーブレットコンテナを再起動せずに 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 を統合し、全てのログメッセージを既存のロガーに出力することも可能です。

バージョン 1.3 から、 Avalon Logkit ロガーとJakarta Log4j ロガーのどちらかを自動選択するようになりました。現在のクラスパスで見つかった方を選択しますが、もし両方ある場合は Logkit を選択します。もし Logkit がなければ Log4j があるかどうか確認します。

この機能を使う手順としては、「依存ライブラリなしの」Velocity JAR ファイルを使い、 (依存ライブラリ込みの JAR ファイルの場合は、Logkit が埋め込まれているので)、 Logkit か Log4j の どちらかの JAR ファイルをクラスパスに含めるだけです。

ロギングについては、通常は以下の選択肢があります。

  • デフォルト設定

    デフォルトでは、Velocity はファイルベースのログをカレントディレクトリに作成します。

  • 既存の Log4j カテゴリ

    バージョン 1.3 から、Velocity ではアプリケーションの他のところでセットアップした、既存の Log4j カテゴリにログ出力できるようになりました。この機能を使うためには、以下のようにする必要があります。

    1. Log4j の JAR ファイルがクラスパスに含まれていることを確認する。 (Velocity を使ったアプリケーションで Log4j を使っているなら、 何はともあれこの作業を行なうでしょう)
    2. SimpleLog4jLogSystem

      を使うように Velocity を設定する。
    3. 'runtime.log.logsystem.log4j.category' プロパティに、 既存のカテゴリの名前を指定する。
    このアプローチは今までの

    Log4JLogSystem

    クラスを置き換えるもので、このクラスは非推奨となります。コードでの例については後述します。
  • カスタムのスタンドアロンのロガー

    カスタムロギングクラスを作成することもできます --

    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 設定キーと値 を參照してください。

既存のカテゴリで Log4j を使う

既存の Log4j カテゴリでログ出力を行なうように Velocity を設定する方法の例を示します。

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;

import org.apache.log4j.Category;
import org.apache.log4j.BasicConfigurator;

public class Log4jCategoryExample
{
    public static String CATEGORY_NAME = "velexample";

    public static void main( String args[] )
        throws Exception
    {
        /*
         *  Log4j でログに出力するよう設定する。
         */

        BasicConfigurator.configure();

        Category log = Category.getInstance( CATEGORY_NAME );

        log.info("Hello from Log4jCategoryExample - ready to start velocity");

        /*
         *  ここで VelocityEngine インスタンスを生成し、
         *  このカテゴリを使うよう設定する。
         */

        VelocityEngine ve = new VelocityEngine();

        ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
            "org.apache.velocity.runtime.log.SimpleLog4JLogSystem" );

        ve.setProperty("runtime.log.logsystem.log4j.category", CATEGORY_NAME);

        ve.init();

        log.info("this should follow the initialization output from velocity");
    }
}
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
この例は、

examples/logger_example

にあります。

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

Velocity のロギングシステムをロガーとして実裝するクラスのインスタンス化の例です。使用するクラス名ではなく、使用するクラスの実際に存在するインスタンスを渡しているところに注意してください。必須なのは、

LogSystem

インタフェースをサポートすることだけです。
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)
        {
            /*
             *  何か行ないます。
             */
        }             
    }

    /**
     *  この init() は、現在の RuntimeServices を用意するために、
     *  LogManager が一度だけ呼び出します。
     */
    public void init( RuntimeServices rsvc )
    {
        // 何も行ないません。
    }

    /**
     *  Velocity がログメッセージを引數に呼び出すメソッドで、これを実裝します。
     */
    public void logVelocityMessage(int level, String message)
    {
        /* なにか意味のあることを行ないます */
    }
...
}            
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
リソースローダの設定

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

      = <チェック間隔 (秒) >
    これはデフォルトのローダで、「カレントディレクトリ」からデフォルトでテンプレートを取得する設定になっています。サーブレットで Velocity を使う場合、サーブレットエンジンを起動するディレクトリにテンプレートを置きたくない時に、問題が発生する可能性があります。詳細はVelocity でサーブレット開発のセクションを見てください。
  • JarResourceLoader : このローダは、特定の JAR ファイルからリソースを取得します。 JAR ファイルにテンプレートをまとめられることを除いて、 FileResourceLoader とほぼ同じです。プロパティについても、

    jar.resource.loader.path

    以外は同じです。このプロパティでリソースをロードしたい JAR ファイル (複數可) のフルパスを指定します。この loader.path で JAR ファイルを指定するには、

    java.net.JarURLConnection

    の標準の JAR URL 構文を使います。
  • ClasspathResourceLoader : このローダは、クラスローダからリソースを取得します。たいていの場合は、 ClasspathResourceLoader が、クラスパス内 (例えば、JARファイル内) のテンプレートをロードするということです。クラスパスは多くの場合大きな悩みの種ですが、サーブレット仕様 2.2 以降に対応したサーブレットコンテナを動かす時には、非常に役に立つ仕組みです。Tomcat は、こうしたサーブレットコンテナの一例です。このローダを効果的に使うには、テンプレートを JAR ファイルに入れて、Webアプリの WEB-INF/lib ディレクトリに置けば十分です。設定オプションを気にする必要はありませんし、JAR リソースローダや File リソースローダで起こりうる絶対パス/相対パスの問題も起こりません。繰り返しますが、ClasspathResourceLoader は、サーブレットコンテナだけでなく、どのアプリケーションコンテキストでも使用できることに注意して下さい。
  • DataSourceResourceLoader : このローダは、データベースなどの DataSource からリソースをロードします。 J2EE サポートが必要なので、標準ビルドでは、このローダはビルドされません。このローダをビルドするためには、J2EE 配布をダウンロードし、 j2ee.jar を

    build/lib

    ディレクトリに移動して、

    jar-j2ee

    というビルドターゲットを使用して VelocityのJARファイルを新たにビルドします。このローダの詳細については、

    org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader

    クラスの Javadoc をご覧下さい。

設定例

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

一つ以上のリソースローダを設定する場合、最初のステップとして Velocity に対してリソースローダを名前で「宣言」します。プロパティ

resource.loader

を使い、一つ以上のローダ名を [コンマ區切りの]リストで指定します。どんな名前でもかまいません ── これらの名前は、該當するローダを設定プロパティに関連づけるために使われます。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
resource.loader = file
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
このエントリでは、「file」として知られているリソースローダを使うと宣言しています。次に行なうのは、重要なプロパティをセットすることです。ここで一番大事なのは、ローダとして使用するクラスを宣言することです。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
この場合、「file」というリソースローダを設定し、それが

org.apache.velocity.runtime.resource.loader.FileResourceLoader

クラスを使用することを Velocity に伝えます。次に、このローダにとって重要なプロパティを設定します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
ここで3つの設定を行っています。ます、テンプレートを見つけるためのパスとして

/opt/templates

を設定しています。次に、テンプレートまたは靜的ファイルが読まれた後、メモリにキャッシュされるように、キャッシュをオンにしています。最後に、新しいテンプレートの更新チェック間隔を2秒にセットしています。

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

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
複數テンプレートパス設定 : テンプレートの検索パスの「ノード」として複數のディレクトリが指定された FileResourceLoader を使用するように設定します。また、キャッシュを使い、テンプレートの変更を10秒間隔でチェックします。プロパティは以下のようになります。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
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
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
複數ローダ設定 : この設定は、FileResourceLoader、ClasspathResourceLoader、JarResourceLoader という 3つのローダを同時に動かすようにセットアップします。ローダは、最初に FileResourceLoader、次に ClasspathResourceLoader、最後に JarResourceLoader が參照されます。こうすれば、クラスパス上にあるテンプレートを置き換える際に、ファイルテンプレートの領域に入れるだけでよく、JAR ファイルを再ビルドする必要はありません。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
#
# 使用する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
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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

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

プラグイン可能なリソースマネージャとリソースキャッシュ

リソースマネージャはリソース (テンプレートと靜的コンテンツ) の主要部分を管理するシステムで、テンプレートへのアプリケーションのリクエストを受け取り、利用可能なリソースローダでそれらを見つけ、オプションとしてパース済みのテンプレートのキャッシュを行ないます。リソースキャッシュとは、リソースマネージャがテンプレートの再利用を高速に行なえるように、テンプレートをキャッシュする仕組みです。ほとんどのアプリケーションの場合、こうした2つの機能のデフォルトのバージョンで十分ですが、上級ユーザなら、デフォルトのリソースマネージャとリソースキャッシュを、カスタム実裝に置き換えることも可能です。

リソースマネージャの実裝時には、

org.apache.velocity.runtime.resource.ResourceManager

インタフェースを実裝しなければなりません。リソースマネージャの要件記述についてはこの文書の範囲外となります。実裝する人はデフォルトの実裝をチェックすることをお勧めします。 Velocity で代わりの実裝をロードするには、以下の設定キーを使います。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
resource.manager.class
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
このキーはまた、

RuntimeConstants.RESOURCE_MANAGER_CLASS

という定數としても定義されています。
國際化のためのテンプレートエンコーディング
バージョン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 文書を使ってみましょう。

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
<?xml version="1.0"?>

<document>
 <properties>
  <title>Developer's Guide</title>
  <author email="[email protected]">Velocity Documentation Team</author>
 </properties>
</document>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
ここで、以下のようなコードを含む小さな Java プログラムを作成します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
...

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 );

...
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
(このやり方についての詳細は、配布の

examples

ディレクトリにある Anakia サンプルを參照してください。)次に、通常の Velocity テンプレートを作成します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
<html>
  <body>
    The document title is 
    $root.getChild("document").getChild("properties").getChild("title").getText()
  </body>
</html>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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

Velocity で XML データを整形する大きな利點の一つは、アプリケーションが用意する他のオブジェクトやデータにアクセスできるということです。その XML 文書にあるデータが使えるだけではありません。出力に関する追加情報を提供するためにコンテキストに何でも追加できますし、 XML データを使いやすくするツールも提供できます。 Bob McWhirter のWerken Xpath はこの種の便利なツールの一つです ─ Anakia での使い方の例は

org.apache.velocity.anakia.XPathTool

にあります。

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
## まず、Velocimacro をどこかで定義します

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

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

#set( $sometext = " < " )
<text>#xenc($sometext)</text>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
この例で escapeEntities() メソッドはエスケープを行ないます。コンストラクタの引數でコンテキストを取得し、以下のメソッドだけを実裝するエンコードユーティリティを作成するという手もあります。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public String get(String key)
{
    Object obj = context.get(key)
    return (obj != null) ? Escape.getText( obj.toString() ) : "";
}
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
コンテキストには "xenc" というキーで設定します。そして以下のように使用します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
<text>$xenc.sometext</text>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド

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

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

Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
#set( $sometext = $jdomElement.getText() )
<text>$sometext</text>
      
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
XML エンティティを扱う前者の方法は、Christoph Reck (Velocityコミュニティへのアクティブな參加者です) のアイデアを元にしています。この文書への彼の (知られざる) 貢獻に、非常に感謝しています。彼のアイデアはそれほどめちゃめちゃにはなってないと思います :)
FAQ (よく聞かれる質問)

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

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

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

org.apache.velocity.app.FieldMethodizer

というクラスがあります。 例えばこんなクラスがあるとしましょう。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
public class Foo
    {
        public static String PATH_ROOT = "/foo/bar";
     
        ....
    }
        
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
これを利用するコードで

Foo

を以下のようにコンテキストに設定します。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
context.put("myfoo", new FieldMethodizer( new Foo() ) );
        
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
テンプレートでこのフィールドにアクセスするには、Java と同じやり方で 簡単にアクセスできます。
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
$myfoo.PATH_ROOT
        
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
Velocity 開発者ガイド
もし、パブリックで靜的でないメンバにアクセスせざるを得ない壊滅的な狀況 (あるいは、プライベートメンバにアクセスしなければならないような破滅間際の狀況) なら、

FieldMethodizer

クラスを自分で継承あるいは修正する必要が あります。(もちろん、それでもなおアクセッサを用意することをお勧めしますが……)

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

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

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

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

まとめ

簡素なガイドではありますが、Java のプロジェクトで Velocity を使うための概論としてお役に立てたなら幸いです。また、Velocity に興味をもっていただいたことを感謝しています。このドキュメンテーションについて、あるいは Velocity テンプレートエンジンそのものに関するコメントは何でも歓迎します。

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

追記1:サンプルサーブレットの配備
初心者のサーブレットユーザが挫折することが多いのは、全てをまとめた上で動かす時です。 Tomcat や Resin といったサーブレットエンジンの使い方は初めて使う人には分かりづらいのです (そして、慣れたユーザでさえも……)。 SampleServlet サンプルを動かすための基本的な手順を以下で説明します (できるだけ分かりやすくしたつもりです)。注意事項として、サンプルテンプレートである

sample.vm

と、サーブレットコードそのものである

SampleServlet.java

は、

examples/servlet_example

ディレクトリにあります。サーブレットエンジンによっては(例えば Resin など)、サーブレットを自動的にコンパイルしてくれますが、動かす前にサンプルをコンパイルするに越したことはないでしょう。コンパイルする方法については、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 ディレクトリに置きます。バージョン 1.2 以降では、(velocity-dep-1.2.jar のような) 全ての依存ライブラリを含む配布の JAR ファイル (自分でビルドしたものも含む)を使うか、WEB-INF/lib ディレクトリに、 依存する JAR ファイルを自分で追加する必要があります。詳しくは先述の「導入」および「依存関係」 をご覧下さい。
  3. SampleServlet.class を velexample/WEB-INF/classes ディレクトリに置きます。
  4. sample.vm テンプレートを velexample ディレクトリに置きます。SampleServlet は、 テンプレートのソースディレクトリとして Web アプリのルートディレクトリを使うので、 それ以外の設定は不要です。
  5. これで Tomcat を起動(または再起動)すればサーブレットにアクセスできるはずです。
  6. サーブレットにアクセスするには、Web ブラウザで以下のアドレスを指定します。
    http://localhost:8080/velexample/servlet/SampleServlet
    もし、うまく動かなければ、以下のアドレスを指定してみてください。
    http://<あなたのコンピュータのIPアドレス>:8080/velexample/servlet/SampleServlet
    [訳注: Tomcat 4.1以降ではセキュリティの観點から、このアドレス指定方法では動作しないようになったため、 Web アプリの web.xml でサーブレットの設定をした上で、別のアドレス指定をする必要があります。詳しくは Tomcat のドキュメントをご覧下さい。]
  7. サンプル出力が表示されるはずです。

Caucho Technology の Resin

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

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

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

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

BEA WebLogic

Paw Dybdahl <[email protected]> が、WebLogic での Velocity の使い方や、サーブレットと一緒に使う場合の一般的なアドバイスを、ここで行っています。