2011年7月14日木曜日

移転しました

都合により、以下のサイトにブログを移転しました。

http://monochromeroad.blogspot.com/

2011年4月6日水曜日

GrailsのMailプラグインでエンコード指定(ISO-2022-JP)なメールを送る

Grailsのバージョンは1.3.7
Mailプラグインのバージョンは1.0-SNAPSHOT

結構やってるんだけど、やり方忘れるので備忘録ということで

import org.springframework.mail.javamail.MimeMailMessage
import org.springframework.mail.javamail.MimeMessageHelper

def mailService

/**
 * メールを送信する
 * 
 * @param mailParams メールサービスへ渡すパラメータ
 */
def sendMail(Map mailParams) {
    mailService.sendMail {
        helper = new MimeMessageHelper(
            mailSender.createMimeMessage(), multipart, "ISO-2022-JP")
        message = new MimeMailMessage(helper)
        
        to mailParams.to
        from mailParams.from
        subject mailParams.subject
        body mailParams.body
    }
}

上のコードをサービスクラスとかに入れて呼び出します。
Mailプラグインの設定方法はここに書いてあるままです。

Grails Mail Plugin

最近はUTF-8でもいいんでしたっけ?
でもまあ日本語メールならISO-2022-JPにしといて損はないんじゃないでしょうか。

2011年3月15日火曜日

Gradleでプロパティなどの設定情報を外出しして切り替えて使う

@bluepapa32さんの記事に触発されて書いてみました。

次のようなビルドスクリプトがあるとき、
task hello << {
    println "Hello, $yourname"
}
Gradleでプロパティ「$yourname」の設定を外だしにして、ビルドごとに結果を柔軟に変えたい、といったことを実現する方法ですね。

@bluepapa32さんも書かれているように、Gradleではさまざまな方法でこれを実現できます。
ここでは、主にGradleの機能を使ってこれを実現する方法について書いてみます。

ビルドスクリプトの設定をいろいろ切り替えるには


task hello << {
    println "Hello, $yourname"
}
上記のビルドスクリプトをそのまま「gradle hello」と実行しても、yournameなんてプロパティはないですと怒られて失敗するので、プロパティyournameをビルドスクリプトに設定してやる必要があります。

このとき、プロパティyournameのような設定情報をビルドスクリプトの外で設定し、切り替えられるようにするには、

  • コマンドライン引数で直接設定
  • 環境変数→プロパティ自動変換機能を使う
  • gradle.propertiesをユーザーのホームディレクトリまたはプロジェクトディレクトリに置く
  • 外部ファイルをビルドスクリプトなどの先頭で読み込む
  • 初期化スクリプト(init.gradle)を使う
の方法が考えられます。

詳しくはユーザーガイド(Gradleプロパティとシステムプロパティ)など見てもらうとして、ここでは一つずつ使いどころなど簡単に考えてみたいと思います。

コマンドライン引数で直接設定


コマンドラインオプションを使って、yournameのようなプロパティを設定できます。
gradle -Pyourname=literalice hello

:hello
Hello, literalice

BUILD SUCCESSFUL
設定したいプロパティが少ないときや簡単なデモなどで使えますね。

環境変数→プロパティ自動変換機能を使う


Gradleは、プレフィックス「ORG_GRADLE_PROJECT_」の付いた環境変数を定義しておくと、その値をプロパティに変換してくれる機能があります。
set ORG_GRADLE_PROJECT_yourname=literalice

gradle hello

:hello
Hello, literalice

BUILD SUCCESSFUL
設定するプロパティの数がそう多くない場合で、ビルドするマシンごとにプロパティを切り替えたいとき、jenkinsなどのCIサーバー上で簡単にビルドを設定したいときなどに。

Gradleだと、環境変数を直接ビルドスクリプトで読む(System.getenv) ようなシチュエーションは限られますね。(外部ツールとの連携時とか?)

gradle.propertiesをユーザーのホームディレクトリまたはプロジェクトディレクトリに置く


gradle.propertiesという名前でプロパティファイルを作成し、プロジェクトディレクトリまたはユーザーのホームディレクトリに置いておくと、読み込んで使ってくれます。

なお、プロジェクトディレクトリ→ユーザーのホームディレクトリの順に読み込まれます。

ユーザーのホームディレクトリのプロパティが優先して使われる(上書きする)ということです。

~/.gradle/gradle.properties
yourname=literalice
実行結果
gradle hello

:hello
Hello, literalice

BUILD SUCCESSFUL

ホームディレクトリのgradle.propertiesは、すべてのビルドスクリプトで使われます。

ツールの場所(grailsHomeとか、javaHomeとか)、ユーザーの(sshやwebページなどへの)ログイン情報などを設定するのに良いかもしれません。

ちなみに、ここまでの設定方法だと、どれ選んだ場合でもビルドスクリプトの方は変更する必要ないんですよね。素晴らしい。

外部ファイルをビルドスクリプトなどの先頭で読み込む


いくつか方法はありますが、

  • Groovyの機能で外部ファイルを読み込んで展開する
  • 外部のスクリプトファイルを読み込む

の二つを紹介しようと思います。

1. Groovyの機能で外部ファイルを読み込んで展開する

この方法は、@bluepapa32さんが解説されています。

GroovyのConfigSlurperを使って、Groovyスクリプト形式の設定ファイルを読み込み、プロパティに展開しています。

既存の設定ファイル(GrailsのDataSource.groovyやBuildConfig.groovyなど)を読み込むときに便利です。

2. 外部のスクリプトファイルを読み込む

たとえば、プロパティのセットをLinux向け、Windows向けなどいくつか定義しておいて、それらを簡単に切り替えできるようにしたい、というときはこの方法が使えます。

build.gradle
apply from:"default.config.gradle"
apply from:"${env}.config.gradle"

task hello << {
    println "Hello, $yourname"
}

設定ファイルをいくつか用意します。
default.config.gradle
yourname = "the name in the default config"
linux.config.gradle
yourname = "the name in the linux config"
windows.config.gradle
yourname = "the name in the windows config"

実行するときは、こんな感じ

gradle -Penv=windows hello

:hello
Hello, the name in the windows config

BUILD SUCCESSFUL

イメージとしては、apply from:"..."で読み込んだファイルが、そのままペーストされる感じで動きます。

読み込んでいる外部スクリプトは、ただのGradleビルドスクリプトなので、上記のようなプロパティの設定だけでなく、タスクの定義やプロジェクト設定の変更など、Gradleでできることはなんでもできます

初期化スクリプト(init.gradle)を使う


Gradleには初期化スクリプトという仕組みがあって、マシン固有の設定をここでも行うことができます。

具体的には、「init.gradle」というファイルをユーザーのホームディレクトリに置いたり、コマンドラインオプションで渡してやったりすると、ビルドが構築される前に「init.gradle」が実行されるというものです。

初期化スクリプト

このスクリプトで、今までのように単純なプロジェクトプロパティをセットするにはかなりめんどくさい方法をとる必要があり現実的ではないです。

ビルドのライフサイクルに対するリスナーや、カスタムのロガーを登録する、外部ツールとの連携に便利らしいのですが、私の使用した範囲だとまだ使いこなせたことはないですね…

まとめ


Gradleのビルドを設定する方法をいくつか見てきましたが、こんな風にいろいろな方法を選ぶことができるのはGradleの魅力の一つだと思います。

場面場面に応じて、適切な方法を選んでいきたいですね。

2010年10月31日日曜日

ビルドシステムをGradleに移行、ユーザーガイドを一部翻訳

おうちで使ってるビルドシステムをGradleに移行

そのとき、Gradleの勉強がてらユーザーガイドを翻訳してました。せっかくだから公開
http://www.monochromeroad.com/artifacts/gradle/userguide/userguide.html
リポジトリ
http://github.com/literalice/gradle-ja/wiki

Mavenもそんなに深く使い込んでたわけじゃないけど、Gradleはいろいろ分かりやすい感じ

というか、MavenとAntはそんなにかぶってた印象無いけど、GradleとGantは丸かぶりでは?
いままでAntで書いてたところも大体Gradleのほうがやりやすいと思います

2010年7月30日金曜日

Grailsを1.3.3に上げたら、ユニットテストがNullPointerExceptionで壊滅

Grailsのバージョンはもちろん1.3.3

タイトル通り、Grailsを1.3.3に上げたら、ユニットテストがNullPointerExceptionで壊滅しました
原因はGRAILS-6482で1.3.4で直るらしいですが、とりあえず回避方法としては次のコードをユニットテストにいれるといいらしいです。
protected void setUp() {
   super.setUp()
   PluginManagerHolder.pluginManager = [hasGrailsPlugin: { String name -> true }] as GrailsPluginManager
}

protected void tearDown() {
   super.tearDown()
   PluginManagerHolder.pluginManager = null
}

ユニットテストが多くなってくるとめんどいので、_Events.groovyに次のコードを入れました。
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.codehaus.groovy.grails.plugins.PluginManagerHolder

eventTestPhaseStart = { phase ->
    if (phase == 'unit') {
        PluginManagerHolder.pluginManager = [hasGrailsPlugin: { String name -> true }] as GrailsPluginManager
    }
}

eventTestPhaseEnd = { phase ->
    if (phase == 'unit') {
        PluginManagerHolder.pluginManager = null
    }
}

これでいいかどうかは不明ですがとりあえずNullポは消えたので。

2010年7月9日金曜日

hudson+antでgrailsアプリをビルドする その1

Grailsアプリケーションをhudson上でビルドするにはいくつか方法があります。
hudsonにGrailsプラグインがあるので、それを使用してビルドすることもできます。シェルでgrailsコマンドを呼び出すこともできます。
しかし、後々ビルド手順が複雑になったりしたときなどを考えると、やはりantのbuild.xmlにビルド手順をまとめて、hudson上からはbuild.xmlのデフォルトターゲットを呼び出すだけ、くらいにしておいたほうがいいかと。
いや、gantでもpomでもいいんですけどね。

まず、build.xmlを作成するところまで書いてみます。ポイントは、

では↓

1:build.xmlを生成
というか、grailsが作ってくれます。
cd [grails-project]
grails integrate-with --ant
これで、Grailsプロジェクトの中にbuild.xml、ivy.xml、ivysettings.xmlができているはず。
(ちなみにこれらのファイルはgrails upgradeでなぜか更新されないので、grailsを更新したらこれらのファイルを削除してもういちどintegrate-withコマンドを実行)

antコマンドを試してみましょう。基本的にgrailsコマンドに対応したantターゲットができています。
必要な環境変数を設定して、実行
普通にやるとメモリ不足で落ちることが多いので、ヒープサイズも指定しておきます。
set GRAILS_HOME=C:\grails\grails-1.3.2
set ANT_OPTS=-Xmx1024m -XX:MaxPermSize=512m

ant compile

download-ivy:
...(略)...

[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]          ::          UNRESOLVED DEPENDENCIES         ::
[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]          :: org.jboss.netty#netty;3.1.5.GA: not found
[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]
[ivy:retrieve]
[ivy:retrieve] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS

BUILD FAILED
D:\project\literalice\sandbox\grails-ant-build\build.xml:60: impossible to resolve dependencies:
        resolve failed - see output for details
…失敗。あれ?
これですね。
http://jira.codehaus.org/browse/GRAILS-6410
1.3.4で直るらしい。でもまあたぶん、リポジトリ追加してやればいいんじゃないかな…

2:依存先リポジトリの追加
先ほど生成したivysettings.xmlに、antビルドが使用しているリポジトリがリストされているので、ここにさっき足りない言われたライブラリのリポジトリを追加します。

  
  
  
  
  
  
    
      
      
      
      
      
      
    
  

で、もういちど
ant compile
...(略)...
compile:
[grailsTask] Resolving dependencies...
[grailsTask] Dependencies resolved in 738ms.

BUILD FAILED
D:\project\literalice\sandbox\grails-ant-build\build.xml:104: The following error occurred while executing this line:
D:\project\literalice\sandbox\grails-ant-build\build.xml:48: Unable to start Grails: java.lang.reflect.InvocationTargetException
うは失敗しかもイミフ

結論から言うと、antのバージョンが1.8系だとダメみたい。
antのバージョンを1.7.1にしてもう一回!
ant compile
...(略)...
[grailsTask]   [groovyc] Compiling 7 source files to D:\project\literalice\sandbox\grails-ant-build\target\classes
[grailsTask]

BUILD SUCCESSFUL
Total time: 5 seconds
OK。

3:依存先リポジトリの追加
さて、私としては、ビルド手順は極力build.xmlに集めたいです。
なので、test、warなどのコマンドをターゲットを順に呼び出すターゲットを作成します。
私はbuild.xmlに直接追加しましたが、別のビルドファイルを作成して、そのファイルからbuild.xmlを呼び出すようにしてもいいかもしれません。

これでもいいですが、私の場合war作成時のビルド環境(dev,prod,test,etc...)を明示したかったので、以下のように修正しました。
あと、non-interactiveをコマンド引数に指定しないと、hudsonに持って行ったときにループっぽくなってビルドが進まなくなります。

まず、antのgrailsマクロにビルド環境の引数を追加します。

    
    
    
    
        
            
            
            
        
    


つぎにデフォルトターゲットに指定するビルド用ターゲット

    
    
    
    


これでbuild.xmlができました。あとはhudson上に持って行ってビルドするだけです。
ただし、このままだとgrailsがビルドやテストに使用するディレクトリ(普通は%HOME%/.grails以下)をhudsonジョブ間で共有します。
並行ビルドなど考えると、各ジョブ間の作業ディレクトリはなるべく分割しておきたいところです。

このへんは次回。

2010年7月6日火曜日

GrailsアプリケーションのAntビルドでSSLHandshakeException

grails1.2系で、初めてプロジェクトをビルドするときにantでビルドすると、こんなエラーが起こることがあります。
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException

これが発生するのは、プロジェクトはあるけど、まだ作業ディレクトリ(.grails)がない状態。つまり、
  • Grailsプロジェクトを新マシンにチェックアウトしてantでビルド
  • 作業ディレクトリを~/.grailsから別の場所に変更してantでビルド
などのときに発生するようです。

Tomcatのプラグインを、httpsのプラグインサイト上から落そうとして証明書エラー…javaが知らない認証局を使ってるらしい。
プラグインサイトが使用している中間認証局の証明書をkeytoolでインポートすれば、とりあえずビルドはできます。

証明書: https://www.startssl.com/certs/sub.class2.server.ca.crt

keytool -import -keystore %JAVA_HOME%/jre/lib/security/cacerts -file sub.class2.server.ca.crt -alias sub.class2.start.com
パスワードは変更していなければ「changeit」
証明書インポートについては、HttpClientでSSL通信が詳しいです。

なお、Grails1.3以降だとtomcatプラグインはネットワークからではなくGRAILS_HOMEから持ってくるようで、このエラーは発生しませんでした。