ファイヤープロジェクト
カスタムタグの内容をタグハンドラで処理する
2004-06-06T15:30+09:00   matsu
今まではJSPコンテナが直接処理していたカスタムタグの内容を,タグハンドラで取得,処理してみた.
タグの内容の評価を単にJSPコンテナに任せるだけの方法は既に確認した.次は,タグハンドラがタグの内容を取得,評価する方法を探ってみる. 本頁では以下のサンプルJSPで,タグの内容の大文字,小文字の変換を行う.
カスタムタグ
<sample:handle-body>
は必須属性upperOrLowerを持つ.値はupper,lowerのいずれかである(大文字,小文字の区別はない).値がupperならタグハンドラによってタグの内容が大文字に変換される.lowerなら逆に小文字に変換される.そのタグハンドラを以下に示す.
タグの内容をタグハンドラで評価するには,BodyTagインタフェースを実装している必要がある,今回のタグハンドラはBodyTagインタフェースを実装したBodyTagSupportを継承している.
サンプルのタグハンドラのdoStartTagメソッドでは
BodyTag.EVAL_BODY_BUFFERED
を返している.これによって,JSPコンテナはタグハンドラがタグの内容を評価することを知り,そのために必要な以下の処理を行う.
JSPWriter変更
PageContextインスタンス(タグハンドラ内ではpageContextに格納されている)にbodyContentをpushBodyする.タグハンドラで
pageContext.getOut()
とすると,最後にpushされたJSPWriterが返る.で,bodyContentは出力ストリームを持たないので,writeしてもブラウザに文字列は出力されない.EVAL_BODY_BUFFEREDのBUFFEREDという文字列から察しがつくかもしれないが,bodyContentにwriteすると,出力がバッファリングされ,後にgetStringすることで一気に取り出せる.
setBodyContent呼び出し
タグハンドラにタグの内容情報であるbodyContentを渡す.
doInitBody呼び出し
タグの内容を初期化するのに使用する.BodyTagSupportのそれは何もしない.必要に応じてオーバーライドする.
(タグの内容の評価)
JSPWriter変更
PageContectインスタンス(タグハンドラ内ではpageContextに格納されている)からpopBodyする.
サンプルのタグハンドラのdoInitBodyを見てみる.
...
    pageContext.getOut().write("doInitBody : out         = "+ pageContext.getOut() + "<br/>");
    pageContext.getOut().write("doInitBody : bodyContent = " + bodyContent + "<br/>");
...
といった処理をしている.先述のように,doInitBodyの段階では,
pageContext.getOut()
で返るJSPWriterと
bodyContent
に格納されているJSPWriter(※)が同じものである.そしてbodyContentは出力ストリームを持たないので,ブラウザに直接この文字が渡されることはない.次にdoEndTagを見てみる.まず
    if (bodyContent == null) {
	pageContext.getOut().write( "doEndTag : bodyContent is null.<br/>");
    }
JSPにカスタムタグが<.../>ではなく<...></...>と記述された場合,setBodyContent(さらにdoInitBody)が呼ばれないらしい.ということで,nullチェックを行っている.あとは属性の値に応じて処理をする.
    else if (upperOrLower == UPPER) {
	pageContext.getOut().write( "doEndTag : \""
	+ bodyContent.getString().toUpperCase()
	+ "\"<br/>");
    }
    else if (upperOrLower == LOWER) {
	pageContext.getOut().write( "doEndTag : \""
	+ bodyContent.getString().toLowerCase()
	+ "\"<br/>");
    }
ここでbodyContentからgetStringしてデータを取り出している.これはタグの内容とdoInitBodyでの
pageContext.getOut().write
による出力である.このようにdoInitBodyではbodyContentをバッファに見立ててそこにwriteし,doEndTagで取り出して出力というのが最も基本的なパターンである.なお,doEndTag時点では,
pageContext.getOut()
で返るJSPWriterと
bodyContent
に格納されているJSPWriterは異なる.すなわち前者はブラウザへとつながるストリームを持っている「いつもの」であり,writeすると出力がブラウザにとぶ. JSPからの出力を確認してみる.
まずdoEndTagによる出力は""で囲っていることに注意.doInitBodyでのwriteでは直接ブラウザへの出力ストリームには流れず,doEndTagで一旦取り出してからwriteすることで,ブラウザまで到達していることが分かる. また,doStartTagでのoutのOIDとdoInitBodyでのoutのOIDが異なり,doInitBody内でのoutとbodyContentのOIDが一致することにも注意. さらにdoInitBodyによる"doInitBody : body ="という出力.これからdoInitBodyではbodyContentにタグの内容はまだ格納されていないことが分かる.故にdoInitBody内のif分の処理の結果(bodyIsEmptyの値の操作)はうまくいっていない.
※ public abstract class BodyContent extends JspWriter
念のために今回のサンプルのtldファイルを以下に示す.
今までのサンプルと同じtaglibに追加した.最後の要素tagが今回のサンプル用のものである.今回はタグの内容はタグハンドラで操作するので,
  <body-content>tagdependent</body-content>
とした.さらに属性upperOrLowerを必須属性にしてみた.
  <attribute>
    <name>upperOrLower</name>
    <required>true</required>
  </attribute>
matsu(C)
Since 2002
Mail to matsu