ありゃりゃ. 困ったもんだな.
test 環境だとどうもドメイン・オブジェクトの delete() がまったく効いていない模様...
MacOSX 10.4.9 / Java 1.5.0_07 / Grails 0.5
2007年6月10日日曜日
delete won't work for test env.
WicketBuilder
さて, いよいよ Wicket Builder を作らねばならぬか, と腰を上げかけて, もしやと思い直して探してみると, あ~るじゃありませんか, Wicket Builder.
http://wicketstuff.org/confluence/display/STUFFWIKI/WicketBuilder
http://bigheadco.blogspot.com/2007/03/wicket-and-groovy.html
しかし, SourceForge を見に行っても, 肝心の wicket-1.3 というブランチは存在しない模様... orz.
しばらく待ちますか...
2007年5月30日水曜日
grail-0.5 bookmarks
杉浦さん@それなりの日記の記事に付け加えて...
grails-0.5 の例題として付いてくる bookmarks を動かすには, 以下のプラグイン
- http://grails.org/XFire+Plugin
- http://sky.geocities.jp/acegiongrails/
% cd .../bookmarks
% grails install-plugin .../grails-xfire-0.5.zip
% grails install-plugin .../grails-Acegi-0.1.zip
すると, run-app できるようになる (それでもなんだか例外を吐いているようだけど:-)
grails-0.5 では 今までの domain-class と同じように hibernate annotation を処理できるようだ (実際ちゃんと永続化されているように見える). ただしそのためには, Java でアノテーション付きのコードを書かないといけない (.../src/java/org/grails/*.java). もっともアノテーションの処理は hibernate に任せているようで, grails のコードにはない.
SS2007
えーと, 告知です...
6 月 27日 (水) から 29日 (金) の三日間にわたって, 新潟市朱鷺メッセで「ソフトウェア・シンポジウム 2007」が開かれます.
初日 27 日に不肖山田が, 2 時間程度のチュートリアル「日常会話的モデル駆動開発 (Groovy/Grails を使ってみる) 」をやることになっています.
中日 28 日は各ワークショップに分かれて一日中議論を行います. 山田はモデリング・ワークショップに参加します.
参加受付は http://www.sea.jp/Events/symposium/ss2007/ss2007cfp.html, 詳細は SS2007 Portal をご覧ください.
日々の業務の中で何か納得のいかないものを抱えている方, このまま行ったらこの業界先はないぞと考えている方, あんまり大きな声では言えないこんな面白い話があるんだけどさという方, どなた様も参加をお待ちしています.
2007年5月29日火曜日
GrailsPlugin のプロパティ
GrailsPlugin のプロパティを GrailsPlugin.java からまとめておく. ただしドキュメントとは幾分異なっている. 5.5 辺りで実装される予定らしい.
- doWithDynamicMethods
- 実行時にメソッドを inject するために呼ばれるクロージャ.
- watchedResources
- このプラグインが変化を監視するリソース.
- evict
- このプラグインが立ち退かせるプラグインのリスト. 立ち退きは PluginManager がロードするときに行われる.
- status
- このプラグインの状態. "enabled" (ロードされる), "disabled" (ロードされない)
- influences
- このプラグインが影響を与えるプラグインのリスト. 監視しているリソースが変化すると, 影響を及ぼすプラグインは refresh() される.
- onChange
- 監視しているリソースが変化したときに呼ばれるクロージャ.
- doWithWebDescriptor
- web.xml の作成時に呼ばれるクロージャ.
- version
- このプラグインのバージョン.
- doWithSpring
- Spring の実行時コンフィギュレーションが行われるときに呼ばれるクロージャ.
- doWithApplicationContext
- 初期化が終わり, アプリケーション・コンテキストが確立したときに呼ばれるクロージャ.
- dependsOn
- このプラグインが依存している他のプラグイン.
- artefacts
- このプラグインがサポートする ArtefactHandler のリスト.
grails-wicket plugin を読む (3)
さて, メタオブジェクトの迷宮からようやく戻ってきた. 残りは wicket を動かすための手続きを grails のコードとして書いているだけだ. WicketGrailsPlugin.groovy に戻ろう.def doWithSpring = {
def applicationClass = application.allClasses.find { Application.class.isAssignableFrom(it) }
if(applicationClass) {
applicationBean(applicationClass)
}
}application
が GrailsApplication
だということが分かった. そうするとここには「この Grails アプリケーションが持つ (ロードした) すべてのクラスの中で wicket.Application
クラスと (ほぼ) 同じクラスがあれば, それを applicationBean
としてインスタンス化する (ここで Spring Bean Builder を使っている)」と書いてあることになる. その「wicket.Application
クラスと (ほぼ) 同じクラス」というのが, grails-app/controllers/WebApplication.groovy
なわけだ.def doWithWebDescriptor = { xml ->
def servlets = xml.servlet[0]
servlets + {
servlet {
'servlet-name'('wicket')
'servlet-class'('wicket.protocol.http.WicketServlet')
'init-param' {
'param-name'('applicationFactoryClassName')
'param-value'('wicket.spring.SpringWebApplicationFactory')
}
'load-on-startup'(1)
}
}
def mappings = xml.'servlet-mapping'[0]
mappings + {
'servlet-mapping' {
'servlet-name'('wicket')
'url-pattern'('/app/*')
}
}
}doWithWebDescriptor
は (アプリケーション起動時に Grails によって動的に作られる) web-app/WEB-INF/web.xml
に関するクロージャ. web.xml の作成時に呼び出され, web.xml に以下を付け加える.<servlet>
<servlet-name>wicket</servlet-name>
<servlet-class>wicket.protocol.http.WicketServlet</servlet-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>wicket</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
こんなくそ XML を書かずに済んでいるのは Groovy の Markup Builder のおかげだ.
で, この plugin がやっているのはこれだけ. つまり普通の J2EE アプリケーションで Wicket を使うときにやる設定の手続きを WicketGrailsPlugin.groovy
に書いているのだ. 後は grails の枠組み (特に GORM) がすべてそのまま使えている.
よくできました.
grails-wicket plugin を読む (2)
2回目. ここでは実は "Convention over Configuration" の実態が実は, grails がインタプリタ (メタオブジェクト) の集合になっていることだというのが分かる. ではいってみよう...
プラグイン定義クラスの規約を決めているやつは, 実はここにいる.
org.codehaus.groovy.grails.plugins.GrailsPlugin
Java インタフェースだが, スーパーインタフェースは Spring Framework の中にある ApplicationContextAware
. ApplicationContextAware
を実装するクラスは Spring Framework の恩恵を得ることができる, ととりあえずは思っておく.
GrailsPlugin には「規約」に相当する (≒ Java Interface に相当する), つまりプラグイン定義クラスで def すべきプロパティが文字列として定義されている. 例えばString DO_WITH_DYNAMIC_METHODS = doWithDynamicMethods;
String WATCHED_RESOURCES = watchedResources;
String EVICT = evict;
// ......
また実装クラスはそれらプロパティへのアクセッサを定義しなさい, となっている. 例えばvoid doWithWebDescriptor(GPathResult webXml);
String getName();
String getVersion();
// .......
つまり GrailsPlugin の実装クラスは, プラグイン定義クラスのインタプリタなのだ!
GrailsPlugin を実装しているのは
org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin
で, つまりプラグイン定義クラスのインタプリタのひな形というわけ. これはさらに AbstractGrailsClass
のサブクラスになっている. AbstractGrailsClass
は Grails 全体で使われる汎用インタプリタのひな形だ. AbstractGrailsClass
のサブクラスには他に DefaultGrailsDomainClass
などがあるが, これはドメイン・クラス定義クラスのインタプリタということになる.
org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin
は AbstractGrailsPlugin
を具体化したもの, つまりデフォルトのプラグイン定義クラス・インタプリタと言える. この中身を見てみると, new するときには対象となるプラグイン定義クラス (例えば WicketGrailsPlugin
) が渡される. これがつまりインタプリタに与えられるプログラムということになる. このプログラムのシンタックスは前述の GrailsPlugin
が決めているわけだ.
だから, プラグイン定義クラスに定義されていない変数 application
が出現したとしても, それをどうするかはインタプリタの都合次第ということになる. インタプリタの中を見てみると application
という変数には GrailsApplication
が入っている (doWithRuntimeConfiguration() メソッド内). 他にもこのクロージャの中では manager, plugin, parentCtx, resolver
という変数が使えることが分かる.GrailsApplication
は多分 Grails アプリケーションのファサードだろうと想像がつく. けど, これが実際にどんな変数とメソッドを持っているかは, GrailsApplication
の JavaDoc のようなドキュメントかソース・コードを見ないと分からない. そこが Grails の弱点だとは思う. つまりインタプリタの世界 (Java) とプログラムの世界 (Groovy/Grails) が分離している. だから何かしようと思うと二つの世界を行ったり来たりしなければならないことになる. Lisp や Smalltalk だとこの二つの世界は同じ言語で記述され, かつ優秀な開発/デバグ環境が存在するのだが...
ちなみにここで「インタプリタ」と呼んでいるものは「メタオブジェクト」と呼び変えてもよい. オブジェクトの挙動を決めているオブジェクトだから.
続く...