Inside of Teeda おおたに
Teeda? JSF実装部分 拡張部分 Ajax 1.1ベース。TCKは(まだ)通してない。 ViewHandlerをエントリポイントとして介入。 PRGパターン、HTMLテンプレート Ajax 実はTeedaに依存してない。
Core 思想 最初のアイデアはJSFのDI機能 負の面で言えば、他JSF実装がいまいちだった(当時) 実はOSSになる予定も無かった。
Core(2) 一通り実装 DIコンテナとの連携を最初から意識 UIComponent、Lifecycle&Phase、Renderer、StateManager、Validator/Converter、Tag、ValueBinding、Handlerなどなど DIコンテナとの連携を最初から意識 普通にVariableResolverでS2を呼ぶ
Core(3) Lifecycleは以下のPhaseから成る RestoreView:Viewの復元 ApplyRequestValue:requestからdecode ProcessValidation:Convert/Validate UpdateModelValue:Modelの更新 InvokeApplication:Model実行 RenderResponse:描画
Core(4) UIComponent Renderer 画面上に配置される各項目を抽象化したもの このツリーが構築される 実際に描画する。 JSFで最も毒素がつまったところ。
Core(5) ValueBinding 内部的にはJSP2.0のEL式 ぶっちゃけCommonsELじゃん。 Extensionで多用 #{aaa.bbb} -> ${aaa.bbb} #{クラス.プロパティ} #{クラス.メソッド名}(メソッドバインディング) ぶっちゃけCommonsELじゃん。 Extensionで多用
Core(6) そのほか StateManager Test 他JSF実装ではしこたまSessionに格納 Teedaでは、ComponentTreeは1つのみ ほとんどのコンポーネントで動的に変更が入るのはvalueとsubmittedValueくらい。だからいいじゃん。 Test JSFとしてのテスト環境は群を抜いて揃ってる Test重要
Extensionのコンセプト S2JSFより軽いHTMLテンプレート 規約重視で設定少ない POJO Page駆動 JavaEE勉強会のyuki_neko_nyanさんの「私がほしいPresentationFramework」には結構影響を受けてる。
Extensionばっさり 基本的なベースは、S2JSFの発展系 Id書いて、HTMLとPageをマッピング ドン引きではそんなことは説明しません サンプル見て。ソース嫁。おしまい。 その代わりにHowを書き殴りご紹介
Extensionばっさり(2) HtmlViewHandlerがエントリポイント restoreView createView renderView
HtmlViewHandler#restoreView restoreView(TagProcessorCache) Teedaで扱う抽象的なリソースの作成・復元 HtmlDesc XercesにXHTMLとして読ませ、HtmlNodeのツリー構築 PageDesc NamingConventionにviewIdをキーにfind /aaa/bbb.html -> aaa_bbbPage ActionDesc どれも更新時間をstoreして、毎回チェック HotDeployのため
HTMLのparseと分類 TeedaではXHTMLとしてparse Neko使わないで、Xercesのみで。 HtmlNodeに分類 DocumentNode DOCTYPEをあらわす要素 ElementNode 基本idがついている要素(カスタマイズ可能) JSFのUIComponentとして処理される TextNode Textとして出力される要素
HTMLのparseと分類(2) XercesのXNIレベルで文字実体参照のまま、ブラウザに任せている。 DocumentScannerでnormalizeさせない http://d.hatena.ne.jp/shot6/20060730
コンポーネントとのマッチング準備編 構築されたDesc系はこのようになる。 HtmlDescはNodeツリーを保持。 PageDescはClassから、各要素を抽出・集約 各DescにあるFileは、更新チェックのため。 HtmlDesc PageDesc Htmlファイル Pageのclass Pageファイル HtmlNodeツリー pageName
各Descを元に規約とマッチングしたものをJSFのコンポーネントとバインディングする。 規約によるコンポーネントとのマッチング 各Descを元に規約とマッチングしたものをJSFのコンポーネントとバインディングする。 AbstractElementProcessorFactory 各JSFコンポーネント毎に継承して作成 Org.seasar.teeda.extension.html.factory isMatch 規約とのマッチング customizeProperties 各コンポーネント用にプロパティをValueBinding式で独自にカスタマイズ。
こんな感じ 各JSFコンポーネント毎の FactoryがDIされる。 protected void assembleTagProcessor(ElementProcessor parentProcessor, ElementNode elementNode, PageDesc pageDesc, ActionDesc actionDesc) { for (int i = 0; i < factories.length; ++i) { ElementProcessorFactory factory = factories[i]; if (factory.isMatch(elementNode, pageDesc, actionDesc)) { ElementProcessor elementProcessor = factory.createProcessor( elementNode, pageDesc, actionDesc); parentProcessor.addElement(elementProcessor); if (!factory.isLeaf()) { assembleElementNodeChildren(elementProcessor, elementNode, pageDesc, actionDesc); } elementProcessor.endElement(); return; 各JSFコンポーネント毎の FactoryがDIされる。
InputTextFactory#isMatch public class InputTextFactory extends AbstractElementProcessorFactory { public boolean isMatch(ElementNode elementNode, PageDesc pageDesc, ActionDesc actionDesc) { if (!JsfConstants.INPUT_ELEM.equalsIgnoreCase(elementNode.getTagName())) { return false; } if (!JsfConstants.TEXT_VALUE.equalsIgnoreCase(elementNode .getProperty(JsfConstants.TYPE_ATTR))) { if (pageDesc == null) { return pageDesc.hasProperty(elementNode.getId()); Tagがinputで、typeはText、PageにプロパティがあればOK。
InputTextFactory#customizeProperties protected void customizeProperties(Map properties, ElementNode elementNode, PageDesc pageDesc, ActionDesc actionDesc) { super .customizeProperties(properties, elementNode, pageDesc, actionDesc); if (pageDesc != null) { properties.put(JsfConstants.VALUE_ATTR, getBindingExpression( pageDesc.getPageName(), elementNode.getId())); } #{addPage.arg1}のようにEL式を生成して、 value属性に突っ込まれる。他もほぼすべてこれと同じ。 ここで初めてJSFのコンポーネントとマッピングされる。
HtmlViewHandler#createView JSPをエミュレートして、動かす 基本的にはS2JSFと同じやり方 ぶっちゃけコンポーネントツリーさえ出来れば良いので、その該当部分であるfindComponentだけ呼んで、構成。
こんな感じ protected void composeComponentTree(FacesContext context, PageContext pageContext, UIComponentTag tag, UIComponentTag parentTag) throws JspException { if (parentTag != null) { tag.setParent(parentTag); } tag.setPageContext(pageContext); Map ignoredProps = setupProperties(tag); tag.setupFacesContext(); UIComponent component = tag.findComponent(context); component.getAttributes().putAll(ignoredProps); tag.pushUIComponentTag(); try { composeComponentTreeChildren(context, pageContext, tag); } finally { tag.popUIComponentTag();
HtmlViewHandler#renderView S2JSFと同じ
PRG POST-REDIRECT-GETの組み合わせによる画面遷移を実現 TSSの記事読んでください。 URLが正しく出るのは、気持ち良い。
PRG、Teedaでの実装 HtmlNavigationHandler.handleNavigationでredirect Pageクラスのスコープはrequest PRGでは当然requestスコープのインスタンスを2つ使うため、インスタンス間でデータのLOSTが無いようにしないといけない。
PRGパターンイメージ(こぴぺ View(Client) Teeda(Server) POST REDIRECT ブラウザが反応 GET addInput.html addResult.html POST GET REDIRECT View(Client) Teeda(Server) AddInputPage AddResultPage 状態をsave 状態をrestore ブラウザが反応
PRG実装雑多ネタ編 HTTPのステータスコードが302の場合、ほとんどのブラウザはconfirmメッセージを出さない。 実は厳密には仕様ではそうじゃない。 PRGを考えた人は確信犯的にこれを狙ってる。 だからconfirmメッセージが出ない。
SessionPagePersistence Pageのプロパティのsave/restore 基本同一のプロパティ名があればコピー 画面から入力されてきそうな型しかサポートしてない。 余分なプロパティを渡さないため LRU形式でviewIdに対して10個のみ管理 TakeOverアノテーションで細かく管理可能
TakeOver public class AddResultPage { private Integer arg1; private Integer result; public static final String jumpAddInput_TAKE_OVER = "type=never"; 後、省略。
設定いらず ほとんどは規約のおかげ Navigationの部分はそれなりにやってる 現在のViewIdとValueBinding結果(outcome)から行き先を類推 viewId=/view/aaa/bbb.html、outcome=ccc とすると、/view/aaa/ccc.htmlと類推。 viewId=/view/aaa/bbb.html、outcome=ddd_ccc とすると、/view/ddd/ccc.htmlと類推。
ま、そんなもんでげす。
Teeda再考 私がほしいPresentationFrameworkをベースに再考してみる。 ここからが実は一番やりたかったこと
Architecture 普通にMVC ひたすらWrap(request/responseAPI、JSFのXxxとか) 当然使うことも当然出来る。 しかしJSF自体を隠蔽しきれてはいない。 Unobtrusiveだとは少しはいえる。
ConfigurationとOCP 新しいAction追加したときに何故かXMLをいじったりしてない? してない。そもそもConfigurationをほとんどXMLでは書かない。 規約ベースはやはり楽。
Rule and Conventions そのルール(規約)は明解か? 余計なことは言わず、必要なことだけちゃんと言ってる? 直感的? 多すぎてない? これらが正直ちょこっと改善の余地あり。規約が増えていったときの対策は必要。 でも規約は決めてしまうと変えずらい。 今後の方向性に影響。
Simplicity/Complexity do one thing very well? とは言えず、多方面に手を出しすぎてる JSF実装した時点でわかれよw>自分 正直自分のポリシーからは、ずれが出ている。 JSFとの協調 ベースのJSFの制約が徐々に増加。 コードベースの拡大につながる。 個人的には割と不安。良い傾向じゃない。
UserInterfaceとしてのFW 動かすまでの設定 開発/運用モードのDebugスクリーン Doltengのサポートつきで及第点 いまだHotDeployをゼロからは多分難しい 開発/運用モードのDebugスクリーン Clickにあるブルースクリーンのような機能は無い。ユーザーに易しいとはいえない。 ExceptionにJIRAとMLのアドレス埋め込むくらいからスタートしてもかも。
UserInterfaceとしてのFW(2) VisualConfiguration(設定の可視化、Deploy/Undeployも操作可能、履歴・状況把握機能など) HotDeploy/CoolDeployなどはようやく可視化 でも他にもやれる事はたくさんある。 Testability 今でもそれなりに高いが、それはUTの話。 IntegrationTestツールの提供は急務
Thanks ありがとうございましたm(_ _)m もう眠いです、限界ですZzzzz