Maven3からはarchetype作るときに$と{のエスケープがいらない

cynipe/maven-archetypes · GitHubにあるcuke4dukeのarchetypeをつくっていたときに気づいたのだけど、maven3からは$と{をVelocity流儀にのっとったエスケープをする必要がなくなってる。

裏は取っていなかったのだけど、のUsing Velocity cleanly with custom maven archetypesにもあるのでMaven3からはいらないようですね。これでarchetypeがもっと作り易く!

あ、ちなみにこれも前述のarchetypeをつくっていた時に知ったんですが

mvn archetype:create-from-project

と叩くと${project.build.outputDirectory}/archetype(つまりtarget/archetype)にそのプロジェクトを元にしたarchetypeが自動生成されるので、簡単なサンプルを構築してしまえば皆に使ってもらえるarchetypeがサクサク起こせますよ!

で、これも前述の(ry archetypeなプロジェクトに対して

mvn integration-test

とするとtarget配下にarchetype:generateゴールを実行したときの結果を生成してくれるのでいちいちインストールして試さなくてもサクサク確認できます。通常はarfchetypeにインタラクティブに渡すプロパティは、src/test/resources/projects/basic/archetype.propertiesに以下な感じで指定してあげればOKです。

maven-archetypes/cuke4duke-quickstart-archetype/src/test/resources/projects/basic/archetype.properties at master · cynipe/maven-archetypes · GitHub

version=0.1-SNAPSHOT
groupId=archetype.it
artifactId=basic
version=0.0.1-SNAPSHOT
package=archetype.it.basic

そんな訳でみなさんも快適なarchetypeライフを!

Apache Maven 3クックブック Javaソフトウェア開発のための特選レシピ集

Apache Maven 3クックブック Javaソフトウェア開発のための特選レシピ集


Apache Maven 2.0入門 Java・オープンソース・ビルドツール

Apache Maven 2.0入門 Java・オープンソース・ビルドツール

HudsonでJMeterを使った負荷テストを定期的に行う

Performance Pluginを使えばant+jmeterで簡単に出来る。jmeter-maven-pluginなんてものもあるけれど負荷テストをプロジェクトのpomに書くのはやり過ぎ感にあふれるので今回は使わなかった。

まずはantを使って負荷テスト用プロジェクトを以下のようなディレクトリ構成で作成。ぶっちゃけPerformance Pluginのwikiのをコピーしてディレクトリをちょこっと弄るだけで済んだ。わーい。

load-test
├── build.xml
├── results:結果ファイル用ディレクトリ
│  ├── html
│  └── jtl
└── scenarios:jmxファイル置き場
    ├── some-dynamic-properties.csv
    └── some-stress.jmx

build.xml

<project default="all">
  <property name="jmeter-home" location="${jmeter.home}"/>
  <!-- ant-jmeter.jar comes with jmeter, be sure this is the release you have -->
  <path id="ant.jmeter.classpath">
    <pathelement
       location="${jmeter-home}/extras/ant-jmeter-1.0.9.jar" />
  </path>
  <taskdef
    name="jmeter"
    classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask"
    classpathref="ant.jmeter.classpath" />
  <target name="clean">
    <delete dir="results"/>
    <delete file="jmeter.log"/>
    <mkdir dir="results/jtl"/>
    <mkdir dir="results/html"/>
  </target>
  <target name="test" depends="clean">
    <jmeter
       jmeterhome="${jmeter-home}"
       resultlogdir="results/jtl">
      <testplans dir="scenarios" includes="*.jmx"/>
    </jmeter>
  </target>
  <!-- This is not needed for the plugin, but it produces a nice html report
       which can be saved usin hudson's archive artifact feature -->
  <target name="report" depends="test">
    <xslt
       basedir="results/jtl"
       destdir="results/html"
       includes="*.jtl"
       style="${jmeter-home}/extras/jmeter-results-detail-report_21.xsl"/>
  </target>
  <target name="all" depends="test, report"/>
</project>

で、これを以下のコマンドで実行。

ant all -Djmeter.home=<your-jmeter-home>

シナリオファイル(jmx)を作る際に動的なパラメータを使う場合の肝はCSV DataSet Configを使うこと。これを使うと対象のjmxファイルと同じディレクトリにあるファイルをロードしてくれるのでファイルのパスに気を使う必要がなくなる。

ここまでできたらあとはHudsonでフリースタイルプロジェクトを選択し、antでのビルドをよしなに設定。Publish Performance test result reportにチェックを入れて以下のような感じで設定すればOK。

f:id:cynipe:20110105193933p:image

Performance thresholdは全件失敗したらそもそも色々おかしいだろうということで100%の場合は失敗。今回はJMeterの結果よりもサーバ側の状況がみたいというのが目的。サーバ側にはmuninをしかけておいてそちらのグラフを参照する感じ。なのでUnstableは特に必要ではないので設定してない。これで定期的にかかる負荷を想定したようなシナリオを流してサーバ状況のシュミレートとかできるー。

RedmineのチケットのURLとタイトルを表示するIRCBot

こんな月並なものは出尽くしているのだろうけど、Ruby勉強ついでに書いてみた。発言中にある#1000とかをタイトルとURLに展開してくれるIRCBot。最初は文字列連結してURLを合成して発言するだけのやつをJavaで書いてたのだけど、タイトルも欲しいなと思って作ってみた。認証が必要になってくるのでJavaでやるとめんどくさいな〜なんて思ってたらMechanizeなんて素晴らしいものが!こういうの書くのはやっぱりLLなんだなぁ。LLにちょっと目覚め始めてみましたよっと。

ただTicketUrlizerのコンストラクタがもっとスマートにかけると思うのだけど、その辺りはまだよく分からない・・・。

Mavenでビルドする際の10のTips

1. 環境別の設定はプロファイルで

環境毎に切り替えたいっていう設定ファイルは大抵のプロジェクトにはあると思います。DB接続先設定だったり、ロギング設定、場合によってはweb.xmlの初期化パラメータとか。最近流行り?のAppEngineだとデプロイ先の設定、開発時のcronの設定とか。こういった環境毎の設定を都度都度書き換えてなんてことをやってたらバージョン管理上うまくない*1ですし、Hudson、その他自動化スクリプトからデプロイを行ったりする際に色々とうまくないです。なので、こういった設定はプロファイルを使ってサクっと切り替えられるようにしてます。

詳しいプロファイルの使い方*2についてはそのうち別エントリで書く*3!...と思います。基本的なことはTECHSCOREさんのここを参照すればかなり分かるはずです。自分はここで覚えました。ただMaven3からはprofiles.xmlの使用が出来ない*4ので、今からやるのであれば使わないほうが無難です。

2. ライブラリの定義はdependencyManagementで

マルチスタイルのプロジェクトで共有するようなライブラリ*5はdependencyManagement句でバージョンを定義しておくのがいいです。dependencyManagementというのはdependenciesとは違って依存関係の定義ではなく、依存関係の定義の為の定義ってところです。百聞は一見にしかず。

親POMなんかで以下の定義をしておきます。これだけだと依存関係に追加されたことにはならないので、クラスパスに展開してくれたりはしません。

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>0.9.21</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
    </dependency>
  </dependencies>
</dependencyManagement>

ここで定義したライブラリを実際に使うモジュール側で"使うこと"を明示して、適切なスコープでクラスパスに追加してあげます*6。この際もう既にdependencyManagementで依存関係の定義、つまりバージョンの指定をしてあるので使う側では書く必要はないです*7

<dependencies>
  <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

この方式でやると別ライブラリが使ってる同じライブラリのバージョンが衝突する場合でもexclusion指定をdependencyManagementで書けるので都度定義する必要がなく、見通しも良く出来て一石二鳥!

3. pluginのバージョンは必ず書く

Mavenはpluginのバージョンを省いても空気を読んで解決してくれちゃったりしますが、これを使ってるとある日突然ビルドが通らなくなったりしてワケワカメなことになるんで、ちゃんと書いてあげるのがいいです。これを書いておけばそういったことは防げますし、Mavenのバージョンを上げてもまず問題はないでないです。Maven3だとこの辺りのチェックが厳しくなって、バージョンが省かれていると警告ログが出るようになってます。警告ログを見にくいって方はid:cynipe:20101023:1287842267をどうぞ。

4. pluginの定義もpluginManagementで

マルチスタイルプロジェクトの場合は、ライブラリの定義よろしくpluginの定義もpluginManagementでやっておくといいです。プロジェクト内で必ず使わないんだけど〜なplugin用に便利。例えばmaven-war-pluginとかmaven-jetty-pluginとか。

5. Eclipseの設定ファイルはバージョン管理しない

これは好みが分かれるところではあるんですが、バージョン管理しておくと生成日時のせいでコミットしないとならなくなったりといらないお世話が必要になるので、mvn eclipse:eclipseすればいいじゃない派です。それに1.をやっているとどのみちmvn process-resourcesとか叩く必要が出てくるので、まぁいいかなと。フォーマットの設定やら、FindBugsの設定とかが必要な場合は適当なフォルダを掘ってそこから参照出来るように書いておくのがいいです。maven-eclipse-pluginプロジェクト的にはsrc/optional/eclipse-configの下においてあるみたいですね。->こちら

6. 共通の設定を持つ親POM必ず作る

Maven主体で色々と管理しだすとプロジェクトのpomが比較的大きくなってきます。JDKのバージョン*8エンコーディング*9、参照するMavenリポジトリ*10Eclipseの設定、使うMavenPluginのバージョンなど色々と書くことになるので、これを毎回書くのはいただけないですし、POMが巨大になってしまい見通しが悪くなってしまいます。なので、シングルプロジェクトだったとしても分けておいた方がいいです。自分は複数のwarが出来上がるマルチスタイルプロジェクトの場合はwarモジュール用に別途大元のParentPOMを継承する形で基底のPOMを作ったりしてます。

7. ビルドを統合するAggregatorPOMを作る

全てのモジュールをまとめてビルドする為のPOMは基底の親POMとは別に作ったりしてます。Mavenは子モジュールのparentで指定しなくても勝手に親POM*11を定義できるのでこれを利用して、modulesの定義をするPOMを別に作ってます。基底の設定は親POMに、ビルドの統合はAggregatorにといった感じです。このAggregatorは基本的にmodulesの統合が主な役割で、それ以外はデプロイ先リポジトリの定義以外は基本的にしません。HudsonのjobはこのPOMに対してゴール、プロファイルの指定をして実行してます。

なぜ6.と7.を分けているのかというと、基底の親POMの設定を別のプロジェクトで使いたかったりするので、modulesの定義も書いてしまうと使いまわせなくなってしまってもひとつうまくないからです。この問題?はMaven3で期待されている*12pom-mixin機能がでてくれば、各種設定を細かく分けておいてそれぞれ統合というのがAggregatorで簡単に出来るようになるはずなのでそれ待ちな感じです。pom-mixinはやくでないかなー。

8. TomcatなどへのデプロイはMavenでやらない

TomcatなどのAPサーバへのデプロイはMavenで書かないのがいいと思ってます。何故かというと、この設定は基本的にはソースレベル、アーティファクトレベルでの影響をプロジェクトに与えないというのと、ここを細々と書いていくとPOMの見通しが悪くなっていってしまうからです。なのでこういったタイプの設定はHudsonで気楽に行うことができるのでPOMでは定義せずどこかにデプロイすればいいよってスタイルでやってます。

9. warプロジェクトはjettyで起動出来るようにしておくといい

8.で言ってることと矛盾するやんけ!と思われるかもしれませんが、SVNからチェックアウトしてmvn jetty:runでその場で確認出来るというのは管理する人とか的には嬉しいことだと思います。わざわざローカルにTomcatを入れて、Eclipseの設定をしてなんてしなくても、簡単なバグの修正確認、その場でデモなんてのも手軽にできるので。

maven-jetty-pluginの設定は特殊なことでもしない限り↓位ですんでしまうので入れておくと少し幸せになれるかと思います。開発する人はSysdeoTomcatプラグインとか使っててもいいと思います。重要なのはチェックアウトしてすぐ確認が出来るようにしておくことです。

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <version>6.1.10</version>
  <configuration>
    <contextPath>/${project.artifactId}</contextPath>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
      <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
        <port>8080</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>
    </connectors>
  </configuration>
</plugin>

10. なんでもMavenでやりすぎない

そしてここが一番重要なんですが、なんでもかんでもMavenでやりすぎないことです。Mavenの便利さに目覚めるとついついMavenでやるにはどうすれば?とかMavenでなんでもかんでもやろうとして複雑怪奇であうあうあーっていうのは比較的良く起こりがちに思います。かくいう自分にもそんな時代がありました。

さっきも上げたようにAPサーバへのデプロイはHudsonで気軽にできたりしますし、コードカバレッジなんかもHudsonで簡単にできる*13のでこういったものを使ってゴニョゴニョすればトータルで楽できますし、不幸せにならずに済むかと思います。

また、Mavenは複雑なことが出来ない!とよく言われますが、そこはそれなりに仰る通りかと思います。とは言われつつも自分はある程度型にはめられるMavenが好きですし、antでゴリゴリ書くのに比べて楽できる部分はほんとに楽に出来ます*14。要は適材適所なのでAntの方が簡単にできるのであればそこだけAntを使う。連携したければmaven-antrun-pluginで。Mavenでやり過ぎてしまうとほんとに作った人しか分からなくなってしまったりするので。

おまけ. defaultGoalを実行するbuild.xmlを作る

これは若干やりすぎなのかもですが、mavenはdefaultGoalに複数のゴールを指定することが現状出来ません。なので初回チェックアウト時の処理だったり、プロファイルを使ったりしてゴニョゴニョしたりしてる場合なんかは若干めんどくさかったりします。こういった際のプリセットコマンド的なものをMaven Ant Tasksを使ってxxx-build.xmlとかしておいておくとちょっぴり幸せになれます。なぜbatでなくAntなのかというとWin、Macユーザがいたりした場合にAntで書いておけば両方書く必要がないので楽チンできるという最近ちょっとお気に入りな手法。

ただこれも若干黒魔術というか、どのコマンドを叩いているのか意識せずにデフォルトセットが使えてしまうようになるので、やりすぎてしまうと綺麗にブラックボックス化されたビルド環境が出来上がり、知らない人は全くメンテ出来ないという事態になりかねないので程々に。

*1:ローカルで変更しててうっかりコミットとか、それがさらにConflictしてあうあうあーとか

*2:resourceのfiltering、propertiesとか

*3:かなり深いので・・・

*4:非推奨なだけかも

*5:ユーティリティ系だったり、兄弟モジュールだったりとか

*6:dependencyManagementでもスコープの定義は出来ますが、使う側で定義するのが筋だと思います。

*7:むしろ書いちゃうと意味ない

*8:maven-compiler-plugin

*9:project.build.sourceEncodingとか

*10:社内リポジトリとか

*11:自分はこれをAggregatorって呼んでます

*12:はず!

*13:自分は[http://wiki.hudson-ci.org/display/HUDSON/Emma+Plugin:title=Emma Plugin]を使ってますが、pomになにも書かずにhudsonでMavenゴールを設定するときにemma:emmaをおまじない的に追加しておけばあとはよしなに計らってくれます。

*14:appassembler-maven-pluginとか凄く楽チンですよ。

はてなプラスにしてみた

少しはアウトプット増やそうという気な今日この頃。とは言え割と三日坊主だったりもするので自戒?もこめてはてなプラスに。頑張って書けばプラスの代金ぐらいアフィリエイトでいけるんじゃないのかなー?なんてぬるいことを考えてます。

ちょっとかゆいところに手が届くようなエントリとか書けたらいいな〜。Maven周りな人ではあると思ってるのでその辺りのTipsとかこうやってるよ!的なことをもう少しこまめに公開していきたい。ゆるく頑張ってみる。