ナビゲーションをスキップ

WebLogic JSP Tag Extensions プログラマーズ ガイド

  前 次 前/次ボタンと目次ボタンとの区切り線 目次  

タグ ハンドラの実装

以下の節では、拡張タグの機能を実装する Java クラスを記述する方法について説明します。

 


タグ ハンドラ API

JSP 1.1 API には、カスタム タグ ハンドラの作成に使用するクラスとインタフェースのセットが定義されています。javax.servlet.jsp.tagext API についてのドキュメントは「http://java.sun.com/j2ee/j2sdkee/techdocs/api/index.html」で参照できます。

タグ ハンドラは、以下の 2 つのインタフェースのうちの 1 つを実装する必要があります。

Tag

カスタム タグが本体のないタグ (空タグ) の場合、javax.servlet.jsp.tagext.Tag インタフェースを実装します。この API では、コンビニエンス クラス TagSupport も提供されています。このクラスは、Tag インタフェースを実装し、このインタフェース内で定義されているメソッド用のデフォルトの空メソッドを提供します。

BodyTag

カスタム タグが本体を使用する必要がある場合、javax.servlet.jsp.tagext.BodyTag インタフェースを実装します。この API では、コンビニエンス クラス BodyTagSupport も提供されています。このクラスは、BodyTag インタフェースを実装し、このインタフェース内で定義されているメソッド用のデフォルトの空メソッドを提供します。BodyTagTag を拡張したものであり、インタフェース メソッドのスーパーセットです。

 


タグ ハンドラのライフ サイクル

Tag インタフェースまたは BodyTag インタフェースのどちらかから継承され、そのタグ ハンドラ クラスに実装されたメソッドは、JSP ページ処理中の特定の時点で JSP エンジンによって呼び出されます。これらのメソッドは、タグのライフ サイクルにおけるさまざまなポイントを表し、以下の順序で実行されます。

  1. JSP エンジンが JSP ページの中でタグを見つけると、新しいタグ ハンドラが初期化されます。javax.servlet.jsp.tagext.Tag インタフェースの setPageContext() メソッドと setParent() メソッドが呼び出されて、そのタグ ハンドラの環境コンテキストが設定されます。タグ開発者は、基本クラス TagSupport または BodyTagSupport を拡張する場合、これらのメソッドを実装する必要はありません。
  2. タグ属性ごとに setXXXX() という JavaBean のようなメソッドが呼び出されます。詳細については、「タグ本体内の例外処理」を参照してください。
  3. doStartTag() メソッドが呼び出されます。タグ ハンドラでこのメソッドを定義すると、タグ ハンドラを初期化したり、データベースなどの必要なあらゆるリソースへの接続を開くことができます。
  4. doStartTag() メソッドの終わりには、タグ本体を評価すべきかどうかを、以下の値定数のうちの 1 つをタグ ハンドラ クラスから返すことで指定できます。

SKIP_BODY

タグの本体をスキップするよう JSP エンジンに指示します。タグが本体のないタグ (空タグ) である場合、この値を返します。タグのライフ サイクルのうち本体に関係のある部分はスキップされ、次に呼びされるメソッドは doEndTag() となります。

EVAL_BODY_INCLUDE

タグ本体のコンテンツを評価して組み込むよう JSP エンジンに指示します。タグのライフ サイクルのうち本体に関係のある部分はスキップされ、次に呼びされるメソッドは doEndTag() となります。

この値を返すことができるのは、Tag インタフェースを実装するタグの場合だけです。この値を使用すると、本体を組み込むかどうかは決定できるが、そのコンテンツには関知しないタグを記述できます。タグが BodyTag インタフェースを実装する (または BodyTagSuport クラスを拡張する) 場合、この値を返すことはできません。

EVAL_BODY_TAG

タグ本体を評価してから doInitBody() メソッドを呼び出すよう JSP エンジンに指示します。この値は、タグが BodyTag インタフェースを実装する (または BodyTagSupport クラスを拡張する) 場合にのみ返すことができます。

  1. setBodyContent() メソッドが呼び出されます。この時点では、タグからの出力は BodyContent という特殊な JspWriter にリダイレクトされ、クライアントには送られません。本体を評価して得られるすべてのコンテンツは BodyContent バッファに追加されます。このメソッドにより、タグ ハンドラは BodyContent バッファへの参照を格納して doAfterBody() メソッドで評価後の処理のために使えるようにできます。
  2. タグが出力を JSP ページ (ネスト タグの場合はその親スコープ) に渡す場合、タグはタグ ライフ サイクルのこの時点から doEndTag() メソッドが終わるまでに、そのタグの出力を親スコープの JspWriter に明示的に書き出す必要があります。タグ ハンドラは、getEnclosingWriter() メソッドを使用して、親スコープの出力にアクセスできます。

    コンビニエンス クラスの BodyTagSupport を使用している場合、このメソッドを実装する必要はありません。これは、タグによって BodyContent への参照が保持され、getBodyContent() メソッドを介してその参照を使用できるようになるためです。

  3. doInitBody() メソッドが呼び出されます。このメソッドを使用すると、タグ本体が初めて評価される直前に何らかの処理を実行できます。ここでは、スクリプト変数を設定したり、タグ本体の前の BodyContent に何らかのコンテンツを挿入したりできます。ここで付加したコンテンツは、JSP ページのタグ本体のコンテンツとは異なり、JSP として評価されることはありません。
  4. このメソッドで実行する処理と doStartTag() メソッドの終わりに実行する処理との大きな違いは (EVAL_BODY_TAG を返そうとしていることが分かった場合)、このメソッドでは、タグの出力のスコープはネストされていて、JSP ページ (または親タグ) には直接向けられないということです。すべての出力は、BodyContent という特殊な JspWriter にバッファされます。

  5. doAfterBody() メソッドが呼び出されます。このメソッドは、タグの本体が評価され BodyContent バッファに追加された後に呼び出されます。タグ ハンドラは、評価済みタグ本体に基づいて何らかの処理を行うためにこのメソッドを実装する必要があります。ハンドラがコンビニエンス クラスの BodyTagSupport を拡張する場合、getBodyContent() メソッドを使用して評価済みタグ本体にアクセスできます。単に BodyTag インタフェースを実装するだけであれば、setBodyContent() メソッドを定義して、そこに BodyContent インスタンスへの参照を格納しておく必要があります。
  6. doAfterBody() メソッドの終わりには、タグのライフ サイクルを、前と同じように以下の値定数のうちの 1 つを返すことで決定できます。

SKIP_BODY

処理を続行し、本体を再び評価しないよう JSP エンジンに指示します。タグのライフ サイクルは doEndTag() メソッドに進みます。

EVAL_BODY_TAG

本体を再び評価するよう JSP エンジンに指示します。評価済み本体が BodyContent に追加され、doAfterBody() メソッドが再び呼び出されます。

この時点で、タグ ハンドラが親スコープに出力を書き出すよう指定できます。親スコープへのライターを取得するには、BodyTagSupport.getPreviousOut() メソッドまたは BodyContent.getEnclosingWriter() メソッドを使用します。どちらのメソッドでも、同じ親ライターが取得されます。

タグ ハンドラは評価済み本体のコンテンツを親スコープに書き出すこともあれば、その評価済み本体をさらに処理して他の何らかの出力を書き出すこともあります。本体の反復処理ごとに BodyContent が既存の BodyContent に追加されるので、SKIP_BODY を返すよう決定した場合、反復処理された本体のコンテンツ全体だけを書き出します。そのようにしないと、後続の各反復処理のコンテンツが何度も出力に現れることになります。

  1. pageContext 内の out ライターが親の JspWriter に復元されます。このオブジェクトは実際にはスタックであり、pushBody() メソッドと popBody() メソッドを使用して pageContext 上の JSP エンジンによって処理されます。ただし、タグ ハンドラの中でこれらのメソッドを使用してこのスタックを処理しようとしてはいけません。
  2. doEndTag() メソッドが呼び出されます。タグ ハンドラはこのメソッドを実装してタグ処理後のサーバサイド作業を実行し、出力を親スコープ JspWriter に書き出して、データベース接続などのリソースをクローズできます。
  3. タグ ハンドラは、doEndTag() メソッド内で pageContext.getOut() を実行して得られる JspWriter を使用して、親スコープに出力を直接書き出します。なお、pageContext.out は、前の手順で popBody()pageContext 上で呼び出されたときに親ライターに復元されています。

    doEngTag() メソッドから以下の値のうちの 1 つを返すことで、JSP ページの残りの部分の評価フローを制御できます。

EVAL_PAGE

JSP ページの残りの部分の処理を続行するよう JSP エンジンに指示します。

SKIP_PAGE

JSP ページの残りの部分をスキップするよう JSP エンジンに指示します。

  1. release() メソッドが呼び出されます。 この呼び出しは、タグ ハンドラ インスタンスが逆参照され、ガベージ コレクション用に使用できるようになる直前に行われます。

 


タグ本体の反復処理

javax.servlet.jsp.tagext.IterationTag インタフェースを実装するタグでは、タグの本体を条件付きで再評価できる doAfterBody() というメソッドを使用できます。doAfterBody()IterationTag.EVAL_BODY_AGAIN を返す場合は、本体が再評価されます。doAFterBody()Tag.SKIP_BODY を返す場合は、本体はスキップされて doEndTag() メソッドが呼び出されます。詳細については、このインタフェースの J2EE Javadoc を参照してください (Sun Microsystems の Javadoc は、「http://java.sun.com/products/jsp/download.html」でダウンロードできます)。

注意 : IterationTag インタフェースは、Sun Microsystems の JSP 1.2 仕様の新機能です。バージョン 1.2 は仕様の最終草案として提案されたもので、変更されることがあります。アプリケーションで JSP 1.2 の機能を使用する場合は、この仕様が最終的なものではなく、将来変更される可能性があることに注意します。

 


タグ本体内の例外処理

javax.servlet.jsp.tagext.TryCatchFinally インタフェースの doCatch() および doFinally() メソッドを実装すると、タグ内から送出される例外を捕捉できます。詳細については、このインタフェースの J2EE Javadoc を参照してください (Sun Microsystems の Javadoc は、「http://java.sun.com/products/jsp/download.html」でダウンロードできます)。

注意 : TryCatchFinally インタフェースは、Sun Microsystems の JSP 1.2 仕様の新機能です。バージョン 1.2 は仕様の最終草案として提案されたもので、変更されることがあります。アプリケーションで JSP 1.2 の機能を使用する場合は、この仕様が最終的なものではなく、将来変更される可能性があることに注意します。

 


タグ属性の使い方

カスタム タグでは、JSP ページから指定できる属性を何個でも定義できます。これらの属性は、タグ ハンドラに情報を渡してその動作をカスタマイズするために使用できます。

各属性名は、TLD の中で <attribute> 要素を使用して宣言します。この要素は、属性の名前とその他の属性プロパティを宣言します。

JavaBean 規約と同じように、タグ ハンドラは属性名に基づいてセッター メソッドとゲッター メソッドを実装しなければなりません。たとえば、foo という属性を宣言する場合、タグ ハンドラは以下のパブリック メソッドを定義する必要があります。

public void setFoo(String f);
public String getFoo();

属性名の先頭の文字は、プレフィックスの set または get の後では大文字になることに注意してください。

JSP エンジンは、タグ ハンドラが初期化されてから doStartTag() メソッドが呼び出されるまでの間に、各属性のセッター メソッドを適切に呼び出します。一般に、タグ ハンドラの他のメソッドからアクセスできるメンバー変数に属性値を格納するには、セッター メソッドを実装しなければなりません。

 


新しいスクリプト変数の定義

タグ ハンドラは、さまざまなスコープで JSP ページから参照できる新しいスクリプト変数を使用できます。スクリプト変数は、それらの定義済みスコープの内部で暗黙的なオブジェクトのように使用できます。

javax.servlet.jsp.tagext.TagExtraInfo を拡張する Java クラスを識別するための新しいスクリプト変数は、<teiclass> 要素を使用して定義します。たとえば、次のようになります。

<teiclass>weblogic.taglib.session.ListTagExtraInfo</teiclass>

次に、TagExtraInfo クラスを作成します。次に例を示します。

package weblogic.taglib.session;
import javax.servlet.jsp.tagext.*;
public class ListTagExtraInfo extends TagExtraInfo {

public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[] {
new VariableInfo("username",
"String",
true,
VariableInfo.NESTED),
new VariableInfo("dob",
"java.util.Date",
true,
VariableInfo.NESTED)
};
}
}

上の例では、VariableInfo 要素の配列を返す getVariableInfo() というメソッドが 1 つ定義されています。各要素は、新しいスクリプト変数を定義します。上記のサンプルでは、java.lang.String 型の usernamejava.util.Date 型の dob という 2 つのスクリプト変数が定義されています。

VariableInfo() のコンストラクタは、以下の 4 つの引数を取ります。

VariableInfo.NESTED

タグの開始タグと終了タグの間でだけ使用できます。

VariableInfo.AT_BEGIN

開始タグとページの最後の間で使用できます。

VariableInfo.AT_END

終了タグとページの最後の間で使用できます。

タグ ハンドラは、ページのコンテキストを介してスクリプト変数の値を初期化しなければなりません。たとえば、上で定義したスクリプト変数の値を初期化するには、doStartTag() メソッドの中で以下の Java ソースを使用します。

pageContext.setAttribute("name", nameStr);
pageContext.setAttribute("dob", bday);

ここで、最初のパラメータはスクリプト変数の名前を指定し、2 番目のパラメータは代入される値を示します。なお、ここでは Java 変数の nameStrString 型で、bdayjava.util.Date 型です。

また、TagExtraInfo クラスを使用して作成された変数にアクセスするには、useBean を使用して作成された JavaBean にアクセスするときと同じようにそれを参照します。

動的名前付きスクリプト変数

タグの属性から、新しいスクリプト変数の名前を定義できます。このように定義することで、1 つのスクリプト変数を定義するタグの複数のインスタンスを同じスコープで使用しつつ、タグのスクリプト変数名の衝突を避けることができます。TagExtraInfo を拡張するクラスからこれを実行するには、getVariableInfo() メソッドに渡される TagData からスクリプト変数の名前を取得する必要があります。

TagData からは、getAttributeString() メソッドを使用して、スクリプト変数の名前を指定する属性の値を検索できます。さらに、id 属性の値を返す getId() というメソッドもあります。これは、JSP タグからもたらされる新しい暗黙的オブジェクトに名前を付けるためによく使用されます。

タグ ライブラリ記述子の変数の定義

タグ ライブラリ記述子の変数を定義できます。 Q詳細については、スクリプト変数を定義します (省略可能)を参照してください。

 


協調的ネスト タグの記述

ネストされているタグが、その親タグに定義されているプロパティを暗黙的に使用するよう設計できます。たとえば、サンプル コードの「SQL Query」(WebLogic Server の samples/examples/jsp/tagext/sql ディレクトリを参照) では、<sql:query> タグが <sql:connection> タグの内部にネストされています。query タグは親スコープの connection タグを検索して、そのタグによって確立された JDBC 接続を使用します。

親スコープのタグを見つけるために、ネスト タグは TagSupport クラスの静的メソッドである findAncestorWithClass() を使用します。次に、QueryTag のサンプルから抜粋したコードを示します。

try {
ConnectionTag connTag = (ConnectionTag)
findAncestorWithClass(this,
Class.forName("weblogic.taglib.sql.ConnectionTag"));
} catch(ClassNotFoundException cnfe) {
throw new JspException("Query tag connection "+
"attribute not nested "+
"within connection tag");
}

この例では、与えられたクラスに一致するタグ ハンドラ クラスを持つ最も近い親タグ クラスが返されます。直系の親タグがこのタイプでなければ、さらにその親がチェックされます。一致するタグが見つかるまでこの処理が繰り返され、それでも見つからない場合は ClassNotFoundException が送出されます。

カスタム タグでこの機能を使用すれば、JSP ページでのタグの構文と使い方を簡素化できます。

 


タグ ライブラリ バリデータの使用

注意 : Java タグ ライブラリ バリデータは、Sun Microsystems の JSP 1.2 仕様の新機能です。バージョン 1.2 は仕様の最終草案として提案されたもので、変更されることがあります。アプリケーションで JSP 1.2 の機能を使用する場合は、この仕様が最終的なものではなく、将来変更される可能性があることに注意してください。

タグ ライブラリ バリデータはユーザが記述する Java クラスです。これを使用すると JSP ページ上でカスタム検証を実行できます。バリデータ クラスは入力ストリームとして JSP ページ全体を取得します。バリデータ クラスに記述した条件に基づいてページを検証できます。バリデータの一般的な使い方としては、バリデータ クラス内で XML パーサを使用して、文書型定義 (DTD) に対してページを検証する場合が挙げられます。バリデータ クラスはページの変換時 (JSP がサーブレットに変換されるとき) に呼び出され、ページが検証されると null 文字列を返します。検証が失敗するとエラー情報を含む文字列を返します。

タグ ライブラリ バリデータを実装するには、次の手順に従います。

  1. バリデータ クラスを記述します。バリデータ クラスは javax.servlet.jsp.tagext.TagLibraryValidator クラスを拡張します。
  2. タグ ライブラリ記述子内のバリデータを参照します。次に例を示します。
  3. <validator>
    <validator-class>
         myapp.tools.MyValidator
      </validator-class>
    </validator>
  4. (省略可能) 初期化パラメータを定義します。バリデータ クラスで初期化パラメータを取得および使用できます。次に例を示します。
  5. <validator>
    <validator-class>
         myapp.tools.MyValidator
      </validator-class>
      <init-param>
         <param-name>myInitParam</param-name>
         <param-value>foo</param-value>
      </init-param>
    </validator>
  6. Web アプリケーションの WEB-INF/classes ディレクトリに、バリデータ クラスをパッケージ化します。タグ ライブラリ jar ファイルにクラスをパッケージ化することもできます。詳細については、「JSP タグ ライブラリを JAR ファイルとしてデプロイする」を参照してください。

 

フッタのナビゲーションのスキップ  ページの先頭 前 次