vol.4

Magazine

Japan Grails/Groovy User GroupContents
祝 !! Grails2.0 リリース

検証 ! Grails2.0 の世界 Part.2… …………… 4
Series 07

JGGUG 合宿 2011 企画アプリ

GDK48 投票アプリの作り方（前編）………… 8
Series 08

GroovyFX で遊ぼう（導入編）… ……………… 14
Series 09

Betamax ことはじめ… ………………………… 18
Series 05

Grails Plugin 探訪〜第 5 回 RabbitMQ プラグイン〜… ………………… 23
JGGUG ４コマ漫画「ぐるーびーたん」第 4 話… …… 27
Information

リリース情報…………………………………………… 28

G*Magazine vol.4

祝 !! Grails 2.0.0 リリース

検証 ! Grails 1.4.0
2.0 の世界 Pt.2
玉田 幸治（株式会社ニューキャスト）

基本的にきゃっきゃ♪ゆうとるひげのおっさん。

Grails 2.0 - 1.4にしておくにはもったいない！
今から半年ほど前の 2011 年 6 月 27 日。Grails 開発チームの発表にあったように、1.4 系にしておくのはもったいないとのこといます。Resources プラグイン対応の jquery プラグインもインストールされています。

で、Grails1.4 系は 2.0 系となりました。詳細は JGGUG の G* ワー

使用方法

い。

■準備編

ズ第二弾ですが、企画開始 ( 前々号 ) から、今回分を ( 多忙な日々の最後に <r:layoutResources/> タグを挿入します。

クショップにて解説された tyama さんのスライドをご覧くださ
さてどの辺りが「もったいない！」程の内容なのかを探るシリーをかいくぐり ) 執筆してる間に、ついに 2011 年 12 月 15 日 (JST) に、
Grails-2.0 が正式リリースされました！

このシリーズは、今後「Grails 2.0 の世界」として継続していく" ハズ " です！

grails-app/views/layouts/main.gsp の head タグ内とコンテンツ<!doctype html>...
<head><meta http-equiv="Content-Type"では、今回は、大きな変更点の一つ「Resources プラグイン」

content="text/html; charset=UTF-8">

を通称 " ヒゲのおっさん " がお送りします！

<meta http-equiv="X-UA-Compatible"
content="IE=edge,chrome=1">■Resources プラグイン<title><g:layoutTitle default="Grails"/></title>

Grails-2.0 には、今回の目玉商品である "Resources プラグイン "...

がデフォルトでインストールされています。Grails 2.0.0には、バー<r:layoutResources/>ジョン 1.1.6 の Resources プラグインがインストールされます。この Resouces プラグインとは静的リソースを管理する為の " リソー
スフレームワークプラグイン " です。

通常の Grails アプリケーションではリソース指定のタグを利用<g:layoutHead/></head><body>...

してリソースを管理 ( 指定 ) していました。しかし、最近の Web<r:layoutResources/>

アプリケーションは JavaScript ＆ CSS のライブラリやフレームワークに依存して開発することが多くなってきているため、管理<g:javascript library="application"/></body>などが複雑で大変になってきます。

</html>

ソース処理の為のマッパー、リソース提供用のサーブレットフィ

head 内とコンテンツの最後の部分へタグを挿入します。これ

そこで、Resources プラグインでは、静的リソースの管理、リルタ等を、わかりやすい DSL で管理可能な " フレームワーク " として提供しています。

まずは、Grails2.0 の BuildConfig.groovy を確認してみます。
plugins {compile ":hibernate:$grailsVersion"
compile ":jquery:1.7.1"
compile ":resources:1.1.5"
build ":tomcat:$grailsVersion"}

スはこの挿入したタグの部分に読み込まれる事になります。

■JavaScript を挿入

準備編で挿入した layoutResources タグ部分へ javascript を挿入してみます。

grails-app/views/index.gsp の body 開始タグ直後に以下のコードを書いて grails アプリケーションにブラウザからアクセスしてみましょう。

<r:script disposition="head">alert('コンテンツ前');</r:script>

plugins の中でしっかりと Resources プラグインが定義されて4で Resources プラグインを使用する準備は完了です。静的リソー

検証 !

Grails2.0 の世界 Part.2<r:script disposition="defer">alert('コンテンツ後');</r:script>

G*Magazine vol.4
コンテンツの読み込み前と読み込み後に alert が表示されます。

html のソースコードを見てみましょう。
<!doctype html>...
<head>...

<script type="text/javascript">alert(' コンテンツ前 ');</script>...
</head><body>...
<div class="footer" role="contentinfo"></div><div id="spinner" class="spinner"style="display:none;">Loading&hellip;</div><script type="text/javascript">alert(' コンテンツ後 ');</script></body></html>script タグの差し込み先が head タグ内とコンテンツの最後にわかれて挿入されているのが確認できます。disposition="head"で head 内の layoutResources へ挿入され、disposition="defer" でコンテンツの最後の layoutResources へ挿入されます。

※ head タ グ 属 性 で 指 定 さ れ た も の は 最 初 に み つ か っ たlayoutResources タ グ 内 に 挿 入 さ れ ま す。head タ グ 内 にlayoutResources タグがなくてコンテンツの最後の箇所にしかlayoutResources タグがない場合はそちらに挿入されます。

css は disposition=head でヘッダー内の layoutResouces に読み込みを行い、コンテンツ読み込み後に実行させたい javaScript や、コンテンツ後は読み込まれた後に実行されていることがわかります。

■画像の挿入web-app/images 内にある懐かしい画像を挿入してみましょう。

<r:img dir="images" ﬁle="grails_logo.jpg" />以下のように変換され懐かしい画像が表示されます。
<img src="/ あなたのアプリ /static/images/grails_logo.jpg" />ページロードに影響を与える javaScript は disposition=defer でコンテンツの最後に読み込むべきです。

※ <r:script> タグで定義された javaScript は require で読み込まれたライブラリより後に配備されます。必要なライブラリが先に読み込まれている必要がある為にこのような動きになっていま
す。

検証 !

Grails2.0 の世界 Part.2

5

G*Magazine vol.4

設定ファイル

上書きする場合は以下のようになります。

grails-app/conf 内 に リ ソ ー ス 定 義 フ ァ イ ル

modules = {（SomeNameResources.groovy という形で 'SomeName' に任意のcore {

名前を付けた groovy ファイルを配置）、もしくは

dependsOn 'jquery, utils'

grails-app/conf/Config.groovy に以下のように記述します。

defaultBundle 'monolith'
resource url: '/js/core.js', disposition: 'head'grails.resources.modules = {}module 名 {utils {

dependsOn 'jquery' // 依存がある場合

dependsOn 'jquery'

defaultBundle 'defaultBundle' // バンドル名

defaultBundle 'monolith'

resource url: リソースファイルのパス ,resource url: '/js/utils.js'

disposition: 'head', or 'defer'}}forms {}

dependsOn 'core,utils'
defaultBundle 'monolith'

リソース定義ファイルは複数のファイルを使用することが可能

resource url: '/css/forms.css' resource url: '/js/forms.js'です。jquery プラグインなどはプラグインの中に既に Resources}

プラグイン用の設定ファイルが含まれています。プラグインの中

overrides {にリソース定義ファイルを配置することで Resources プラグイン

jquery { defaultBundle 'monolith' }対応のプラグインを作成することが可能です。

}■モジュールResources プラグインではリソースのファイルをモジュールという単位で管理しています。複数のリソースファイルをモジュールという単位に統合し、gsp でモジュールを require タグで指定することで利用が可能です。基本的なリソースを common モ
ジュールとしてまとめて、管理画面等の別のリソースを必要とする場合、common モジュールを dependsOn した管理画面用のadmin モジュールを作るなどの手法が考えられます。
モジュール名称 {dependsOn 'jquery' // 依存関係の定義

リソースフレームワークは " マッパー " を使用して、最終フォー

マットへリソースを変化させてユーザへ配信します。時にはこのマッパーで処理させたくないリソースもあります。

特定のファイルを指定してマッパーの処理を行わないように定義することも可能です。例えば、"hashandcache" マッパーの処理をさせたくない場合は、

resource url: '/css/my.css', nohashandcache: true
上記のように、no マッパー名称 :true のように指定します。

まれます。

また、ファイルタイプによって、マッパーの定義をする場合

defaultBundle 'monolith' // バンドル名称
resource url: '/js/core.js', disposition: 'head'// モジュールのリソース}

は grails-app/conf/Config.groovy 内に以下のように指定が可能です。

grails.resources.zip.excludes = ['**/*.zip', '**/*.exe']※ zip ファイルと exe ファイルを zip マッパーを通さない場合の設■バンドル

バンドルというセットを利用してリソースの上書きが可能になります。リソースを上書きする場合、"overrides" を利用します。
overrides {jquery { defaultBundle ' 上書するためのバンドル ' }}このように defaultBundle を別のバンドルで overrides することができます。

たとえば、jQuery と他のライブラリをまとめてバンドルして、検証 !

■マッパー定義

設定してある場合は設定してあるモジュールが先に読み込

6}

Grails2.0 の世界 Part.2

定 (zip マッパーは zipped-resources で提供されています。)

grails.resources.bundle.excludes = ['**/*.less']※ファイルタイプ less をバンドルしないようにする。

G*Magazine vol.4

コ ラ ム
jquery プラグインの中の設定ファイルはどうなっているのか
jquery プラグインの中の resources プラグイン用のリソース

設定ファイル JQueryPluginResources.groovy を見てみます。
// Resource declarations for Resources plugin
def jqver = org.codehaus.groovy.grails.plugins.
jquery.JQueryConﬁg.SHIPPED_VERSION
modules = {'jquery' {resource id:'js', url:[plugin: 'jquery',
dir:'js/jquery', ﬁle:"jquery-${jqver}.min.js"],
disposition:'head', nominify: true

関連プラグイン■zipped-resources プラグイン

ページロードの時間と帯域を短縮するためのプラグインです。

gif, jpeg, png の既に圧縮されているファイルを除いたコンテンツを自動的に圧縮するマッパーが用意されています。
grails install-plugin zipped-resources
このように、zipped-resources プラグインはインストールするだけで使用できます。

■cached-resources プラグイン

クライアントのブラウザにリソースをキャッシュさせる仕組みのプラグインです。リソースのファイル名をそれぞれのハッシュ}値に変換し、キャッシングヘッダーを全てのリソースのレスポン'jquery-dev' {resource id:'js', url:[plugin: 'jquery',
dir:'js/jquery', ﬁle:"jquery-${jqver}.js"],
disposition:'head'}}<r:require modules="jquery"/> を 利 用 す る こ と に よ り

圧 縮 さ れ た jquery-min を 読 み 込 む こ と が で き、<r:require

modules="jquery-dev"/> で、圧縮前の jquery ライブラリを読み込むことが可能になっているのがわかります。このように開発環境とプロダクション環境をモジュールによって分けられるのも resources プラグインの利点といえます。

スにセットすることによりブラウザにキャッシュさせ、ページ
ロード時間の短縮を行います。

grails install-plugin cached-resources
同じく cached-resources プラグインはインストールするだけで使用できます。

まとめ
Grails 2.0 の世界として、駆け足で Resources プラグインの紹介をしてきましたがこのプラグインを使用することで静的リソースの管理が楽になることがおわかりいただけたでしょうか？まだまだ紹介しきれていない部分もありますので公式のドキュメントを一度みていただくことをおすすめします。それではまたお会いで開発中時のデバッグ指定
Resources プラグインにはデバッグの際に使用する機能が幾つきる時まで ! 基本的にきゃっきゃゆうとるヒゲのおっさんがお送りしました。

か提供されています。開発環境では X-Grails-Resources-Original-

リンク

した元のリソースが示されています。

• tyama さんの jggug 発表スライド http://slidesha.re/n43zfq

Src ヘッダーが追加されます。このヘッダーにはリソースを構成

また、URL に _debugResources=y のクエリパラメータを付加することにより Resources プラグインは元のリソースファイルを読み込むことが可能となります。また、ブラウザによるキャッシュ• Resouces プラグインドキュメント

http://grails-plugins.github.com/grails-resources/を防ぐため、ユニークなタイムスタンプが付加されます。毎回ク
エリに _debugResources=y を付けなくてもいいように、
grails.resources.debug=trueと grails-app/conf/Config.groovy に記述することができます。

これにより、_debugResources=y のクエリパラメータを省いての開発が可能になります。開発中は development 環境内に追記しておくことをおすすめします。

検証 !

Grails2.0 の世界 Part.2

7

G*Magazine vol.4

JGGUG合宿2011企画アプリ

GDK48 投票アプリの作り方（前編）
series07

奥 清隆（おく きよたか）

仕事でもときどき Groovy と戯れるプログラマ。
日本 Grails/Groovy ユーザーグループ関西支部長。
著書：『Seasar2 による Web アプリケーションスーパーサンプル』

GDK48 投票アプリの作り方 ( 前編 )今回は「Griffon 不定期便」をお休みして、JGGUG 合宿 2011 で行われた GDK48 という企画で使われたアプリケーションついて

Gist に投稿した URL をツイートして GDK48にエントリーする

お話ししたいと思います。

1.

投票して 1 位を決めようという企画でした。企画の詳細な内容に

3.

GDK48 とは、みんなで G* なコードを書いて、それをみんなでついては合宿運営レンジャーレッドの資料を御覧ください。

GDK48 にエントリーする流れは次のような感じです。
GDK48 エントリー用のコードを書く

2.

書いたコードを Gist(http://gist.github.com) に貼り付ける

貼りつけた Gist の URL とハッシュタグ「#gdk48」を付けてツイートする例）「Groovy で Git コマンド。

http://www.slideshare.net/kazuchika/gdk48

GDK48 と言っておきながら、残念なことに 48 本までは集まりませんでしたが、大変役に立つコードが集まりました。合宿で使用したアプリケーションは下記の URL で現在も見ることができます。

http://gdk48.kiy0taka.org/gdk48/

今回はこの GDK48 総選挙システムの作り方についてお話ししていきます。GDK48 総選挙システムのソースコードは GitHub 上で公開していますので、合わせて御覧ください。
http://git.io/gdk48

https://gist.github.com/1341311 #gdk48」

ハッシュタグと Gist の URL があれば GDK48 総選挙システムが勝手に拾ってくれてエントリーされます。

GDK48 エントリ用ドメインクラスの作成
それではエントリ用のドメインクラスを作成しましょう。エン

トリ用ドメインクラスと言っても、総選挙システムで管理するのは Gist の ID だけにします。Gist の ID とは、Gist にコードを投稿したときに割り当てられる URL の後ろにつく数字です。例えば、■GDK48 総選挙システム概要「https://gist.github.com/1341311」 と い う URL な ら、Gist の ID

リーとしては次の 2 つになります。

修正されることもあるのでシステムではコード内容を保持せず、• Twitter アカウントで認証済みのユーザが GDK48 に投票する

してドメインクラスを作成します。

GDK48 総選挙システムはとてもシンプルなものです。ストー• Gist に投稿した URL をツイートして GDK48 にエントリーする
今回はこの「Gist に投稿した URL をツイートして GDK48 にエは「1341311」になります。コードの内容などはエントリー後に
Gist へのリンクが生成できれば良しとします。クラス名は Gist とントリーする」の実装についてお話ししていきます。

cd gdk48■アプリケーションの作成

grails-app/domian/gdk48/Gist.groovy が生成されました。Gist

GDK48 総選挙システムはシンプルなアプリケーションなのでGaelyk で作るという選択肢もありましたが、Twitter 連携などのgrails create-domain-class Gist

クラスには Gist の ID だけあればいいので、次のように編集します。

必要な機能がプラグインで提供されているため Grails を使って実装しました。Grails のバージョンは 1.3.7 を使いました。Grails2.0

package gdk48

Grails2.0 については山本さんの記事を熟読してください。それでclass Gist {が出たところですが、この記事でも 1.3.7 で作成していきます。
は gdk48 という名前でアプリケーションを作成しましょう。

Long gistNograils create-app gdk48
static constraints = {gistNo nullable:false, unique:true}}

8

GDK48 投票アプリの作り方（前編）G*Magazine vol.4
プロパティ gistNo が Gist の ID となります。gistNo は null 値を許可せず、ユニークな値になるように制約を定義しておきます。

Gist コントローラの作成
ドメインクラスが出来たのでコントローラを作成しましょう。
grails create-controller Gist
grails-app/controllers/gdk48/GistController.groovy が 生 成 さ れました。GDK48 総選挙システムでは、CRUD の画面は必要ないのですが、とりあえず動かしてみたい人はスカッフォルドで動きを確認してみましょう。GistController.groovy を次のように編集します。

昇順）でソートします。リクエストパラメータの入力チェックな
ど細かいことは気にしないことにします。

一覧画面の作成
Gist の一覧を表示する画面を作りましょう。grails-app/views/

gist/list.gsp ファイルを次のように作成します。
<%@ page import="gdk48.*" %><html><head><meta name="layout" content="main" /><title>GDK48 総選挙 </title></head>package gdk48
class GistController {static scaffold = true}

<body><div class="container"><h1>GDK48 総選挙 </h1><div class="paginateButtons"><g:paginate controller="gist" action="list"
total="${Gist.count()}" max="5" /></div>

この状態でアプリケーションを起動すれば、スカッフォルドされた CRUD の画面を動かせます。「grails run-app」コマンドを実行してからブラウザで「http://localhost:8080/gdk48/gist」にアクセスしてみましょう。最終的にこの CRUD の画面は必要ではな<div><g:each var="gist" in="${gists}"><div class="gist"><script
src="https://gist.github.com/${gist.gistNo}.js">

いので詳細は省きますが、スカッフォルドでアプリケーションを動かすことで、システムのイメージが掴めることもあるかと思います。コントローラに少し工夫をするだけで CRUD の画面が確認できるスカッフォルド機能はとても便利ですね。

それでは、実際に必要な処理を実装しましょう。GistControllerに必要なアクションはエントリされた Gist の一覧を表示するためのアクションです。一覧表示用に list という名前のクロージャを定義します。

</script></div></g:each></div><div class="paginateButtons"><g:paginate controller="gist" action="list"
total="${Gist.count()}" max="5" /></div></div>

package gdk48
class GistController {def list = {def gists = Gist.list(max:5,
offset:(params.offset?:'0').toLong(),
sort:'gistNo',order:'desc')[gists:gists]}}
list クロージャではエントリされた Gist の最大 5 件まで取得し</body></html>
ページング用のタグと、script タグを使って Gist のコードを表

示 し て い ま す。Gist で は「https://gist.github.com/1341311.js」のような URL で Gist コードを表示するための JavaScript コードを取得することができます。

■テストデータの登録

この段階で一覧画面を確認しても、Gist を登録する部分を実装していないのでデータは何も表示されません。しばらくは
BootStrap を使って適当な Gist を登録しておきましょう。grailsapp/conf/BootStrap.groovy を次のように編集します。

ます。リクエストパラメータ offset で開始件数を指定すればページングするようにします。検索結果は Gist の新しい順（gistNo のGDK48 投票アプリの作り方（前編）9G*Magazine vol.4

import grails.util.Environment<%@ page import="gdk48.*" %>import gdk48.Gist<html><head><meta name="layout" content="main" />class BootStrap {<title>GDK48 総選挙 </title><blueprint:resources/>

def init = { servletContext ->if (Environment.current == Environment.DEVELOPMENT) {[1261979, 1129161, 1059105, 1031115,<style>body {
background-color: #FAEBD7;1020384, 1020286, 1015558, 1012403].each {new Gist(gistNo:it).save(failOnError:true,
ﬂush:true)}.gist {
margin-bottom: 30px;

}
}
}

}
</style>def destroy = {</head>}<body>}
アプリケーション初期化のタイミングで、適当な Gist を何件か登録する処理を追加しました。それでは「grails run-app」コ

マンドでアプリケーションを起動して「http://localhost:8080/
gdk48/gist/list」にアクセスしてみましょう。
次のような画面が表示されれば成功です。

<div class="container"><h1>GDK48 総選挙 </h1><div class="paginateButtons"><g:paginate controller="gist" action="list"
total="${Gist.count()}" max="5" /></div><div class="span-26 last"style="background-color: #FFB6C1; padding: 30px;"><g:each var="gist" in="${gists}"><div class="gist"><script src="https://gist.github.com/${gist.gistNo}.js"></script></div></g:each></div><div class="paginateButtons"><g:paginate controller="gist" action="list"
total="${Gist.count()}" max="5" /></div></div></body>■UI を改善する

Gist を一覧することが出来ましたが、見た目がすこし残念な

感 じ な の で、 少 し UI を 改 善 し ま し ょ う。Blueprint CSS(http://

blueprintcss.org/) と い う CSS フ レ ー ム ワ ー ク を 使 っ て み ま す。
Grails には Blueprint CSS 用のプラグインがありますのでインストールします。

grails install-plugin blueprint
それでは Blueprint CSS を使って list.gsp を改善しましょう。

10 GDK48 投票アプリの作り方（前編）</html>G*Magazine vol.4
これで次のような画面になりました。

まだ残念な感じがするかもしれませんが、これが私の限界です。Grails には他にも UI 系のプラグインがたくさんあるので、好きなものを使ってみるといいかと思います。

GDK48 エントリ Tweet を取得する
それでは、GDK48 エントリ Tweet を取得する処理を実装しま

しょう。処理の内容は次のとおりです。
1.

定期的にハッシュタグ「#gdk48」が含まれるツイートを2.

検索結果のツイートに Gist の URL が含まれていればデータをこ れ で、grails-app/jobs/gdk48/TweetCrawlerJob.groovy と いうファイルが生成されました。TweetCrawlerJob は少しコードが長いので、紙面の都合上ポイントだけ解説しておきます。完全なソースはサンプルコード (http://git.io/gdk48job) を御覧ください。

Twitter から検索

■トリガーの定義

登録

す。Quartz ではクーロン式を使ったトリガーなどいくつかの形式■Job の作成

定期的に処理を実行するために Quartz プラグインを使用します。Quartz プラグインは、スケジューリングされた処理を実行す

今回は 1 分おきにこの Job を実行するようトリガーを定義しま

でトリガーを定義できるようになっています。ここでは「simple」
タイプのトリガーを定義します。
static triggers = {simple name: 'TweetCrawlerTrigger',

るための Java ライブラリである Quartz(http://quartz-scheduler.
org/) の Grails プラグインです。

まず、Quartz プラグインをインストールしましょう。
grails install-plugin quartz
Quartz プラグインをインストールすると「create-job」コマン

ドを使って定期的に行う処理を実装する Job クラスを作成できます。それでは GDK48エントリツイート取得用 Job を作成しましょう。

startDelay: 10000, repeatInterval: 60000}
name 属性は任意のトリガー名、startDelay はアプリケーションが起動してから初めてトリガーが起動されれるまでの時間をミリ秒で指定、repeatInterval はトリガーを起動する間隔をミリ秒で指定します。

この設定では、「TweetCrawlerTrigger」という名前でアプリケー

ションが起動してから 10 秒後に最初の Job が実行され、その後 1分間隔で Job が実行されます。

grails create-job TweetCrawler

GDK48 投票アプリの作り方（前編） 11

G*Magazine vol.4■Job の並列実行

Job は 1 分おきに実行されますが、1 分以上処理に時間がかかっ

repositories {た場合、2 つの Job が平行して実行されます。TweetCrawlerJob

grailsPlugins()

は並列に実行されても問題はありませんが、意味が無いので並列

grailsHome()に実行されないようにしておきます。TweetCrawlerJob にプロパ

grailsCentral()

ティ concurrent を定義しておけば、並列実行を制御することがmavenLocal()できます。

mavenCentral()def concurrent = false
プロパティ concurrent を定義しなかったり、値を true にした

場合は並列に実行されることを許可します。

■テスト実行時のトリガーの制御

今回はテストコードについては紹介しませんが、サンプルコー

ドにはいくつかテストコードを書いています。デフォルトの設定
ではテスト実行時にもトリガーが起動されてしまうので、予期しないタイミングで実行されテストが失敗するケースも出てきてし}dependencies {compile 'org.twitter4j:twitter4j-core:jar:2.2.5'}■処理の実装TweetCrawlerJob のメソッド execute() を実装します。
def execute() {def twitter = new TwitterFactory().instance

まいます。テスト時にトリガーを起動しないように次のようなtwitter.search(new Query('#gdk48'))

ファイルを grails-app/conf/QuartzConcifg.groovy として作成しておきます。

.tweets.each { parse it }}quartz {autoStartup = true
jdbcStore = false
waitForJobsToCompleteOnShutdown = true

Twitter4J の検索 API を使ってハッシュタグで検索し、解析してデータを登録するためのメソッド parse() に検索結果を渡します。
このまま実行してもおそらく「#gdk48」では検索結果が返って}こないので、適当に変更して実行してみてください。

environments {トの本文に Gist の URL が含まれるかどうかを判定してデータを登メソッド parse() については詳細な解説を省きますが、ツイー

test {
quartz {autoStartup = false}}}

録するように実装します。この処理のポイントとしては次の 2 点が考えられます。

• URL は短縮 URL(http://t.co/BOFnltIQ のような形式など ) の場合がある• 短縮 URL は他の短縮 URL サービスで短縮された URL をさらに短縮している場合がある

この 2 点を考慮して、ツイート内容から Gist の URL を取得する

ために、ツイート内の URL でリクエストを試みてから、短縮 URL■Twitter4J のライブラリを追加

Twitter か ら ハ ッ シ ュ タ グ「#gdk48」 で 検 索 す る た め に

Twitter4J を使用します。grails-app/config/BuildConfig.groovy にTiwtter4J の依存関係を追記しておきましょう。

12 GDK48 投票アプリの作り方（前編）の場合に返される Location ヘッダを取得し判定するようにします。処理の流れは次の図のようになります。

G*Magazine vol.4

Location ヘッダの取得には java.net.URL クラスを使って次のよ

うにヘッダだけ取得しています。

def conn = new URL(url).openConnection()conn.followRedirects = false
def location = conn.getHeaderField('Location')

まとめ
今回は、GDK48にエントリされた Gist を登録し、アプリケーショ

ンで一覧するところまでを紹介しました。本当は 1 回ですべてを紹介する予定でしたが、文章にすると予想以上にボリュームがあったので、続きは次回に回したいと思います。次回は Twitterを使った認証と投票の仕組みについてです。それではまた次回お会いしましょう！

GDK48 投票アプリの作り方（前編） 13

G*Magazine vol.4

GroovyFX で遊ぼう！（導入編）
series08

関谷 和愛（せきや かずちか）

Groovy、Java、Apple 製品を愛するおっさんエンジニア。日本 Grails/Groovy ユーザーグループ運営委員長。
共著『プログラミング GROOVY』、共訳『Groovy イン・アクション』

今年 10 月に開催された JavaOne 2011 で、Java の次世代クライ

今 年 の JavaOne で は、 オ ー プ ン ソ ー ス 化 と JCP(Java

アントソリューションである JavaFX 2.0 がついに正式リリースさ

Community Process) での標準化の計画も発表され、さらに、今に使いこなすための GroovyFX という新しい仲間が増えました。

期メジャーアップデートである JDK8 に標準 API として統合されれました。そして G* エコシステムにも、この JavaFX を Groovy

このシリーズでは、この GroovyFX を取り上げ、その使い方や魅力を紹介していきたいと思います。

JavaFX って何だっけ？
JavaFX は、Java SE プラットフォームに、従来 Java があまり得意でなかった下記のような機能を追加する拡張ライブラリです：

後の JDK7 リリースにバンドルされるようになること、そして次ることなども明らかにされました。

これにより、JavaFX はもはや単なる拡張ライブラリの一つではなく、AWT や Swing の後継として、今後の Java のクライアン
ト UI 開発の主役の座につくことが確実になったのです。

GroovyFX 登場！
GroovyFX は、Jim Clarke (Oracle) と Dean Iverson (Virginia• アニメーションやエフェクト、3D といった高度なグラフィッ

Tech) によって開発された、Groovy による JavaFX のラッパーで• メディア（動画や音声）の再生と制御ンに該当します。
（「Java ライブラリをラップして使いやすく」）

クス• web ブラウザとの統合・連携

す。Groovy 活用法７パターンでいうところの、"Lipstick" パター

JavaFX 2.0 の API は す べ て Java ベ ー ス な の で、Groovy か ら

普 通 の Java ラ イ ブ ラ リ の よ う に 利 用 す る こ と も 可 能 で す が、GroovyFX では、さらに次のような機能を提供することによって、JavaFX をより Groovy らしく、簡単・便利に利用できるようにしています：• Groovy のビルダーを活用した DSL• SceneGraphBuilder: シーングラフの構築• TimelineBuilder: タイムラインの構築• Groovy の言語機能を活用した便利な記法
Java SE を拡張する JavaFX• Duration リテラル : 100.ms, 5.s, 3.h など• 疑似定数 : red, vertical, ease_out など

JavaFX 2.0 は、今日の GPU の性能をフルに引き出せるよう設計• 属性値の自動型変換 : 文字列→ Font、リスト→ Point3D など現されたグラフィックス /UI 要素を高速に描画します。シーング

JavaFX 1.x までは JavaFX Script という独自の言語が使われておされた新しい描画エンジンを備え、シーングラフという形で表

ラフの各ノードには多彩なエフェクトやトランジションを適用り、この言語によって、JavaFX のシーングラフ構築などを簡潔

GStreamer ベースのメディアプレーヤを内蔵し、これらをシーンではこの言語が廃止され、すべてが Java ベースになったため、す。

GroovyFX を使えば、Groovy が持つ豊かな言語機能と、GroovyFXすることができます。さらに、WebKit ベースのブラウザ実装や、かつ見通しよく記述することができました。しかし、JavaFX 2.0

グラフに埋め込んだり、Java から自在に制御することもできま

記述は煩雑になってしまいました。JavaFX Script の後継としてJavaFX の開発が始まったのは Oracle による Sun 買収の数年前までさかのぼり、途中何度かの開発方針の見直しなどを経て、現が提供する JavaFX に特化したサポートの組み合わせが、JavaFX
Script の抜けた穴を補って余りあるでしょう。

在の形に落ち着きました。現時点では、Windows 用の正式版と、■入手とビルド

年には Linux 版も予定されています。

や jar などの便利なバイナリディストリビューションもありませ

Mac OS X 用の開発者プレビュー版がリリースされており、2012

14 GroovyFX で遊ぼう！（導入編）

残念ながら GroovyFX はまだアルファリリースの段階です。zip

G*Magazine vol.4ん。利用するためにはまずソースを入手し、自分でビルドする必要があります。

とは言ってもビルドには難しいところはありませんので、下記の手順にそってぜひやってみてください：
1. 必要なソフトウェアの用意• JavaFX SDK ( 最新バージョン : 2.0.2)

http://www.oracle.com/technetwork/java/javafx/downloads/index.html

JavaFX の ラ ン タ イ ム。Java SE 7 Update 2 か ら は、Java SE にもバンドルされています。インストール後、環境変数 JAVAFX_HOME にインストール先を設定しておいてください。
• Groovy ( 最新バージョン : 1.8.4)

簡単なプログラムの例
では実際に GroovyFX プログラムの例を見てみましょう。
import groovyx.javafx.*
key = ' ※ Google+ の API キー 'uid = 110611905999186598367// user ID

url = "https://www.googleapis.com/plus/v1/
people/$uid?key=$key".toURL()
json = new groovy.json.JsonSlurper().
parseText(url.text)
GroovyFX.start {def sg = new SceneGraphBuilder()http://groovy.codehaus.org/Download

Groovy のランタイム。（G* Magazine の読者はインストール済stage = sg.stage(title: "Proﬁle", width: 640, height:380) {みだと思いますが！）scene(ﬁll: black) {imageView(x: 20, y: 40, rotationAxis: [0, 1.0, 0]) {• Gradle ( 最新バージョン : 1.0-milestone-6)

image(json.image.url.replaceAll(/sz=50/, 'sz=200'))

http://www.gradle.org/downloads

effect reﬂection(fraction: 0.25)

Groovy で作られた汎用ビルドツール。

transition =rotateTransition(1.s, from:0, to:360, tween: ease_out)

2. ソースを入手

onMouseClicked { transition.play() }リポジトリからソースをチェックアウトします。

}
text(x: 240, y: 60, text: json.displayName,% svn co http://svn.codehaus.org/gmod/groovyfx/trunk/ﬁll: white, font: "32pt", textOrigin: "top") {effect bloom()

執筆時点のリビジョンは 1072 でした。

}
text(x: 240, y: 120, text: json.tagline,

3. ビルド実行

ﬁll: white, font: "16pt", textOrigin: "top")build.gradle のあるディレクトリで gradle コマンドを実行しま

}

す。

}

% cd groovyfx/trunk/groovyfx/

stage.show()% gradle build

transition.play()}

4. クラスパスの設定

build/libs の下にできた groovyfx-0.1-SNAPSHOT.jar にクラスパスを設定します。もしまだなら、$JAVAFX_HOME/rt/lib/jfxrt.jar※下記から Google+ の API キーを入手し、key 変数に設定してください。

https://code.google.com/apis/console/

もクラスパスに入れておきます。

以 上 で、GroovyFX の 利 用 準 備 が 整 い ま し た。src/demo/

groovy の下にたくさんのデモスクリプトがあるので、実行してみたりソースを眺めてみるとよいでしょう。

GroovyFX で遊ぼう！（導入編） 15

G*Magazine vol.4
このプログラムは、Google+ の API を使って特定のユーザのプ

ロフィール情報を取得し、次のような画面を出力します：

このサンプルのシーングラフは下図のようになっています：

サンプルのシーングラフ構造

トップレベルのウィンドウに相当する Stage の下に、各ノード を 収 容 す る コ ン テ ナ で あ る Scene、 さ ら に そ の 下 に 1 つ の実行結果

簡単なアニメーション要素として、起動時に一度、そしてクリッ

クするたびにプロフィールイメージが回転するようにしてあります。

ImageView と 2 つの Text ノードがあります。各コンテナやノードの属性は、Groovy の他のビルダーと同様、マップのリテラル形
式（key:value）で記述され、エフェクトやトランジション、イ
ベントハンドラなども各ノードの子要素として記述されています。

■コードの概要説明

最初の数行では、Google+ の API にアクセスして、JSON のレ

スポンスを受け取っています。JavaFX には JSON パーサが盛り込まれる予定もあったのですが、最終的には入りませんでした。
Groovy には標準で JSON パーサが装備されており、このような
web API の利用では大いに役立ちます。
GroovyFX.start {def sg = new SceneGraphBuilder()
この部分は GroovyFX アプリの決まり文句です。
GroovyFX クラスは JavaFX の Application クラスのサブクラス

で、start メソッドも Application クラスのものと同様の意味を持ちます。ただし、GroovyFX ではクロージャを渡せるようになっており、このクロージャが JavaFX のアプリケーションスレッド
で実行されます。シーングラフの構築などはこのクロージャの中で行われる必要があります。

次の行では SceneGraphBuilder のインスタンスを生成しています。以下、このビルダーを使ってアプリケーションのシーングラ
フを構築しています。

上記の構造図と比較しながらコードを眺めると、シーングラフの構造と各ノードの属性や振る舞いが、簡潔かつ明快に表現されていることがよくわかると思います。

もう少し細かいところも見てみましょう。
rotateTransition(1.s, from:0, to:360, tween: ease_out)
この行には 1.s という表現がありますが、ここは本来 JavaFX では Duration を指定するところです。GroovyFX では、Groovy のメ

タプログラミング機能を使って Number クラスに getS、getMs などのメソッドを追加して、Number から Duration への変換を実現しています。これにより、5.s、100.ms、3.h などの表現が可能になっています。

また、上のコードでの ease_out や、色を指定している black、

white などはいったい何者でしょうか？これらは一見定数のよ
うに見えますが、実はそうではありません。SceneGraphBuilder
クラスの中に定義した propertyMissing メソッドで未知のプロパ

ティへのアクセスをフックし、対応する値に変換するというからくりで、簡潔な表現の疑似定数として実現されています。

さらに、JavaFX なら Font や Point3D、VPos といった型で指定すべき属性に対して、リストや文字列などが使われていることにも気づかれたかもしれません。これらは FXHelper というクラス
で、渡された型に応じて、しかるべきクラスに自動変換する仕組みが実装されています。

以上のように、GroovyFX では、ビルダーによるシーングラフの宣言的な構造記述に加え、Groovy の機能を駆使して記述を簡潔にするさまざまな仕組みによって、JavaFX の快適な利用を実現しているのです。

16 GroovyFX で遊ぼう！（導入編）

G*Magazine vol.4

まとめ
今回は GroovyFX の概要とインストール、そしてごく簡単なコードを例にその特徴を見てきました。

GroovyFX( と JavaFX) に は、 変 数 の バ イ ン ド 機 構 や FXML、

Swing や Griffon との統合、HTML5 コンテンツとの連携など、面白い話題がまだまだたくさんあります。次回以降はそういった話
題を取り上げ、サンプルコードを使ってみなさんと一緒に「遊んで」いきたいと思います。どうぞお楽しみに！

■リンク• JavaFX http://javafx.com/• GroovyFX http://groovy.codehaus.org/GroovyFX• 使用したサンプルコード https://gist.github.com/1341142

GroovyFX で遊ぼう！（導入編） 17

G*Magazine vol.4

Betamax ことはじめ
series09

須江 信洋（日本アイ・ビー・エム株式会社）エンタープライズ Java を中心にミドルウェア製品のプリセールスを担当。日本 Grails/Groovy ユーザーグループ サポートスタッフ。『Groovy イン･アクション』（毎日コミュニケーションズ）翻訳チーム、および『プログラミング GROOVY』（技術評論社）執筆チームの一員。本稿は著者個人の考えおよび経験に基づいて記述したものであり、所属する会社や組織の意見を表すものではありません。

JGGUG でサポートスタッフを担当させていただいている @スコードが 200 であることを確認するテストケースを Spock で記

今回は Groovy ベースのテスト支援ツールである Betamax の紹▼src/test/groovy/MySpec.groovy

nobusue と申します。

介記事を書かせていただくことになりました。G*Magazine には述してみます。テストケースは以下のようになります。

初登場となりますが、よろしくお願いいたします。

import betamax.Betamax

Betamax とは

import spock.lang.*

import betamax.Recorderimport org.junit.*

Betamax は Web へのアクセスを記録して再生することのでき

import groovyx.net.http.RESTClient

最 近 の ア プ リ ケ ー シ ョ ン は Twitter や Facebook な ど 外 部 のProxySelectorRoutePlanner

る record/playback proxy です。

WebAPI と連携するものが多くなってきていますが、Betamax を利用すると実際に WebAPI や Web サイトへのアクセスを行わず

import org.apache.http.impl.conn.

class MySpec extends Speciﬁcation {にアプリケーションのテストを行うことができます。

@Rule Recorder recorder = new Recorder()Betamax は HTTP リクエスト・レスポンスのペアを、HTTP リ// (1)Recorder の設定

クエストの内容をキーとして「tape」というテキストファイル(YAML) に記録します。テストケースに対して tape を指定してやることで、既に記録済みの HTTP リクエストに対しては tape の内@Shared RESTClient http = new RESTClient()

得られたレスポンスをキャプチャして tape に記録します。

def setupSpec() {容が再生されます。未記録の HTTP リクエストであれば、実際に

http.client.routePlanner =Betamax を使うことで、例えば以下のような効果が期待できま

new ProxySelectorRoutePlanner(す。

// (2)Proxy の設定• WebAPI を利用するアプリケーションのテストをオフラインでhttp.client.connectionManager.schemeRegistry,

行うことができる。

ProxySelector.default)

新幹線で移動中でも OK。

• いちいち WebAPI にアクセスする必要がなくなるため、スロー}• WebAPI 側の障害や仕様変更などからテストを分離できるた@Betamax(tape = "my tape")

テスト問題を解決できる。

def "simple http get response data"(){

め、テストを安定化することができる。

when:• 再現が難しいレアケースなどに対するテストを容易にできる。

def response = http.get(uri:"http://grails.org/")

例えば Twitter API の呼び出し回数制限に引っかかった場合な

then:

ど。

response.status == 200• tape を資産として再利用したり、加工したりできる。

Betamax の発想の元となった vcr(Ruby ベース ) というプロダク
トでは、既に多くの資産が蓄積されています。

Betamax の開発者は Rob Fletcher 氏です。Rob は Geb のコミッタでもあり、Betamax には Geb/Spock/Grails といった G* エコシ
ステムとの連携があらかじめ織り込まれています。

Hello, Betamax
何はともあれ、まず実際に Betamax を動かしてみましょう。

http://grails.org/ にアクセスして、HTTP レスポンスのステータ

18 Betamax ことはじめ// (3)Tape の設定}}(1) では、JUnit の @Rule アノテーションを利用して、Betamaxの Recorder を MethodRule として定義しています。この設定により、テストケースで Betamax の機能が利用できるようになります。

(2) では、RESTClient の proxy 設定として JVM の proxy 設定が反映されるようにしています。
（Betamax は JVM の proxy 設定を利用してリクエスト・レスポンスのキャプチャーを行います。）(3) では、テストケースを実行する際にリクエスト・レスポ

G*Magazine vol.4
ンスを記録する tape を指定しています。ここで指定した名称がtape のファイル名として利用されます。

このテストケースをビルドして実行するための Gradle ビルド

ファイルは次のようになります。
▼build.gradle▼my_tape.yaml( 抜粋 )!tape
name: my tapeinteractions:- recorded: 2011-12-17T10:07:58.216Z
request:apply plugin:"groovy"

method: GET
uri: http://grails.org/

repositories {headers:
Accept: '*/*'

mavenCentral()Accept-Encoding: gzip,deﬂate}

Host: grails.org
Proxy-Connection: Keep-Alive

dependencies {groovy "org.codehaus.groovy:groovy-all:1.8.4"

response:

testCompile "com.github.robﬂetcher:betamax:1.0"

status: 200

testCompile("org.codehaus.groovy.modules.

headers:
Content-Encoding: gzip

http-builder:http-builder:0.5.1") {exclude module:"groovy"Content-Language: en-US

exclude module:"httpclient"Content-Type: text/html;charset=UTF-8}

Date: Sat, 17 Dec 2011 10:07:50 GMT

testCompile("org.spockframework:spock-core:0.5-groovy-1.8") {Server: Apache/2.2.3 (Red Hat)
Vary: Accept-Encoding

exclude mogule:"groovy-all"}

body: "<!DOCTYPE html>\n<!--[if lt IE 7 ]><html class=\"ie6\"> <![endif]-->}\n<!--[if IE 7 ]>（ こ れ ら の コ ー ド は https://github.com/nobusue/betamax-

・・・

らは Gradle を導入していない環境でも実行できるように Gradle

HTTP リクエストの記録日時、URI とヘッダ、およびレスポン

examples/tree/master/HelloBetamax か ら 入 手 で き ま す。 こ ちWrapper を仕込んであります。）

それではテストケースを実行してみましょう。build.gradle の配置されているディレクトリから以下を実行します。
> gradle test

(Gradle Wrapper を使う場合 ) > gradlew test
「BUILD SUCCESSFUL」と表示されれば、テストは成功です。

こ の と き、src/test/resources/betamax/tapes を 確 認 す る と、

my_tape.yaml というファイルが生成されているはずです。これが Betamax が記録した HTTP リクエスト・レスポンスです。

スのヘッダとボディが記録されていることがわかります。

それでは、tape が記録済みの状態で再度テストを実行してみましょう。（初回実行時は Gradle が依存ライブラリを取得するのに時間がかかるため、何回かテストを実行してみるとよいです。）
記録済みの URI に対するリクエストを Betamax が横取りして tapeを再生するため、tape なしでテストを実行した場合よりも早くテストが完了するはずです。私の環境では、tape なしの場合はビルド完了まで 10 秒程度かかっていましたが、tape ありの場合
は 6 秒程度まで短縮できました。

また、my_tape.yaml をリネームして保存しておき、再度 tapeを記録して比較してみると、レスポンスの差分を確認することができます。grails.org のコンテンツが変更されていなければ、recorded と Date ヘッダの値のみが変わっていることが確認できるはずです。

Grails + Geb + Betamax サンプルコードの実行
も う 少 し 実 用 的 な 使 い 方 と し て、Grails の テ ス ト ケ ー ス でBetamax を使う場合にどうすればよいかを見てみましょう。

Betamax の ソ ー ス を 見 て み る と、https://github.com/

robfletcher/betamax/tree/master/examples/grails-betamax 以 下
Betamax ことはじめ

19

G*Magazine vol.4にサンプルの Grails アプリケーションがあります。これは Twitterによりオリジナルの Betamax のサンプルではテストケースが通るアプリケーションですが、テストケースの中で Betamax を利正を施したバージョンを https://github.com/nobusue/betamax/

API 経由で「betamax」というキーワードを含む tweet を表示す用して実際の API 呼び出しをエミュレートするようになっています。

ただし、2012/12/18 時点では、Twitter Web サイトの仕様変更

らなくなってしまっています。Twitter の仕様変更に対応した修
tree/fix-grails-sample で公開していますので、「テストが fail するのは気持ち悪い」という方はこちらをご利用ください。参考までに、オリジナルからの修正点は以下のとおりです。

diff --git a/examples/grails-betamax/grails-app/views/twitter/tweets.gsp
b/examples/grails-betamax/grails-app/views/twitter/tweets.gsp
index 7f84680..187706d 100644--- a/examples/grails-betamax/grails-app/views/twitter/tweets.gsp+++ b/examples/grails-betamax/grails-app/views/twitter/tweets.gsp@@ -4,7 +4,7 @@<li><blockquote><p>${it.text}</p><small><a href="http://twitter.com/${it.user}" rel="external">@${it.user}</a></small>+<small><a href="http://m.twitter.com/${it.user}" rel="external">@${it.user}</a></small></blockquote></li></g:each>diff --git a/examples/grails-betamax/test/functional/betamax/examples/TwitterPageSpec.groovyb/examples/grails-betamax/test/functional/betamax/examples/TwitterPageSpec.groovyindex 53e03d7..340a499 100644--- a/examples/grails-betamax/test/functional/betamax/examples/TwitterPageSpec.groovy+++ b/examples/grails-betamax/test/functional/betamax/examples/TwitterPageSpec.groovy@@ -50,7 +51,7 @@ class TwitterPageSpec extends GebSpec {$('#tweets li').eq(0).ﬁnd('small a').click()then:title == "Christine Romero (@la_dyosa) on Twitter"$('div.user-screen-name').text() == "la_dyosa (Christine Romero)"+}}

サンプルアプリケーションの実行には Grails が必要ですので、別途導入しておいてください。( 私の環境では Grails-1.3.7 で動作確認を行いました。)

実 行 方 法 は 簡 単 で、 ソ ー ス を clone し て examples/grails-

betamax/ に移動し、以下を実行するだけです。
> grails run-app「Server running. Browse to http://localhost:8080/grails-

betamax」が出力されたら、ブラウザでアクセスすると以下の画面が表示されます。

このアプリケーションは画面表示毎に Twitter API を実行しているので、ためしに Twitter で「betamax 最高！」などとつぶや
いてから、画面を再表示してみてください。あなたの tweet が一覧に表示されるはずです。

アプリケーションの動作を確認したら、サーバーを停止しておいてください。
「twitter」リンクをクリックすると、Twitter から「betamax」

を含む tweet を 10 件と、Twitter クライアントの分布を表示する
画面に遷移します。

20 Betamax ことはじめ

次に、テストを実行してみます。このサンプルではユニッ

ト テ ス ト (test/unit/betamax/examples/) と 機 能 テ ス ト (test/
functional/betamax/example) が提供されています。さきほどと同様に以下を実行してみてください。

G*Magazine vol.4> grails test-app
テストコードがビルドされ、ユニットテストおよび機能テストが実行されます。機能テスト実行時は自動的にアプリケーションが起動されるため、テスト完了まで少し時間がかかります。

Tests PASSED - view reports in target\test-reports
Application context shutting down...
Application context shutdown.
と い う 表 示 が 出 た ら テ ス ト は 完 了 で す。taget/test-reports/

html/index.html を開いてテスト結果を確認してみてください。

テストが完了したところで、具体的にテストケースで何をしているのか確認してみましょう。
▼test/unit/betamax/examples/TwitterServiceSpec.groovyclass TwitterServiceSpec extends UnitSpec {File baseDir = BuildSettingsHolder.settings?.baseDir ?: new File("examples/grails-betamax")@Rule Recorder recorder = new Recorder(tapeRoot: new File(baseDir, "test/resources/tapes"))
TwitterService service = new TwitterService()
def setupSpec() {def log = Logger.getLogger("betamax")
log.addHandler(new ConsoleHandler())}
def setup() {def restClient = new RESTClient()
restClient.client.routePlanner = new ProxySelectorRoutePlanner(
restClient.client.connectionManager.schemeRegistry, ProxySelector.default)
service.restClient = restClient}@Betamax(tape = "twitter success")def "returns aggregated twitter client stats when a successful response is received"() {when:
def clients = service.tweetsByClient("betamax")

}

then:
// (1)Twitter クライアントの分布のテスト
clients.size() == 6
clients["\u00DCberSocial for BlackBerry"] == 4clients["TweetDeck"] == 2clients["Echofon"] == 1
clients["Mobile Web"] == 1
clients["Snaptu"] == 1
clients["Twitter for BlackBerry\u00AE"] == 1

@Betamax(tape = "twitter success")def "only retrieves tweets containing the search term"() {when:
def tweets = service.tweets("betamax")

}

then:
// (2)betamax を含む tweet の検索結果件数と内容のテスト
tweets.size() == 10
tweets.every { it.text =~ /(?i)betamax/ }@Betamax(tape = "twitter rate limit")
def "sets an error status when twitter rate limit is exceeded"() {when:service.tweetsByClient("betamax")

}

}

then:
// (3) 異常系 ( 例外発生 ) のテスト
thrown TwitterException

Betamax ことはじめ

21

G*Magazine vol.4(1) と (2) はいずれも Twitter API の実行結果に依存しているので、本来であればテスト用にモックやスタブを用意しなければなりません。しかし、ここでは Betamax の tape を利用することで、まとめ
今 回 は、Groovy で 実 装 さ れ た record/playback proxy で あ る

Twitter API の呼び出しを Betamax の proxy で代替しています。

Betamax についての簡単な紹介と、Grails のテストケースでの活かかったケースを tape として記録しておき、それを再生するこンや、内部動作についてご紹介したいと思います。

(3) についても同様で、Twitter API の呼び出し回数制限に引っとでテストを実行しています。このようなテストは WebAPI に負荷をかけるなどの問題があるため通常は再現が難しく、モックやスタブで置き換えるのも一筋縄ではいきません。Betamax が効果を発揮する典型的なケースであるといえます。

Betamax をソースからビルドする場合の注
意点■SonaType のアカウント設定

Betamax のソースコードを clone してビルドしようとすると、「No such property: sonatypeUsername」 と い う 例 外 が 発 生 してビルドができません。これは「sonatypeUsername」および「sonatypePassword」が設定されていないことが原因です。

これらの設定は SonaType に成果物 ( アーティファクト ) をアッ

プロードする際に必要となるもので、単にビルドして利用するだけなら利用されることはありません。回避策として、build.

gradle と同じディレクトリに以下のファイルを作成してください。

▼gradle.properties
sonatypeUsername=sonatypePassword=■一部のテストが通らない

Betamax の実装はエンコーディングやタイムゾーンの考慮が不十分な箇所があり、日本語環境で実行すると通らないテストがあります。単に使うだけであれば特に実害はないので無視していた
だいてかまいません。

我こそはと思われる方は、ぜひバグ取りにご協力ください。

22 Betamax ことはじめ

用について説明しました。次回は Betamax のコンフィグレーショ

Betamax の最新安定バージョンは 1.0 ですが、まだまだ発展途

上のプロダクトであり 2012 年 12 月現在も活発な開発が続いています。Betamax について興味をもたれた方は、ぜひ以下を参照してみてください。
バグフィックスや機能拡張への貢献も歓迎です。
• Betamax Web サイト

http://robfletcher.github.com/betamax/• Betamax ソースコードリポジトリ

https://github.com/robfletcher/betamax

G*Magazine vol.4

Grails Plugin 探訪
第5回~ RabbitMQ プラグイン ~URL: http://www.grails.org/plugin/rabbitmq
プラグインのバージョン : 0.3.2対応する Grails のバージョン : 1.2 以上

杉浦孝博
最近は Grails を使用したシステムの保守をしている自称プログラマ。
日本 Grails/Groovy ユーザーグループ事務局長。

共著『Grails 徹底入門』、共訳『Groovy イン・アクション』

はじめに今回ご紹介する Grails プラグインは、RabbitMQ プラグインです。

本記事は、次の環境で動作確認をしております。

• OS : Mac OS X 10.6.8

RabbitMQ サーバの設定
RabbitMQ を 利 用 す る た め の 設 定 は、grails-app/conf/Config.

groovy に記述します。
rabbitmq {connectionfactory {• Java : 1.6.0_29

username = 'guest'• Grails : 1.3.7

RabbitMQ とは
RabbitMQ とは、Advanced Message Queuing Protocol(AMQP)を使用 し た オ ー プ ン ソ ー ス の メ ッ セ ー ジ ン グ シ ス テ ム で す。
2010 年に Spring Source 社が買収し、現在は同社が RabbitMQ のpassword = 'guest'
hostname = 'localhost'}}設定できるプロパティは、次のとおりです。
プロパティ名説明

デフォルト値

rabbitmq.
connectionfactory.
username

RabbitMQ サーバに接続するための
ユーザ名なし

rabbitmq.
connectionfactory.
password

RabbitMQ サーバに接続するためのア
カウント用のパス
ワード

なし

ます。

rabbitmq.
connectionfactory.
hostname

RabbitMQ サーバの
ホスト名

なし

RabbitMQ プラグインのインストール

rabbitmq.
connectionfactory.
virtualHost

RabbitMQ サーバに接続するための仮
想ホスト名

'/'

rabbitmq.
connectionfactory.
channelCacheSize

接続チャネルのキャッシュサイズ

10

rabbitmq.
concurrentConsumers

メッセージハンドラごとに作成する
同時コンシューマ
の数

1

開発・サポートを行っています。

詳しくは、RabbitMQ を参照してください。

RabbitMQ プラグインとはRabbitMQ プラグインとは、RabbitMQ との統合・連携をする

ためのプラグインです。RabbitMQ プラグインは、メッセージ送受信を高レベルに抽象化するため、Spring AMQP を使用していアプリケーションを作成し、RabbitMQ プラグインをインス

トールします。

$ grails create-app rabbit$ cd rabbit$ grails install-plugin rabbitmq

Grails Plugin 探訪

第 5 回〜 RabbitMQ プラグイン〜

23

G*Magazine vol.4

キューの設定durableブローカの再起動
後もキューが存在するかどうか

false

exclusive

キューを作成したクライアントのみがキューに接続できるようにするか
どうか

false

arguments

キュー作成時の引数

null

キューの設定は、次の 2 つの方法があります。

• Spring Bean で定義する• DSL で定義する■Spring Bean で定義する

org.springframework.amqp.core.Queue 型 の Spring Bean の 定義を、grails-app/conf/spring/resources.groovy にします。
例えば、次のようになります。

エクスチェンジの設定

beans = {myQueue(org.springframework.amqp.core.Queue, 'myQueueName')
myOtherQueue(org.springframework.amqp.core.Queue,'myOtherQueueName') {autoDelete = false

エクスチェンジは、メッセージを受け取る役割を担います。エクスチェンジが受け取ったメッセージはバインドに従って、適切なキューに送られます。

エクスチェンジの設定は、grails-app/conf/Config.groovy で行

durable = trueいます。

exclusive = false
arguments = [arg1: 'val1', arg2: 'val2']}

rabbitmq {connectionFactory {

}

...
}
queues = {■DSL で定義する

exchange name: 'my.topic', type: topic

先 程 の Spring Bean の 定 義 を、DSL で grails-app/conf/Config.

groovy に記述することができます。

}}

rabbitmq {exchange に設定できる項目は、次のとおりです。

connectionfactory {項目

説明

デフォルト値

name

エクスチェンジの
名前

なし

type

エクスチェンジの種類。direct
fanout, topic,
headers から指定

なし

autoDelete

クライアントの接続がなくなった場
合にブローカーからエクスチェンジ
を削除するかどうか

false

durableブローカの再起動
後もエクスチェンジが存在するかど
うかfalse

username = 'guest'
password = 'guest'
hostname = 'localhost'}queues = {myQueueName()
myOtherQueueName autoDelete: false,
durable: true, exclusive: false,
arguments: [arg1: 'val1', arg2: 'val2']}}■設定できる項目

両方の定義方法で設定できる項目は、次のとおりです。
項目

autoDelete

説明

デフォルト値

クライアントの接続がなくなった場
合にブローカーからキューを削除す
るかどうか

false

24 Grails Plugin 探訪 第 5 回〜 RabbitMQ プラグイン〜

キューとエクスチェンジのバインド
エクスチェンジとキューのバインドも、設定で指定できます。
バインドの設定は、grails-app/conf/Config.groovy で行います。

G*Magazine vol.4

エクスチェンジの購読による受信

rabbitmq {connectionFactory {エクスチェンジの購読による受信では、まずエクスチェンジの定義を行います。

...

Grails アプリケーションが発行者となる場合、grails-app/conf/}
queues = {exchange name: 'my.topic', type: topic,
durable: false, {foo durable: true,
binding: 'shares.#'bar durable: false,
autoDelete: true,

Config.groovy でエクスチェンジの定義をします。

次に、メッセージを購読する処理のため、rabbitSubscribe という名前の静的プロパティと、handleMessage() という名前のメッセージを処理するメソッドを持つサービスを作成します。
package rabbit

binding: 'shares.nyse.*'}class SharesService {static rabbitSubscribe = 'shares'}}

void handleMessage(message) {

上記の例では、'my.topic' という名前のエクスチェンジを 1 つ// handle messageを定義し、'foo', 'bar' という名前のキューにバインドします。

...

どのメッセージをキューにバインドするかは、binding で指定

}

します。

}

にバインドされます。

rabbitSubscribe プロパティに指定するのはエクスチェンジのルーティングキーが 'shares.' で始まるメッセージは、foo キュー
ルーティングキーが 'shares.nyse.' で始まり 1 語続くメッセージ

は、bar キューにバインドされます。

メッセージの送信
メ ッ セ ー ジ の 送 信 は、rabbitSend メ ソ ッ ド で 行 い ま す。

rabbitSend メソッドは、コントローラ、サービス、タグリブといった Grails アーティファクトに RabbitMQ プラグインによって追加されます。

名前で、指定されたエクスチェンジ宛てに送られたメッセージを購読することになります。

エクスチェンジが受け取ったメッセージは、handlerMessage()メ ソ ッ ド の 引 数 と し て 指 定 さ れ、 購 読 対 象 の サ ー ビ ス のhandlerMessage() メソッドが呼び出されます。

topic タイプのエクスチェンジの場合、ルーティングキーを指定することで、受信するメッセージをコントロールできます。

rabbitSubscribe プロパティをハッシュ形式で指定し、name でエクスチェンジの名前、
routingKey でルーティングキー( のパター

class MessageController {def sendMessage = {rabbitSend 'someQueueName', 'someMessage'...

ン ) を指定します。

package rabbitclass SharesService {static rabbitSubscribe = [ name: 'shares',}routingKey: 'NYSE.GE' ]}rabbitSend メソッドは、引数を 2 つとります。1 つ目はキュー...
}の名前で、2 つ目は送信するメッセージそのものです。

メッセージの送信は、org.springframework.amqp.rabbit.core.

RabbitTemplate インスタンスを使う方法もあります。この方法については、後ほど説明します。

メッセージの受信メッセージの受信は、次の 2 通りの方法があります：

キューからの受信キューからの受信では、まずキューの定義を行います。

次に、メッセージを受信する処理のため、rabbitQueue という名前の静的プロパティと、handleMessage() という名前のメッ
セージを処理するメソッドを持つサービスを作成します。

• エクスチェンジの購読による受信 ( 発行 / 購読モデル )• キューからの受信

Grails Plugin 探訪

第 5 回〜 RabbitMQ プラグイン〜

25

G*Magazine vol.4

package rabbitclass DemoService {static rabbitQueue = 'someQueueName'
void handleMessage(message) {// handle message...

RabbitTemplate クラスを使用する。
自分で細かい制御をしたい場合、org.springframework.amqp.

rabbit.core.RabbitTemplate ク ラ ス の イ ン ス タ ン ス を Bean と して、コントローラやサービスにインジェクションし使用することができます。

Bean の名前は、rabbitTemplate です。
class MessageController {}}def rabbitTemplaterabbitQueue プロパティに指定するのはキューの名前です。

def sendMessage = {メッセージは handlerMessage() メソッドの引数として指定さrabbitTemplate.convertAndSend('someQueueName',

れ、受信対象のサービスの handlerMessage() メソッドが呼び出'someMessage)

されます。

...
}

メッセージ
RabbitMQ プラグインでは、メッセージとして、次の型のオブジェクトを使用することができます：* 文字列* バイト配列* マップ* シリアライザブル
handleMessage() メソッドをオーバーロードすることで、メッ

セージの型ごとに呼び出すメソッドを変えることができます：
package rabbitclass DemoService {static rabbitQueue = 'someQueueName'
void handleMessage(String textMessage) {// handle String message...
}
void handleMessage(Map mapMessage) {// handle Map message...
}
void handleMessage(byte[] byteMessage) {// handle byte array message...
}}

26 Grails Plugin 探訪 第 5 回〜 RabbitMQ プラグイン〜}
RabbitTemplate ク ラ ス の 詳 細 は、http://static.springsource.

org/spring-amqp/docs/latest-ga/ を参照してください。

終わりに
アプリケーションで非同期処理を行う際、メッセージシステム

を使うことを、そして RabbitMQ を使うことを検討してみてはいかがでしょうか。

G*Magazine vol.4▼ぐるーびーたん

第 3 話までのあらすじ

プログラマを目指して熊本から上京したぐるーびー

たん。いろいろ覚えて楽しそうなんだけど。。。君の名は確か !?

※この作品は、たいがいフィクションです。
実在の人物、
団体とは関係ありません。

ぐるーびーたん

第4話

27

G*Magazine vol.4

リリース情報 2011.12.15
GrailsGrails は、Groovy や Hibernate などをベースとしたフルスタックの Web アプリケーションフレームワークです。
URL: http://grails.org/
バージョン : 1.2.5, 1.3.7, 2.0.0■更新情報• 2.0.0 では、ページスコープで <g:include> が <g:set> を壊してしまうバグや、"formula" 派生プロパティが不正になるバ
グなど、いくつかバグの改修や、機能の改善が行われています。
• 2.0.0 リリースノート : http://grails.org/2.0.0+Release+Notes• 山本さんのブログ：
http://d.hatena.ne.jp/mottsnite/20111215/1323965990■更新情報• 1.9.7 では、ANT_HOME に空白文字が含まれている場合 gant.
bat が失敗するバグに対応しています。
• 1.9.7 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=11660&version=17496

GradleGradle は、Groovy でビルドスクリプトを記述し実行するビルド管理ツールです。
URL: http://www.gradle.org/
バージョン : 0.9.2, 1.0-milestone-6■更新情報• 1.0-milestone-6 では、依存解決が以前のリリースより速くなったり、デーモンが改良されたりするなど、いくつかバグの改修や、機能の改善が行われています。
• 1.0-milestone-6 リリースノート : http://wiki.gradle.org/
display/GRADLE/Gradle+1.0-milestone-6+Release+Notes

GroovyGroovy は、JavaVM 上で動作する動的言語です。
URL: http://groovy.codehaus.org/
バージョン : 1.7.10, 1.8.4, 2.0.0-beta-1■更新情報• 1.8.4 では、匿名の内部クラスでプロパティにアクセスした際に NullPointerException が発生するバグや、DefaultTypeTransformation.booleanUnbox のパフォーマン
スの改善など、いくつかバグの改修や、機能の改善が行われています。
• 1.8.4 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=17852• 2.0.0-beta-1 では、Grab の簡略表記が正しく動作しないバグ
や、@Immutable が java.util.UUID をサポートする改良など、いくつかバグの改修や、機能の改善が行われています。
• 2.0.0-beta-1リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=17925

Griffon
Griffon は、デスクトップアプリケーションを開発するためのア
プリケーションフレームワークです。
URL: http://griffon.codehaus.org/
バージョン : 0.9.4■更新情報• 0.9.4 では、ビルド時にソースのエンコーディングを指定できるようになったり、griffon.core.ServiceManager 型のインスタンスを介して全てのサービスのインスタンスにアクセスできるようになるなど、いくつかバグの改修や、機能の改善が行われています。
• 0.9.4 リリースノート :http://griffon.codehaus.org/Griffon+0.9.4

Gant
Gant は、XML の代わりに Groovy で Ant タスクを記述し実行する
ビルド管理ツールです。
URL: http://gant.codehaus.org/
バージョン : 1.9.7

28 リリース情報

GaelykGaelyk は、Groovy で記述する Google App Engine for Java 用のライトウェイトなフレームワークです。
URL: http://gaelyk.appspot.com/
バージョン : 1.1■更新情報• 1.1では、Groovy が1.8.4、
App Engine SDK が1.6.0にアップデー
トされたり、データストアサービスに get() メソッドが追加されるなど、いくつかバグの改修や、機能の改善が行われています。
• 1.1 リリースノート : http://gaelyk.appspot.com/download

Google App Engine SDK for Java
Google App Engine SDK for Java は、Java で Google App Engine
用の Web アプリケーションを開発するための SDK です。
URL: http://code.google.com/intl/ja/appengine/バージョン : 1.6.1■更新情報• 1.6.1 では、プログラムでアプリケーションのログを読み取ることができるようになったり、ハイレプリケーションデー
タストアの移行ユーティリティが一般利用可能な機能となるなど、いくつかバグの改修や、機能の改善が行われています。
• 1.6.1 リリースノート : http://code.google.com/p/
googleappengine/wiki/SdkForJavaReleaseNotes

GPars
GPars は、Groovy に直感的で安全な並行処理を提供するシステム
です。
URL: http://gpars.codehaus.org/
バージョン : 0.12GA

Groovy++Groovy++ は、Groovy 言語に対して静的な機能を拡張します。
URL: http://code.google.com/p/groovypptest/
バージョン : 0.9.0

G*Magazine vol.4■更新情報• 0.9.0 では、Groovy 1.8.2 対応されています。
• 0.9.0 リリースメール : http://groups.google.
com/group/groovyplusplus/browse_thread/thread/237434c427c57f11?pli=1

Spock
Spock は、Java や Groovy 用のテストと仕様のためのフレームワー
クです。
URL: http://code.google.com/p/spock/バージョン : 0.5

GroovyServ
GroovyServ は、Groovy 処理系をサーバとして動作させることでgroovy コマンドの起動を見た目上高速化するものです。
URL: http://kobo.github.com/groovyserv/
バージョン : 0.9

Geb
Geb は、Groovy を使用した Web ブラウザを自動化する仕組みです。
URL: http://www.gebish.org/
バージョン : 0.6.0

Easyb
Easyb は、 ビ ヘ イ ビ ア 駆 動 開 発 (Behavior Driven
Development:BDD) 用のフレームワークです。
URL: http://www.easyb.org/
バージョン : 0.9.8

Gmock
Gmock は、Groovy 用のモック・フレームワークです。
URL: http://code.google.com/p/gmock/バージョン : 0.8.1

GMetrics
GMetrics は、Groovy ソースコードのサイズや複雑さを計算したり報告するためのツールです。
URL: http://gmetrics.sourceforge.net/
バージョン : 0.4■更新情報• 0.4 では、Groovy が 1.7 にアップグレードされたり、Groovy
1.7.7 以上で GMetrics ができないバグなど、いくつかバグの改修や、機能の改善が行われています。
• 0.4 リリースノート :http://sourceforge.net/projects/gmetrics/files/gmetrics-0.4/

GContracts
GContracts は、Groovy で契約プログラミングを行うためのフレームワークです。
URL: https://github.com/andresteingress/gcontracts
バージョン : 1.2.4

GroovyFX
GroovyFX は、JavaFX を Groovy で書きやすくするためのフレームワークです。
URL: http://groovy.codehaus.org/GroovyFXバージョン : 1.0 Alpha

GBenchGBench は、Groovy のためのベンチマーク・フレームワークです。
URL: http://code.google.com/p/gbench/
バージョン : 0.2.2

Betamax
Betamax は、HTTP 通信の内容を保存し再生するテストツールです。
URL: https://github.com/robfletcher/betamax
バージョン : 1.0

HTTPBuilder
HTTPBuilder は、HTTP ベースのリソースに簡単にアクセスするための方法です。
URL: http://groovy.codehaus.org/modules/http-builder/バージョン : 0.5.1

CodeNarc
CodeNarc は、Groovy 向けの静的コード解析ツールです。
URL: http://codenarc.sourceforge.net/
バージョン : 0.16.1■更新情報• 0.16.1 では、Groovy 1.8 で CodeNarc を実行した際にStackOverflowError が発生するバグに対応しています。
• 0.16.1 リリースノート : http://sourceforge.net/projects/
codenarc/files/codenarc/CodeNarc%20Version%200.16.1/

リリース情報29

■企業スポンサー■個人サポーター
須江 信洋 様関谷 和愛 様
田中

明様

個人サポータ制度のお知らせ
JGGUG では , 2011 年度より個人サポータ制度を始めました .
今まで JGGUG の経済的な基盤はすべて法人会員の年会費に依存していました。 しかし、個人会員も金銭面からサポート

したいという声があがり、JGGUG 運営基盤の裾野を拡げるためにも、個人サポータという形で個人会員からの寄付を受け入れることにした次第です。

個人サポータとなっていただいた方には、一年間にわたって JGGUG が発行する G* Magazine（年数回刊。基本的に電子版として配布予定）に個人サポータとしてお名前を掲載します（掲載を希望しない旨お申し出いただけば掲載しません）。
個人サポータとなるには、まず supporters@jggug.org にメイルで• お名前• 予定金額G* Magazine へのご芳名掲載の可否をお知らせください。追って、運営委員より振込先の情報などを返信します。
皆様のサポートをお待ちしております。

日本 Grails/Groovy ユーザーグループ
代表

山田 正樹

G* Magazine vol.4 2011.12
http://www.jggug.org

発行人：日本 Grails/Groovy ユーザーグループ
編集長：川原正隆
編集：G* Magazine 編集委員（杉浦孝博、奥清隆）
デザイン：㈱ニューキャスト
表紙：川原正隆
編集協力：JGGUG 運営委員会
Mail：info@jggug.org© 2011 JGGUG 掲載記事の再利用についてはCreative Commons ライセンスによります。

Publisher：Japan Grails/Groovy User Group
Editor in Chief：Masataka Kawahara
Editors：G* Magazine Editors Team
(Takahiro Sugiura, Kiyotaka Oku)
Design：NEWCAST inc.
CoverDesign：Masataka Kawahara
Cooperation：JGGUG Steering Committee
Mail：info@jggug.org