フォトアルバム

2009年7月

      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

なかのひと

アンケート

  • Do you Like?
    アンケート
    どのColdfusion用フレームワークが好き?
    ModelGlue:Unity
    ModelGLue
    Mach-II
    FuseBox
    LiteWire
    OnTap
    ColdBox
    OnAir
    cfWheels
    CFRails

    [PR]アンログ.jp 自動車保険

373news.com

想ひ出

  • Dvc00050
    携帯で撮った写真をアルバムにしています。

サムネイル

  • CF-OOP









  • ganymean.org









  • シナプス

Google Analytics

ModelGlue

Answer from Railo developper!

ModelGlue3(Gesture)がRailoでエラーメッセージを吐く事象について、ModelGlue-MLとRailo-MLに各々投げました。結果、以下のようになりましたー。

1 Create Java Object エラー
  Railoのバグ:ネクストリリースでバグフィックス予定。

2 include .cfm インクルードエラー
  Railoの仕様(ポリシー)
  以下のステートメントは、認めない。

<cfset this = variablues />

   以下のステートメントで代用。

<cfloop collection="#variables#" item="key">
    <cfset this[key]=variables[key] />
</cfloop>

  パッチファイルをModelGlue-MLに投げました・・・


Do not work the gesture helpers on Railo!

Railo3.0(Ver3.0.0.005 for Windows)で、Model-Glue 3.0(Gesture)のサンプルアプリケーションを動かしてみた。
helpers機能を利用するサンプリアプリケーションが動作しない。
問題は2つあるようだ。

1.MathLib.cfm
 インクルードエラー(Include error)

 MathLib.cfmを直接コールしてみると、次のようなエラーが返される。RailoのMLに問い掛け中・・・

Railo 3.0.0.005 Error (Java.lang.verifyerror)
Message (class: modelglue/helpers/cflib/mathlib$cfm, method: udfCall8 signature: (Lrailo/runtime/PageContext;Lrailo/runtime/type/UDF;I)Ljava/lang/Object;) Illegal target of jump or branch
Java Stacktrace
(class: modelglue/helpers/cflib/mathlib$cfm, method: udfCall8 signature: (Lrailo/runtime/PageContext;Lrailo/runtime/type/UDF;I)Ljava/lang/Object;) Illegal target of jump or branch
at java.lang.Class.getDeclaredConstructors0(Native Method):-2
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source):-1
at java.lang.Class.getConstructor0(Unknown Source):-1
at java.lang.Class.newInstance0(Unknown Source):-1
at java.lang.Class.newInstance(Unknown Source):-1
at railo.runtime.PageSourceImpl.a(Unknown Source):-1
at railo.runtime.PageSourceImpl.a(Unknown Source):-1
at railo.runtime.PageSourceImpl.loadPage(Unknown Source):-1
at railo.runtime.PageContextImpl.include(Unknown Source):-1
at railo.runtime.listener.ClassicAppListener._onRequest(Unknown Source):-1
at railo.runtime.listener.MixedAppListener.onRequest(Unknown Source):-1
at railo.runtime.PageContextImpl.execute(Unknown Source):-1
at railo.runtime.engine.CFMLEngineImpl.serviceCFML(Unknown Source):-1
at railo.loader.servlet.CFMLServlet.service(CFMLServlet.java:32):32
at javax.servlet.http.HttpServlet.service(HttpServlet.java:91):91
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:103):103
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:175):175
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:240):240
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:263):263
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:481):481
at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:685):685
at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:607):607
at java.lang.Thread.run(Unknown Source):-1

2.IncludeHelperShell.cfc
  インクルードCFMのCFC関数化ができていない。
 Coldfusionでは動作する以下のステートメントがRailo3.0では無視される・・・
 <cfset this = variables />

 結果として、該当ファンクション無しエラーが発生。
 RailoでのDUMP結果は以下のとおり。Railo固有のバグか・・・

Component (ModelGlue.gesture.helper.Helpers)
Only the function and data member that are accesible from your location are displayed
Hint I act as a target for the helpers loaded into a Model-Glue application.
public
DateLib
Component (ModelGlue.gesture.helper.IncludeHelperShell)
Only the function and data member that are accesible from your location are displayed
Hint I am a shell CFC into which an include-based helper file is loaded.
public
INIT
init
Includes a .cfm's functions into this CFC.
Public Function init
arguments
label name required type default hint
TEMPLATE false string null
return type any

   

Model-Glue3.0の新機能9:Model-Glueリモーティング

Model-Glue3.0の新機能9は、Model-Glueリモーティングです。

Joe曰く、「HTMLだけのWebアプリは終わりました。典型的なColdFusionアプリケーションは、HTMLおよびFlex(Flexベースのウィジェット)の両方を包含することになるでしょう。」とのことです。確かにそうですね。

★Flex / Flashのサポート
Gestureでは、HTMLのエントリーポイントとしてのindex.cfmはもちろん、FlexまたはFlashウィジェットのためのエントリポイントとしてのModelGlueGateway CFCも含みます。

★Flexアプリでのユーザリスト取得例
JSON(.XMLデータも同様):

<event-handler name=”user.list.page”
        <broadcasts>
        <message name=”needUserList” />
        </broadcasts>
        <views format=”HTML,HTMLPartial”>
        <include template=”dspUserList.cfm” name=”body” />
        </views>
        <views format=”JSON”>
        <include template=”dspDataAsJson.cfm” name=”body”>
                <value name=”data” name=”userQuery” />
        </include>
        </views>
        <results format=”HTML”>
        <result do=”view.template” />
        </results>
</event-handler>

. MXML:

<mx:RemoteObject id=”modelGlueGateway”destination=”ColdFusion”source=”ModelGlueGateway” />

. AS3:

var event:ModelGlueEvent =new ModelGlueEvent(“user.list”, [“userQuery”]);
modelGlueGateway.runEvent(event);

現時点では未実装ですが、HTML、Flex、Flashのエンドポイントに対応できることは大変楽しみです。
Model-Glue:Gestureは、Model-Glue:Flexを統合することになるのでしょうか?

Model-Glue3.0の新機能8:マルチ出力フォーマット対応

Model-Glue3.0の8番目の新機能は、マルチ出力フォーマット対応機能です。
なお、この機能は現時点で未実装ですので、注意してください。

Webアプリケーション用MVCフレームワークは、もはやWebページだけでなく、さまざまな出力フォーマットに対応できる必要があります:

  • HTML形式
  • 部分HTML形式
  • XML形式
  • JSON形式

今までのModel-Glue開発では、悪評の高い重複作業が発生していました。
つまり、N個のフォーマット形式に対応するため、N個のイベントハンドラーを必要とします。

HTMLフォーマット:

<event-handler name=”user.list.page”>
        <broadcasts>
        <message name=”needUserList” />
         </broadcasts>
        <views>
        <include template=”dspUserList.cfm” name=”body” />
        </views>
        <results>
        <result do=”view.template” />
        </results>
</event-handler>

断片HTMLフォーマット(<div>置換):

<event-handler name=”user.list.pagepartial”>
        <broadcasts>
        <message name=”needUserList” />
        </broadcasts>
        <views>
        <include template=”dspUserList.cfm” name=”body” />
        </views>
</event-handler>

XMLフォーマット:

<event-handler name=”user.list.xml”>
        <broadcasts>
        <message name=”needUserList” />
        </broadcasts>
        <views>
        <include template=”dspDataAsXML.cfm” name=”body”>
                    <value name=”data” name=”userQuery” />
        </include>
        </views>
</event-handler>

JSONフォーマット:

<event-handler name=”user.list.json”>
        <broadcasts>
        <message name=”needUserList” />
        </broadcasts>
        <views>
        <include template=”dspDataAsJson.cfm” name=”body”>
                <value name=”data” name=”userQuery” />
            </include>
        </views>
</event-handler>

Gestureでは、<broadcasts>、<views>、<results>ブロックは、特定のフォーマットだけに作用するように設定できます。
フォーマット名は、URLまたはFormのHTTP要求で指定される要求メッセージの書式設定方法(デフォルト:"requestFormat")です。
これにより、Gestureでは4つのフォーマットを1つのイベントハンドラーで定義可能となります:

<event-handler name=”user.list.page”>
    <broadcasts>
        <message name=”needUserList” />
        </broadcasts>
        <views format=”HTML,HTMLPartial”>
            <include template=”dspUserList.cfm” name=”body” />
        </views>
        <views format=”JSON”>
        <include template=”dspDataAsJson.cfm” name=”body”>
                <value name=”data” name=”userQuery” />
        </include>
        </views>
        <results format=”HTML”>
        <result do=”view.template” />
        </results>
</event-handler>

Model-Glue3.0の新機能7:コンテンツキャッシュ

Model-Glue3.0の7番目の新機能は、コンテンツキャッシュ機能です。

ポイントは、以下の3点のようです。

  1. 大部分のMVCフレームワークは、何らかのキャッシングメカニズムを提供しています。
  2. Model-Glue3.0は、オブジェクトキャッシュを提供しません。サービス層の仕事だと思うからです
  3. Model-Glue3.0は、コンテンツキャッシュを"dead-simple"に提供します。

★キャッシュキーとタイムアウト
以下のコードは、アプリケーションスコープにおいて、コンテンツ内にhomepageというキーがあるものをキャッシュします。タイムアウト時間は、300秒です。

<event-handler name=”page.home” cache=”application” cacheKey=”homepage” timeout=”300”/>

★キャッシュキー・バリュー(Cachekeyvalues)
.イベントキーからダイナミックにキャッシュを生成するには、CacheKeyValues を使用します。

<event-handler name=”user.profile” cacheKeyValues=”sessionId”/>

<event-handler name=”product.details” cacheKeyValues=”productId”/>

★キャッシュの解除方法は?
.コントローラー内のリスナー関数で、指定イベントのキャッシュキーを無効にできます:

<cfset beans.cacheAdapter.purge(“page.home”) />

続きを読む "Model-Glue3.0の新機能7:コンテンツキャッシュ" »

Model-Glueの新機能6:Beanインジェクション

Model-Glue3.0の6番目の新機能は、Beanインジェクション機能です。

一言でいうと、Autowiringがより便利になったよ!ってことです。

Model-Glue2.0では、コントローラ内に"ビーンA"のsetter関数を定義することによって、コントローラーが"ビーンB"をビーンAに自動的にAutowiringします。

Model-Glue3.0では、Beanインジェクション機能という名称に進化し、コントローラ内のsetter関数定義が一切不要になりました。

どういうことかと言うと、"Beans"スコープをビーンCFCに定義するだけで、コントローラーが直接Autowiringしてくれるというものです。便利!

<cfcomponent beans=”someDAO” />

また、 コントローラー内では、以下のように使い方もできます。

  <cfset beans.SomeDAO.save(SomeThing) />


Model-Glue3.0の新機能5:ヘルパー

Model-Glue3.0の5番目の新機能は、ヘルパー機能です。

以前のModel-Glueで使用してきたUDFはどうなるのでしょうか?
. 以前のModel-Glueでは、UDFの使用は、ちょっと不便でした・・・
. view内でUDFライブラリーをインクルード可能であったが、そのための厄介な設定が必要でした。
. またコントローラー層で利用できませんでした。

★簡単なヘルパー:Include-Style
. CFLib.orgのdateLib.cfmを"/helpers"フォルダに配置すると、そのすべての関数がコントローラーと
  ビューの内部で"helpers"スコープ関数として利用できます。

<cfoutput>#helpers.dateLib.daysTilXmas()#</cfoutput>

★簡単なヘルパー: CFC-Style
. ヘルパー関数として動作するCFCを"/helpers"フォルダに配置すると、
  includeのようにそのすべての関数が"helpers"スコープにコピーされます。

Model-Glue3.0の新機能4:SES URLとURLマネージャー

Model-Glue3.0の4番目の新機能は、SES URLとURLマネージャーです。

. SES URLをサポートしました。
  index.cfm/eventname/key1/value1/key2/value2 形式でのSES URLでアクセス可能です。

. オーバーホールされたEventContext常駐アーキテクチャーのおかげで、URLManagerを通してSES URLをプラグイン的に実装することができました。

. SES URLセーフであるViewをビルドするために、イベントコンテキスト機能を使用します:

  <a href=”#event.linkTo(“user.profile”, “userId,profileId”) />

このように、Viewファイルに記述すると、リンクURLは、次のようにSES形式/非SES形式の両方でアクセス可能となります。

  • 非SES URL形式:index.cfm?userId=2&profileId=42
  • SES URL形式 :index.cfm/userId/2/profileId/42

Model-Glue3.0の新機能3:Application.cfcとの統合

Model-Glue3.0の3番目の新機能は、Application.cfcとの統合です。

. アプリケーション開始、セッション開始もしくはセッション終了を知りたい場合、
. Model-Glue3では、メッセージリスナーに次のように定義するだけです:

<message-listener message=”onApplicationStart” .../>
<message-listener message=”onSessionStart” .../>
<message-listener message=”onSessionEnd” .../>

Model-Glue3.0の新機能2:イベントタイプ

Model-Glue3.0の2番目の新機能は、イベントタイプ(Event Type)です。

この機能は、ModelGlue.xmlファイルの<Event-handler>タグ内でサイト横断的なビューテンプレートを使用すると、<results>タグを反復して記述する必要があります。

<event-handler name="do.this">
    <results>
        <result do="view.template" />
    </results>
</event-handler>

Model-Glue3.0では、イベントハンドラーのサブクラスを定義することによって、イベント完了後に継続して実施するイベントをイベントタイプの引数として与えられるようになっています。つまり、

<Event-handler name="do.this" type="events.templatedEvent" />

"view.template"を実行する<results>タグだけを定義したイベント"events.templatedEvent"をtype属性で与えると、"do.this"の実行後に、"events.templatedEvent"が実行されるという仕掛けです。

定義するイベントのサブクラスは、<results>タグの他に、<broardcasts>タグや<views>タグを含めることができます。

Model-Glue3.0の新機能1:イベント自動生成

Model-Glue3.0の新機能1は、Event eneration(イベントの自動生成)です。

一言でいうと、Model-Glue.xmlのイベントハンドラーを逐一定義せずに、URLにイベントを定義していくと、自動的にイベントが作成され、対応するコントローラー(CFC)、ビューファイル(CFM)、イベント定義&リスナー定義ファイル(ModelGlue.xml)を作成してくれるという優れものです。
この機能は、開発モード(deveropment=true)のみで提供されます。
ColdBoxで先行提供された機能ですが、私もまだ試していないので、あとから実施に試してみます(笑。

以下のYouTubeは、Joe RinehartによるEvent Genarationのデモビデオです。
雰囲気をつかむのには、いいかもしれません。

YouTube: Model-Glue 3 (

続きを読む "Model-Glue3.0の新機能1:イベント自動生成" »

Model-Glue3(Gesture)αリリース!

先週末は、久しぶりにCF-OOP関連のサイトを渡り歩いた。
理由は、Flex3やAIR(APPLO)がリリースされて以降、ColdFusionの開発環境に大きな刺激が加わり、Model-Glue:Unityでは限界かなあと思い始めていたからであった。

そういう意味では、ColdBox が一番開発ニーズを先取りしているような気がしたのだが、Model-Glueが先月3.0(コードネーム:Gesture)をαリリースしていたので、こちらを先にチェックしてみることにした。

Model-Glue3(Gesture)の新機能は、SVN内の開発ロードショウ.PDFを抜粋すると、以下のとおりです。
      ■Model-Glue3.0の新機能
・新機能1:イベント自動生成(開発モード)
・新機能2:イベントタイプ
・新機能3:Application.cfcとの統合
・新機能4:SES URLとURLマネージャー
・新機能5:ヘルパー
・新機能6:Beanインジェクション(Autowiring)
・新機能7:コンテンツキャッシュ
・新機能8:マルチ出力対応 ※未実装
・新機能9:Model-Glueリモーティング ※未実装

ColdBoxに先を越された分、しっかりと原点に返っているような気がします。
次回以降、意訳したものを紹介していこうと思います。



Model-Glue:UnityにおけるAutowiringのミステリー

久しぶりにブログを書く気になりました。
サボッていた自分にムチ打って、継続は力なりを実践しようと思います。

今日は、Model-Glue:UnityにおけるAutowiringについて、プレゼンテーション資料を作成したので、Googleドキュメントを使って公開してみようと思います。

続きを読む "Model-Glue:UnityにおけるAutowiringのミステリー" »

Ajax Scaffolds in ModelGlue

Ajax・・・世の中全盛ですね。
Joe Rinehartが、ModelGlue:UnityでAjaxベースのScaffoldsを行う方法を彼のブログで紹介しています。

Video: Ajax Scaffolds in Model-Glue

彼のビデオをadamが彼のブログで要約しています。
ご参考まで!

CFOpenID

OpenIDって、Coldfusionの自分サイトで使ってます?
日本における代表的OpenID認証サイトであるopenid.ne.jpでは以下のようにOpenIDが紹介されています。

  • OpenIDとは、webサイトのURL 形式で構成されたユーザーの身元確認をするためのIDです。
  • 誰でもインターネット上で自分の情報を作成・管理することができます。
  • 発行されるOpenIDはウェブ構築のまさに核心部分と呼べるURL形式で構成されているため、スパムメールや不正アクセス等の心配がなく、安全にログインすることができます。
  • OpenIDとは、webサイトのURL 形式で構成されたユーザーの身元確認をするためのIDです。

OpenID認証サーバ用のプロジェクトとして、RIAForgeでOpenID認証フレームワークが立ち上がっています。このフレームワークを使って、OpenID認証サーバも立ち上げてみようと思います。

また、OpenIDに関して、Brian RinaldiのColdfusion  Open  Source  Update で2つの記事が紹介されていたので、ご参考に!

続きを読む "CFOpenID" »

cf.objective 2007 サマリ

Coldfusionファンには、生唾ものの情報です。

CF-OOPのまとめをしなきゃと思って、本家メンバーのRSSフィードをチェックしていたら、cf.objectiveのプレゼン概要を、Matt Woodwardが日々google Docs形式でアップしています。ご覧あれ!

 cf.objective 2007 - Jason Delmore KeynoteColdFusion Weekly Flickr Photos
 Mark Mandel - Intro to Transfer ORM
 Hal Helms - Object Modeling
Sean Corfield - AJAX in Scorpio
Adam Lehman - .NET and Exchange Integration with Scorpio 
 CFEclipse Project - Mark Drew
Adam Lehman - Scorpio Server Monitoring and Alerts
 Peter Farrell - Head First Mach-II
 Peter Farrell - What's New in Mach-II 1.5
Jason Delmore - 1337 Scorpio
Sean Corfield - Real World SOA With ColdSpring and Transfer
Ben Forta - Top Secret Scorpio
 Dave Ross - ColdSpring 101
 Maxim Porges - Maximizing Your CF/Flex Applications With Java

 


MG1.1からMG:Unityへのアップグレード(その1)

ModelGlue:UnityによるCFアプリケーション開発の慣らし運転として、ModelGlue1.1ベースで作成されたサンプルアプリケーションをModelGlue:Unityにアップグレードしてみます。

選定するサンプルアプリケーションは、以前の記事で紹介したBrian Kotekのmgbookstorereactor。DIにColdspringを、ORMにReactorを使用しているので、ModelGlue:Unityへの移行ポイントがつかみやすいと思います。

移行ポイントは、以下の3点になります。

  1. Coldspring.xmlによる依存性注入パラメータの集中管理
  2. ormAdaptorとormServiceによるORM選択(Reactor/Transfer)
  3. 各種コントローラからinit()メソッドの削除

続きを読む "MG1.1からMG:Unityへのアップグレード(その1)" »

CF-OOPのリソースリスト

昨日に続いて、CF-OOPに関する頭の体操をしています。
やはり、参考になるのは、Brian Rinaldi のディレクトリかなあーと思って、ググッてみると、
Objects and Frameworks - the Big Resource List
というタイトルで、CF-OOPマニアにはヨダレが垂れるような記事をわかりやすく整理してくれています。

これを読んで頭慣らしかなあー。

Model-Glue:Unity 最新プレゼンテーション2

4/1に人事異動でカスタマフロント部門の責任者に配置されました。
現場の状況をつぶさに眺めてみると、一人ひとりのスタッフは本当によくがんばっているなあーという印象です。
でも、じっくりとスタッフのワークフローを見ていると、忙しい、時間がない、手作業、記憶・勘頼りと言った状況で、チームリーダしっかり考える余裕もなく、ひたすらワークに専念しています。
彼ら一人ひとりの持っている能力を引き出すことを通じて、会社の業績を向上させるのが、私の仕事。
というわけで、スタッフを拘束している単純作業を開放するための業務支援用WebプログラムをModel-Glue:Unityで作ることにしました。

ひさしぶりのModel-Glue:Unityプログラミングなので、慣らし運転用のチュートリアル教材を再度整理してみることにしました。

まずは、Model-Glue:Unityの開発者Joe Rinehartのビデオチュートリアル
時間は9分弱。
とても早口ですが、Scaffoldingのアウトラインを掴むだけにいいかもしれません。

次に、Steve "Cutter" Bladesのビデオチュートリアル
時間は1時間余り。
これもScaffolding向けのプレゼンです。前述のプレゼンよりはゆったりしているので、時間をかけて確認したい方に向いているかもしれません。

最後に、本家Joeのビデオチュートリアル
時間は1時間程度。
Model-Glue:Unityの全体像を理解するのに良いと思います。

Model-Glue:Unityドキュメント意訳

Model-Glue:Unity公式ドキュメントの意訳をmediawikiで立ち上げました。

具体的なプログラミング方法やサンプルプログラムも随時アップしていく予定です。
ご質問や間違いなどがあれば、このブログの左サイドバーのメールフォームからご連絡ください。

どうぞよろしくお願いします。

ColdSpring in MG:Unity No.3

ColdSpringの公式ドキュメントのAutoWiringを意訳してみました。
前回紹介したpropertyチャイルドタグ/constructor-argチャイルドタグは、依存性の注入方法を規定していましたが、beanタグのautowire属性はColdSpringが注入先のCFCをどのようにして発見するかを規定していて、autowire属性が指定されていれば、セッターメソッドは不要であることが記述されています。
また、autowiringの設定には、"byName"および"byType"の2つがあるようです。

"autowire"とは、Bean定義用xmlファイルでお互いの依存性を定義せずに、ColdSpringのbeanFactoryが依存する相互のオブジェクトを自動的に結合する能力のことを指します。

ColdSpring beanFactoryの中でCFCsを定義すると、ColdSpringは各CFCのメタデータを点検して、他のCFCにpropertyかconstructor-argで指定するものがあるかどうかを探します。

autowiringはBeanFactory内で、デフォルトで'オフ'にされていますが、'オン'にセットすると(bean全体かbeanの要素毎にセットできます)、ColdSpringは自動的に、依存性の注入(と自動的にオブジェクト結合)を行います。

autowiringの設定には、"byName"および"byType"の2つがあります。

推測できると思いますが、"byName"は、beanのname属性つまりCFC内にsetSomeService(...)メソッドか"SomeService"をコンストラクタ引数に持つCFCとColdSpring.xmlでid="SomeService"がある<bean/>内のCFCを結合し、"SomeService"を該当するCFCにいつでも注入します。

"byType"は、ColdFusionコード内に"type"属性、つまり、セッターメソッドの引数(または、コンストラクタ引数に) type="type.of.SomeService"を使用することによって、ColdSpring.xmlにclass="type.ofSomeService"があるbeanがあれば、そのbeanを該当するCFCにいつでも注入します。

benaタグのエンティティ全体にautowiringをセットするには、default-autowire属性を使用してください:

<beans default-autowire="byName">
    <bean id="cfc1" class="..."/>
    <bean id="cfc2" class="..."/>
...
</beans>

各々のbean(default-autowire設定をオーバライドすることになります)にautowiringをセットするには、autowire属性を使用してください:

<beans>
    <bean id="cfc1" class="..." autowire="byType"/>
    <bean id="cfc2" class="..."/>
    <bean id="cfc3" class="..." autowire="byName"/>
...
</beans>

ColdSpring in MG:Unity No.2

前回に引き続き、Nandoのブログを紹介してみます。
Nando曰く、ModelGlue:UnityでColdSpringについて学ぶべきことは、最低3つとのことです。

最初に専念したほうがよいことは、Bean FactoryリファレンスのうちのBeanタグ属性Beanチャイルドタグチャイルドタグのconstructor-argとpropertyの3セクションです。

これらを理解すると、ModelGlueでColdSpingを使いこなすことができると思います。

なお、個人的には、Bean FactoryリファレンスAutoWiringDeveloping w/ColdSpringService Layers and ColdSpringも一読したほうがよいと思います。

beanのチャイルドタグであるpropertyタグとconstructor-argタグについて、Nandoは次のように解説しています。

1.propertyタグ

constructor-argと全く同様です。しかしながら、この場合、ColdSpringはname属性で特定されるセッターメソッドへの引数として何らかの単純変数かオブジェクトをBeanに渡します。

したがって、CFCには、propertyタグのname属性に合致するセッターメソッド名がなければなりません(例えば、propertyが"foo"なら、CFCはsetFoo()メソッドを必要とします)。

2.constructor-argタグ

constructor-argタグは、(CFCがinit()メソッドを通して)CFCが初期化されるときに、name属性で指定された引数を渡すことによって単純変数かオブジェクトへの参照をbeanに対して提供することを、Coldspringにもたらします。

以上の2つのチャイルドタグを使って、あるファクトリクラスの初期化の際にパラメータを注入する方法が、次のように紹介されています。

◆bean.xml
<!-- "samasati.model.appFactory"クラスを"appFactory"として定義 -->
<bean id="appFactory" class="samasati.model.AppFactory">
   <!-- appFactory.init()に対して、appConfigを引数として渡す -->
   <constructor-arg name="appConfig">
      <!-- AppConfigビーンを参照 -->
      <ref bean="AppConfig" />
   </constructor-arg>
</bean>

<!-- "ModelGlue.Bean.CommonBeans.SimpleConfig"クラスの"AppConfig"として定義 -->
<bean id="AppConfig" class="ModelGlue.Bean.CommonBeans.SimpleConfig">
   <!-- Bean"AppConfig"の引数の実体は、property"config" -->
   <property name="config">
      <map>
         <entry key="dsn"><value>samasati</value></entry>
         <entry key="imagePath"><value>images/</value></entry>
      </map>
   </property>
</bean>


◆someContoroller.cfc
<cffunction name="init" access="public" output="false">
   <cfargument name="appConfig" required="true">
   <!--- Instansiated by setAppConfig Method passed through arguments.appConfig --->
   <cfset setAppConfig(arguments.appConfig) />
</cffunction>

<!--- autowire setters and getters for bean id:AppConfig --->
<cffunction name="setAppConfig" access="public" returntype="void" output="false">
   <cfargument name="appConfig" required="true">
   <cfset variables.appConfig = arguments.appConfig />
</cffunction>
   
<cffunction name="getAppConfig" access="private" output="false">
   <cfreturn variables.appConfig />
</cffunction>
   
<!--- autowire setters and getters for bean id:AppFactory --->
<cffunction name="setAppFactory" access="public" returntype="void" output="false">
   <cfargument name="appFactory" required="true">
   <cfset variables.appFactory = arguments.appFactory />
</cffunction>

<cffunction name="getAppFactory" access="private" output="false">
   <cfreturn variables.appFactory />
</cffunction>

ColdSpring in MG:Unity

ModelGlue:Unityを使って本格的なアプリケーションを考えようと、過去の記事やModelGlue、ColdSpring、Reactorの公式サイトのドキュメントを眺めていました。

そんなところに、Sean CorfieldがNandoのブログを紹介しているのが目に留まりました。
彼は、ModelGlueやColdSpringのメーリングリストにおいて、NewBie的なアプローチから大きな貢献をしているので、彼の書く記事は私と同じ目線、つまり独学でColdFusionやオブジェクト指向(OO)を学んでいるため、非常に共感できるものがあります。

彼の記念すべき第一回目の記事は、The Mystery of AutoWiring in Model-Glue Unity
つまり、ModelGlue:UnityにおけるAutoWiringに関するものです。

AutoWiringは、ColdSpringの公式ドキュメントにおいて、以下のように定義されています。

"autowire"は、Bean定義用xmlファイルでお互いの依存性を定義せずに、ColdSpringのbeanFactoryが依存する相互のオブジェクトを自動的に結合する能力のことを指します。

このことをNandoも、最初のころはなんのこっちゃ全然わからんかったと言っています。

MGを学ぼうとする人々を困らせるように思えるものの1つは、autowiring機能です。

多くの人々が、ドキュメンテーションでまだそれほど明確に説明していないので、それが存在するのを知ってさえいないかもしれません。

autowiringを使いこなすには、ColdSpringを少しいじくる必要があります。

ColdSpringがColdFusionと異なった名称を使うので、最初は外国に行ったみたいな感覚になります。

ColdSpringでは、CFCをBean、structをmap、arrayをlist などと呼びます。

しかし、あなたがいったん使用される用語を翻訳して、少しそのやり方に慣れると、突然として、とても簡単に使用することができるようになります。

そして、Nando曰く、ModelGlue:UnityにおけるAutoWiringとは、次のようなことであると・・・

簡単に言うと、AutoWiringは、ColdSpringを使用してModelGlueのコントローラに記述されたCFCに初期化パラメータを注入する非常に便利な方法です。

そのことを、EmailServiceを例にとって、以下のように説明しています。

アプリケーション規模が大きくなると、おそらくModelGlueコントローラ内でサービスレイヤのCFCを初期化する必要が生じるでしょう。

そして、おそらくアプリケーションを論理的な単位に分割するため、複数のコントローラを使用し始めるでしょう。

そうなると、例えば、EmailService自身を初期化する代わりに、EmailServiceを必要とする各々のコントローラのinit()メソッドで、ColdSpringが作成するEmailServiceのインスタンスに初期化パラメータを注入する際に、AutoWiringを使えばいいのです。

うーん、こういう風に説明されると、とてもしっくりと頭に入ります。

以前の記事で紹介したように、第三世代のMVCフレームワーク、即ちModel層における単調なコードの繰り返し記述を回避するため、Modelをビジネスロジック、サービス、パーシスタントという複数レイヤに分割することを支援してくれるんだなーという実感です。

MG:Unity Beta2の強化内容

Joe Rinehartのブログで、ModelGlue:Unityのパブリックベータ2の強化内容が紹介されています。

1.ベータ2リリース時期
  8月下旬のようです。
2.GenericList Enhancements
 ・criteria引数に、URL変数を使用できるようになった。
 ・getewayメソッドを指定できるようになった。
3.Scaffold Enhancements
 ・
カラム名の表示規則をcamel-baseにした。
  firstname --> FirstName

MG2:Unity Action Packs

ちょっと古い記事(6/12)ですが、Joe Rinehartが"Model-Glue:Unity ActionPacks"を彼のブログで紹介していました。今後のために、意訳してみます。

私がModel-Glueに関して聞いた1つの批評は、既存のアプリケーションに「ぶら下がれる」機能モジュールを作成する簡単な方法が全くないということでした。

私は、フォーラムアプリケーションを書くのが楽しくないので、「これをModel-Glueアプリケーションに追加してくださいか?」とただただ言うだけです。

さて、Model-Glue:Unityには、まさしくこれを可能にする新しいタグがあります:
<modelglue>の子としての<include>タグです。しばらくその批評に耐えてきましたが、<include>タグが正常に動作して、Model-Glueフレームワークにとても素晴らしい機能が追加できたと思います。

この機能追加は、どんなModelGlue.xmlファイルも他のModel-Glue.xml形式のファイルになリ得るし、そして、"子"ファイルでは、それ自身の<controllers>と<event-handlers>を定義できることです。

さらに、"部品化"されたModel-Glue XMLファイルでは、Viewマッピングに使用する追加ディレクトリはもちろん、ColdSpringにロードする追加XMLファイルを宣言するための<setting>タグを使用できます。

例)
以下は、Wiki.xml用"部品"ファイルに、mgwikiに必要なすべてを宣言できることを意味します:

<modelglue>
    <config>
      <!-- Add the wiki /views dir to the viewmappings -->
      <setting name="viewMappings" setting="/mgwiki/views" />
    </config>
 
    <controller name="wikiController" type="mgwiki.WikiController">
      <message-listener message="wiki.page" function="getPage" />
      <!--- other listeners... --->
    </controller>
 
    <event-handlers>
      <event-handler name="wiki.displayPage">
        <broadcasts>
          <message name="wiki.page" />
        </broadcasts>
        <views>
          <include name="body" template="dspWikiPage.cfm" />
        </views>
        <results>
          <result do="view.template" />
        </results>
      </event-handler>
 
      <!--- More event handlers... --->
    </event-handlers>
 
</modelglue>

次に、Wiki機能を他のModel-Glueアプリケーションに加えたいなら、Wiki"部品"を含むように、ModelGlue.xmlファイルを以下のように変更すればいいのです:


<modelglue>
    <include template="/mgwiki/config/Wiki.xml" /> 
 
    <!--- Application stuff...--->
  </modelglue>

<include>の危険性

<include>を使用することに、全く危険がない訳ではありません:<include>タグが、既存のイベントハンドラーやコントローラーを上書きする可能性も有り得ます。"wiki"部品を親アプリケーション定義の前に置いたのはその理由に拠ります:-)。


"ActionPacks?"

Model-Glue:Unity(2.0)の正式リリースに向けて、"ActionPacks"と呼ぶ2、3のModel-Glue部品のリリースを計画しています。ひとつ目は、使いやすく、構成変更可能なe-mailサービスです。他に、ロールベース兼行レベルのセキュリティ対策、ユーザプロファイル管理及びユーザ管理用のインタフェースを提供する予定です。

これらの"ActionPacks"は、Model-Glueフレームワークに少しの変化も必要とせず、まさしくModel-Glue XML部品であるので、誰でも自由にModel-Glueコミュニティに貢献できます。もし誰かがその開発に興味を持ったなら、私は可能な範囲で手伝う
ことに満足するでしょう。そして、Action Packsの選定(多分フォーラムアプリがそうなるでしょうけど)のために、それをModel-Glueの開発に追加するでしょう。

MG2:Unity Customizing Scaffold .XSL Files

今回は、Scaffoldのテンプレートで使用される.XSLファイルのカスタマイズ方法について紹介します(原文タイトル:Customizing Scaffold .XSL Files)

■Scaffold.xslファイルをカスタマイズする。

scaffoldタグが生み出すView CFMLを変えることは、全く可能です。全ては、.XSLファイルを編集することから始まります。xslファイルの編集は、このガイドの範囲外です。しかし、全く難しいわけではありません。

.XSLファイルをカスタマイズするには、3つの方法があります。

□デフォルト.XSLファイルを直接編集する方法

/ModelGlue/unity/xslティレクトリを参照すると、アプリケーションにscaffoldを追加する際に生成されるためにCFMLを定義したいくつかの.XSLファイル(edit.xsl, list.xsl, view.xsl)を見出すでしょう。

全Model-Glueアプリケーションの振る舞いを変更するためには、直接これらのファイルを編集してください。

□新しく.XSLファイルを作成する

自分用の.XSLファイルを作成することによっても、全Model-Glueアプリケーションの振る舞いを変更できます。所与のscaffoldにカスタムXSLファイルを使用するように教えてあげるために、以下のことを行います。

1./ModelGlue/unity/config/Configuration.xmlを開きます。
2."eventHandlerFactory"ビーンを探します。
3.EventHandlerTypesのコンストラクタ引数を定義する<map>タグにある.xslファイルの場所を示すxslキーをカスタム.XSL用に変更します。
  以下、list.xslの例を抜粋します。

    <constructor-arg name="EventHandlerTypes">
       <map>
         <entry key="eventhandler">
           <map>
             <entry key="scaffold"><value>false</value></entry>
             <entry key="class"><value>ModelGlue.unity.eventhandler.EventHandler</value></entry>
             <entry key="views"><list /></entry>
           </map>
         </entry>
         <entry key="list">
           <map>
             <entry key="scaffold"><value>true</value></entry>
             <entry key="class"><value>ModelGlue.unity.eventhandler.scaffold.List</value></entry>
             <entry key="views">
               <list>
                 <map>
                   <entry key="name"><value>List</value></entry>
                   <entry key="xsl"><value>/ModelGlue/unity/xsl/list.xsl</value></entry>
                   <entry key="prefix"><value>dsp</value></entry>
                   <entry key="suffix"><value>List.cfm</value></entry>
                 </map>
               </list>
             </entry>
           </map>
         </entry>

全Model-Glueアプリケーションの振る舞いを変更するために、直接これらを編集します。

□アプリケーション固有の.XSLファイルを編集する方法

特定のModel-Glueアプリケーションで使用される.XSLファイルを変更するには、/ModelGlue/unity/config/Configuration.xml内のEventHandlerFactoryビーン全体を適用したいアプリケーションのColdspring.xmlにコピーします。

そして、"新しく.XSLファイルを作成する"内のインストラクションに従い、/ModelGlue/unity/config/Configuration.xmlファイルの代わりにColdspring.xmlファイル内EventHandlerFactoryセッティングを編集します。

MG2:Unity Using Broadcasts, Results and Views in Scaffolds

今回は、Scaffoldタグで、Broadcasts、Results、Viewsタグを使用することについてご紹介します。

■Scaffoldsで、Broadcats, Results及びViewを使用する

"Scaffoldを追加する"で見てきたように、単なるscaffoldタグは複数のイベントハンドラーを定義するだけです。Model-Glue XMLフォーマットを容易に学習するために、scaffoldタグはイベントハンドラーと同じ子タグ(broadcasts, views, and results)をサポートします。

scaffoldタグ配下に追加されたbroadcasts, views, もしくは resultsタグは、与えられたscaffoldが作成する全てのイベントハンドラーに適用されます。(broadcasts, views, 及び resultsの作成方法を学習するには、クイックスタートガイドを参照してください。)

このことによって、よりパワフルにScaffold機能を拡張できます。

たとえば、Model-Glue Application Templateから、所定のScaffoldから作成される全てのイベントハンドラーにサイト全般のテンプレートを使用するためには、単にresultタグを追加するだけです。

<scaffold object="Contact">
    <results>
        <result do="view.template" />
    </results>
</scaffold>

同一オブジェクトに対して、複数のscaffoldタグを作成し、scaffoldのTYPE属性で分割することによって、メッセージのブロードキャストを特定のscaffoldが生成するイベントハンドラーに適用することもできます。

誰でもcontacsを参照可能で、管理者だけがcontactを更新可能なアプリケーションがある場合、非認証アクセスからEdit、Commit及びDeleteイベントハンドラーを保護するため、ModelGlue.xml内に次のXML(セキュリティ機能と果たす"UserMustBeAdministrator"というメッセージをリスンし、イベントへの不正アクセスに対して"SecurityViolation"と呼ぶresult結果を追加する)を使用します。

<scaffold object="contact" type="list,view" />
    <scaffold object="contact" type="edit,commit,delete">
        <broadcasts>
            <message name="UserMustBeAdministrator" />
        </broadcasts>
        <results>
            <result name="SecurityViolation" do="SecurityViolation" redirect="true" />
        </results>
    </scaffold>

MG2:Unity Adding Specific Event Handlers

今回は、Scaffoldタグに特定のイベントハンドラーを追加する方法を紹介します。
(原文タイトル:Adding Specific Event Handlers)

■特定のイベントハンドラーを追加する。

デフォルトで、<scaffold>タグは、5つのイベントハンドラー:table.list, table.view, table.edit, table.commit, table.deleteを追加します。

しかしながら、デフォルトで追加されるこれらのイベントハンドラーの全てを必要としないともあるでしょう。自動的に生成されるscaffoldsのイベントリストを調整するために、ColdSpring.xml内のModelGlueコンフィグいーンのデフォルトScaffoldsプロパティの値リストを変更します。

<property name="defaultScaffolds"><value>list,view</value></property>

Edit, Commit及びDelete Scaffoldsは、まだ利用できますが、scaffoldsタグのTYPE属性を指定する必要があります(以下、参照)。

■TYPE属性を使用する

所与のscaffoldタグにTYPE属性を使用することによって、作成するイベントハンドラーのリストを指定できます。

例えば、誰でもcontacsを参照可能で、管理者だけがcontactを更新可能なアプリケーションがある場合、非認証アクセスからEdit、Commit及びDeleteイベントハンドラーを保護するため、ModelGlue.xml内に次のXML(セキュリティ機能と果たす"UserMustBeAdministrator"というメッセージをリスンし、イベントへの不正アクセスに対して"SecurityViolation"と呼ぶresult結果を追加する)を記述します。

<scaffold object="contact" type="list,view" />

<scaffold object="contact" type="edit,commit,delete">
    <broadcasts>
        <message name="UserMustBeAdministrator" />
    </broadcasts>
    <results>
        <result name="SecurityViolation" do="SecurityViolation" redirect="true" />
    </results>
</scaffold>

MG2:Unity How To Add A Scaffolds

今回は、Scaffoldsの追加方法を紹介します。(原文タイトル:How To Add A Scaffolds)

■Scaffoldsを追加する。

1.データベースにテーブルを追加します。
  現時点では、このテーブル(及びリレーションシップで使用するどのテーブルも)は、プライマリキーとして動作する1つのカラムだけを有しているものとします。

2.テーブルが、1対多や多対多の形態で他のテーブルと結合している場合、そのリレーションシップを<objects>、<hasMany>、<hasOne>及び関連するタグを使ってReactor.xmlファイルに追加します。

3.ModelGlue.xmlに以下のタグを追加します。

      <scaffold object="contact" />

そうすると、次のようなイベントハンドラーを作成します。

1.Contact.List -contactテーブルの全リストを表示
2.Contact.View -特定レコードを読み出し専用で表示
3.Contact.Edit -contactレコードの編集用フォームの提供
4.Contact.Commit -contactレコードのデータベースへの保存
5.Contact.Delete -所定のcontactレコードの削除

MG2:Unity How To Use Scaffolds

前回までModel-Glue:UnityのGDMを紹介してきましたが、今回からScaffoldsを紹介していきます。
(原文:How To Use Scaffolds)

■Scaffoldsの使用方法

・Scaffoldsは、データベースアクセス用基本ユーザインタフェースをとても簡単に作成できるツールです。

*Display a "master list" of records in a table
テーブルのマスターリストレコードの表示

*Display an editing form capable of editing both a record's data and its relations to other tables (one-to-many and many-to-many)
レコードデータと他のテーブルとのリレーションシップ(1対多、多対多)を編集可能な編集フォームの表示

*Display a read-only view of a record
レコードの読み出し専用ビューの表示

*Update a record's data
レコードデータを更新

*Delete a record
レコードの削除

Scaffoldsを使用し、Scaffoldsが生み出すコードの修正することを適切に学習することによって、データベース制御タスクの開発時間を大幅に削減できます。

MG2:Unity Using modelglue.GenericDelete

今日は、ジェネリック・データベース・メッセージ(GDM)のGenericDeleteについて、紹介します。(原文タイトル:Using modelglue.GenericDelete)

modelglue.GenericDelete

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルから特定のレコードを削除しようとします。

このmodelglue.genericListメッセージは、次の<argument>タグを使用することによって構成されます:

1.Object (必須) -レコードを削除したいテーブル名
2.Criteria (必須) -フィルタとして使用するviewstateプロパティリストです。ターゲットテーブル中のカラム名にマッチする名前の値リストが、クエリーの'WHERE'節で使用するフィルタとして使用されます。

例)基本的なGenericRead

Contactテーブルに基本的なGenericDeleteを実行するためには、次のように<event-handler>タグに<message>タグを追加します:

<message name="modelglue.GenericDelete">
    <argument name="object" value="Contact" />
    <argument name="contactId" value="Contact" />
</message>

イベントハンドラ名を"contact.delete"として、以下のURLでこのイベントハンドラーを呼び出すと、'ContractId'が'42'であるcontactテーブルの削除結果を得るでしょう。
index.cfm?event=contact.delete&contactId=42

MG2:Unity Using modelglue.GenericRead

今日は、ジェネリック・データベース・メッセージ(GDM)のGenericReadについて、紹介します。(原文タイトル:Using modelglue.GenericRead)

modelglue.GenericRead

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルから特定のレコードを読み出そうとします。

このmodelglue.genericListメッセージは、次の<argument>タグを使用することによって構成されます:

1.Object (必須) -レコードを読み出したいテーブル名
2.RecordName (任意) -レコードデータセットを格納するviewstate名
デフォルトは、Object&"Record"です。
3.Criteria (任意) -フィルタとして使用するviewstateプロパティリストです。ターゲットテーブル中のカラム名にマッチする名前の値リストが、クエリーの'WHERE'節で使用するフィルタとして使用されます。

例)基本的なGenericRead

Contactテーブルに基本的なGenericReadを実行するためには、次のように<event-handler>タグに<message>タグを追加します:

<message name="modelglue.GenericRead">
    <argument name="object" value="Contact" />
</message>

ビューで次のコードを実行することによって、クエリー結果を<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactRecord") />

注:Criteriaを全く指定していないので、新しく空のレコードを返します。

■Viewstate名をカスタマイズする

Contactテーブルに基本的なGenericReadを実行し、Viewstateに特定名をセットするために、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericRead">
    <argument name="object" value="Contact" />
    <argument name="recordName" value="myContact" />
</message>

ビューで次のコードを実行することによって、クエリー結果を<cfdump>できます:
<cfdump var="#viewstate.getValue("myContact") />

注:Criteriaを全く指定していないので、新しく空のレコードを返します。

■特定のレコードを読み出す

Contactテーブルに基本的なGenericReadを実行し、ViewstateのContactId値でフィルタリングするために、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericRead">
    <argument name="object" value="Contact" />
    <argument name="criteria" value="ContactId" />
</message>

イベントハンドラ名を"contact.read"として、以下のURLでこのイベントハンドラーを呼び出すと、'ContractId'が'42'であるcontactテーブルの読み出し結果を得るでしょう。
index.cfm?event=contact.read&contactId=42

MG2:Unity Using modelglue.GenericList

今日は、ジェネリック・データベース・メッセージ(GDM)のGenericListについて、紹介します。(原文タイトル:Using modelglue.GenericList)

modelglue.GenericList
このメッセージがブロードキャストされると、DataControllerは与えられたテーブルからレコードをリストアップしようとします。

このmodelglue.genericListメッセージは、次の<argument>タグを使用することによって構成されます:

1.Object (必須) -リストアップするテーブル名
2.QueryName (任意) -クエリー結果を格納するviewstate名
 デフォルトは、Object&"Query"です。
3.Criteria (任意) -フィルタとして使用するviewstateリストです。ターゲットテーブル中のカラム名にマッチする名前リストが、クエリーの'WHERE'節で使用するフィルタとして使用されます。
4.OrderBy (任意) -クエリーをソートするための単一カラム名
5.Accending (任意) -真(true)の場合、昇順になります。偽(false)の場合、降順になります。

例)基本的なGenericList

Contactテーブルに基本的なGenericListを実行するためには、次のように<event-handler>タグに<message>タグを追加します:

<message name="modelglue.GenericList">
    <argument name="object" value="Contact" />
</message>

ビューで次のコードを実行することによって、レコードを<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactQuery") />

■Viewstateのをカスタマイズする

Contactテーブルに基本的なGenericListを実行し、Viewstateに特定名をセットするために、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericList">
    <argument name="object" value="Contact" />
    <argument name="queryName" value="aListOfContacts" />
</message>

ビューで次のコードを実行することによって、レコードを<cfdump>できます:
<cfdump var="#viewstate.getValue("aListOfContacts") />

■フィルターを適用する

Contactテーブルに基本的なGenericListを実行し、ViewstateのFirstname値でフィルタリングするために、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericList">
    <argument name="object" value="Contact" />
    <argument name="criteria" value="Firstname" />
</message>

イベントハンドラ名を"contact.list"として、以下のURLでこのイベントハンドラーを呼び出すと、'firstname'が'Fred'であるSELECT結果を得るでしょう。
index.cfm?event=contact.list&firstname=Fred

■ソート

Lastnameを昇順でソートされたContactテーブルの基本的なGenericListを実行するには、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericList">
    <argument name="object" value="Contact" />
    <argument name="orderBy" value="Lastname" />
</message>

降順にするには、次の引数を追加します:
<argument name="ascending" value="false" />

ビューで次のコードを実行することによって、クエリー結果を<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactQuery") />

MG2:Unity Using modelglue.GenericCommit

今日は、ジェネリック・データベース・メッセージ(GDM)のうち、GenericCommitについて、紹介します。(原文タイトル:Using modelglue.GenericCommit)

modelglue.GenericCommit
このメッセージがブロードキャストされると、DataControllerは与えられたテーブルにレコードを保存しようとします。

その実行プロセスは以下のとおりです。

1.アップデートするために既存レコードをロードするか、criteriaで指定されたものにマッチするものがない場合は、挿入するために新規レコードをクリエイトします。
2.レコードのフィールド値をアップデートします。 デフォルトでは、viewstate(FORMとURLスコープの組み合わせ)に対応するフィールドはどれもviewstateの値で設定されます。

  このことは、所与のcontactテーブルに関して、"firstname"というフォーム入力の値が、contactレコードのFirstnameの値に自動的に永続化されることを意味します。

  デフォルトで、DataControllerはすべてのフィールドに対してviewstate内の同一プロパティ名の値で永続化しようとします。どのプロパティを永続化するかをコントロールするために、以下に示される「properties」引数を使用してください。

3.Validate()メソッドと呼ぶことによって、レコードを検証します。

4.レコードが検証されると、DataControllerはデータベースにデータを保存します。

5.最後に、DataControllerは、2つの結果"commit"か"validationError"のいずれかの1つを加えます。これらのresult名をもつresultマッピングの追加は、他のresultマッピングとも同様に動作します。

このmodelglue.genericCommitメッセージは、次の<argument>タグを使用することによって構成されます:

1.Object (必須) -Commitするレコードオブジェクトのテーブル名

2.Criteria (必須) -フィルタとして使用するviewstate値のリスト
ターゲットテーブル中のカラム名にマッチする名前の値リストが、クエリーの'WHERE'節で使用するフィルタとして使用されます。
通常は、テーブルのプライマリーキーのリストに設定されます。ヌルだと、新しいレコードが作成されます。 所与のレコードが、指定されたCriteriaに合致すると、レコードはアップデートされます。さもなければ、新しいレコードが挿入されます。

3.RecordName (任意) -レコードデータセットを格納するviewstate名
デフォルトは、Object&"Record"です。

4.ValidationName (任意) -検証エラー時のメッセージコレクションを格納するviewstate名
デフォルトは、Object&"Validation"です。

5.Properties (任意) -viewstate内の同一名の値から永続化しようとするRecordのフィールド名
デフォルトでは、全てのレコードフィールドが対象となります。

例)基本的なGenericCommit

Contactテーブルで基本的なGenericCommitを実行するために、次のように<event-handler>タグに<message>タグを追加できます:

<message name="modelglue.GenericCommit">
    <argument name="object" value="Contact" />
    <argument name="contactId" value="Contact" />
</message>

ビューで次のコードを実行することによって、レコードを<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactRecord") />

ビューで次のコードを実行することによって、検証メッセージを<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactValidation") />

イベントハンドラ名を"contact.commit"として、以下のURLでこのイベントハンドラーを呼び出すと、'ContactId=42'の'firstname'を'Fred'にアップデートする結果を得るでしょう。
index.cfm?event=contact.commit&contactId=42&firstname=Fred

Viewstate値の引数リストをカスタマイズする。

Contactテーブルに基本的なGenericCommitを実行し、レコードと検証の両方を格納するviewstate名を指定するためには、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericCommit">
    <argument name="object" value="Contact" />
    <argument name="contactId" value="Contact" />
    <argument name="recordName" value="myCommittedContact" />
    <argument name="validationName" value="validationForContact" />
</message>

ビューで次のコードを実行することによって、レコードを<cfdump>できます:
<cfdump var="#viewstate.getValue("myCommittedContact") />

ビューで次のコードを実行することによって、検証メッセージを<cfdump>できます:
<cfdump var="#viewstate.getValue("validationForContact") />

イベントハンドラ名を"contact.commit"として、以下のURLでこのイベントハンドラーを呼び出すと、'ContactId=42'の'firstname'を'Fred'にアップデートする結果を得ます。
index.cfm?event=contact.commit&contactId=42&firstname=Fred

特定のプロパティをコミットする。

Firstnameだけ更新されるようにContactテーブルに基本的なGenericCommitを実行するには、次のように<message>タグを<event-handler>タグに追加します:

<message name="modelglue.GenericCommit">
    <argument name="object" value="Contact" />
    <argument name="contactId" value="Contact" />
    <argument name="properties" value="Firstname" />
</message>

ビューで次のコードを実行することによって、レコードを<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactRecord") />

ビューで次のコードを実行することによって、検証メッセージを<cfdump>できます:
<cfdump var="#viewstate.getValue("ContactValidation") />

イベントハンドラ名を"contact.commit"として、以下のURLでこのイベントハンドラーを呼び出すと、'ContactId=42'の'firstname'のみ'Fred'にアップデートし、Lastnameは"finklebuster"にアップデートしない結果を得ます。
index.cfm?event=contact.commit&contactId=42&firstname=Fred&lastname=Finklebuster

MG:Unityジェネリック・データ・メッセージ(GDMs)

今回は、ジェネリック・データベース・メッセージ(GDM)の使用方法について、紹介します。(原文タイトル:How To Use Generic Database Messages)

Model-Glue:Unityの最も無視できない特徴の1つは、自動化されたデータベース能力です。Reactorフレームワークを使用することによって、Model-Glue:Unityは、一般的なデータベースタスクの創造-単一テーブルCRUD(Create、read、update、delete)と実行を自動化します。

Reactorフレームワークは、"Generic Database Messages" (GDMs)をリスンするコントローラ("DataController")を自動的にロードすることによって、このことを達成します。GDMsは、ModelGlue.xmlの中で自動的に呼び出し可能なコマンドセットです。

また、GDMsは、<scaffold>タグを通して作成されるイベントハンドラに対するすべてのデータ・アクセス機能を提供します。

DataControllerがリスンするように構成されている4つのGDMsは、以下の通りです:

1.modelglue.GenericList

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルからレコードをリストアップしようとします。

2.modelglue.GenericRead

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルから特定レコードの読み出しようとします。

3.modelglue.GenericCommit

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルにレコードを保存しようとします。

4.modelglue.GenericDelete

このメッセージがブロードキャストされると、DataControllerは与えられたテーブルからレコードを削除しようとします。

MG:Unity カスタムコンフィグレーションの追加方法

今日から数回に分けて、Model-Glue:Unity(MG2:Unity)のマニュアルのうち、Ver1.1から大きく変更・追加されたところを紹介していきます。

第一回目は、ColdSpring.xmlを利用したカスタムコンフィグレーション方法についてです。
(原文タイトル:How To Add Custom Configuration)
メールサーバの情報を、Coldspring.xmlにbean定義し、メッセージリスナー内でこれを呼び出す方法を紹介しています。

アプリケーションでは、しばしばデータソース名かメールサーバなどの何らかの構成情報を知る必要があります。 例として、アプリケーションで<cfmail>タグを使用する必要があり、ファイル中にサーバ名、ユーザ名およびパスワードを、ソースコードの外部に保存する場合を仮定しましょう。このことは、とても良い習慣です。

(1.xからのアップグレードでない)どのModel-Glue: Unityアプリケーションには、全てのアプリケーション構成情報を集中管理するためのColdSpring.xmlがあります。

このColdsping.xmlファイルは、数組の<bean>タグで構成されています。 各々のbeanは、Model-Glueアプリケーション内で問い合わせ可能なCFCを表しています。

Model-Glue:Unityには、一般的な構成の雑事に適したbean(ModelGlue.Bean.CommonBeans.SimpleConfig)があります。そのbeanは、setConfig()ファンクションを通して構造体をセット可能な単一プロパティ(のコンフィグ)を持っています。 この構造は、アプリケーション構成情報を「登録」するのに役立ちます。beanのgetConfigSetting()ファンクションに検索するプロパティ名を与えることによって、各々の設定値にアクセスできます。

これをメールサーバのシナリオに適用するために、ColdSpring.xmlに以下を加えます:

<bean id="mailConfiguration" class="ModelGlue.Bean.CommonBeans.SimpleConfig">
    <property name="config">
        <!-- In Coldspring, a "map" represents a struct -->
        <map>
            <entry key="mailserver">
                <value>mail.mydomain.com</value>
            </entry>
            <entry key="username">
                <value>smtpUsername</value>
            </entry>
            <entry key="password">
                <value>smtpPassword</value>
            </entry>
        </map>
    </property>
</bean>

このXMLベースの構成情報をColdSpring.xmlに追加した後に、この構成設定を使用するのは簡単です。以下に、<cfmail>タグで構成設定を使用する例のリスナー機能を示します:

<cffunction name="sendEmail" access="public" returnType="void" output="false">
    <cfargument name="event" type="any">

    <cfset var message = arguments.event.getValue("message") />
    <cfset var subj = arguments.event.getValue("subj") />
    <cfset var to = arguments.event.getValue("to") />

    <!--- Get mail configuration --->
    <cfset var mailCfg = getModelGlue().getBean("mailConfiguration") />

    <!--- Use the mail configuration to send mail --->

    <cfmail
        to="#to#"
        subject="#subject#"
        server="#mailCfg.getConfigSetting("mailserver")#"
        username="#mailCfg.getConfigSetting("username")#"
        password="#mailCfg.getConfigSetting("password")#"
        >
        #message#
    </cfmail>

</cffunction>

Model-Glue:Unity Scaffolding

Sean Corfieldのサンプルアプリケーションggcc11を通じて、Model-Glue:UnityのScaffolding機能を含めた「15分で作るWebアプリケーション」の作成手順を体感しつつあります。

しかしながら、私のローカルマシンやHostNexusホスティングで完璧に動作していません。
Model-Glueメーリングリストでも私と同様のエラー発生が報告されているので、ベータ2までには解決するだろうと思います。
Seanが記述してくれたGGCC11作成体験記を意訳してみたので、ご参考までに。
詳細は、添付ファイルをご確認ください。

1.modelglueapplicationtemplateを雛形にして、ANT適用

a. modelglueapplicationtemplate内のbuild.xmlファイルを開き、
b. <property>タグのtarget属性のvalue値に、"ggcc11"へのフルパスを設定し、
c. <replace>タグのtoken属性のvalue値に"ggcc11"を設定する。 

2.Reactor.xmlファイル

a.データベースオブジェクトの定義
b.リレーションの定義

3.ModelGlue.xmlファイル

a.scaffoldタグの追加
   note
   task

    <event-handlers>
        <scaffold object="note" />
        <scaffold object="task" />
    </event-handlers>

4.アプリケーションの実行

http://[host]/ggcc11/

5.自動生成ファイルの確認と移動

a.viewファイル(確認と移動)
  VIEW(cfm) :/ggcc11/config/scaffolds/dsptaskList.cfm   ---> /ggcc11/views/
                                       frmtask.cfm       ---> /ggcc11/views/
b.modelファイル(確認のみ)
  MODEL(cfc):/ggcc11/model/data/

6.Scaffolds.xmlファイル内容をModelGlue.xmlファイルにコピー

コピー元:/ggcc11/config/scaffolds/Scaffolds.xml 

<event-handler>タグ  task.list, task.edit, task.commit, note.commit

コピー先:/gggcc11/config/ModelGlue.xml          

<event-handlers>タグ

7.<event-handler>タグへの追記

a.task.commit用<event-handler>
   note.commitへのforward

b.note.commit用<event-handler>
   task.editへのredirect

8.controllerへのリスナーメソッドの追記

getQueryStruct()メソッド

9.ModelGlue.xmlの修正

a.メッセージリスナーの登録
    <message-listener message="makeLookupFromQuery" function="getQueryAsStruct" />
b.task.list<event-handler>へのメッセージ追加
    <message name="makeLookupFromQuery">
         <argument name="queryName" value="statusQuery" />
         <argument name="lookupName" value="statusLookup" />
         <argument name="key" value="statusId" />
         <argument name="value" value="statusName" />
    </message>
    <message name="makeLookupFromQuery">
         <argument name="queryName" value="userQuery" />
         <argument name="lookupName" value="userLookup" />
         <argument name="key" value="userId" />
         <argument name="value" value="firstName" />
    </message>

10.dsptaskList.cfmの修正

 HTMLの整形:status、username、最終更新月日 

11.frmtask.cfmへの追記

 a.validationError時の対応
    <cfmodule template="customtags/validationErrors.cfm" property="ownerID" validation="#validation#" />
b.その他

12.未達成事項

a.note書き込み時のセキュリティチェック
   ggcc7を参照

Model-Glue:Unity 最新プレゼンテーション

Joe RinehartによるModel-Glue:Unityの最新プレゼンテーションがBreezeCentral.comにアップされました。
Model-Glue:Unityの新機能(scaffoldsやGDM)を実際に体験できるので、大変有用です。

最初にデモンストレートされる「15分でブログアプリケーション」がおもしろかったです。

1時間弱のプレゼンですが、こちらからどうぞ!

Model-Glue:Unityサンプルアプリ

早速、Sean Corfieldが彼のブログでModel-Glue:Unity対応のサンプルアプリケーションggcc11をアップした。
このサンプルアプリケーションは、彼がFuseBox、Mach-II、Model-Glue、ColdSpring、TartanなどColdfusion向けFramework Sample Code、ggccシリーズの最新版です。
Model-Glue:Unityによって、

プレゼンテーション層:ModelGlue:Unity
コントローラー:ModelGlue:Unity(ビジネスロジック)
サービス層:ColdSpring
ORM層:Reactor

と各々のフレームワークが相当の機能を分担したため、今回Sean自身が書いたものは、プレゼンテーション層であるviewと、ビジネスロジック層のcontroller.cfcだけになっています。
私のホスティング環境では、エラーが発生しています。Reactor関連のパーミッションかもしれません。



Model-Glue:Unityの新機能

Joe RinehartがAdobe's Developers Weekで実施したModel-Glue:Unityのプレゼン内容を、Brian Rinaldiが彼のブログで紹介しています。

彼のプレゼンは、まだAdobeサイトにアップされていないので、Brian RinaldのブログからModel-Glue:Unityの新機能を読み取ってみます。

1.Model-Glue1.1との完全下位互換

  • Model-Glue1.1は、第二世代のフレームワークである。

即ち、MVCアーキテクチャを使って、プレゼンテーションからモデル層を分離することがその目的であった。
しかしながら、beans/Records、DAOs、Gatewaysなどの共通タスクを取り扱う繰り返しのコードを生むことになった。

  • Model-Glue:Unityは、第三世代のフレームワークである。

モデル層における単調な繰り返しコード生成作業を自動化する。

2.他のフレームワークとの統合

  • 第三世代フレームワーク化推進のため、他のフレームワークとの統合を図った。

ColdSpring
サードバーティサービスの統合と依存性の注入(DI/IoC)をの実現。
依存性の注入は、Model-GlueとReactorのコンフィグ情報をColdSpring.xmlに記述することで実現。
Reactor
ORMの自動化に、Reactorを採用。
ModelGlue自身が実装したData Controllerを使って、イベントハンドラー内の<message>タグでGDMと呼ぶメッセージを記述して、DAOやGatewayを呼び出す。

  • ModelGLue.GenericList(Gateway)
  • ModelGLue.GenericRead(Read)
  • ModelGLue.GenericCommit(Create&Update)
  • ModelGLue.GenericDelete(Delete)

ORM用フレームワークには、Reactor以外も利用可能であるが、自分自身でcustom adapter, DataController, 及びscaffold .XSL を作成する必要がある。

     

3.Scaffolding

  • XSLによるカスタマイズ可能なHTMLの "scaffolds(足場)"を実現。
  • ModelGlue.xml内の<event-handlers>タグ内に<scaffold>タグを定義すれば良い。
  • <Scaffold>タグにより、5つのイベントを作成可能。
    • マスターリストの表示(table.list)
    • レコードデータとリレーションデータの修正フォームの表示(table.edit)
    • レコードデータの読み出し専用ビューの表示(table.view)
    • レコードデータの更新(table.commit)
    • レコードデータの削除(table.delete)
  • <Scaffold>タグ内には、<Broadcasts>、<Results>、<Views>タグを記述可能。
  • <Scaffold>タグの属性に、typeを指定することで、作成するイベントハンドラータイプを指定可能。

4.レコードデータのAutoValidation

  • GDMのGeneric.Commitで、<arguments>タグにname="validationName"を指定することにより、自動的にValidateを実行できます。(より複雑なValidateのカスタマイズは、Reactorが自動生成するDAOオブジェクトを拡張する必要がありますが・・・)

最後に、Joe Rinehartのビデオデモも参考になるので、一読をお勧めします。

ModelGlue:Unity Public Beta1リリース!

Joe Rinehartのブログで、ModelGlue:Unity Public Beta1のリリースがアナウンスされています。
ダウンロードサイトは、こちらです。また、ドキュメントは、こちらです。

私のCF-OOPサイトで、ドキュメントの意訳を行っていきますので、今しばらくお待ちを・・・

ModelGlu2.0:Unityを使う10の理由

Joe Rinehartが彼のブログで、ModelGlu2.0:Unityを使う10の理由を書いている。

  1. Expression over depression. UI関連作業を大幅に削減できること
  2. Near-instant applications. かんたんにアプリケーションが構築できること
  3. MVC without the guesswork. 明快なMVCであること
  4. It does CRUD for you. CRUD機能を提供すること
  5. It makes OOP easier to learn. OOPを簡単に学べること
  6. Already got CFC code? Reuse it effortlessly. CFCの再利用を高められること
  7. Don't like something? You can change it. フレームワークの機能拡張性が高いこと
  8. It's fast. 高速であること(旧版と比較して)
  9. It's free. 無料であること
  10. It's open source. オープンソースであること

しばらく、ModelGlueやColdspringから遠ざかっているので、再度ModelGlue:Unity+Coldspring1.0RCを楽しんでみよう・・・(Reactor1.0RCも含めて)

CF-Unitedでの発表

[ColdSpring-Dev]のメーリングリストで、Sean A Corfieldが予告した。
6月下旬のCF-Unitedで、ModelGlue、ColdSpring、Reactor、そしてFuseBoxが商用利用可能なオープンソースとして公開されるらしい。
非常に楽しみだ。自社の開発に持ち込むか、このまま趣味の世界で続けるか悩むなあ・・・

ModelGlue 1.1.10 RC

Joe Rinehartが彼のブログで、ModelGlue 1.1.10RCについてアナウンスした。

今回のリリースの特徴は、パフォーマンスの改善(ModelGlue2.0 Unityからのフィードバック)。Sessionスコープを使った場合のパフォーマンスが6倍に改善されたとのことです。
サンプルアプリ:PostMarket

This release is focused on performance, but also removes the necessity for the session scope to be enabled. Without session, you will simply lose the state container during a redirect/forward and all references to asynchronous requests.

Below is a series of benchmarks against the Model-Glue PetMarket homepage. Each test consisted of 100 concurrent threads, 50 requests each thread, 3 seconds between each request.

Average response times:   

Model-Glue 1.1:  2591ms   

Model-Glue 1.1.1 Private Test:  1144ms   

Model-Glue 1.1.1 Release Candidate: 491ms   

Model-Glue 2.0 (Revision 78): 308ms

   

MG/CS/Reactor連携アプリケーション例

Brian Kotekが、ModelGlue-ColdSpring-Reactor連携のブックストアアプリケーションを
彼のブログにアップしています。
早速、私のサイトにインストールしてみました。
(彼は、Windowsマシンで開発しているらしく、View関連のフォルダ名とファイル名は一部変更が必要です)

1.ColdSpringによるModelGlue用BeanFactoryLoaderとAutowiring用コントローラー
2.ColdSpringによるReactorオブジェクトのファクトリー機能
を活用して、Model内がビジネスロジック層、サービス層、パーシスタント層にきれいに構造化されています。

次回は、その概要を紹介してみます。

また、Mach-II-ColdSpring-Reactor連携モデルも彼のブログにアップされています。

ModelGlue V1.1リリース!

Joe Rinehartが彼のブログで、ModelGlue V1.1をリリースしたことをアナウンスしました。
V1.1の新規フューチャーは、ColdSpringのAutowiring用コントローラの実装です(By Sean Corfield)。

V2.0 Alpha(コード名:Unity)もSVNで公開されました。
同時に、彼のブログで、2.0アプリケーション例も別の記事で紹介されています。

フレームワーク連携

以前、ModelGlue+ColdSpring+reactorによるフレームワークの連携が
今後の主流になるかもしれないと予想しましたが、その後、
1.reactorの機能強化
2.ColdSpringによる外部Factory呼び出しの実装
3.ModelGlueにおけるAutowiringControllerの実装
を経て、それが現実的になろうとしています。

Seanの最近の記事には、彼のフレームワークサンプルggccのバリアント、
ModelGlue+ColdSpring+reactorに対応させるためのColdSpringとreactorの
連携が紹介されています。以下は、その関連記事です。

Model-Glue, ColdSpring and Reactor
Model-Glue, ColdSpring and Reactor - follow-up
Model-Glue, ColdSpring and Reactor - another follow-up

Sean曰く、bean.cfc、DAO.cfc、Gateway.cfcなど12のCFCsが不要に
なったとのことです。Seanのggcc10アプリケーションアップをアップを
楽しみにして待っていよう。

AjaxCFC

昨年、CFAjaxを見て、フレームワークとの整合性が悪いなあーと思っていたら、
CFCベースのAjaxフレームワークが出てきました。
Rob Gondaのブログに行くと、ModelGlueとの連携も紹介してくれています。
Robさん、サンキュ!
これで、GoogleMapsとのマッシュアップが簡単に出来そう!

ajaxCFC for Model-Glue Explained

Ajax.cfcは、ModelGlueで利用可能な汎用modelです。したがって、コントローラで利用可能です。コントローラ内のinitファンクションで初期化し、コントローラ内のvariablesスコープに常駐させます。

<cffunction name="Init" access="Public" returnType="controller" output="false" hint="I build a new SampleController">
  <cfargument name="ModelGlue">
 
  <cfscript>
      super.Init(arguments.ModelGlue);
    variables.echo = createObject("component", "blog.projects.ajaxcfc.examples.modelgluesamples.echo.model.echo");
    variables.ajax = createObject("component", "blog.projects.ajaxcfc.examples.modelgluesamples.echo.model.ajax");
  </cfscript>
  <cfreturn this />
</cffunction>

Ajaxのリモートリクエストは、標準的なWebリクエストと同じく、以下のようにフローします。 

  1. ページがAJAXリクエストを発生させる。
  2. ModelGlueフレームワークによって、イベントが捕捉される。
  3. ModelGlueのイベントハンドラーがメッセージをブロードキャストする。
  4. コントローラでメッセージをピックアップする。
  5. AjaxCFCを使い、onRequestStart内で、メッセージをパースする。
  6. イベントに応じて他のmodelを利用し、レスポンスデータを作成する。
  7. 再度AjaxCFCを使い、レスポンスに備える。
  8. 'ajaxResponse'にレスポンス値をセットし、viewに渡す。
  9. modelGlue.xmlで、レスポンスを運びJavaScriptのコールバックファンクションに返すviewとしてのajaxResponse.cfmを含める。

ModelGlue+AjaxCFC+ColdspringでGoogleMapsとの連携版を作ってみよう!

ModelGlueV1.1近し!

Joe Rinehartのブログに、ModelGlue V1.1のリリースが近いことが
1月になって発表されていたようです。

彼の記事を2件引用すると・・・・こんな感じになるようです。
Model-Glue 1.1 Preview

  • ColdSpringとの統合
    1. ChiliBeansとColdspringの簡易切替(modelglue.xml内の<setting>タグ)
    2. Controllerとservice/conponent間の自動ワイヤリング(自動Bean化、beanFactoryLoader使用)
  • スタータキット(テンプレート)のリニューアル
    1. MySQL/MSSQLサポート(ColdSpringのDAO/Gateway経由?)
    2. 基本Webアプリ用テンプレート(ログイン/ログアウト、プロフィール管理、ユーザ管理)
  • redirectタグのバグフィックス
    1. リダイレクト先未指定の場合に、リダイレクトを実施しないようにした
  • 静的ブロードキャスト機能の追加
    1. controller内のOnRequestStartファンクション内でスタティックなリダイレクトが可能になった。

Model-Glue "Headstart" Preview (screenshots!)

  • MySQL and MS SQL Server Support

  • ロールベース/キーベースセキュリティ(グループレベル/レコードレベルセキュリティ)

  • ユーザ管理ツール

  • ユーザサインアップの設定(on/off)

  • ログインアクセスの設定(on/off)

  • 手のかかる例外処理のハンドリング

    • エラー情報、スコープ情報、デバッギングスタック情報付メールの自動通知

  • メールサービス用CFCのビルトイン

上記管理ツールのスクリーンショットはこちら

CFMX用フレームワーク比較

Sean CorfieldがColdfusion用フレームワークの比較プレゼンを彼のブログにアップした。
Fusebox4、Mach-II、Model-Glueの3つについて、特徴と概観図をシンプルに比較しており、大変わかりやすい。
早速、Model-Glue+ColdSpringとTartanの比較資料における概観図に引用させてもらった。

ModelGlue+TarTan or ColdSpring(その2)

前回、紹介した資料の最終ページにあるとおり、
Sean CorfieldのColdfusionフレームワーク用サンプルアプリケーションGGCCでファイル数を比較してみると、ModelGlue+ColdSpringのModelGlue+Tartanに対する優位性がはっきりわかります。

  1. ggcc7 : ModelGlue                       17Files (Corrected at Nov 17, 2005 By suggest Sean Corfield)
  2. ggcc8 : ModelGlue+Tartan            27Files
  3. ggcc9 : ModelGlue+ColdSpring      21Files

Tartanは、サービスコントローラがあり、コマンドcfcを介して、VO/DAO/Gateway/Exceptionなどのモデルcfcにアクセスするため、サービスコントローラやCommandファイルの分だけファイル構成が複雑になります。
したがって、ModelGlueのフットワークの軽さにフィットするのは、ColdSpringになるのかもしれません。

ModelGlue+TarTan or ColdSpring

ColdSpringに触れてから、ModelGlue+ColdSpringの組合せを研究してきたけど、
ここらで一旦

  1. ModelGlue+Tartan
  2. ModelGlue+ColdSpring

の違いについて整理してみる。

  • Tartan
    • サービスフレームワーク
    • コマンドドリブンベース
    • IoC機能(DI機能)
    • サービスレイヤ機能
      • Service, VO, DAO, Gateway, Utility, Exception
  • ColdSpring
    • MVCフレームワークのサポート
    • AOP機能
    • IoC機能(DI機能)
    • サービスレイヤ支援機能(Bean化)
      • Service, VO, DAO, Gateway, Utility, Exception

各々の特徴と概観を資料 にまとめてみました。ご参考までに 。

LoggingAOP with ColdSpring

今日は、ColdSpringAOPとLog4jを使ったロギングサービスについて、解説します。
Chris ScottのColdSpringAOPのチュートリアルから引用してみます。

1.最初に、LoggingServiceを定義します。javaのlog4jからloggerクラスを生成しています。

<cfcomponent name="LoggingService" output="false">

  <cffunction name="init" returntype="net.klondike.service.LoggingService" access="public" output="false">
    <cfset var category = CreateObject("java", "org.apache.log4j.Category") />
    <cfset variables.logger = category.getInstance('net.klondike') />

    <cfreturn this />
  </cffunction>
 
  <cffunction name="info" access="public" returntype="void" output="false">
    <cfargument name=message" type="string" required="true" />
    <cfif variables.logger.isInfoEnabled()>
    <cfset variables.logger.info(arguments.message) />
    </cfif>

  </cffunction>
 
</cfcomponent>

2.次に、AOPパートです。loggingBeforeAdviceを定義します。

<cfcomponent name="loggingBeforeAdvice" extends="coldspring.aop.BeforeAdvice">

  <!--- setters for dependencies --->
  <cffunction name="setLoggingService" returntype="void" access="public""false" hint="Dependency: security service"> output=
    <cfargument name="loggingService" type="net.klondike.service.LoggingService" required="true"/>
    <cfset variables.m_loggingService = arguments.loggingService />
  </cffunction>
<cffunction name="getLoggingService" returntype="net.klondike.service.LoggingService""public" output="false" hint="Dependency: security service"> access=
    <cfreturn variables.m_loggingService />
  </cffunction>
 
  <!--- before() is called by the aop framework before method invocation --->
  <cffunction name="before" access="public" returntype="any">
    <cfargument name="method" type="coldspring.aop.Method" required="true" />
    <cfargument name="args" type="struct" required="true" />
    <cfargument name="target" type="any" required="true" />
   
    <cfset var arg = '' />
    <cfset var argString = '' />
    <cfset var objName = getMetadata(arguments.target).name />
    <cfloop collection="#args#" item="arg">
      <cfif isSimpleValue(args[arg])>
        <cfif len(argString)>
          <cfset argString = argString & ', ' />
        </cfif>
        <cfset argString = argString & arg & '=' & args[arg] >
      </cfif>
    </cfloop>
        <cfset variables.m_loggingService.info("[" & objName & "] " & method.getMethodName() & "(" & argString & ") called!") />
      </cffunction>
  </cfcomponent>

3.最後に、ColdSpringのbean定義を行います。

<beans>
 
  <!—define the logging service -->
  <bean id="loggingService"
        class="net.klondike.component.LoggingService" />

 
  <!--define the loggingBeforeAdvice and set its logging service property to reference the bean above -->
  <bean id="loggingBeforeAdvice"
        class="net.klondike.aspects.loggingBeforeAdvice">

    <property name="loggingService">
      <ref bean="loggingService" />
    </property>
  </bean>
 
  <!—now define a NamedMethodPointcutAdvisor, set the advice property to the bean above, and set its mappedNames property to ‘*’ which will create a pointcut to match all methods excluding any init method -->
  <bean id="loggingAdvisor"
        class="coldspring.aop.support.NamedMethodPointcutAdvisor">

    <property name="advice">
      <ref bean="loggingBeforeAdvice" />
    </property>
    <property name="mappedNames">
      <value>*</value>
    </property>
  </bean>
 
  <!-- to create the proxy object, first create our dao as the target object -->
  <bean id="catalogDaoTarget"
        class="net.klondike.component.catalogDAO">
    <property name="dsn">
      <value>klondike</value>
    </property>
  </bean>
 
  <!-- now create a ProxyFactoryBean with the id catalogDAO, set the target to the catalogDaoTarget bean above, and give it ,the id of the NamedMethodPointcutAdvisor above in the list of interceptorNames -->
  <bean id="catalogDAO"
        class="coldspring.aop.framework.ProxyFactoryBean">
    <property name="target">
      <ref bean="catalogDaoTarget" />
    </property>
    <property name="interceptorNames">
      <list>
        <value>loggingAdvisor</value>
      </list>
    </property>
  </bean>

 
  <!--now to use the proxy DAO, we give the id of the ProxyFactoryBean to the catalog service as the reference for the property catalogDAO -->
  <bean id="catalogService"
        class="net.klondike.component.CatalogService">
    <property name="catalogDAO">
      <ref bean="catalogDAO" />
    </property>
  </bean>

</beans>

ModelGlue1.0.01の新機能

ModelGlue1.0.01の新機能について、ドキュメントの該当部分を和訳したので紹介しておきます。

1.ステートフルResultリダイレクト    <result name="xxx" do="yyy" redirect="ture" append="zzz" />
2.ステートフルフォワーディング      arguments.event.forward( )

■クイックスタート: ステートフルResultリダイレクト

しばしば、あるフォームがポストされたときに、"Reload"によってユーザがフォームをリポストすることを防ぐために、新しいページへのCFLocation を行うことが定例化しています。Model-Glue1.0 では、ModelGlue.xml ファイルを通じてこの動作を模倣することが可能になりました。

どのような<result>タグにも、REDIRECT属性を追加することができるようになりました。REDIRECT="true"にセットされている場合、フレームワークはすぐ現在の要求を停止し、すべての変数値を維持しながら、あらかじめ設計された<event-handler>へのサーバーサイドリダイレクトを実行します。

URL のparamaters を含んでいるページにリダイレクトしたいと思うことはかなりありうることです。例えば、誰かがコンテンツ管理システムのあるセクションに新しい記事をポストしたら、"index.cfm?event=showSection&sectionId=12345" のようなURL に遷移することを望むはずです。しかしながら、resultタグ上のREDIRECT属性は、url に追加すべきの"sectionId" 変数の値を知る方法がありません。この理由のために、オプションとしてAPEND属性が今回サポートされました。それは、変数コレクションをURLに追加するために、コンマ区切りの変数リストを含まなければなりません。フレームワークはURL に自動的にこのリストの単純変数すべてを追加します。

オーケー、それでは簡単なサンプルを見てみましょう:

<result name="articleAdded" do="showSection" redirect="true" append="sectionId">

全然OKでしょう?

■クイックスタート: ステートフルフォワーディング

行くためにどうしてもどこに知らない時があります。例えば、"ポッド" の中にあるフォームは、何かを行い、そしてどんなイベントから来たかユーザに示すことが必要になるでしょう。<result>タグを書くとき、"do"属性を動的にセットする方法はありません。

このような特別な事例のために、(arguments.event として知られている) EVENTオブジェクトは、Forward()メソッドを実装しました。このメソッドの使用方法は、次のようになります:

arguments.event.forward(<event-handler>名) - 直ちに指定された<event-handler>へのステートフルリダイレクトを実行する。arguments.event.forward("showSection ") は、index.cfm?event=showSection と同等です。

arguments.event.forward(<event-handler>名, append) - 直ちに、appendで与えられる変数コレクションをURLに追加しながら、指定された<event-handler>へのステートフルリダイレクトを実行します。arguments.event.forward("showSection" , sectionId )は、"12345" という値を有するsectionIdという変数コレクションを与えられた、index.cfm?event=showSection&sectionId=12345と同等です。

ColdSpringAOP Sample

SeanのModelGlue+ColdSpringサンプルアプリケーションGGCC9における
ColdSpringのAOP機能をチェックしてみます。

ggcc.xmlを眺めてみると・・・task関連処理におけるセキュリティチェックに
AOP機能を適用しているようです。

Target:
 taskDAOTarget(class->ggcc9.model.taskDAO)
 taskGatewayTarget(class->ggcc9.model.taskGateway)
Advice:
 checkIdentity(class->ggcc9.aspects.checkIdentity)
Advisor:
 securityAdvisor(Advice->checkIdentity MappedNames->*)
Service:
 taskDAO:Target->taskDAOTarget  InterCepternames->securityAdvisor
 taskGateway:Target->taskGatewayTarget  InterCepternames->securityAdvisor

このことによって、event-handlerの定義からセキュリティチェックの前処理がなくなって
います。
ggcc9->ModelGlue.xml->event-handler:showManager

        <event-handler name="ggcc.showmanager">
            <broadcasts>
                    <--
                    <message name="checkIdentity"/>        <--- AOP化したことにより、コメント化
                    -->
                <message name="needMembers"/>
                <message name="needMembersByID"/>
                <message name="needTasks"/>
                <message name="needStatii"/>
                <message name="needStatiiByID"/>
            </broadcasts>
            <views>
                <include template="dspShowTaskList.cfm" name="content">
                    <value name="XFA.AddTask" value="ggcc.newtask"/>
                    <value name="XFA.ChangeIdentity" value="ggcc.identify"/>
                    <value name="XFA.TaskDetail" value="ggcc.showtask"/>
                </include>
                <include template="layGGCC.cfm" name="final"/>
            </views>
        </event-handler>

また、DAOとGatewayをビーン化したことにより、コントローラーtaskManager.cfcの
内部が非常にシンプルになっています。

■GGCC7->taskManager.cfc->saveTask

    <cffunction name="saveTask" returntype="ModelGlue.Core.Event" access="public" output="false">
        <cfargument name="event" type="ModelGlue.Core.Event" required="true"/>
        <cfset var taskID = arguments.event.getValue("taskID") />
        <cfset var ownerID = arguments.event.getValue("ownerID") />
        <cfset var statusID = arguments.event.getValue("statusID") />
        <cfquery datasource="#variables.dsn#" username="#variables.dbUser#" password="#variables.dbPass#">
            UPDATE ggcctask
            SET ownerID = <cfqueryparam value="#ownerID#" cfsqltype="cf_sql_varchar"/>,
                statusID = <cfqueryparam value="#statusID#" cfsqltype="cf_sql_varchar"/>,
                lastUpdated = <cfqueryparam value="#now()#" cfsqltype="cf_sql_date"/>
            WHERE taskID = <cfqueryparam value="#taskID#" cfsqltype="cf_sql_varchar"/>
        </cfquery>
        <cfreturn arguments.event />
    </cffunction>

■GGCC9->taskManager.cfc->saveTask

    <cffunction name="saveTask" returntype="ModelGlue.Core.Event" access="public" output="false">
        <cfargument name="event" type="ModelGlue.Core.Event" required="true"/>

        <cfset var task = createObject("component","ggcc9.beans.taskBean").init(argumentCollection=arguments.event.getAllValues()) />
        <cfset variables.taskDAO.update(task) />

        <cfreturn arguments.event />

    </cffunction>

次回は、Javaのlog4Jをロギングに使う場合のサンプルについて解説します。


ModelGlue+ColdSpringAOP

Model-Glue + ColdSpringAOP連携アプリケーション ggcc9
じっくりながめてみた。
Model-Glue + tartan連携アプリケーション ggcc8 と比べてみると
ColdSpringAOPのAOP機能ではなく、bean(VO)機能によって
ずいぶんシンプルコードがシンプルになったなーという印象。
 


続きを読む "ModelGlue+ColdSpringAOP" »

ColdSpringAOP & ModelGlue

ModelGlue+Tartanで当面はアプリケーションを作っていこうと思っていたら、
今月、Dave Ross & Chirs ScottによるColdSpringAOP0.2.1がリリースされ、ModelGlueとの連携も
あっという間に、Seanが作り上げてしまった。

しばらく、ColdSpringAOP関連を追っかけて、
Model-Glueとの連携についても整理したので、まとめておきます。

ColdSpringAOPのまとめ ColdSpringAOP.txtをダウンロード
Model-Glue + ColdSpringAOP連携アプリケーション ggcc9

次回から数回にわたって、ColdSpringAOPの解説してみます。

modelglue+tartanのサンプル紹介-5

今日は、getMembersについて・・・
init()メソッドで定義したLoacalServiceへのproxyとサービス定義を使って、これに
コマンド名
引数パラメータ(struct)
戻り値(struct)
を定義して、あとはほいっと

  <cfset result = proxy.invokeCommand(service, command, args) />

でコールするだけです。

<cffunction name="getMembers" returntype="ModelGlue.Core.Event" access="public" output="false"  hint="I return a query object containing all of the members' information">
    <cfargument name="event" type="ModelGlue.Core.Event" required="yes" />

    <!--- appended for Tartan handling 2005/06/28 By Tomoaki Tanaka --->
    <cfset var proxy = GetTartan() />
    <cfset var service = getHelloService() />
    <cfset var command = "getMembers" />
    <cfset var args = structNew() />
    <cfset var result = structNew() />

    <cfset result = proxy.invokeCommand(service, command, args) />
    <cfif structKeyExists(result,"users") >
         <cfset arguments.event.setValue("users",result.users) />
         <cfset arguments.event.setValue("userByCookie",result.userByCookie) />
         <cfset arguments.event.setValue("userByID",result.userByID) />
   </cfif>
   <!---
        <cfif structKeyExists(result,"result") >
                <cfset arguments.event.addResult("setIdentitySuccess") />
        <cfelse>
                <cfset arguments.event.addResult("setIdentityFailure") />
        </cfif>
   --->
   <cfreturn arguments.event />
 
<!--- Original setting & scripts ggcc7
    <cfset var users = 0 />
    <cfquery name="users" datasource="#variables.dsn#" username="#variables.dbUser#" password="#variables.dbPass#">
    SELECT * FROM ggccuser
    ORDER BY firstName
    </cfquery>
    <cfset arguments.event.setValue("users",users) />
    <cfreturn arguments.event />
--->
</cffunction>

modelGlue+tartanは、modelGlueのControllerをシンプルにすることが、重要かなあー。
なぜなら、modelGlueのControllerを複雑にしても、Tartan側のサービスは一つだけだから・・・
それに、ModelGlueからTartanをコールする際にメモリを節約したいよねえ・・・

modelglue+tartanのサンプル紹介-4

さて、modelglue.xmlの一例を紹介したところで、controller<userManager>を見てみます。
 controller<userManager>は、ModelGlue.Core.Controllerを拡張したものです。
冒頭に、お決まりのinit( )メソッドがありますが、一般的なmodelglueアプリケーションの場合と比較して、tartan連携モデルでは、tartanサービスの呼出し手続きをinit( )で行います。

1.一般的modelGlueアプリケーション

    <cffunction name="init" returntype="usermanager" access="public" output="false">
        <cfargument name="core" type="ModelGlue.ModelGlue" required="true"/>
        <cfset super.init(arguments.core) />
        <cfset variables.dsn = arguments.core.getConfigSetting("dsn") />
        <cfset variables.dbUser = arguments.core.getConfigSetting("dbUser") />
        <cfset variables.dbPass = arguments.core.getConfigSetting("dbPass") />
        <cfreturn this />
    </cffunction>

2.tartan連携modelGlueアプリケーション

<cffunction name="Init" access="Public" returnType="userManager" output="false" hint="I build a new SampleController">
  <cfargument name="ModelGlue" type="ModelGlue.ModelGlue" required="true" />
  <cfset var result = "" />

  <cfset super.Init(arguments.ModelGlue) />
 
  <!--- Load the config params for the Tartan app we're talking to --->
  <cfset result = getModelGlue().getConfigBean("Tartan.xml") />
 
  <!--- Load the Tartan proxy --->
  <cfset variables.tartanProxy = createObject("component", "ModelGlue.Util.TartanProxy").init(result) />
 
  <!--- We're going to need the catClub service universally --->
  <cfset variables.clubService = getTartan().CreateService("catClub") /> 

<!--- append from original "init" function ---> 
  <cfset variables.dsn = arguments.ModelGlue.getConfigSetting("dsn") />
  <cfset variables.dbUser = arguments.ModelGlue.getConfigSetting("dbUser") />
  <cfset variables.dbPass = arguments.ModelGlue.getConfigSetting("dbPass") />


  <cfreturn this />
</cffunction>

tartan連携アプリケーションでは、以下の部分をおまじないとして追加すればいいようです。
(ただし、CreateService( ) 内のサービス名をターゲットに応じて変更してください。)

  <!--- Load the config params for the Tartan app we're talking to --->
  <cfset result = getModelGlue().getConfigBean("Tartan.xml") />
 
  <!--- Load the Tartan proxy --->
  <cfset variables.tartanProxy = createObject("component", "ModelGlue.Util.TartanProxy").init(result) />
 
  <!--- We're going to need the catClub service universally --->
  <cfset variables.clubService = getTartan().CreateService("catClub") /> 


次回は、メソッド<getMembers>について、紹介します。

modelglue+tartanのサンプル紹介-3

ggcc8におけるevent-handlerとcontrollerの関係を、ggcc.homeイベントを例にじっくり見てみる。
ggcc.homeイベントは、以下のように定義さrている。

<event-handler name="ggcc.home">
    <broadcasts>
        <message name="needMembers"/>
    </broadcasts>
    <views>
        <include template="dspShowHome.cfm" name="content">
            <value name="XFA.ShowTasks" value="ggcc.showmanager"/>
            <value name="XFA.Constitution" value="ggcc.showpage"/>
            <value name="XFA.Bylaws" value="ggcc.showpage"/>
            <value name="XFA.Minutes" value="ggcc.showpage"/>
        </include>
        <include template="layGGCC.cfm" name="final"/>
    </views>
</event-handler>

ggcc.homeイベントの挙動は次のようになる。
1.<needMembers>リスナーを呼び出し、
2.<dspShowHome.cfm>にいくつかのパラメータを渡しながら、その表示結果を<content>に保存し、
3.最後に<layGGCC.cfm>で端末に表示している。

<needMembers>リスナーはどこで定義されているかと、controllersセクションを見渡すと、
controller<userManager>に"needMembers"がある。

<controller name="usermanager" type="ggcc8.controller.usermanager">
<message-listener message="needMembers" function="getMembers"/>
 <message-listener message="choseIdentity" function="setIdentity"/>
<message-listener message="checkIdentity" function="checkIdentity"/>
</controller>

したがって、message<userManager>がブロードキャストされると、userManager.cfc内のファンクション<getMembers>をコールしています。つまり、フレームワーク名:ModelGlueの指し示すとおり、イベントとモデル(ビジネスロジック)を接着することがこのフレームワークの特徴と言えます。

modelglue+tartanのサンプル紹介-2

さて、前回のディレクトリ構成とコンフィグ構成に続いて、今日はコンフィグ構造に着目します。まずは、modelglue.xmlから。

1.<controllers>セクション
  5つのcontrollerが定義されている。
    mailer                        メール送信マネージャ
     taskmanager               タスクマネージャ
     usermanager              ユーザマネージャ
     relocator                  リロケータ
     viewConstants           キュー完了フォロワー
2.<event-handlers>セクション
   13のevent-handlerが定義されている。
    ggcc.home                 デフォルトイベント
    ggcc.showpage           スタティックページ表示用イベント
    ggcc.contact              コンタクト問い合わせイベント
    ggcc.sendmail             メール送信イベント
    ggcc.identify              ユーザ認証イベント
    ggcc.setidentity         ユーザ完了イベント
    ggcc.showmanager    最新情報表示イベント
    ggcc.showtask           最新タスク表示イベント
    ggcc.newtask             新規タスク生成イベント
    ggcc.savetask            タスク保存イベント
    ggcc.addtask              タスク追加イベント
    addnoteandnotify       記事追加&通知イベント
    failure                      例外発生イベント

modelglue+tartanのサンプル紹介-1

前回、再度紹介したmodelglue+tartanアプリケーション例”ggcc8”について、しばらく解説していきたいと思います。初回は、ディレクトリ構成とコンフィグ構成について紹介します。なお、アプリケーション名とアプリケーションフォルダはともに、ggcc8とします。

1.ディレクトリ構成
  ColdFusionのWWWルートフォルダの配下に、modelglue、tartan及びggcc8フォルダを配置します。

    cfmx_wwwroot--+---modelglue/
                           +---tartan/
                           +---ggcc8/--+--application.cfm
                                               +--index.cfm
                                               +--config/--+--ModelGlue.xml
                                               |                  +--service.xml
                                               |                  +--beans/tartan.xml
                                               +--controller/--+--mailer.cfc
                                               |                        +--relocate.cfc
                                               |                        +--taskmanager.cfc
                                               |                        +--usermanager.cfc
                                               |                        +--viewconstants.cfc
                                               +--view/--+--layGGCC.cfm
                                               |                +--dspShowHome.cfm
                                               |                +--dspxxxxxxxxx.cfm
                                               |                +--exception.cfm
                                               |                +--etc.cfm
                                               +--tartan/--+--services/localservice.cfc
                                                                  +--commands/someCommand.cfc
                                                                  +--vo/someBean.cfc
                                                                  +--data/--+--someDAO.cfc
                                                                  |                 +--someGateway.cfc
                                                                  +--exceptions/xxxxxx.cfc
2.コンフィグ構成
  ggcc8の配下にあるconfigフォルダに、
  1)modelglue用コンフィグファイル:ModelGlue.xml
  2)tartan用コンフィグファイル   :service.xml
  config/beansフォルダに、
  3)tartanマッピング用コンフィグビーン:tartan.xml
  を配置します。

次回は、各々のコンフィグファイルについて解説します。

Model-Glue+Tartan その2

ModelGlueとTartanの連携について、資料 をまとめてみた。

しばらく、このパターンでアプリケーション開発にいそしんでみようと思う。
また、ModelGlueのサンプルアプリケーションの中から、tartan連携アプリケーション:helloWorldをまとめてみた。modelgluetartan_example.txtをダウンロード

SeanCorfieldに紹介された応用アプリケーションggcc8のダウンロードはこちらから、どうぞ!

Model-Glue DTD#2

Model-Glue DTDで紹介したとおり、Model-Glue.xmlもXML DTDに対応する動きとなったことを紹介しましたが、Wayne GrahamがXML SchemaやRelaxNGに対応させる記事をポストしています。
対応するModel-Glueのバーションは0.9となっています。

XML Schema         :こちら
RelaxNG(Full)         :こちら
RelaxNG(Compact) :こちら


 




Model-Glue Viewデータのキャッシング

topica.comのModel-GlueのMLで、'Caching Content in MG'というタイトルでコンテンツのキャッシングに関するスレッドが立った。

解決方法は、ズバリ・・・
ModelGlue.Core.controller.cfc内のGetFromCache

ModelGlue.Util.TimedCache.cfc内のItemNotFound

ModelGlue.Core.controller.cfc内のAddToCache
を使う。つまり、
1.キャッシュしたいコンテンツ<"news">を定義し、
 <cftry>

   <cfset news =GetFromCache("news") />
2.次に、キャッシュの有無をチェックし、
   <cfcatch type="ModelGlue.Util.TimedCache.ItemNotFound">
3.例外が生じた場合、特定の処理を実施し、キャッシュに追加

     something query
     <cfset addToCache("news", news) />

       <cfcache />

  </cftry>

するようだ。

<cffunction name="GetNews" access="Public" returnType="void"
output="false" hint="I am an event handler.">
  <cfargument name="event" type="ModelGlue.Core.Event" required="true">

  <cfset var news = "" />

  <cftry>
    <!--- Try to get it from the cache --->
    <cfset news = getFromCache("news") />
    <!--- If it's not in the cache --->
    <cfcatch type="ModelGlue.Util.TimedCache.ItemNotFound">
      <cfquery datasource="foo" name="news">
        SELECT newsId, title FROM news
      </cfquery>
      <cfset addToCache("news", news) />
    </cfcatch>
  </cftry>

  <cfset arguments.event.setValue("news", news) />
</cffunction>

うーん、やはりModelGlueの内部をもう少し学ぶ必要がありそうだなあー。



 

Model-Glue DTD

Model-Glueの公式サイトに、Model-GlueのDTDに関するエントリーがVer1.0のリリースにあわせてポストされた。
Wayne Graham's blogのエントリーと併用するとModel-Glueのxml定義が楽になりそう。

<!ELEMENT modelglue (config,controllers,event-handlers)>
<!ELEMENT config (setting+)>
<!ELEMENT setting (#PCDATA)>
<!ATTLIST setting name CDATA #REQUIRED value CDATA #REQUIRED>
<!ELEMENT controllers (controller+)>
<!ELEMENT controller (message-listener+)>
<!ATTLIST controller name CDATA #REQUIRED type CDATA #REQUIRED>
<!ELEMENT message-listener (#PCDATA)>
<!ATTLIST message-listener message CDATA #REQUIRED function CDATA #REQUIRED>
<!ELEMENT event-handlers (event-handler+)>
<!ELEMENT event-handler (broadcasts*,views*,results*)>
<!ATTLIST event-handler name CDATA #REQUIRED access CDATA #IMPLIED>
<!ELEMENT broadcasts (message*)>
<!ELEMENT message (argument*)>
<!ATTLIST message name CDATA #REQUIRED>
<!ELEMENT argument (#PCDATA)>
<!ATTLIST argument name CDATA #REQUIRED value CDATA #REQUIRED>
<!ELEMENT results (result*)>
<!ELEMENT result (#PCDATA)>
<!ATTLIST result name CDATA #IMPLIED do CDATA #REQUIRED relocate CDATA #IMPLIED>
<!ELEMENT views (include*,value*)>
<!ELEMENT include (value*)>
<!ATTLIST include name CDATA #REQUIRED template CDATA #REQUIRED append CDATA #IMPLIED>
<!ELEMENT value (#PCDATA)>
<!ATTLIST value name CDATA #REQUIRED value CDATA #REQUIRED overwrite CDATA #IMPLIED>

 

Model-Glue.xmlの拡張

Sean Corfieldのブログで、Model-Glue DTD がVer1.0のリリースにあわせて検討されているらしい旨を書かれていたが、Ver1.0RC1では今だリリースされていない。
そんなところに、Wayne Grahamのブログで、modelglue.xmlに、DOCTYPEを定義して拡張する方法が記述されていた。

ポイントは以下のとおり。
1.modelglue.xml内に、DOCTYPEを定義する。
2.外部拡張用フォルダとして、wwwroot内(もしくは、マッピングフォルダ内)にtempletesフォルダを作成する。
3.templetes配下にmodelGlueアプリケーションフォルダ:stockQuateを作成し、三つの拡張xmlファイルを作成する。
 1)config.xml
  2)controllers.xml
  3)event-handlers.xml
4.model.glue.xmlの定義イメージは以下のとおり。

<!DOCTYPE  [
     <!ENTITY mapping
"/modelgluesamples">
     <!ENTITY appName "StockQuote">
     <!ENTITY folder "stockquate">
     <!ENTITY hello "HelloWorld">
     <!ENTITY config SYSTEM "http://localhost/modelgluesamples/templates/stockquate/config.xml">
     <!ENTITY controllers SYSTEM "http://localhost/modelgluesamples/templates/stockquate/controllers.xml">
     <!ENTITY events SYSTEM "http://localhost/modelgluesamples/templates/stockquate/event-handlers.xml">
  ]>
    <modelglue>
     &config;
     &controllers;
         &events;
  </modelglue>

5.config.xmlの定義イメージは以下のとおり。

<?xml version="1.0" encoding="UTF-8"?>
  <config>
              <setting name="defaultEvent" value="&appName;" />
              <setting name="applicationMapping" value="&mapping;/&folder;" />
              <setting name="beanMappings" value="&mapping;/&folder;/config/beans/" />
              <setting name="viewMappings" value="&mapping;/&folder;/views" />
              <setting name="reload" value="false" />
              <setting name="reloadKey" value="init" />
              <setting name="reloadPassword" value="true" />
              <setting name="statePrecedence" value="Form" />
              <setting name="eventValue" value="event" />
              <setting name="modelGlueMapping" value="/ModelGlue" />
              <setting name="defaultExceptionHandler" value="Exception" />
              <setting name="debug" value="true" />
              <setting name="defaultCacheTimeout" value="5" />
       </config>

6.controller.xmlの定義イメージは以下のとおり。

<?xml version="1.0" encoding="UTF-8"?>
  <controllers>
      <controller name="myController" type="&mapping;.&folder;.controller.Controller">
          <message-listener message="OnRequestStart" function="OnRequestStart" />
          <message-listener message="OnRequestEnd" function="OnRequestEnd" />
          <message-listener message="DoHelloWorld" function="GetGreeting" />
          <message-listener message="DoStockQuote" function="GetStockQuote" />
      </controller>
  </controllers>

7.event-handler.xmlの定義イメージは以下のとおり。

<?xml version="1.0" encoding="UTF-8"?>
  <event-handlers>
      <event-handler name="Home">
          <results>
              <result do="Layout" />
          </results>
      </event-handler>
            <event-handler name="&hello;">
          <broadcasts>
              <message name="DoHelloWorld" />
          </broadcasts>
          <views>
              <include name="content" template="dsp.helloworld.cfm">
                  <value name="greeting" value="I am the default greeting." />
              </include>
          </views>
          <results>
              <result do="Layout" />
          </results>
      </event-handler>
            <event-handler name="&appName;">
          <broadcasts>
              <message name="DoStockQuote">
                  <argument name="DefaultSymbol" value="MACR" />
              </message>
          </broadcasts>
          <views>
              <include name="content" template="form.&folder;.cfm" />
          </views>
          <results>
              <result name="BadSymbol" do="BadStockSymbol" />
              <result do="Layout" />
          </results>
      </event-handler>
            <event-handler name="BadStockSymbol" access="private">
          <views>
              <include name="content" template="dsp.badStocksymbol.cfm" />
          </views>
      </event-handler>
            <event-handler name="Layout" access="private">
          <views>
              <include name="main" template="layout.main.cfm" />
          </views>
      </event-handler>
            <event-handler name="Exception">
          <views>
              <include name="body" template="exception.cfm" />
          </views>
      </event-handler>
  </event-handlers>

ModelGlue Ver1.0RC1

Model-GlueのVer1.0のRC1がここから入手できます。
ダウンロードするには、SVNクライアントが必要なようです。


Model-Glue+Tartan

Sean Corfieldの記事にあったサンプルアプリケーションGGCCをModelGlue+Tartanに移植してみた。
移植に際してのベースアプリケーションは、GGCC7(ModelGlue)+GGCC6(FuseBox4.1+Tartan)。
動作確認済コードは、GGCC8です。興味のある方はこちら から、どうぞ!

FuseBox4.1+Tartanの動作環境から大きく変更したポイントは以下のとおりです。

  1. LocalService.cfc内FunctionのReturnTypeを"void"から"struct"に変更
  2. ModelGlue用Controllerのinit( )FunctionにtartanProxyの初期化ブロックを追加。
  3. ModelGlue.xml内<broadcasts>セクションから、needMemberByIDとneedStatiiByIDをコメント化。

詳細は、ぼちぼちご案内します。

 

Mach-IIは死んだ?

Sean Corfieldのブログでは、最近"Mach-IIが死んだ""Mach-II退場、ModelGlue入場"を意味するような記事やタイトルが飛び交っている。私も昨年からMach-IIのドキュメントを読みあさったりしていたのだけど、なかなかサンデープログラマーには敷居が高くて、なかなかサンプルアプリケーションを作り出せずにいた。
でも、Model-Glueに接していらい、Mach-IIから乗り換えることに決めた。

先日、SeanがFuseBoxベースのCatClubというプログラムを、Mach-II、Model-Glueに移植した例を彼のブログに掲載した。確かにModel-Glueが一番エレガントだ。今後は、Model-Glue+TarTanが主流になると思う。

Model-Glue Ver0.9リリース

Sean CorfieldのAn Archtecture's ViewModel-GlueのVer0.9がリリースされた旨のアナウンスがありました。
今回のリリース内容は以下のとおりのようです。

  1. Controllerがタイムキャッシュももてるようになった。
  2. サブアプリケーションのサポート(ModelGlue_APP_KEY)
  3. eventオブジェクトにデバックトレースが追加された。
    • arguments.event.trace(label, value)
    • 任意形式の値
    • CFDump結果同様に扱えるようになった。
  4. デバッグトレースは、例外が発生したときのみ表示するようになった。

Mach-IIとModel-Glue(続き)

Sean Corfieldが、Mach-IIとModel-Glueに関する記事の続きを書いた。

More thoughts on Mach II and Model-Glue
Mach-II アプリケーションのModel-Glueへの移管でわかったこと。

総じてModel-Glueの長所を言及している。

1.event-handlerの定義がMach-IIとModel-Glueで異なる。ちょっと混乱?
    Mach-II          <event-handler event= ... >
    Model-Glue    <event-handler name=... >
2.シンタックスの構造化とシンプルなタグ
    Mach-II           フラットシンタックス
         event-handlersセクション:連続した1行単位のXMLタグ

              event-handlerセクション

                   event-mappingセクション
                   event-argsセクション
                   notifyセクション
                   annouceセクション
                   filterセクション

    Model-Glue    ネステッドシンタックス

         event-handlersセクション:ネストされ、インデントされ構造化されたXMLタグ
              broadcastsセクション
                   messageセクション   
              viewsセクション
                   includeセクション
              resultsセクション
                   resultセクション

結果として、Mach-IIと比較して、Model-Glueのほうが、コントロールロジックとプレゼンテーションロジックを明確に分離でき、eventオブジェクトをデータバスとして一貫して使用できる・・・

3.リスナー定義数の削減
    Mach-II            25個のListnerCFCs
    Model-Glue        6個のControllerCFCs
4.ちょっと困ったこと
    notifyセクションとview-pageセクションの組合せで実現できていたビューの結果をMach-IIではビジネスロジック中で使用できていたが、Model-Glueでは代替手段(Cfsavecontent)を使うことでしかできない。

5.総括:Model-Glueがいい!
    There's no doubt that Model-Glue has benefitted from the experiences of both Mach II and Fusebox but it has also added its own unique elements. Consistency and simplicity are key drivers for Model-Glue which means you sacrifice some power and expressiveness. As always, it's all about tradeoffs and you need to make the choice based on the needs of your project (and, to some extent, your own personal preferences).

Mach-IIとModel-Glue

最近は、Model-Glueのマニュアルの日本語化を通じてModel-Glueの概要を作成していた。
Model-GlueってMach-IIより敷居が低くて結構使えるなーって思いつつ会社の新しい業務プロセスに応用してみようと思っていたところ、Sean Corfieldがブログでそのことを言及していました。

MachII OUT, Model-Glue In!
MacromediaのWebチームのスタンダードになっているMach-IIは、アプリケーション構造、コントロールフローがmacii.xmlファイルに書かれているので、メンテナンス性が悪い。いわば、コンテナのマネージメント:"Inversion of Control"(制御の逆転)を行うため、Model-Glueへの移行を検討した。

Mach-ii.xml file:
    522行, 23Kバイト(XML圧縮後), 25個のListner定義
ModelGlue.xml file:
    427行, 11Kバイト(XML圧縮前), 6個のController定義、5個のConfigBeanCFCs、
    22個のBean定義ファイル(710行, 16Kバイト).

早速、Mach-IIとModel-Glueの比較をビジュアル化してみようと思う。

CFMX開発 フレームワーク比較表2

CFMX用フレームワーク比較表で、Fusebox、Mach-II、Model-Glueの比較をしていたことを思い出して、もう比較表を見直してみました。
やっぱり、Fuseboxは敷居の低さ、Mach-IIはプロフェッショナル用、Model-Glueは両方のいいとこ取りって感じです。

各比較項目のうち、1行目は共通点、2行目以降は差異点です。
(以下、各フレームワークの略称 FB:Fusebox/M2:Mach-II/MG:Model-Glue)

・XML
All use XML config files
FB has multiple XML,  M2/MG has one XML
・MVC
Can use MVC
FB allows but does not enforce, M2/MG pretty much forces it
・MVC Structure
Model/View directories
FB typically has controller circuit directory, M2/MG has implicit controller in framework
・CFCs
Can use CFCs
FB allows but does not enforce, M2/MG pretty much forces it
・Plugins
All have plugin points
FB has more plugin points, M2 distinguishes events and views, MG has simple request/queue model
・Access control
All have private / public concepts
FB has per circuit and per fuseaction as well as roles-based model, M2/MG has per event access only
・Auth / Security
None
FB has roles support builtin, M2 provides a sample filter, MG is free form
・Install / Config
One-stop core files, basic properties in XML file
One-stop core files is brand new in FB41, FB provides finer control over framework behavior, MG has a simple framework control model
・Modularity of Application
None
FB has circuits to partition large applications
・Modularity of Site
None
M2 allows multiple sub-applications to share application scope
・Commonality
Can explicitly invoke fuseactions / announce events / add results to handle common functionality  FB has per-circuit pre-/post-fuseaction hooks, providing framework level support for commonality
・Views
All encourage views to contain “only HTML” (no logic)
FB/MG lets you include a view directly, M2 requires that you declare all views in XML
・Handler Model
All declare 'handlers' for 'events' in XML
FB is a static, explicit invocation model, M2 is a dynamic, implicit invocation model, MG is somewhere in between
・Data bus
Can use request scope as data bus (but it's not always best practice) – MG uses event object   FB allows variables scope as data bus, M2 allows event object as data bus, MG enforces event object as data bus
・Global data
None
FB has fusebox.init.cfm, M2 uses either 《property》 tags or plugin (or both), MG has settings
・Model CFC Structure
Most CFC methods could be the same
FB uses standard init() construction controlled by explicit code in fusebox.init.cfm or circuit, M2 reserves init() and uses a managed configure() method to initialize CFCs – with no arguments – and CFCs must extend the framework, MG has base controller init() method
・Conditional logic
None
FB has some conditional logic in the XML grammar, M2 requires conditional logic placed in CFCs, MG requires controller CFCs
・Model Actions
All have the concept of separating business model logic from presentation logic
FB allows a model action to set multiple outputs, M2 uses strict call/return semantics so each action can have only one result, MG allows a model to set multiple outputs via event object
・Model Queries
None
FB specifically separates out persistence operations (by a naming convention on files), M2/MG draws no distinction between actions and queries

ちょっと長かったかな?

CFMX開発 Model-Glue

Tartanのことを調べていたら、Model-Glueにたどり着いた。
確かに、一回目の記事で、Coldfusion用フレームワークのひとつとしてSeanの記事を引用していたのだけど、Model-GlueがTartanの機能を包含しているようだ。

There's been a lot of talk about using ColdFusion Components (CFCs) to seperate presentation layer from business logic. Model-Glue facilitates this by giving you an easier, more powerful way to connect your presentation layer (View) from your business logic (Model). It does this by letting you create what are called "Controllers", and then letting you define how they interact with the presentation layer (We're calling it View from now on!) through a simple XML schema.

Model-Glue also provides a configuration utility for your applications called ChiliBeans. It makes it easy to offload configuration information (like development datasource vs. production datasource) into XML files. More on that in another Quickstart.

Mach-IIの思想を取り入れつつ、Fuseboxの敷居の低さを追求しているのだろうか?もう少し調べてみよう。

ログイン

  • コントロールパネルへのログイン
    アカウント:

    パスワード:

PR情報

  • [[PR]]
  • おすすめバナー

更新ブログ

google Search

  • Google
    blog.ganymean.org
    WWW

最近のトラックバック

Google

SHINOBI

Blog powered by TypePad
Member since 04/2005