Literal Ice
開発中の備忘録、旅行日記、ゲーム日記、本の感想とかもうごった煮
2018年10月4日木曜日
2013年4月18日木曜日
Cloud FoundryにWebアプリをIntelliJでデプロイする
IntelliJのバージョンいくつかから、Cloud FoundryおよびCloudBeesとの連携機能がバンドルされるようになっていたので試してみました。
ここではとりあえず、GrailsアプリをCloud Foundryにデプロイしてみます。
プロジェクトを作成
デプロイするwarファイルを作成する
「Ctrl+Alt+G」から「prod war」コマンドを実行して、デプロイするwarを作成します。
実行設定を作成
「Edit Configuration」から……
「Defaults」から「Cloud Foundry Server」を選択して、緑の+ボタンで実行設定を追加
「Server」タブの「Configure」でCloud Foundryアカウントを設定
「Deployment」タブでデプロイするwarを設定
デプロイするアプリの設定を行う。とりあえず、「Type」を「Grails」に。MongoDBとかサービスを追加するときは「Edit services」から適宜追加。
設定したwarをデプロイ
「Application Servers」タブから、緑の矢印でCloud Foundryに接続、デプロイ
で、warがデプロイされて、ブラウザが開いてアプリケーションに繋がるはず。
アプリケーションを更新したら
「prod war」でもう一回warを作り直して、実行画面から更新。更新中404になるのがイケてない。
うわぁ簡単すぎて書くことない…もうちょっと複雑なことしようとしたらいろいろ出てくるかも、ということで
2012年12月14日金曜日
GrailsでMongoDBの複合キーインデックスに属性を指定するプラグインを公開
先日、Grailsプラグインgrails-mongodb-compound-index-attributesを紹介して、セントラルリポジトリに公開するまでもないので何とかかんとかと書きましたが、公開してもいいですよということなのでやっぱりお言葉に甘えてGrailsセントラルに公開することにしました。
以下、プラグインについて。
MongoDBでは複合キーに対してインデックスをはることができます。 GrailsのMongoDBプラグインでは、以下のように指定します。
class Book { static mapping = { compoundIndex contributor: 1, name: 1 } String contributor String name }
が、今のところ、このインデックスにユニーク属性などの属性を指定できません。
それを解決するのが、今回公開したMongoDBプラグインのアドオンであるgrails-mongodb-compound-index-attributesです。インストールすると以下のようにできます。
class Book { static mapping = { compoundIndex contributor: 1, name: 1, indexAttributes: [name: "contributorUniqueName", unique: true] } String contributor String name }
ブラボーGrailsプラグインシステム
2012年12月11日火曜日
GrailsのプラグインをCloudBeesで公開する
どうも、G* Advent Calendar 2012、11日目担当、@literaliceです。
さて、突然ですが先日、grails-mongodb-compound-index-attributesというGrailsのプラグインを公開しました。
このプラグインは、GrailsのMongoDBプラグインを拡張し、compound indexにunique属性などを追加できるようにするものです。こんな:
class Book { static mapping = { compoundIndex contributor: 1, name: 1, indexAttributes: [name: "idxName", unique: true] } String contributor String name }
で、この機能はどうせ将来的にMongoDBプラグインに実装されるでしょうし、わざわざGrails本家のプラグインリポジトリに公開するまでもない気がしますね。
以前はこういうとき、Githubをプラグインリポジトリにして公開していました。
が、ナウい方法はCloudBeesのDEV@cloudを使うことです。
DEV@cloudは登録するとJenkinsサーバーとMavenリポジトリ、Gitのリポジトリをもらえます。
Mavenリポジトリはいろいろハウスキーピングしてもらえますし、何よりプライベートリポジトリにできるのがGithubをムリヤリ使う方法に比べてイケてますね。
と言うわけで前置きが長くなりましたが、GrailsプラグインをCloudBees、DEV@cloudで公開する手順を紹介します。
- Grails version
- 2.1.1
手順
Grailsプラグインを作る
作ります。例:grails-mongodb-compound-index-attributes
CloudBeesにアカウントを作る
作ります。→CloudBees
releaseプラグインをCloudBees用に設定する
releaseプラグインはGrailsのcreate-pluginコマンドでプラグインを作成すれば入ってるはずです。
このreleaseプラグインを、CloudBees上に作られたWebDAVのMavenリポジトリにリリースするよう設定します。
// BuildConfig.groovy or ~/.grails/settings.groovy grails.release.scm.enabled = false // プラグインのソースコードはリリースしない grails.project.repos.default = "releaseRepository" // リリース先未指定時のリリース先 grails.project.repos.releaseRepository.url = "dav:https://repository-[CloudBeesアカウント名].forge.cloudbees.com/release/" // リリース先"releaseRepository"のURL grails.project.repos.releaseRepository.type = "maven" grails.project.repos.releaseRepository.username = "[CloudBeesのUser SettingsにあるUsername]" grails.project.repos.releaseRepository.password = "[CloudBeesのログインパスワード]"
私の場合は、CloudBeesのJenkinsからビルド、リリースしているので、システムプロパティでファイルを渡して、そのファイルから上記設定を読み込むようにしています。その設定ファイルは、CloudBeesに用意されるプライベートなファイルストレージに置いておきます。
例: BuildConfig.groovy
publish-pluginコマンドでリリース
grails publish-plugin --repository=releaseRepository --protocol=webdav
なお、CloudBees上のJenkinsでビルド、リリースする場合は、前述のようにシステムプロパティに認証情報などを記述した設定ファイルのパスを渡し、そのファイルから設定を読み込むようにします。
sh ./grailsw -DhogehogeFile=/private/[CloudBeesアカウント名]/grails/credential.properties publish-plugin --repository=releaseRepository --protocol=webdav --non-interactive
公開したプラグインをGrailsプロジェクトで使用する
このようにプラグインを公開すると、Grailsプロジェクトから以下のようにして使用できるようになります。
//Build.groovy grails.project.dependency.resolution = { // ... repositories { // ... // For the plugin mavenRepo "http://repository-[CloudBeesアカウント名].forge.cloudbees.com/release" } // ... plugins { // ... compile ":[公開したプラグイン名]:[公開したプラグインバージョン]" } }
まとめ
というわけで、こんな感じにCloudBeesを使ってGrailsプラグインを流れるようにpush→Jenkinsビルド→Mavenリポジトリに公開しましょう。
G* Advent Calendar 2012、12日目は@yamkazuさんです。
2012年6月1日金曜日
PaaSでGrailsならCloudBeesがイイ
HerokuとかCloud Foundryとか、いろんなPaaSを試してみましたが、今のところCloudBeesが良い感じだと思いました。
なお、パフォーマンスや安定性を調査したわけではなく、アプリを動かしてみたときの単純な感想です。
Jelasticなど、Javaをメインに想定したPaaSであればGrailsとの相性もいいと思うので、更に調査したいと思っています。
さて、CloudBeesですが、無料範囲だと、1アプリにつき2インスタンス、5アプリまで作れるようです。さらにビルド環境も用意してくれます。
メモリ制限がきついので本格運用するときは有料プランが必要でしょうけど、試しに始めてみるにはいいGrails実行環境なんじゃないでしょうか。
以下いいとこ雑感
- Amazon EC2で動作
- これはメリットデメリットあると思いますが、とりあえずMongoHQとかMongoLabとかAmazon SESとか、AWS使った豊富なサービスが使えるのが嬉しい。
例えばcloudfoundry.comとかだとそうは行かない - ビルドサーバー付き
- DEV@cloudというCloudBeesのサービスでJenkinsサーバーが使えます。
ソースコードをプッシュしたら、CloudBees上のTomcatで公開するまで全自動。
HerokuにもBuildpackというシステムがあって、ソースコードをプッシュしたら自動でビルドが走ってデプロイしてくれる…
が、Grailsのように依存性解決なんかでビルドに時間がかかる場合、途中でタイムアウトになってデプロイに失敗するんですよね。2回に1回くらい。
あとやっぱりJavaな人ならJenkinsが慣れてて使いやすいと思いますし - 普通にTomcatにデプロイ
- Grailsは大体Tomcatで動かしながら開発するのでTomcatが安心
- スティッキーセッション、セッションクラスタリングに対応
- クラスタリング時のセッションストアはそれなりに価格高いですけど、なんにしてもこの辺はHerokuでは使えません。
- 再デプロイ時にダウンタイムがない
- CloudBeesはアプリケーションアップデート時、新しいクラスタでアプリを起動させてから古いアプリケーションを破棄してくれるのでダウンタイムが発生しません。
- URLのGETパラメータが化けない
- Cloud Foundryェ…
今のとこの気になる点
- 独自ドメイン対応
- CloudBees上のアプリを独自ドメインで参照する場合、CNAMEでエイリアスとして設定します。
普通の人は独自ドメインのルート(example.comとか)にCNAMEレコード作れないと思うので、www.example.com、とかのサブドメインを使わなければなりません。
Herokuだと普通にAレコードで設定できます。 - メモリ
- 無料範囲だと使用できるのが最大256mで、ここからPermGenなんかを割り当てるようです。
Grailsを動かす場合256mのPermanent領域が推奨されるということですが、もちろんそんなに割り当てたら起動できなくなります。
本格的に動かすときは有料プランで
時間があったら、動かしてみた手順でも書いてみます。
2012年1月7日土曜日
Grails2.0のユニットテスト用アノテーションを整理してみる
- Grails Version
- 2.0.0
Grails 2.0から、アノテーションを使ってユニットテストを書くことになってるのですが、
そのアノテーションの使い方が少しややこしかったので整理してみました。あんまり自信ないです。
Grailsのテストで使うアノテーションは以下のとおり。
- grails.test.mixin.TestMixin
- grails.test.mixin.Mock
- grails.test.mixin.TestFor
@TestMixin
- 使用例
- @TestMixin(GrailsUnitTestMixin)
テストクラスに以下のようなミックスインを適用して、テスト用、モック作成用のメソッドやプロパティを追加、設定するのに使用する。
リストを渡せば複数のミックスインを適用できる。
- grails.test.mixin.support.GrailsUnitTestMixin
- grails.test.mixin.domain.DomainClassUnitTestMixin
- grails.test.mixin.services.ServiceUnitTestMixin
- grails.test.mixin.web.ControllerUnitTestMixin
- grails.test.mixin.web.FiltersUnitTestMixin
- grails.test.mixin.web.GroovyPageUnitTestMixin
- grails.test.mixin.web.UrlMappingsUnitTestMixin
- grails.test.mixin.webflow/WebFlowUnitTestMixin
以下にいくつかの使用例を挙げる。
GrailsUnitTestsMixin
以下のような機能をテストクラスに追加する、全てのミックスインの基盤となるミックスイン
- grailsApplicationやmessageSourceなどのGrailsのコンテキストプロパティを追加
- mockForConstraintsTests、mockForなどの基本的なモック作成メソッドを追加
import grails.test.mixin.TestMixin import grails.test.mixin.support.GrailsUnitTestMixin import org.junit.Test @TestMixin(GrailsUnitTestMixin) class GenericTests { @Test void genericTest() { mockForConstraintsTests(Book) def book = new Book(title: "") assert !book.validate() assert book.errors["title"] == "blank" } }
DomainClassUnitTestMixin
さっきの「GrailsUnitTestsMixin」を適用し、さらにドメインクラスのテスト用にmockDomainメソッドを追加する。
import grails.test.mixin.TestMixin import grails.test.mixin.domain.DomainClassUnitTestMixin import org.junit.Test @TestMixin(DomainClassUnitTestMixin) class GenericTests { @Test void genericTest() { mockDomain(Book) def book = new Book(title: "") assert !book.save() assert book.errors.getFieldError("title").code == "blank" } }
ServiceUnitTestMixin
さっきの「GrailsUnitTestsMixin」を適用し、さらにサービスのテスト用にmockServiceメソッドを追加する。
import grails.test.mixin.TestMixin import grails.test.mixin.services.ServiceUnitTestMixin import org.junit.Test @TestMixin(ServiceUnitTestMixin) class GenericTests { @Test void genericTest() { mockService(HelloService) assert applicationContext.helloService.hello() == "Hello, World" } }
ControllerUnitTestMixin
「GrailsUnitTestsMixin」を適用し、さらにコントローラーのテスト用にmockControllerメソッドやサーブレットコンテキストのモックなどを追加する。
import grails.test.mixin.TestMixin import grails.test.mixin.web.ControllerUnitTestMixin import grails.test.mixin.services.ServiceUnitTestMixin import org.junit.Test @TestMixin([ControllerUnitTestMixin, ServiceUnitTestMixin]) class GenericTests { @Test void genericTest() { mockService(HelloService) def controller = mockController(BookController) controller.show() assert response.text == "Hello, World" } }
などなど。
@Mock
- 使用例
- @Mock(BookController)
- 指定クラスに応じて、適当にミックスインを適用する
- 更に指定クラスのモックを作成してコンテキストに登録する
例えば……
- ドメインクラスの場合: DomainClassUnitTestMixinを適用し、更に指定クラスに対してmockDomainを適用する
- サービスクラスの場合: ServiceUnitTestMixinを適用し、更に指定クラスに対してmockServiceを適用する
- コントローラークラスの場合: ControllerUnitTestMixinを適用し、更に指定クラスに対してmockControllerを適用する
- などなど
import org.junit.Test import grails.test.mixin.Mock import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes @Mock([BookController, HelloService]) class GenericTests { @Test void genericTest() { def controller = webRequest.currentRequest.getAttribute(GrailsApplicationAttributes.CONTROLLER) controller.show() assert response.text == "Hello, World" } }
@TestFor
- 使用例
- @TestFor(BookController)
- 指定クラスに対して@Mock相当の機能を適用してモックを作成
- 指定クラスのモックに、アーティファクト名のプロパティでアクセスできるようにする
- testで始まるメソッドに、@Testアノテーションを付加
このアノテーションには、複数のクラスを引数に渡すことができない。
import grails.test.mixin.Mock import grails.test.mixin.TestFor @TestFor(BookController) @Mock(HelloService) class GenericTests { void testGenericTest() { controller.show() assert response.text == "Hello, World" } }
ちなみに
Grailsのコマンド、test-appを使ってテストを実行すると、いくつかの処理を自動で行ってくれるようです。
例えば、ドメインクラスがBookで、テストクラスがBookTestsという名前だった場合、BookTestsに@TestFor(Book)が何も書かなくても適用されるように見えます。
この辺の動作はまだよく分かりません。
おわりに
もっぱら使用するのは@TestForと@Mockであって、@TestMixinで直接テストメソッドをミックスインすることはあまりないと思いますが、大体こんな役割になってそう、ということです。
動作確認はしましたが、ソースはあまり追っていないので間違ってるところもあるかもしれません。
気がついたことなどありましたら、教えてもらえると幸いです。
2011年12月16日金曜日
ConfluenceのHTML→PDF変換ライブラリを利用する
JIRA Advent Calendar 2011、15日目です。
ってすみません、ConfluenceネタですがまあJIRA使ってる人は連携して使ったりしますよねとか、そんな感じで。
GradleのユーザーガイドをPDFに変換するときにお世話になったので、紹介してみます。
Confluenceは、バンドルされているプラグインでページをPDFに変換して出力できるのですが、この機能に使われているライブラリを使って、XHTMLをPDFに変換しようという話です。
ConfluenceのXHTML→PDF処理にはFlying SaucerというJavaのライブラリが使われています。
Flying Saucerを使うと、XMLやXHTMLファイルを、PDFやSWT、Swingのスクリーンに出力させることができます。デザインはCSSで指定できます。
ただ、このFlying Saucer、PDFに変換したときに、文字列が空白位置でしか改行されません。
英文Onlyならいいのですが、日本語で長文をだらだら書いていると画面外にあふれて見えなくなってしまうわけですね。
ConflueceのPDFエクスポートでの禁則 - azuki note
この問題を、Atlassianさんがパッチを当てて修正しているので、しかもMavenリポジトリ上に上げてくれているので、今回はそれを使います。
@Grape+Groovyスクリプトでもいいですが、いろいろ面倒なのでGradleスクリプトで。
フルのサンプルはGithubに上げたのでそちらを見てもらうとして、ポイントだけ書いておきます。
AtlassianさんのMavenリポジトリからFlying Saucerを取得
AtlassianさんのMavenリポジトリから、パッチの当たったFlying Saucerライブラリを取得します。
GradleとかMavenとかIvyとか、そのあたりの設定に依存関係を追加するのがいいですね。
ライセンスが気になるところですが、LGPLのままみたいなので大丈夫でしょう、多分…
- Mavenリポジトリ
- https://maven.atlassian.com/repository/public
- アーティファクト
- org.xhtmlrenderer:xhtmlrenderer:8.3-atlassian
Flying SaucerはPDF生成にiTextを使うのでそちらも
- Mavenリポジトリ
- セントラルリポジトリ
- アーティファクト
- com.lowagie:itext:2.0.8
// Gradleの例 buildscript { repositories { mavenCentral() mavenRepo url: "https://maven.atlassian.com/repository/public" } dependencies { classpath "org.xhtmlrenderer:xhtmlrenderer:8.3-atlassian" classpath "com.lowagie:itext:2.0.8" } }
PDFへの変換処理
PDFへの変換処理は、次のような感じで書きます。
import org.xhtmlrenderer.pdf.ITextRenderer def renderer = new ITextRenderer() renderer.setDocument(new File("sample.html")) renderer.layout() new File("sample.pdf").withOutputStream { renderer.createPDF(it) }
このコードを実行すれば、sample.htmlがsample.pdfに変換されます。
CSSでPDFに埋め込むフォントを指定する
日本語を使うには日本語フォントをPDFに埋め込むか参照させる必要があります。変換元のHTMLに次のようなCSSを適用しましょう。
@font-face{ font-family: "IPAexGothic"; src: url(ipaexg.ttf); -fs-pdf-font-embed: embed; -fs-pdf-font-encoding: Identity-H; } body { font-family: "IPAexGothic"; }
なんか、使えるフォントと使えないフォントがあるみたいです。
fsなんたらはFlying Saucerのベンダー拡張ですね。詳しくはFlying Saucerのユーザーガイドを見てみてください。
長い文章を折り返すための設定
Atlassianさんのパッチが当たったFlying Saucerを使うと、次のようにCSSでword-wrapを指定することで長い文章が折り返されるようになります。
p { word-wrap: break-word; }
おわりに
いやぁ、便利ですね。ちょっとしたPDF作るだけなら、それ用のHTMLファイル作って変換するのが簡単かもしれません。
さて、かなり脱線気味でしたが、こんなところで。
引き続きJIRA Advent Calendar 2011をお楽しみください。