WebLogic JSP Tag Extensions プログラマーズ ガイド
![]() |
![]() |
![]() |
![]() |
以下の節では、拡張タグの機能を実装する Java クラスを記述する方法について説明します。
シンプル タグ ハンドラでは、従来のタグ ハンドラと比べて、大幅に簡素化された呼び出しプロトコルが提示されます。タグ ライブラリ記述子は、物理的な基底の実装に対して、タグ ライブラリ宣言をマップします。シンプル タグ ハンドラは、SimpleTag インタフェースを実装するクラスによって Java で表現されます。
シンプル タグ ハンドラのライフサイクルは、簡単明瞭なものであり、キャッシングのセマンティクスによって複雑化されていません。一旦コンテナによってインスタンス化されたシンプル タグ ハンドラは、実行され、その後破棄されます。同じインスタンスをキャッシュして再利用することはできません。初期パフォーマンスのメトリックにより、タグ ハンドラ インスタンスをキャッシュしても、必ずしもパフォーマンスが向上するわけではないことが分かります。そのようなキャッシングに対応しようとすると、ポータブル タグ ハンドラの記述が困難になり、タグ ハンドラでエラーが生じやすくなります。
扱いが簡単であることに加えて、シンプル タグの拡張では、いかなるサーブレット API にも直接的な依存がないため、将来的な他の技術との統合の可能性にも対応できます。この機能は、Page-Context によって拡張された JspContext クラスで促進されています。JspContext は、JspWriter の格納やスコープ指定された属性の追跡など、一般的なサービスを提供します。一方、PageContext はサーブレットのコンテキストにおける JSP の処理に特化した機能を備えています。Tag インタフェースは PageContext に依存していますが、SimpleTag は JspContext のみに依存しています。SimpleTag の本体は、もしあれば、JSP フラグメントに変換され、setJspBody メソッドに渡されます。タグはその後、必要な回数、そのフラグメントを実行できます。「JSP フラグメント」を参照してください。
従来のタグ ハンドラとは異なり、SimpleTag インタフェースは、Tag を拡張したものではありません。doStartTag() および doEndTag() をサポートするのではなく、SimpleTag インタフェースは単純な doTag() メソッドを提供します。このメソッドは任意のタグ呼び出しごとに一度だけ呼び出されます。すべてのタグのロジック、反復、本体評価などが、この単一のメソッド内で実行されます。したがって、シンプル タグ ハンドラは BodyTag と同等の能力を持ちますが、そのライフサイクルとインタフェースはずっと単純です。
本体のコンテンツをサポートするために、setJspBody() メソッドが提供されています。コンテナは、JspFragment オブジェクトがタグの本体をカプセル化している状態で setJspBody() メソッドを呼び出します。タグ ハンドラの実装は、そのフラグメントに対して invoke() を呼び出し、本体を評価できます。SimpleTagSupport コンビニエンス クラスでは、これをさらに容易に行うための、getJsp-Body() やその他の有用なメソッドが用意されています。
以下では、作成から呼び出しに至るまでのシンプル タグ ハンドラのライフサイクルを説明します。シンプル タグ ハンドラが呼び出されると、次のイベントが順番に発生します。
属性がスクリプト記述式 (たとえば、JSP 構文の「<%= 1+1 %>」または XML 構文の「%= 1+1 %」) である場合、式は評価され、その結果が変換されてセッターに渡されます。
また、属性に何らかの式言語表現 (たとえば、「Hello ${name}」) が含まれていると、式は評価され、その結果が変換されてセッターに渡されます。
また、属性のタイプが JspFragment ではない場合、コンテナは <jsp:attribute> 要素の本体を評価します。この評価は、コンテナ固有のものとして行うことができます。コンテナの実装者は、この本体評価プロセスにおいて、他のカスタム アクションが呼び出される可能性があることに留意してください。
また、属性のタイプが JspFragment である場合、Jsp-Fragment オブジェクトのインスタンスが作成されて渡されます。
本体のコンテンツが空である、本体が存在しない、またはこの呼び出しに対して空の本体が渡されたとタグで宣言されている場合には、setJspBody() は呼び出されません。
また、<jsp:body> または <jsp:attribute> 要素が存在しない場合は、タグの本体は <jsp:body> 要素の本体であるか、カスタム アクション呼び出しの本体であるかのいずれかです。この場合、Jsp-Fragment オブジェクトのインスタンスが作成され、セッターに渡されます。タグが、tagdependent という本体コンテンツを有すると宣言された場合、JspFragment は本体のコンテンツを逐語的に返す必要があります。
また、タグが、scriptless というタイプの本体コンテンツを有すると宣言された場合、JspFragment は本体のコンテンツを JSP のスクリプトなし本体として評価する必要があります。
JSP フラグメントとは、必要に応じて何度でも呼び出せる、JSP コードのタグ ハンドラに渡される部分です。フラグメントは、カスタマイズされたコンテンツを生成するためにタグ ハンドラによって使用されるテンプレートであると考えることができます。したがって、コンテナによって評価される単純な属性とは異なり、フラグメント属性はタグ呼び出し中にタグ ハンドラによって評価されます。
JSP フラグメントは、フラグメントを構成する JSP コード内の JSP 式言語 (JSP EL) 変数を使用して、パラメータ化できます。JSP EL 変数はタグ ハンドラによって設定されるため、ハンドラはフラグメントが呼び出される度に、そのフラグメントをカスタマイズできます。JSP 式言語の詳細については、『WebLogic Server Web アプリケーション、サーブレット、JSP の開発』の「WebLogic JSP リファレンス」を参照してください。
シンプル タグ ハンドラのライフサイクルの期間中、SimpleTag の本体は、もしあれば、JSP フラグメントに変換され、setJspBody メソッドに渡されます。変換フェーズの期間中、ページのさまざまな部分が、タグ ハンドラに渡される前に javax.servlet.jsp.tagext.JspFragment 抽象クラスの実装に変換されます。これは、タグ ライブラリ記述子 (TLD) 内で、フラグメントとして宣言された、または JspFragment タイプである、名前付き属性の本体における任意の JSP コード (<jsp:attribute> で定義される) に対して自動的に行われます。また、シンプル タグ ハンドラによって処理されるどのタグの本体に対しても、自動的に行われます。一度渡されると、タグ ハンドラはフラグメントを必要に応じて何度でも評価および再評価でき、タグ ファイルの場合にはさらに他のタグ ハンドラに渡すことさえできます。
JSP フラグメントは、フラグメントと関連付けられた JspContext 内のページ スコープ属性を設定することで、タグ ハンドラによってパラメータ化できます。これらの属性にはその後、式言語を利用してアクセスできるようになります。
JSP フラグメントに変換されるはずの JSP コードの一部に、スクリプトレットまたはスクリプトレット式が含まれていた場合、変換エラーが発生します。
Tag
インタフェースまたは BodyTag
インタフェースから継承され、そのタグ ハンドラ クラスによって実装されたメソッドは、JSP ページの処理中の特定の時点で JSP エンジンによって呼び出されます。これらのメソッドは、タグのライフサイクルにおけるさまざまなポイントを表し、以下の順序で実行されます。
javax.servlet.jsp.tagext.Tag
インタフェースの setPageContext()
メソッドと setParent()
メソッドが呼び出されて、そのタグ ハンドラの環境コンテキストが設定されます。タグ開発者は、基本クラス TagSupport
または BodyTagSupport
を拡張する場合、これらのメソッドを実装する必要はありません。 setXXXX()
という JavaBean のようなメソッドが呼び出されます。詳細については、「タグ本体内の例外処理」を参照してください。 setBodyContent()
メソッドが呼び出されます。この時点では、タグからの出力は BodyContent
という特殊な JspWriter
にリダイレクトされ、クライアントには送られません。本体を評価して得られるすべてのコンテンツは BodyContent
バッファに追加されます。このメソッドにより、タグ ハンドラは BodyContent
バッファへの参照を格納して doAfterBody()
メソッドで評価後処理のために使えるようにすることができます。 タグが出力を JSP ページ (ネスト タグの場合はその親スコープ) に渡す場合、タグはタグ ライフサイクルのこの時点から doEndTag()
メソッドが終わるまでに、そのタグの出力を親スコープの JspWriter
に明示的に書き出さなければなりません。タグ ハンドラは、getEnclosingWriter()
メソッドを使用して、親スコープの出力にアクセスできます。
コンビニエンス クラスの BodyTagSupport
を使用している場合、このメソッドを実装する必要はありません。これは、タグが BodyContent
への参照を保持し、BodyContent
メソッドを介してその参照を使用できるようにするからです。
doStartTag()
メソッドが呼び出されます。このメソッドを使用すると、タグ本体が初めて評価される直前に何らかの処理を実行できます。ここでは、スクリプト変数を設定したり、タグ本体の前の BodyContent
に何らかのコンテンツを挿入したりできます。ここで付加したコンテンツは、JSP ページのタグ本体のコンテンツとは異なり、JSP として評価されることはありません。 このメソッドで実行する処理と doStartTag()
メソッドの終わりに実行する処理との大きな違いは (EVAL_BODY_TAG
を返そうとしていることが分かった場合)、このメソッドでは、タグの出力のスコープはネストされていて、JSP ページ (または親タグ) には直接向けられないということです。すべての出力は、BodyContent
という特殊な JspWriter
に書き込まれます。
doAfterBody()
メソッドが呼び出されます。このメソッドは、タグの本体が評価され BodyContent
バッファに追加された後に呼び出されます。タグ ハンドラは、評価済みタグ本体に基づいて何らかの処理を行うためにこのメソッドを実装する必要があります。ハンドラがコンビニエンス クラスの BodyTagSupport
を拡張する場合、getBodyContent()
メソッドを使用して評価済みタグ本体にアクセスできます。単に BodyTag
インタフェースを実装するだけであれば、setBodyContent()
メソッドを定義して、そこに BodyContent
インスタンスへの参照を格納しておく必要があります。 この時点で、タグ ハンドラが親スコープに出力を書き出すよう指定できます。親スコープへのライターを取得するには、BodyTagSupport.getPreviousOut()
メソッドまたは BodyContent.getEnclosingWriter()
メソッドを使用します。どちらのメソッドでも、同じ親ライターが取得されます。
タグ ハンドラは評価済み本体のコンテンツを親スコープに書き出すこともあれば、その評価済み本体をさらに処理して他の何らかの出力を書き出すこともあります。本体の反復処理ごとに BodyContent
が既存の BodyContent
に追加されるので、SKIP_BODY
を返すよう決定した場合、反復処理された本体のコンテンツ全体だけを書き出します。そのようにしないと、後続の各反復処理のコンテンツが何度も出力に現れることになります。
pageContext
内の out
ライターが親の JspWriter
に復元されます。このオブジェクトは実際にはスタックであり、pushBody()
メソッドと popBody()
メソッドを使用して pageContext
上の JSP エンジンによって処理されます。ただし、タグ ハンドラの中でこれらのメソッドを使用してこのスタックを処理しようとしてはいけません。
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 でダウンロードできます)。
javax.servlet.jsp.tagext.TryCatchFinally
インタフェースの doCatch()
および doFinally()
メソッドを実装すると、タグ内から送出される例外を捕捉できます。詳細については、このインタフェースの J2EE Javadoc を参照してください (Sun Microsystems の Javadoc は、http://java.sun.com/products/jsp/download.html でダウンロードできます)。
カスタム タグでは、JSP ページから指定できる属性を何個でも定義できます。これらの属性は、タグ ハンドラに情報を渡してその動作をカスタマイズするために使用できます。
各属性名は、TLD の中で <attribute>
要素を使用して宣言します。この要素は、属性の名前とその他の属性プロパティを宣言します。
JavaBean 規約と同じように、タグ ハンドラは属性名に基づいてセッター メソッドとゲッター メソッドを実装しなければなりません。たとえば、foo
という属性を宣言する場合、タグ ハンドラは以下のパブリック メソッドを定義しなければなりません。
public void setFoo(String f);
public String getFoo();
属性名の先頭の文字は、プレフィックスの set または get の後では大文字になることに注意してください。
JSP エンジンは、タグ ハンドラが初期化されてから doStartTag()
メソッドが呼び出されるまでの間に、各属性のセッター メソッドを呼び出します。一般に、タグ ハンドラの他のメソッドからアクセスできるメンバー変数に属性値を格納するには、セッター メソッドを実装しなければなりません。
タグ ハンドラは、さまざまなスコープで JSP ページから参照できる新しいスクリプト変数を使用できます。スクリプト変数は、それらの定義済みスコープの内部で暗黙的なオブジェクトのように使用できます。
javax.servlet.jsp.tagext.TagExtraInfo
を拡張する Java クラスを識別するための新しいスクリプト変数は、<tei-class>
要素を使用して定義します。以下に例を示します。
<tei-class>weblogic.taglib.session.ListTagExtraInfo</tei-class>
次に、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
型の username
と java.util.Date
型の dob
という 2 つのスクリプト変数が定義されています。
VariableInfo()
のコンストラクタは、以下の 4 つの引数を取ります。
String
String
。java.lang
パッケージ以外のパッケージに含まれる型の完全パッケージ名を指定します。 boolean
。タグ ハンドラが Java 以外の言語で書かれている場合を除き、この変数は「true」に設定します。 int
。以下に示す VariableInfo
に定義されている静的フィールドを使用します。 タグ ハンドラは、ページのコンテキストを介してスクリプト変数の値を初期化しなければなりません。たとえば、上で定義したスクリプト変数の値を初期化するには、doStartTag()
メソッドの中で以下の Java ソースを使用します。
pageContext.setAttribute("name", nameStr);
pageContext.setAttribute("dob", bday);
ここで、最初のパラメータはスクリプト変数の名前を指定し、2 番目のパラメータは代入される値を示します。なお、ここでは Java 変数の nameStr
は String
型で、bday
は java.util.Date
型です。
また、TagExtraInfo
クラスを使用して作成された変数にアクセスするには、useBean
を使用して作成された JavaBean にアクセスするときと同じようにそれを参照します。
タグの属性から、新しいスクリプト変数の名前を定義できます。このように定義することで、1 つのスクリプト変数を定義するタグの複数のインスタンスを同じスコープで使用しつつ、タグのスクリプト変数名の衝突を避けることができます。TagExtraInfo
を拡張するクラスからこれを実行するには、getVariableInfo()
メソッドに渡される TagData
からスクリプト変数の名前を取得しなければなりません。
TagData
からは、getAttributeString()
メソッドを使用して、スクリプト変数の名前を指定する属性の値を検索できます。さらに、id
属性の値を返す getId()
メソッドも存在します。これは、JSP タグからもたらされる新しい暗黙的オブジェクトに名前を付けるのによく使用されます。
タグ ライブラリ記述子の変数を定義できます。詳細については、タグ ライブラリ記述子の作成手順の 手順 7. (7. スクリプト変数を定義します (省略可能)。) を参照してください。
ネストされているタグが、その親タグに定義されているプロパティを暗黙的に使用するよう設計できます。たとえば、コード例の「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 クラスです。これを使用すると JSP ページの XML 表示の検証を実行できます。バリデータ クラス上の validate(String, String, PageData)
は、変換時 (JSP がサーブレットに変換される時) に JSP コンパイラによって呼び出され、ページが検証された場合には null
文字列を、検証が失敗した場合にはエラー情報を含む文字列を返します。
タグ ライブラリ バリデータを実装するには、次の手順に従います。
<validator>
<validator-class>
myapp.tools.MyValidator
</validator-class>
</validator>
<validator>
<validator-class>
myapp.tools.MyValidator
</validator-class><init-param>
</validator>
<param-name>myInitParam</param-name>
<param-value>foo</param-value>
</init-param>
WEB-INF/classes
ディレクトリに、バリデータ クラスをパッケージ化します。タグ ライブラリ jar ファイルにクラスをパッケージ化することもできます。詳細については、「JSP タグ ライブラリの JAR ファイルとしてのパッケージ化」を参照してください。
![]() ![]() |
![]() |
![]() |