S2JSFでWebParts その5
複数のInitActionが呼び出せない件について、一歩前進。
複数のHTMLファイルを1画面に表示させたいので
<span m:inject="s:insert" m:src="hoge.html"/>
こんな風にしてHTMLファイルを呼び出す予定だけど、
呼び出される側のHTML(hoge.html)では、initActionが実行されなくて困っている。
と言うわけで、InitAction周辺のソースコードを読んでみて、下のように理解した。
- InitActionのinvokeは、org.seasar.jsf.runtime.ViewRendererImpl#executeInitActionで実行される。
- このexecuteActionは、ViewRendererImpl#renderViewから呼ばれている。
- ViewRendererImpl#renderViewは、org.seasar.jsf.lifecycle.LifeCylcleImplから呼ばれる。
→ つまり、InitActionの呼び出し元であるrenderViewは、一回のリクエストについて、原則一度しか呼ばれない。
一方、s:insert辺りはどうかと言うと、
- s:insertタグを解釈する実体は、org.seasar.jsf.processor.InsertProcessor#processInclude
- processIncludeでは特にInitActionの呼び出しを行なっていない。
→ ここでInitActionを強引に実行させることができるハズ。
ということで、ViewRendererImplを参考にしながら
InsertProcessorに手を入れてみたら、insertされる側のinitActionが実行された。
変更箇所のソースはこんな感じ。
protected void processInclude(JsfContext jsfContext, Tag parentTag, String src) throws JspException { S2Container container = SingletonS2ContainerFactory.getContainer(); ViewTemplateFactory factory = (ViewTemplateFactory) container .getComponent(ViewTemplateFactory.class); ViewTemplate template = factory.getViewTemplate(src); ViewProcessor viewProcessor = (ViewProcessor) template .getRootTagProcessor(); InsertProcessor insertProcessor = viewProcessor .getInsertProcessor(null); // -- 変更 BEGIN String initAction = viewProcessor.getInitAction(); FacesContext context = FacesContext.getCurrentInstance(); if (initAction != null) { executeInitAction(context, initAction); } // -- 変更 END insertProcessor.process(jsfContext, parentTag); } // -- メソッド追加 BEGIN protected void executeInitAction(FacesContext context, String initAction) { Application app = context.getApplication(); MethodBinding mb = app.createMethodBinding(initAction, null); InvokeUtil.invoke(mb, context); } // -- メソッド追加 END
ViewRendererImplでは、ErrorPageManager(エラー発生時に特定のページを表示させる)の
処理が入ってたけど、実験なのでその辺りは割愛。
とりあえず、複数のInitActionを呼ぶための方法が一つはできた。
ところで、まだ未追跡なんだけど、
initActionがnull以外をreturnした場合には、renderViewメソッドが繰り返して呼ばれるみたい。
遷移する場合には、次の画面をレンダリングするって事だと思うけど。
とすると、
1つめのPartsのInitAction → Interceptorで戻り値を書き換え → 2つめのPartに遷移
→ 2つめのPartsのInitAction → Interceptorで戻り値を書き換え → 3つめのPartsに遷移・・・
なんて風にうまくやれば、InitActionを連鎖的に呼び出せるかも知れない。
こっちの方がエレガントなので、また後から調べてみよう。