第6回grails code readingにご参加いただいた皆さん, 有り難うございました.
今回は年末ということもあって, 人数は少なめでしたが, 内容はとってもホットでしたよ.
来られなかった人は残念というほかありませんが, 有り難いことに資料, コードは
http://groups.google.com/group/grails-ja
に上げていただいています.
リーダを努めて下さった須江さん, 有り難うございました.
さて, 次回第7回は1/28 (月) にいつもと同じ場所 (横浜CIJ), 時刻 (19:30) で行います.
内容は, 山田がリーダでView周り (GSP, taglib) を読みます.
というわけで, 残念ながら内容は浅いですが orz, みんな来るべし.
2007年12月24日月曜日
第6回 grails code reading 終了
オープンソースな grails/groovy アプリケーションの例
この間, 山本さんから教えてもらったのを含めて, grails/groovyを使ったアプリケーションの例を挙げておく.
CoW
Gravl
wiki engine. けど, なにやらけったいなもの (オントロジとか:-) をいっぱい詰め込もうとしているようで, 多分あまり実用を目的としていないと推測される. まだバージョンは0.1だし (嫌いじゃないけど).
ここまではgrailsベースのアプリケーションで, まだ開発途上.
1000行で書くblog engine. Glen Smithがやっているプロジェクトで, 期待大. 彼のブログも面白いし, pebble使っているところも「お, 分かってるじゃん」って感じで:-)
Woko
そのうち, 山本さんが1時間で作ったという, 辞書アプリケーションも登場するでしょう. 合木さんの掲示板はどうかな.
これは面白い! 一言で言えば, Java版Zopeというか, POJOをそのままCRUDビューを自動生成して, Webアプリケーションとして公開するプラットホーム. それが何でここに出てくるかというと, CRUDのビューをユーザがWeb上で (ランタイムに) 拡張できるんだけど, そこでgroovyが使えるのだ. こんなのはgrails上でもひとつ欲しいところだ (いろいろいじってはいるんですけどね). searchable pluginとか, feeds pluginとか組み合わせて, CRUDを頑張ればできそうだよね.
2007年12月23日日曜日
Composition on Grails by SAP
ちょっと古いですが (2008.12.19), grailsを作っているGraemeが自分のblogにこんな記事を書いています .
「SAPがComposition on Grails 1.0を発表したよ」
元記事をたどってみるとこれです.
NetWeaverというSAPの基盤となるプラットホームを利用するWebアプリケーションをgrailsで書けるというのが, Composition on Grailsみたいです. 出しているのはSAP自身ですが, 将来, 正式な製品とするかどうかは未定, とりあえずコミュニティの反応を見たいといっています.
ベースはgrails-1.0-RC2で, 今のところ, ちゃんとついていっているみたい.
世の中にはこういうこともあるですよ.
2007年12月1日土曜日
NetBeans + grails/groovy
NetBeans6.0ではgrails/groovyプラグインが公式に用意される(といってもデフォルトでは含まれない). 6.0は11月中にリリースされる予定だったけど, 12月に延期された. 今普通に配られている6.0RCではだめ. 正式な6.0が出たらまた書く.
というわけで, 12/4に出たのですが, ダメですね. NetBeans6とgrails/groovyプラグインの組み合わせは現時点ではcreate-appさえできない状態です... GUIも2秒待たされる感じだなぁ. (on MacOSX 10.5.1)
Leopard + grails-1.0-RC1
Leopard + grails-1.0-RC1だと, そもそも% grails ...の段階で引っかかる.
.../bin/startGrailsの
MAX_FD_LIMIT=`ulimit -H -n` (155行目)の次に以下の行を追加し,
if [ "$MAX_FD_LIMIT" != "unlimited" ]; then
warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT" (168行目)の次に以下の行を追加する.
fi
これはRC2では修正済み.
日本語を使うためのおまじないはまだ必要のようだ.
2007年11月30日金曜日
第6回grailsコード・リーディング
第5回grailsコード・リーディングは盛況のうちに終了しました.
リーダを勤めていただいた山本さん, 会場や懇親会のセッティングをしていただいたCIJの皆さん, 参加していただいた皆さん, 有り難うございました.
さて, 次回のお知らせをさくっとしておきます.
次回は12/21(金), 19:30から2時間程度, 今までと同じ横浜CIJ本社にて行います. 終了後は同じ場所で忘年会を行う予定です.
内容は須江さんをリーダとして, WebFlow関連部分を読みます.
詳細はgrails-jaで, またお問い合わせはgcr@metabolics.co.jpまで.
なお, 今まで半年間は横浜でやってきましたが, 「横浜まで行くのはちょっと遠い」「うちの近くでやってほしい」「場所は提供できる」という方がありましたら, ご連絡くださいませ.
2007年11月12日月曜日
第 5 回 grails コード・リーディング
第 5 回 grails コード・リーディング を 11/29 (木) 19:30 から横浜 CIJ 本社で開催します.
今回は山本さん@ニューキャストをリーダに grails プラグインの実例を読みます.
山本さんの Grails eXchange 2007 での講演の再現なるか?! (もちろん日本語)
関心のある方はどなたでもご参加いただけます.
詳細は grails-ja でご覧下さい.
皆さんのご参加をお待ちしております.
2007年11月5日月曜日
grails plugin
10/31 の grails code reading で, plugin 周りのコードをとりあえず読んだ. そのときの資料はこちら. まぁきりがないのだけれど, 風邪の体と冴えない頭と足りない時間の間で折り合いを付ける.
その後は山本さんと上原さんの Grails Exchange 2007 の帰朝報告会もあり, grails 本や JGGUG の打ち合わせもし, その他いろいろ面白くなりそうな話もあり. うっしっし.
次回は 11/29 (木) 横浜. リーダは山本さんで, 内容は彼自身が書いた acegi plugin. 刮目して待て.
# 次回辺りは久しぶりに全員の自己紹介/近況報告もしようか.
# 横浜以外の場所も考えた方がいいのかなぁ.
2007年9月23日日曜日
grails on Agile Knowledge
エンタープライズ・アジャイルをまとめるつもりながら開店休業状態だった Agile Knowledge に, grails コード・リーディングのネタを書き始める. とりあえずは 9/19 に使うつもりだったネタを.
# Snip Snap が使うポート 8668 が開いてなくて... 80 にマッピングすればいいのだが...
# MediaWiki はもともとそうだからしようがないんだけど, 「書籍」的に書くのには使いにくい.
grails コード・リーディングのネタだけでなく, grails 本の素材を溜めていこうかと.
<追記>
今はこれはここにあります.
2007年9月3日月曜日
第 3 回 grails コード・リーディング
さて, 第 3 回 grails code reading のご案内です.
------
日時: 9/19 (水) 19:30 - (多分 2 時間くらい)
場所: CIJ (http://www.cij.co.jp/map/ykhm.html) (横浜駅徒歩10分ほど)
(当日 7 階受付に案内の者がいるはずです)
対象: grails に興味のある方ならどなたでも
目標: grails をよりよく使うためのノウハウを参加者で学習/共有する
費用: 不要 (懇親会は別途)
準備: できれば grails-0.6 のインストール済/可能なノートPC
内容: grails-0.6 を動かしながら, なぜ動くのかを少しずつ探っていきます.
当日連絡先: 045-324-0111 石田 (19:30 以降は内線 7912) または 090-6486-7624 山田携帯
------
第 2 回は groovy の簡単な復習をしました.
第 3 回から grails の世界に入っていきます.
着実に進化していますよ! 今からの参加でもぜんぜん大丈夫!
前回は懇親会を教室でやりましたが, 次回は気分を変えてお店に行こうと思います.
ただ, 時刻と人数から言って人数を確定しないとお店を押さえるのが難しいのです.
なので,
=== 重要 ===
懇親会に参加希望の方は遅くとも 9/17 (月) 中までに http://groups.google.co.jp/group/grails-ja 宛に「懇親会参加希望」の旨のメイルをください.
=== 重要 ===
コード・リーディングそのものは当日ふらりと来ていただいても構いませんが, http://groups.google.co.jp/group/grails-ja に前もって参加表明を頂けると有り難いです.
皆様の参加をお待ちしています.
grails-0.6
プロジェクトを 0.6 に上げた.
(少なくとも一部の単体テストは) 驚くほど速くなっている. 一桁くらい...
つまり十数分かかっていたテストが, 数十秒で終わるようになった, という... 喜んでいいのか, 今までが情けなさ過ぎだ.
それから, 非 grails 環境から grails の domain class が扱えるようになった! これでようやく jbpm などとつなぐことができる! というか, この一週間の苦労は何だっただろうか...
まだ問題も山積みだけど, 後は 1.0 に向かって成功を祈るしかないね.
2007年9月1日土曜日
domain class をパッケージに入れる
のが, どうやら 0.5.5 以降可能になっているようだ.
package foo.bar
などという宣言を入れればよい. もちろん create-domain-class で生成されるのはデフォルト・パッケージに入るコードなので, この宣言は手で入れる.
パッケージに入った domain class に対応する controller の方は今まで通りすべてデフォルト・パッケージに置く. したがって domain class の名前はパッケージを除いて一意でなければならない. controller の中では
scaffold = foo.bar.Baz
などと書けばよい.
だいたいうまく動いているようだけど, web-app/WEB-INF/classes の下に作られる foo/bar/*.class が消えないで, ソース・コードを変更しても反映されなくてびっくりさせられる. とりあえず忘れないように手で消しているけど...
2007年8月14日火曜日
MacOSX で IntelliJ で grails
IntelliJ の新しいバージョン (7) も着々とリビジョンを上げている (7126) が, 体感的にはなかなか厳しいところもある今日この頃である.
ところで MacOSX 上の IntelliJ (7.0-M2) で grails を run-app したときに "Environment variable GRAILS_HOME not set." などと文句を付けられたら, 以下のようにすると幸せになれるかもしれない.
% mkdir ~/.MacOSX
% cd ~/.MacOSX/
% cat > environment.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://
www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>GRAILS_HOME</key>
<string>/path/to/grails/home</string>
</dict>
</plist>
^D
少なくとも一度再ログインが必要.
困ったやっちゃ.
# これは grails や java に依存しない, MacOSX の tips.
# もちろん PropertyListEditor.app などを使ってもよい.
2007年8月6日月曜日
第2回 grails code reading
第1回に引き続き, 第2回 grails コード・リーディングを行います.
実質的な内容は最初ということになります. まずは Groovy のお勉強をざっとします.
------
第 2 回 grails コード・リーディング
日時: 8/24 (金) 19:30 - (多分 2 時間くらい)
場所: CIJ (http://www.cij.co.jp/map/ykhm.html) (横浜駅徒歩10分ほど)
(当日 7 階受付に案内の者がいるはずです)
対象: grails に興味のある方ならどなたでも
目標: grails をよりよく使うためのノウハウを参加者で学習/共有する
費用: なし (懇親会は別)
準備: テキストとして groovy-little-book の日本語訳 (http://grails-ja.googlegroups.com/web/groovy-little-book.pdf) を使うので, ざっと目を通して来てください. 当日手元にあると便利だと思います.
内容: まずは groovy のおさらい
当日連絡先: 045-324-0111 石田 (19:30 以降は内線 7912) または 090-6486-7624 山田携帯
------
http://groups.google.co.jp/group/grails-ja を本拠地としていますので, こちらに参加表明いただければと思いますが, もちろん当日ふらりと来ていただいても構いません.
皆さんの参加をお待ちしております.
2007年7月28日土曜日
第1回 grails code reading 終了!
第1回 grails code reading は 20 名以上の参加者を迎えて, 無事終了しました. 参加者の皆さん, 有り難うございました. みんな終電近くまで飲んでいたのですが, 無事帰れたでしょうか?
内容は
- 自己紹介
- これからどうするか?
- 時間が余ったので山田のソフトウェア・シンポジウム 2007 での grails チュートリアルの超短縮版再演.
で, 決まったことは
- 今後メイリング・リストには http://groups.google.co.jp/group/grails-ja を使うので, 参加 (希望) 者はこれに登録する
- 次回はここに山本さんがアップロードしてくれた groovy-little-book を読みながら, groovy の基礎体力を付けるので, 目を通してくる
- 次回は 8/24 (金) 19:30 から, 場所は第1回と同じく CIJ 横浜本社
2007年7月18日水曜日
2007年7月14日土曜日
IntelliJ IDEA を使う
eclipse で grails を扱うにはどうにももどかしい. ほとんど emacs でやってきたけどちょっと限界っぽい.
ので IntelliJ IDEA を使ってみることにした.
本体 (Selena と呼ばれる version 7 の未公式リリース) をここから, groovy/grails プラグインをここから持ってくる (JetBrains にあるものよりこっちの方が新しかった).
JetGroovy プラグインは IntelliJ IDEA を展開したフォルダの plugins の下に展開する. この辺は eclipse と同じ.
さて IDEA を立ち上げてみる. まずは
- File | Settings ... の IDE Settings の
- Groovy/Grails から Groovy と Grails のインストール場所を設定して (grails の開発だけならば, groovy の設定は多分要らないだろう),
- General から File Encoding の Default encoding を UTF-8 にして,
- 再起動する
- File | New Project ... して,
- JavaVM を指定したりなどしてウィザードを進めていくと,
- 最後の方でモジュール・タイプを指定するところがあるので Grails Application を指定する
- "% grails run-app" が行われてプロジェクトができあがる
- Run | Edit Configuration ... して,
- "+" をポチッとして,
- Configuration Type に Run Application あるいは Run Test を設定すると,
- IDEA の run または debug で "% grails run-app または test-app" が IDEA 内部で走るようになる
- プロジェクトを右クリックして New | Groovy | Grails Domain Class,
- ドメイン名 (例えば book) を入力すると,
- ドメイン・クラス Book.groovy が生成されて, エディタに表示される.
- ついでになぜか BookController.groovy も静的に (つまり各 action 込みで) 生成されちゃうのがうっとうしいけど.
- これに関しては File | Settings ... | IDE Settings | Files Templates で JavaEE | Groovy と来れば, テンプレートを変更できる. この生成は grails のものじゃなくて, IntelliJ 側でやっていたのね...
コード補完は大して効かない (これは仕方ない. ワード補完すれば多少は楽). emacs 風キー・バインディングも eclipse に較べていまいちの感がある.
けど eclipse よりストレスはだいぶ少ない. この plugin を提供しているのは IntelliJ 本体を作っているのと同じ JetBrains だし. IntelliJ 自体は eclipse のようななんでもありとは違うけど, 玄人筋の評価は割と高い.
これに $250 (Personal Edition) あるいは $500 (Enterprise Edition) 払うか? 払ってもいいかな...
# とりあえず 30 日間は使えます.
# こういう変態な言語の開発環境は最終的には自分 (groovy/grails) 自身で書くしかないのかも.
2007年7月6日金曜日
grails に関する五つの誤解
grails に関する5つの誤解を grails の中心的開発者のひとり, Graeme Rocher が自分の blog に書いている. 特に grails は業務系で実際に使われることを目指しているのであって, Rails のクローンではない, というのがおもな主張だ.
Graeme の書いた「Grails に関する五つの誤解」を大急ぎで, およそのあらましだけを訳しておく.
1) JRuby on Rails があれば Grails なんて要らないじゃん.
だから Grails のゴールは Rails とはぜんぜん違うんだって. Grails のゴールは実績のある Java コンポーネント (Hibernate, Spring, ...) を統合して, DRY (同じコトは二度しない) の原則に従って使いやすくすること. 焦点は Java にある. Rails とは違って, あらゆる J2EE コンテナで動かせる.
2) じゃあ Java でいいじゃん, Groovy なんかじゃなくて.
だから Groovy は Java の替わりをしようとしているんじゃないって. Java は複雑なロジックや低レベルなアルゴリズムを書くのにはいいけど, 高レベルのところは Groovy で書いた方が絶対にいい. 両方が共生することによって新しい力が生まれる.
3) なんでエンタプライズ系には Rails より Grails がいいの?
理由はいっぱいあるけど, 最大の理由は Hibernate & Spring だな. それに較べると Rails は EJB2 っぽい. ActiveRecord とかに縛られちゃうでしょ. ドメイン・モデルの存在も大きい.
4) Groovy/Grails は Ruby/Rails に較べれば信頼性の低い競争相手じゃないか?
確かに Groovy/Grails は新しくて, ユーザ・ベースも少ない. でも Groovy/Grails はものすごく信頼性が高いフレームワーク上に作られている. もう一つはどこで戦うかということだ. Groovy/Grails には二つのゴールがあって, その一つは Java コミュニティが作ってきたプラットホーム, 技術, ツールを活かして, 簡単でエレガントで DRY な Web フレームワークを作ること. もうひとつは Java で Web アプリケーションを作るときの敷居を低くしたいということ. 相反する要求だけど, 今のところうまくやっていると思う. 今は個人や小さい会社が中心だけど, これからはもっと大規模開発にも適応していくだろう.
5) Sun は Ruby をバックアップしているぜ?
確かに Sun は JRuby が動くように手助けしている. でも僕の答えはこうだ. 最高のものは滅多に Sun から出てこない.
2007年7月4日水曜日
第 1 回 grails コード・リーディング
grails は groovy という Java VM の上で動く動的オブジェクト言語を用いた, アジャイルな Web アプリケーション開発環境です.
http://grails.codehaus.org/
http://groovy.codehaus.org/
その名前から想像されるとおり, それぞれ Rails, Ruby に強くインスパイアされています. が, Rails/Ruby とは異なる特徴もあり, 大変興味深いところです.
でも Rails/Ruby がなぜか大変もてはやされているのに対して, grails/groovy について日本語ではあまり情報もないのが現状です.
まぁまだ 0.5.6 ですからね. 今年 10 月予定の 1.0 リリース時にはきっとたいへん盛り上がることでしょう.
そこでとりあえず月一回くらいのペースで grails のコード・リーディングを始めることにしました.
grails は使っているだけだと単に超高生産性な Web アプリ開発ツールなわけですが, その中身がなかなか面白いし, 使っているとだんだん plugin などを作りたくなってくるわけです.
場所は横浜になりますが, 最近オープン・ソース・ビジネスやアジャイル・プロセスにも積極的な CIJ さんにお借りします.
------
第1回 grails コード・リーディング
日時: 7/25 (水) 19:00 - (多分 2 時間くらい)
場所: CIJ (地図)
(部屋は当日 7 階受付に張り出します)
対象: grails に興味のある方ならどなたでも
目標: grails をよりよく使うためのノウハウを参加者で学習/共有する
費用: なし
準備: grails-0.5.6 のコードが読める環境があるとよろし.
(プロジェクションしますから無くても大丈夫だと思います)
当日連絡先: 045-324-0111 石田 (19:00 以降は内線 7912) または 090-6486-7624 山田携帯
------
もっともいきなり grails のコード読みに入るかどうかは, 最初に集まっていただいた時点で考えようと思います.
(最初はまず grails とは何ぞやとか, groovy のリテラシも必要でしょうし)
おおざっぱな人数が知りたいので, masaki@metabolics.co.jp まで, 「第1回 grails コード・リーディング参加希望」というようなメイルを下さい.
締め切りは特にありません.
「25日は中華街でデートの予定だったのに, いきなり振られちゃったよ」というような場合, 当日直接来ていただいても構いません.
皆様の参加をお待ちしております.
2007年7月2日月曜日
grails でワークフロー (手で書く編3)
前述した組織モデルを前提として, jbpm を使ったワークフローを実現してみる.
では, ワークフローを定義する方法を決めましょう.
例えば Meeting というワークフローを表すクラスの名前は MeetingWorkflow ということにして, まずは controllers に置くことにします (Controller という sufiix は付きませんが).
その中身はこういう感じで, 状態機械に似ています.import jp.co.metabolics.jbpm.grails.ProcessDefinition
import org.jbpm.graph.exe.ProcessInstance
import org.jbpm.graph.exe.Token
import jp.co.metabolics.jbpm.grails.ActionHandler
import jp.co.metabolics.jbpm.grails.AssignmentHandler
import org.jbpm.graph.exe.ProcessInstance
import org.jbpm.graph.exe.ExecutionContext
import org.jbpm.taskmgmt.exe.Assignable
/*
* convention として Workflow という名前にする.
現在は grails-app/controllers に置いているが,workflows などにするかもしれない.
*/
class MeetingWorkflow implements AssignmentHandler, ActionHandler {
// 実際には def workflow (WorkflowBuilder で作成またはリソース名を表す文字列) だけ書けばよい.
// ここでは ProcessDefinition になっている.
def workflow = {
def writer = new StringWriter()
def b = new groovy.xml.MarkupBuilder(writer)
b.'process-definition'(name:'meeting') {
swimlane(name:'promoter')
swimlane(name:'participant')
b.'start-state'(name:'start') { transition(to:'propose') }
b.'end-state'(name:'end')
b.'task-node'(name:'propose') {
task(name:'propose', swimlane:'promoter')
transition(to:'confirm')
}
b.'task-node'(name:'confirm') {
task(name:'confirm', swimlane:'participant')
transition(to:'decide')
}
b.'task-node'(name:'decide') {
task(name:'decide', swimlane:'promoter')
transition(to:'end')
}
}
ProcessDefinition.parseXmlString(writer.toString())
}
// 以下は dynamic に inject される.
private processInstance
private token
MeetingWorkflow() {
processInstance = new ProcessInstance(workflow())
token = processInstance.getRootToken()
}
void execute(ExecutionContext executionContext) {
def taskName = executionContext.getToken().getName()
def meeting = executionContext.getVariable('meeting')
// これらの情報からタスクを作って, 適切な inbox に入れる
// 例えば URL. jp.co.metabolics.inbada/meeting/propose/123/...
// アプリケーション名 (context path) /ワークフロー名/タスク名/id にリダイレクトすればよい
// grails の controller の仕組みが全部使える (はず)
// taskInstance も覚えておく必要があるが (end), そのためには jbpm の DB に直接アクセスする必要がある?
}
void assign(Assignable assignable, ExecutionContext executionContext) {
}
def start = { token.signal() }
}
書くべきことは状態機械と同様, ワークフローの定義 (workflow) のみです. 後は動的注入可能 (今はそうなっていませんが:-) です.
ユーザが自分の tasklist に入ったタスクを選択すると, それに対応する controller/action に飛ぶことになります.
grails でワークフロー (手で書く編2)
jpbm がとりあえず状態機械として動くことは判った. ワークフロー・エンジンとして使うためには (convention として) 組織モデルを考える必要がある. それをまずは決めておこう
組織モデル
ここでは組織モデルの作り方を決めましょう. 組織は永続してもらわないと困るので, とりあえずドメイン・クラスとして作ります (scaffold すればメンテナンス・フロントエンドができます). ただし Foo という組織は FooOrganization, Foo という組織のメンバは FooMember というクラス名にすることにします. また個人を表すドメイン・クラスは Person とします. いずれも後で楽ができることを期待した convention です.Person.groovy の中身は例えばこんな感じになります.
class Person {
String name
String password
String email
String toString() { name }
static constraints = {
name(nullable:false, unique:true)
password(nullable:false)
email(nullable:true, email:true)
}
}
name と password が必要なこと以外は適当なプロパティがあっても構いません.一方, 例えば Project という組織があるとしたら, ProjectOrganization.groovy という組織クラスを作ります.
class ProjectOrganization {
static belongsTo = ProjectOrganization
static hasMany = [subs:ProjectOrganization, members:ProjectMember]
ProjectOrganization zuper
String name
String toString() { name }
static constraints = {
name(nullable:false, unique:true)
zuper(nullable:true)
}
}
「組織は階層化している」「組織はメンバを持っている」のが肝です. やろうと思えばこれらは自動的に注入できるでしょう. その他のプロパティを必要に応じて追加しても構いません.ProjectOrganization.groovy に対応して ProjectMember.groovy というメンバ・クラスを作ります.
class ProjectMember {
static roles = ['leader']
static belongsTo = [Person, ProjectOrganization]
static hasMany = [participations:Participation]
String role
Person person
ProjectOrganization project
List tasklist
static constraints = {
role(inList:roles, nullable:true)
person(nullable:false)
project(nullable:true)
}
}
roles は組織ごとに書く必要があります. また tasklist はワークフローで与えられたタスクが入るトレイになります. roles を除けば自動注入可能です. 組織と Person をつなぐ役割をしています.テスト・コードはここには載せませんが, 使い方はまぁ自明でしょう. Person から自分がどの組織に属しているのか見えた方がいいかもしれません.
また今回は Project というような具体的な組織構造をクラス構造にハード・コードしました. 別の方法としてはもっと汎用的な組織構造だけをクラスにして, 個々の組織構造は実行時に組み立てるやり方もあります. 個々の組織構造が持つ振る舞いを組み込みたいと思ったので前者の方法を採りましたが, grails/groovy なら後から振る舞いを追加するのは可能でしたね.
さて, ようやくワークフローを定義することができます.
grails でワークフロー (手で書く編1)
grails で jbpm を使ってみる. まずは convetion over configuration の精神に則りつつ, すべて手書きしてみる. また最初は永続化は考慮しない (つまり, サーバを再起動するとすべてのワークフローはリセットされてしまう. 普通はこれでは役に立たない)
ステップは以下の通り.
- 状態機械として使う
- 組織モデルの作り方を決める
- ワークフローとして使う
状態機械として使う
例えば ActionItem というドメイン・クラスに対する状態機械を jbpm で動かしてみたいとしましょう. ActionItem.groovy に以下のようなコードを追加します.// statemachine
static states = [start:'開始', notyet:'未着手', inhand:'着手済', completed:'完了', suspended:'中断', end:'終了']
// まずは永続性は考えない
private def statemachine = new ActionItemStatemachine()
// 以下は dynamic inject する
// states がなければ state() の結果をそのまま
public def state = { states[statemachine.state()] }
public def start = { statemachine.start() }
public def begin = { statemachine.signal('begin') }
public def done = { statemachine.signal('done') }
public def suspend = { statemachine.signal('suspend') }
public def abandon = { statemachine.signal('abandon') }
public def resume = { statemachine.signal('resume') }
public def end = { statemachine.end() }
どうやら grails はドメイン・クラスのプロパティに modifier を付けると永続化の対象としないようなので (本当か?), それを利用しています.ここでまず states という Map を定義していますが, これは定義した状態名と人間が見る状態名のマッピングをするためのものです. これはなくてもいいかもしれませんね.
次にドメイン・クラス Foo に対する状態機械 statemachine の名前を FooStatemachine と決め打ちしています (convention).
statemachine, state, start, end はすべての状態機械に共通, begin から resume はこの状態機械が定義している状態です. いずれも動的な注入が可能でしょう.
一方, ActionItemStatemachine という状態機械クラスを作ります. 今は便宜上 controllers に置きます.
import jp.co.metabolics.jbpm.grails.ProcessDefinition
import org.jbpm.graph.exe.ProcessInstance
import org.jbpm.graph.exe.Token
class ActionItemStatemachine {
// 実際には def statemachine (WorkflowBuilder で作成またはリソース名を表す文字列) だけ書けばよい.
// ここでは ProcessDefinition になっている.
def statemachine = {
def writer = new StringWriter()
def b = new groovy.xml.MarkupBuilder(writer)
b.'process-definition'(name:'action-item-statemachine') {
b.'start-state'(name:'start') { transition(to:'notyet') }
state(name:'notyet') {
transition(name:'begin', to:'inhand')
}
state(name:'inhand') {
transition(name:'done', to:'completed')
transition(name:'suspend', to:'suspended')
}
state(name:'completed') { transition(to:'end') }
state(name:'suspended') {
transition(name:'abandon', to:'completed')
transition(name:'resume', to:'inhand')
}
b.'end-state'(name:'end')
}
ProcessDefinition.parseXmlString(writer.toString())
}
// 以下は dynamic inject される
private token
ActionItemStatemachine() {
token = (new ProcessInstance(statemachine())).getRootToken()
}
def signal = { token.signal(it) }
def start = { token.signal() }
def end = start
def state = { token.getNode().getName() }
}
最初に
jp.co.metabolics.jbpm.grails.ProcessDefinition を import していますが, これは jbpm の ProcessDefinition が 'def' というパッケージに入っているために groovy から直接読めない ('def' は groovy ではキーワード) からです.src/java の下に以下のような内容の ProcessDefinition.java を置いています. 内容は何もない単なる wrapper です.
package jp.co.metabolics.jbpm.grails;
public class ProcessDefinition extends org.jbpm.graph.def.ProcessDefinition {
public static org.jbpm.graph.def.ProcessDefinition parseXmlString(String xml) {
return org.jbpm.graph.def.ProcessDefinition.parseXmlString(xml);
}
}
次に statemachine を定義しています. ここでは groovy の MarkupBuilder を使って, jbpm の jpdl 形式の XML を直書きです. これは例えば eclipse プラグインを使って書いたものをファイルとして読み込んでも構いません. が, いずれにしろプログラマが書くしかありません.
token, コンストラクタ, signal, start, end, state はすべての状態機械に共通なコードですから, やろうと思えば動的な注入が可能です.
さてこれを動かしてみましょう.
def ai1 = new ActionItem()
assert '開始' == ai1.state()
ai1.start()
assert '未着手' == ai1.state()
ai1.begin()
assert '着手済' == ai1.state()
ai1.suspend()
assert '中断' == ai1.state()
ai1.resume()
assert '着手済' == ai1.state()
ai1.done()
assert '完了' == ai1.state()
ai1.end()
assert '終了' == ai1.state()
OK のようです.今度は jbpm をワークフローとして使ってみましょう. そのためにはまず組織モデルを決める必要があります.
2007年6月10日日曜日
delete won't work for test env.
ありゃりゃ. 困ったもんだな.
test 環境だとどうもドメイン・オブジェクトの delete() がまったく効いていない模様...
MacOSX 10.4.9 / Java 1.5.0_07 / Grails 0.5
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 だとこの二つの世界は同じ言語で記述され, かつ優秀な開発/デバグ環境が存在するのだが...
ちなみにここで「インタプリタ」と呼んでいるものは「メタオブジェクト」と呼び変えてもよい. オブジェクトの挙動を決めているオブジェクトだから.
続く...
grails-wicket plugin を読む (1)
せっかくだから grails-wicket プラグインのソース・コードを読んでみる. たった40行くらいだし. ただし自分も修行中の身ゆえ, 間違いあればお許しのほどを.
grails-wicket プラグインのコードはここ. 本質的にはこの WicketGrailsPlugin.groovy だけ.
一行ずつ読んでいくことにする.def version = 0.1
バージョンを指定している. これはプラグイン・パッケージを作る (% grails package-plugin
) と自動的にパッケージ名 (grails-プラグイン名-バージョン.zip) に含まれる. そのほかにも他のプラグインへの依存性を書くときに使われる (後述). "0.1" とか "1.0" とか書くのが普通だろうけど, 文字列なら多分なんでもいい.def dependsOn = [:]
このプラグインが依存している他のプラグインを書く. ここでは空だけど例えば [foo:0.1, bar:0.2]
ってな感じ. 後ろの数字はバージョン.def evicts = ['controllers']
このプラグインによって不要になった他のプラグインを記述する (evict とは立ち退き, 強制退去). ここでは組み込みの controllers プラグインが指定されているけど, なぜか依然として controller は使えるようだ... (もしかして evict が正しい?)
def doWithSpring = {
def applicationClass = application.allClasses.find { Application.class.isAssignableFrom(it) }
if(applicationClass) {
applicationBean(applicationClass)
}
}
doWithSpring では Spring Bean Builder を使って必要な bean を定義するのが普通. しかしここでは何をやっているのだろう? 中身を見てみるといきなり "application" という変数が出てくる. どこにも定義されていない. これはいったい何だ?
今までもいろいろ def したが, このクラスはスーパークラス (extends) があるわけでもインタフェース (implements) があるわけでもない. これらの def が必要なのはひとえに「規約」による. 標語としてはいわゆる「covention over configuration (設定より規約)」というやつだ (実際には config ではないので少し違うが). いずれにしろ, この規約を決めているやつがどこかにいるはずだ. それを探してみよう.
続く...
grails + wicket
grails で wicket と scaffolding された GSP を簡単に両立させられるみたい.
それなりの日記
これは嬉しい. だってマスタ・メンテ用のアプリは scaffold されたものにちょっと手を入れればいい (現状ではちと厳しいのも事実だが:-) し, エンド・ユーザ用のアプリはちゃんとデザイナに HTML を作ってもらえるわけだ.
素晴らし.
2007年5月25日金曜日
grails でルール
さて, 今度は grails でルール・エンジンが使えるか.
例えば drools (今は JBoss Rules とか言うのか? 嫌な感じだ:-). rete アルゴリズムが載っていてオープンと言えば drools. groovy くらいの記述力があれば, ちょっとしたビジネス・ロジックだったら別にルール・エンジンを動かすこともない. ルール・エンジンの出番はもうこんがらがって人手に負えない, というようなときだから, エンジンそのものや環境がちゃんとしているものでないと意味がない. というわけで drools.
なのだが.
drools はルールの集まりを Java と同様「パッケージ」として扱う. 無名のデフォルト・パッケージはない. ルール内で参照するオブジェクトは (同じパッケージでなければ) ちゃんと full qualified name で import しなければならない.
一方 grails は domain class を無名のデフォルト・パッケージに置く. ちょっとやってみたところでは, 好き勝手なパッケージには置けない (Spring のエラーになる).
ということで, grails の domain class に drools からアクセスできないのだな. 意味ない.
grails で適当なパッケージに置けるようにするためにはどうすればいいか, まだ見てないけど, うーん, 「ちょっとしたこと」ではなさそうだなぁ.
続きはまた書く.
2007年5月19日土曜日
grails でワークフロー
grails で jbpm が使えるかどうか, まずは試してみる. jbpm を選んだのは, 前にワークフロー・エンジンを使うときに一番まともそうで, これを使ったから.
grails でワークフローを扱おうと思ったら, とりあえず Java の既存のワークフロー・エンジンを取り込んでしまうのが簡単で (これが grails のいいところ), 例えば jbpm だとこんな感じになる.
まずは <project>/lib/ に jbpm の jbpm-jpdl.jar を放り込む.
次に, jbpm では残念ながら "def" というパッケージ名を多用していて, これは groovy では当然キーワードなので, 文法的に許してもらえない. 仕方がないので, (とりあえず最小限必要な) 次のようなラッパを作って,package jp.co.metabolics.jbpm.grails;
public class ProcessDefinition extends org.jbpm.graph.def.ProcessDefinition {
public static org.jbpm.graph.def.ProcessDefinition parseXmlString(String xml) {
return org.jbpm.graph.def.ProcessDefinition.parseXmlString(xml);
}
}
これをjar にして, 同じく <project>/lib/ に放り込んでおく. これだけ.
jbpm のユーザ・ガイドにある最初の例題を groovy で書いてみよう.
MarkupBuilder のおかげでこんな感じに書ける.import jp.co.metabolics.jbpm.grails.ProcessDefinition
import org.jbpm.graph.exe.ProcessInstance
import org.jbpm.graph.exe.Token
void testHelloWorldProcess() {
// ここでワークフローを定義している.
def writer = new StringWriter()
def b = new groovy.xml.MarkupBuilder(writer)
b.'process-definition' {
b.'start-state' { transition(to:'s') }
state(name:'s') { transition(to:'end') }
b.'end-state'(name:'end')
}
def processDefinition = ProcessDefinition.parseXmlString(writer.toString())
assert processDefinition
println processDefinition
// プロセス・インスタンスを作る
def processInstance = new ProcessInstance(processDefinition);
assert processInstance
println processInstance
// トークンを得る
def token = processInstance.getRootToken();
assert token
println token.getNode()
assertSame(processDefinition.getStartState(), token.getNode());
// 開始
token.signal();
assertSame(processDefinition.getNode("s"), token.getNode());
println token.getNode()
// 次のノードへ
token.signal();
assertSame(processDefinition.getNode("end"), token.getNode());
println token.getNode()
}
jbpm はワークフロー・エンジンとしても, 状態機械としても, BPEL エンジンとしても使える. ワークフローそのものは, eclipse でグラフィカルに描くこともできる. 基本的な使い方は (def パッケージのクラスを使う場合にラッパを挟む以外は) Java の場合と一緒. Java と一緒というのは楽と言えば楽だけど, groovy / grails の強力さを生かし切れていないとも言えるので, できれば, plug-in を作って, builder を提供したり, 必要なメソッドは inject したいところだ.
その辺はまたそのうち.
2007年5月18日金曜日
wicket plug-in
Grails の wicket plug-in が出ている.
http://graemerocher.blogspot.com/2007/05/grails-wicket-wonders-of-grails-plug-in.html
しかも作ったのは Graeme Rocher だ. 20 分で書いたとか言っている:-)
今までの Grails とは controller の構造も少し変わってくるし, scaffolding もされないけど, カスタムなページだけでも HTML だけで (gsp タグを使わずに) 書けるのは嬉しいかもしれない.
2007年5月10日木曜日
日本語 on MacOS X
MacOSX で grails を使っていると, .groovy コード中に埋め込まれた日本語が web ブラウザ上で化ける. 例えば
static constraints = {
attendance(inList:['未定', '出席', '欠席'])
......
}
とすると, 生成される GRUD アプリケーションで attendance はセレクトボックスで表示されるのだけど, 項目名が読めない.
ま, ここにこういうコードが埋め込まれているのがいいかどうかという議論はあり得るわけだが, それはそれとして.
MacOSX だと, Java のデフォルトのエンコーディングが多分 sjis みたいのになっているから, ${GRAILS_HOME}/bin/startGrails というシェル・スクリプトの適当な場所 (前の方) に,
JAVA_OPTS="-Dfile.encoding=utf-8"
を付け加えておけばOK.
もちろん, 元の .groovy コードは utf-8 で書いておかねばだけど.
.gsp ファイル中の日本語は (utf-8で書いておけば) 大丈夫だし, g:message タグを使えば i18n できる.
many-to-many mapping
[0.5 のリリースノートには出ていなかったけど, 関連クラスのようなものや Hibernate の マップ・ファイルを書かずに多対多のマッピングが GORM で可能になった模様.
まだ試してない.
http://www.nabble.com/Many-to-Many-Mapping-without-Hibernate-XML-tf3719083.html
ビジネス・ロジックの置き所
いわゆる「ビジネス・ロジック」と呼ばれているものがある. ドメイン知識の一部だけれど, 「処理」的なもの, 複数のドメイン・クラスにまたがる何かを指している.
grails ではビジネス・ロジックは service として実装しなさい, というのが基本だ. domain class には書かない. そして service は controller が呼び出すもので, domain class が呼び出すものではない. これは grails に限らず, 最近の実装法はこの方向にある. domain class という名前ではあるけれど, 実態は DTO (Data Transfer Object) に過ぎない. そして DAO (Data Access Object) を通してアクセスする. しかし, そもそも DTO とか DAO とかいう名前, 存在そのものはオブジェクト指向としてどうなのよ? 気持ち悪いなぁ.
元々オブジェクトは現実世界の何かに関する知識を表すものだった. ドメイン・クラスとか概念オブジェクトとかは, その中でも問題ドメインに関する知識を表すオブジェクトだ. でも DTO とか DAO とかって解決領域に関するものでしょう? 実装依り過ぎる. それは裏に隠れている (別のドメインである) べきなんじゃないの?, というのが僕の, 実行可能知識の立場.
例えばあるメーカが小売店に対して報奨金を出している. 前期の売上額の範囲に応じて, 報奨金の割合が変わるとする. もちろんこの報奨金のルールの内容自体は不安定なもの (人間の恣意によって変わりやすい) ものだから, 「ルール」として抽出してよい (するべき). でも, このルールによって計算される報奨金というものがあると言うことは「ドメイン・クラス」の中に書かれているべき.
むろん, 昨今の実装上の問題として, 永続化層がオブジェクトをそのまま保存できない場合が多いので, この「ルール」がいつ起動されるべきか難しいわけだが...
続きはまた書く.
2007年5月9日水曜日
なぜ grails か
grails は普通には CRUD 生成フレームワークと思われているわけだが, 僕にとってはそれはどうでもいい (いや, もちろん CRUD アプリケーションが生成されることはいいことには違いないんだけど).
ここで grails を扱っている理由は何よりも「モデル駆動開発環境」としてだ. それも「日常会話的モデル駆動開発」環境.
モデル駆動開発のツールもいっぱいある. けど, 日常会話ができない. ものすごくしゃっちょこばって, ぎごちなく, 難しく, 辞書を引き引き, 話さないと伝わらない.
例えば BridgePoint. 高い. まずそれだけで駄目だ. 舌がつっちゃう.
例えば OptimalJ のたぐい. ださい. 会話が弾まない. 本当に嬉しいのかどうか分からない.
例えば eclipse の Modeling Project. 頑張っているとは思うけど, まだまだ発展途上だし (いつ発展が終わるの?), これを使うのは大変だ. プログラムを書くのと同じくらいモデルを書くのが大変だ. それじゃあ意味ないよなぁ.
もっと自然に会話したいわけだ. 自分の気持ちを素直に伝えたい. プログラマに馴染みのある例で言えば, emacs のような. grails にはその可能性があるんじゃないか, と思った. grails では普通は UML のような絵は書かないけど, 一見ふつうのプログラミング言語みたいだけど, 実はモデルを書いているわけだね (そう思い込もうとしている).
特に Groovy の Builder で簡単に内部 DSL を作ることができる. Groovy の MOP (Meta Object Protocol) で上位の知識を形式化 / モジュール化できる. この二つはモデリング言語として強力.
grails は emacs と同じで「環境」だから, 生の状態でも使えることは使えるけど, その真価は plugin にある. 自分たちのノウハウは plugin の形で追加され, grails は進化していく.
なぜ Ruby on Rails じゃないか. R on R はみんなにとってもクールだって評判がいいから (僕はへそ曲がりだからね). schemaから始まるのは趣味じゃない. Groovy は Java VM の上で走る. 「Java の一種です」と言えば保守的な人でも騙せる. Java の膨大な資産を使える. もちろんあまりイカしてないのも多いわけだけど, それは裏に隠れているから構わない. それよりも「立っている者は親でも使え」だ (ちょっと意味が違う気もするが).
eclipse からの run
今までは emacs でやっていたので, これが 0.5 になってからの現象かどうかは分からないのだけれど, eclipse で Run | Run... -> Java Application -> <project> でプロジェクトを起動すると, ダイナミックなビューを scaffold しようとして落ちる. テンプレートが (あると思いこんでいる場所に) 無いと言うのだが, うーむ. なぜだ.% grails dev package
はやってある. テンプレートは
にはあって,
${basedir}/web-app/WEB-INF/templates/scaffolding/% grails dev run-app
しているときはこれで大丈夫なのだが, eclipse からだとなぜかまず${basedir}/src/templates/scaffolding/
を, それがなければ (development 環境では普通はない)
${grailsHome}/src/grails/templates/scaffolding/
を見に行く. ところが, このコード中で ant の環境から GRAILS_HOME を取り損なっているようで {grailsHome} が null なのだ. 仕方がないので, ${basedir}/src/templates/scaffolding/
にテンプレートをコピーすることにする.% grails package
(dev なし) しても多分いいはず.
0.5 で test が error
0.5 に移行してから % grails test-app すると,Error running tests: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Foo#1]
などと言われることがある. テストの中でデータベースを更新したりしている場合ね.
こんなときには ${GRAILS_HOME}/scripts/TestApp.groovy の 162 ~164 行目app.domainClasses.each { dc ->
dc.clazz.executeUpdate("delete from ${dc.clazz.name}")
}
をコメントアウトすると, とりあえず上記のエラーは出なくなるはず. このコードはテストメソッド終了時にデータベースをクリーンアップしているのだけど, 消すには消す順序ってぇものがあるわけで, それを無視して適当に消しているのがまずいわけだ.
一方でこの修正を入れるとクリーンアップを自動でしなくなるので, データベースの中身は tearDown() 辺りでちゃんと消しておかないと, 前のテスト・メソッドの影響が残ってしまうということになるのじゃね.
http://www.nabble.com/Unit-tests-and-GORM-%28Hibernate%29-tf3697726.html