Pulseを使ってEclipseの設定を共有すると便利(ただし、閉鎖環境では使えません)

Eclipseワークスペース設定を共有することは難しい

EclipseJavaの開発では最も人気の高いIDEであり、もちろん、私も仕事でも自宅でもずっとメインのIDEとして使ってきました。もちろん、NetBeansやIDEAなど他の優秀なIDEもフリーで利用できる時代なのですが、やはり、入力支援機構やリファクタリング機能の豊富さについては、やはり、Eclipseが他と比べて一歩優れているように思われます。*1
そして、Eclipseの最大の特徴の一つは柔軟なプラグインアーキテクチャであり、豊富なプラグインの中から選択して好みの機能を拡張することができます。ただし、これはEclipseの最大のメリットでもあるのですが、大量のプラグインを管理して複数の端末で効率的に共有するということは案外大変なことでした。
Pleiadesのオールインワンパッケージを利用したり、また、SpringやJBossなど特定のフレームワークを対象にする場合は、Spring Tool SuiteJBoss Toolsなどを利用することで、有用なプラグインをまとめてインストールできます。これである程度問題は軽減されるとはいえ、結局

  • 足りない機能に対して独自にプラグインを追加
  • 起動パラメーターやフォーマットなどワークスペースレベルの設定をカスタマイズ
  • Java用、PHP用、Ruby用など複数の言語環境を使い分ける

などを行った場合、これらのカスタマイズした環境を複数のPC上で共有し、きちんとバージョンアップにも対応するような運用することはかなり面倒です。つまり、プロジェクトごとの設定情報はSVNなどの構成管理ツールを使って簡単に共有できるのですが、プロジェクトをまたがったワークペースレベルの設定を共有することが、簡単そうでいて実は難しいということがありました。
このような問題の一つの解決策はDropboxなどの共有サービスを使って、Eclipseの構成情報を共有することですが、それでもカスタマイズした複数の環境を管理することは容易ではありません。

Pulseを使ってどこからでもEclipseの設定を共有する

そのような問題を解決する手段として、Pulseというツールを利用すると非常に便利です。実は、私はかなり最近になって知ったのですが、実は、数年前から存在するようですね。MyEclipseという有償のEclipseのオールインパッケージを作っている会社が提供しています。
Pulseは個人で利用するだけであれば、以下からCommunity Editionを無償でダウンロードして使うことができます。
IDE Management by Secure Delivery Center - Genuitec
使い方はものすごく簡単です。まず、WindowsMacLinux用のバイナリが提供されているので自分のプラットフォームに合ったインストーラーを使ってインストールします。次に、以下のサイトであらかじめユーザー登録をしておくか、
IDE Management by Secure Delivery Center - Genuitec 
あるいは、Pulseの初期起動画面でRegisterを選択しユーザー登録を行います。

ユーザー登録時に使用したメールアドレス宛てに確認のメールが届くので、リンクをクリックして登録確認を行います。ユーザー登録が正しくできていれば、ログイン画面でログインすることで、以下のPulse Explorerの画面が開きます。

最初にPulse Explorerを起動した段階では、あらかじめ一覧から選択可能なEclipseの構成が表示されるだけですが、My Profilesのペインに好みの構成をドラッグすることで、独自のプロファイルを好きなだけ追加することができます。追加したプロファイルに対しては、以下の画面で好みのプラグインを追加することができます。

もちろん、新規のUpdateサイトを登録することで、予め登録されていないUpdateサイトのプラグインを追加することもできます。
そして、Install Nowのボタンをクリックすることで、実際にローカルにEclipseがダウンロードされてインストールされます。さらに、便利なことに、インストール後にプラグインの構成だけでなく、エディタのフォーマットなどワークスペースの設定情報をあわせて管理することができます。そのためには、以下のようにCollaborationタブをクリックし、Let Me At ItボタンをクリックしてTeam of One機能を有効化します。

Pulseは複数のプラットフォームに対応していますし、自分の使う複数のPC上にインストールしておけば、クラウド上に設定情報を共有することでどこでも同一の環境を利用することができるようになります。

有償版を使うとチーム間での共有も可能

さらに、月6$、年間60$を支払ってTeam Editionを購入することで、チームメンバー間でカスタマイズした設定を共有することも可能です。ちょっと高いと感じられるかもしれませんが、メンバー間で同一の環境を共有して同期させる手間を考えれば、むしろリーズナブルな価格設定と言えるかもしれません。
確かに、Eclipseの環境構築は面倒なのですが、このようなところに目を付けてビジネスにしてしまう発想には感心させられます。他には、EclipseSourceというEclipseを専門でビジネスをしている会社もあるようですが、オープンソースがビジネスになってしまう外国はちょっとすごいと思います。
それから、当然ですがこのような便利なツールも、インターネット接続が遮断されたいわゆる閉鎖環境では使うことができません。*2実際、閉鎖環境では外部からの情報が遮断されていることもあり、いまだにEclipse3.3などの太古の化石のようなバージョンが現役で使われているプロジェクトも存在するようです。セキュリティ面からやむを得ないところはあるとはいえ、そのような環境ではどんどん時代の最先端から取り残されていくというのは否定できませんね。

*1:個人的な慣れの問題が大きいことも確かなのですが。

*2:ただし、Private Labelと呼ばれるエンタープライズ向けのソリューションも提供されており、そのバージョンであれば閉鎖環境でも運用できるようです。Eclipseに限らず、アプリケーションを配信するメカニズムとして利用できるようですね。

EclipseでJava EE6を使った開発をするときは型フィルター機能が便利

CDIなどJava EE6の新機能を使うときに、ちょっと厄介と感じるのは、複数のパッケージに同名のアノテーションが存在していることです。
大混乱に陥っているJavaEE 6のアノテーションに関する使い分けについて - 達人プログラマーを目指して
うっかり間違えてimportしてしまうと、正しく動作せず混乱のもとになります。
eclipseを使う場合、型フィルターという機能を利用することで、型検索の対象から外すことができ、また、「Ctrl+Shift+O」による自動インポート編成の際にも対象から除外されるため、知っていると便利かもしれません。

この機能はStringUtilsなどクラスパス上に同名のクラスが多数あり、規約で特定のライブラリーのクラスに限定するような場合にも使えると思います。

ConQATを利用してソースコードの品質をチェックする

ある程度プログラマーとして経験を積めば、ソースコードを読んだときに、そのソースコードの良し悪しというものは、嗅覚を使って直感的に嗅ぎ分けることができるものです。実際、そのように体の感覚を使ってこのコードは不吉だと感じるところは実際大いにあり、コードの臭い(code smell)として知られています。
コードの臭い - リファクタリングの必要性を示す兆候
これはファウラーの名著

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

リファクタリング―プログラムの体質改善テクニック (Object Technology Series)

  • 作者: マーチンファウラー,Martin Fowler,児玉公信,平澤章,友野晶夫,梅沢真史
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/05
  • メディア: 単行本
  • 購入: 94人 クリック: 3,091回
  • この商品を含むブログ (312件) を見る
でも紹介されており、こういった不吉な部分を適切に嗅ぎ分けて、リファクタリングしていくスキルというのは、プログラマーにとって欠かすことのできない大切なスキルだと思います。
しかしながら、SI業界の多くの開発組織では、技術者としてPGのスキルや意見を尊重してくれるところは少ないのが現実ですし、ソースコードの品質が感覚的によくないといってもなかなか信じてもらえないところもあると思います。そういうときこそ、客観的、定量的にソースの品質を計測するメトリクスツールの導入を検討するのがよいのではないでしょうか。
メトリクスとは何か | Think IT(シンクイット)
Eclipseで使えるメトリクス計測ツール (4/5):Eclipseで使えるテストツールカタログ(3) - @IT
こうしたツールには本格的な商用のツールから、フリーのものまで最近ではさまざまなものが出回っているようです。フリーのもので、私が今まで利用してきたものを挙げると

などがあります。これらの解析はビルド時に自動的に行って定期的にレポートを生成させることもできます。
ただし、もともとのソースコードの品質があまりにもひどい状態の場合、以上のメトリクスを計測してもあまり面白いデータが採れないということもありますね。恐ろしいことですが、放射線量があまりにも多くてガイガーカウンターの針が振り切れてしまい計測不能という危険な状態のコードもたくさん存在するのです。そういった状態のレガシーコードを相手にするときには、問題の存在を視覚的に表現してくれるようなツールがあると便利です。そういうことで、何かよいツールはないかなと探していたのですが、先日
http://conqat.in.tum.de/index.php/ConQAT
という非常に面白いツールを発見しました。Apache2のオープンソースライセンスで提供されているのですが、

  • コード行数など基本的なメトリクスの計測
  • パッケージ間の依存関係などアーキテクチャの整合性の確認
  • クローン検出(いわゆるコピペコードの検出、ABAP、ADA、C#C/C++CobolJavaVisual Basic、PL1、PL/SQLに対応。それ以外は検出精度が下がるが、テキストとして検出可能。)
  • メトリクス計測結果の視覚化
  • FindBugsなど他のツールとの連携
  • Hudson、Jenkinsなどとの連携

などが行えるだけでなく、計測する処理フローを独自の言語とフローエディタを使って編集したり、新しい処理を独自に開発して追加したり、非常に柔軟性が高く高度なフレームワークとして作成されているようです。Eclipseの拡張として作成されているため、基本的には直感的に操作することができます。以下は、解析フローを編集する画面で、ライブラリーとして提供されているさまざまな処理を組み合わせて、全体の解析処理を組み立てることができます。

このツールの中でも、特にクローン検出の機能は非常に強力です。実際、昨日紹介したサーティファイの認定試験(改良後のもの)Javaプログラミング能力認定試験の問題がかなり改善されていました - 達人プログラマーを目指してに対して、クローン検出の機能を実行すると、以下のようなマップが得られます。

この図で長方形の面積はソースコードのステップ数に比例しており、赤い色の濃いところはクローンペアとして検出された行数の比率を示しています。濃い赤色のところほどコピペされた部分の割合が高いことを示しています。さらに、各クローンペアについては、Eclipseソースコードエディタ上で実際の箇所を確認することができます。

まったく同一の部分だけでなく、似たような部分もクローンとしてきちんと検出されます。
こういうツールは自動ビルドツールと連携させて、定期的にコードレビューを自動化する目的で活用すれば、非常に有用だと思います。

IntelliJ IDEAはGroovyの学習や開発に最適なIDEだった

先日、業務系のJavaプログラマーが知っておくべき10個のBad Partsとその対策 - 達人プログラマーを目指してで、Javaのイケていない部分について説明し、そこでGroovyやScalaといったいわゆる軽量言語(LL)を使うことでコードが単純化されるという説明をしました。私自身も勉強会や書籍などで「軽量言語は簡単ですよ」という説明をされるたびに、軽量言語に乗り換えてみたいなという気になるのですが、いざ試してみると圧倒的に高機能で安定しているJavaIDEと比較して見劣りがしてしまい(特に入力補完とリファクタリング機能において)、結局Javaに戻ってしまうということが今までに何度かありました。
先日参加したGroovyの勉強会(JGGUGの勉強会(G*ワークショップ)に初めて参加してきました - 達人プログラマーを目指して)でJenkinsの川口さんがIntelliJを使ってGroovyのコードを書いていたのですが、Groovyの機能を使うには高額なエディションが必要で、一般のサラリーマンプログラマーが個人で使うにはとても高額なライセンス料が必要で、高嶺の花と思ってあきらめていたのですが、実際サイトを調べるとフリーのコミュニティーエディションでもGroovyはしっかりとサポートされているということがわかりました。プログラミング言語としてサポートしているというだけでなく、Gradleを使ったビルド機能との連携やGithubとの連携など便利な機能も入っています。これは試してみない手はないということで実際にダウンロードして使ってみました。以下にHello Worldを実行するまでの手順をまとめておきます。(IntelliJ IDEAについて、バージョンは古いですが次の記事も参考になります。Googlerも使っているIntelliJ IDEAのOSS版を試す (1/2):ユカイ、ツーカイ、カイハツ環境!(9) - @IT

Groovyのインストール

まずは、以下のサイトからGroovyをダウンロードしてインストールします。(もちろん、JDKがインストールされていなければ先にインストールしておく)
http://groovy.codehaus.org/Download
Windowsなら正式のインストーラー版が提供されており、パスや拡張子の設定を自動的にやってくれるので、Groovyが初めての初心者の人にはお勧めします。ダウンロードしたらインストーラーを起動し、手順に従って適当なフォルダーにインストールします。

IntelliJ IDEAのインストール

以下からIntelliJ IDEAのコミュニティー版をダウンロードします。
http://www.jetbrains.com/idea/
ダウンロードしたら、インストーラーを起動してインストールを実行します。なお、エディションによる違いは以下にまとめられています。基本的にGroovyやScalaの勉強をするだけであれば、コミュニティー版で大丈夫そうですね。ただし、RailsGrailsを使ったWebアプリケーション開発やSpringやJava EEなどのエンタープライズ系の開発のサポートは有償版を利用する必要があります。*1
Ultimate vs. Community - Compare Editions | IntelliJ IDEA

実験用helloプロジェクトの作成手順

IntelliJ IDEAをインストールしたら、好みにしたがってフォントとキーマップをまずは変更しておくのがよいでしょう。
設定ダイアログは、「File→Settings」の順にメニューを選択することで開きます。

あとは以下の手順に従ってGroovyのプログラムを作成できます。

1.「File→New Project」で新規プロジェクト作成ダイアログを開く

2.プロジェクト情報を入力する

ここでは簡単のためデフォルト選択のままJava Moduleを選択しておきます。Eclipseに慣れていると用語が混乱するのですが、およそ、以下の対応関係があるみたいです。

IntelliJ Eclipse
Project ワークスペース
Module プロジェクト

3.モジュールにJDKを関連付ける

次のダイアログで、Configureボタンをクリックし、JDKのインストール先を登録します。

4.モジュールにGroovy SDKを関連付ける


5.Hello.groovyファイルの作成

専用のGroovyファイルの作成メニューは見当たらないのですが、以下のようにsrcパッケージを選択して右クリックし、普通に「Hello.groovy」という名前のファイルを作成することができます。

すると、以下のような画面になります。

すでにGroovyの場所登録はしていたはずなので多少違和感があるのですが、「Configure Groovy SDK」のリンクをクリックしてGroovy SDKの場所を指定します。

あとは、普通にGroovyのコードを書いて実行することができます。

まだ使いこんでいませんが、入力補完などはきわめて高速に動作しますし、リファクタリングもしっかりと利用できます。

なお、私はまだ試していませんが、Scalaプラグインもよくできているとのことですがこれもフリー版で利用できます。以下からダウンロードできます。
http://plugins.intellij.net/plugin/?idea&id=1347
(追記)id:kimukou_26さんのコメントを参照。Scalaプラグインのインストールについて

*1:一人前のオープンソースプロジェクトの開発に携わっている人は有償版の機能をフリーで使わせてもらえる制度もあります。このエディションを使ってこそ一人前の開発者と川口さんが懇親会の席でおっしゃっていたと思います。http://www.jetbrains.com/idea/buy/buy.jsp#openSource

AJDTを使って規約違反のコードを検出する方法

AspectJというと、メソッドなどに処理を織り込むAOPのイメージが強いと思いますが、AJDTというeclipseプラグインを使うと強力なコード検証ツールとして利用できることは意外と知られていないようです。(AJDTはSpring Tool Suiteには最初から内蔵されています。)
実際、

  • コントローラークラスのメソッド内でフィールドの設定を行う
  • サービス層を経由せずに直接DAOを呼び出している
  • 日付オブジェクトを直接newしている*1

などの箇所をコンパイル時に検証して、警告やエラーとして検出できます。
たとえば、Spring MVCのコントローラークラスのメソッド内でフィールドの設定を行っている箇所を警告として検出するには以下のようなアスペクトを書くだけです。

package sample.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

public aspect CondingRules {

	pointcut setFieldInHandlerMethod() : withincode(@RequestMapping * (@Controller *).*(..)) && set(* *);
	
	declare warning : setFieldInHandlerMethod()
        : "コントローラークラスのリクエストハンドラーメソッド中でフィールドに設定しています。";
}

こうすると、

のように警告してくれます。FindBugsなどの静的解析ツールと併用することで、かなり強力な規約チェックが実施できます。
(補足)
構文的には

declare warning : ポイントカット : 警告メッセージ;
declare error : ポイントカット : エラーメッセージ;

のようにアスペクト中で指定するだけなのですが、一番難しいのは警告やエラー対象の場所指定をするポイントカット式の書き方の部分ですね。この部分は例を参考にしながら書き方を覚えるしかありません。
AspectJ/ポイントカット - アスペクト指向なWiki
http://www.limy.org/program/aspect/
あと、制約としてポイントカットの部分にcflowとかcflowbelowなど動的なものは使えません。こうした動的なポイントカットによるチェックが必要な場合は、例外を発生させるアドバイスを適用して、自動化テストなどでアプリを動作させて検証させるしかありません。

*1:多くの場合、システム試験時に時刻を容易に変更可能なようにサービスモジュール経由で日付を生成することが普通

開発時ビルドのバージョン番号の付け方に対するMavenとIvyの思想の違いについて

Apache Ivyの紹介と基本的な使い方 - 達人プログラマーを目指してに関連して説明させていただきます。
Mavenに慣れている人がIvyを使うときに必ずつまづくポイントとして、開発中の中間ビルド時のバージョン番号の付け方に対する両者の思想の違いがあります。Mavenの場合は、規約により開発中のバージョンには「-SNAPSHOT」という接尾辞をつけ、次のリリースを行うまでは同じバージョン番号のまま既存のビルド結果を上書きしながら使い続けることが前提となっています。
一方、もともとIvyの思想では、バージョン番号はビルド内容と1対1に対応しているべきという考え方があります。ビルド結果の中身が違うのであれば、バージョン番号も異なるべきという考え方です。ですから、中間ビルド(Ivyの用語では結合ビルドと呼ばれている)のバージョン番号にタイムスタンプを付けるとか、インクリメンタルなビルド番号を付けるなどの設定が簡単にできるようになっています。実際、タグを使うことで、次に来るべき番号を自動的に計算する機能があります。なお、バージョン番号の付け方の思想については、以下にベストプラクティスとして説明されています。
Best practices | Apache Ivy™ Documentation
マルチプロジェクトのアプリケーションで、この方式でバージョン番号をビルドごとに変更する場合に、ivy.xmlにて依存関係にある兄弟のプロジェクトのバージョン番号に固定の番号を記述してしまうと管理が大変になります。兄弟のモジュールのバージョンがすべて同一と言い切れるならプロパティーファイルなどでバージョンを一元管理しておき、${プロパティ名}の記法で参照すればよいですが、一般にはモジュールごとの番号がそろっている保障はありません。
Ivyではこの問題に対処するために「動的レビジョン番号」という機能があります。たとえば、以下のように依存している対象のバージョンを"latest.integration"のように指定することで、その時点で最新のビルドに依存していると解釈してくれます。

<dependency org="foo" name="bar" rev="latest.integration"/>

さらに、Ivy2.0からはrevision constraintという仕掛けが設けられています。上記のような動的レビジョンの記述をレポジトリー上に直接パブリッシュする代わりに、パブリッシュ時(厳密にはdeliver時)にivy.xmlの依存定義を以下のように自動変換するようになっています。

<dependency org="foo" name="bar" rev="その時点の実際の静的レビジョン" revConstraint="latest.integration" />

こうすることで、レポジトリー上にパブリッシュ済みのアーティファクトについてはレビジョン番号を固定してビルド時の再現性を高くすることができるようになっています。ただし、revConstraint属性にもともとの動的レビジョンの情報を残しておくことで、必要に応じて動的な解決も可能になります。revConstraintの方を使うにはタグを明示的に使って、resolveMode属性をdynamicに指定するか、ivysettings.xmlでデフォルトのresolveModeをdynamicにします。(開発中は全プロジェクトのビルドの代わりにモジュール単位での差分ビルドを行うことが多いのでdynamicモードが重宝します。)
このように、Ivyではビルドごとにレビジョン番号を設定することが推奨されているのですが、Maven風のSNAPSHOT的なやり方をまねることもできます。このような場合にIvyでは忘れずにchanging revisionの設定を行います。特定のレビジョン番号のパターンをchanging revisionであると宣言することで、レポジトリーのキャッシュ動作を抑制する必要があるのです。(デフォルトではIvyはビジョン番号が同一で中身が異なるということのない前提で、レポジトリーのダウンロード結果をキャッシュしてしまうからです。これはトラブルの元になります。)このためには、ivysettings.xmlでレポジトリーに対するレゾルバーを宣言する部分で以下のようにcheckModified属性とchangingPattern属性を合わせて指定します。

<filesystem name="local" checkmodified="true" changingPattern=".*SNAPSHOT">
  <ivy pattern="${ivy.local.default.root}/${ivy.local.default.ivy.pattern}" />
  <artifact pattern="${ivy.local.default.root}/${ivy.local.default.artifact.pattern}" />
</filesystem>

この点については以下が参考になります。
Main Concepts | Apache Ivy™ Documentation
Ivy is Useful
いずれにしてもかなり複雑ですね。この点はIvyで最初にはまるポイントの1つだと思います。私は最初はIvyのマニュアルのベストプラクティスに従って、ビルドごとに番号を振り出す方式を使っていたのですが、動的レビジョンの解決などかなり複雑ですし、レポジトリーのサイズがビルドごとに増大してディスク容量が足りなくなるなどの問題もありました。ただし、SNAPSHOT方式にすると以上に説明したようにIvy固有のキャッシュの問題でトラブルが発生したりします。なかなか悩ましいところです。

Apache Ivyの紹介と基本的な使い方

Apache Ivyについては本ブログでも何回か用語自体は取り上げてきましたが、現状日本語での情報が限られるためか、AntそのものやMavenに比べるとユーザーが少ないように思われます。ここで基本的な使い方やMavenとの違いについて簡単に紹介させていただきたいと思います。

Apache Ivyとは

本家のホームページは以下の通りです。
Home | Apache Ivy ™
もともとはJayasoftという組織で開発されていたツールですが、バージョン2.0以降、Antの関連プロジェクトとしてApacheプロジェクトの元に加わっています。(Apacheというブランド名はツールを組織に導入する際に結構重要ですね。)
上記のホームページでは「アジャイルな依存性管理ツール」として紹介されていますが、Mavenの機能の中からビルド機能やプロジェクト管理機能を無くして、ライブラリーの依存関係の管理に特化したツールとなっています。「アジャイル」として紹介されている意味は、おそらく多くの機能を詰め込んでいるMavenと比較して、依存関係管理に特化していることにより、身軽であるということを強調しているのだと思います。しかし、実際に使いこんでみるとわかりますが、非常に高度なカスタマイズが可能な柔軟性も備えており、かなり奥の深いツールになっています。好みの分かれるところですが、確かに、多少押し付けがましい規約の多いMavenと比較して、本当に使いたい機能のみ利用して「The simplest thing that could possibly work = 要件を満たすもっとも単純なやり方」を実現するにはより適したツールであると言える思います。
基本的には以下のような場合に利用を検討するとよいと思います。

  • 長年Antを使っている組織で、ソースツリーのディレクトリー構造を変えられない場合
  • earファイルの生成など複雑なビルド対象を扱う場合
  • ビルドスクリプト専門の開発、保守担当をアサインできる場合

Antの専門家のいるプロジェクトで、かつ、Mavenに移行するのも大変という場合に重宝するツールです。有名なところだとSpring Framework(本体部分とWebFlowの部分)のビルドシステムがIvyを使って構築されています。また、Twitterscalaを使ったプロジェクトのいくつかでIvyを使っている例があったと思います。
なお、MavenとIvyとの選択については、以下もご覧ください。(Ant + Ivy vs Maven

Ivyのインストール手順

1.JDKのインストール

AntやIvyを利用するためには、当然JDKJREでなく)のインストールが必要です。
Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle
インストール後環境変数JAVA_HOMEをインストール先のディレクトリーに指定します。

2.Antのインストール

Ivyを使うためには、Antのインストールが必要です。
Apache Ant - Binary Distributions
からBinary版をダウンロードし、適切なディレクトリーに展開します。環境変数ANT_HOMEを展開先ディレクトリに設定します。

3.Ivyのインストール

Download | Apache Ivy ™
からBinary版をダウンロードし、適切なディレクトリーに展開します。次に、展開したディレクトリーの直下に入っているivy-バージョン番号.jarをANT_HOME配下のlibサブディレクトリーにコピーします。

4.HTTPプロキシーの設定(オプショナル)

インターネットに対して直接接続できない環境では、
FAQ | Apache Ivy ™
を参考にしてANT_OPTS環境変数を設定してください。

5.PATH環境変数の修正

PATH環境変数の先頭に%JAVA_HOME%\bin;%ANT_HOME%\binを追加します。(もちろんWindowsの場合。LinuxMacユーザーの方は常識ですよね。)

hello-ivyサンプルを実行してみる

まずはサンプルを実行する

Ivyのインストールができたら、インストールの確認も兼ねて、まずは付属しているhello-ivyサンプルを動作させてみます。
コマンドプロンプトを開き、

(Ivyインストール先)\src\example\hello-ivy

に移動します。そこでantと入力し、

Buildfile: D:\development\tools\Apache\apache-ivy-2.2.0\src\example\hello-ivy\build.xml

resolve:
[ivy:retrieve] :: Ivy 2.2.0 - 20100923230623 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/D:/development/tools/Apache/apache-ant-1.8.1/lib/ivy-2.2.0.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#hello-ivy;working@Ruby
[ivy:retrieve] 	confs: [default]
[ivy:retrieve] 	found commons-lang#commons-lang;2.0 in public
[ivy:retrieve] 	found commons-cli#commons-cli;1.0 in public
[ivy:retrieve] 	found commons-logging#commons-logging;1.0 in public
[ivy:retrieve] :: resolution report :: resolve 190ms :: artifacts dl 10ms
[ivy:retrieve] 	:: evicted modules:
[ivy:retrieve] 	commons-lang#commons-lang;1.0 by [commons-lang#commons-lang;2.0] in [default]
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      default     |   4   |   0   |   0   |   1   ||   7   |   0   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#hello-ivy
[ivy:retrieve] 	confs: [default]
[ivy:retrieve] 	0 artifacts copied, 7 already retrieved (0kB/10ms)

run:
    [javac] D:\development\tools\Apache\apache-ivy-2.2.0\src\example\hello-ivy\build.xml:53: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
     [java] standard message : hello ivy !
     [java] capitalized by org.apache.commons.lang.WordUtils : Hello Ivy !

BUILD SUCCESSFUL
Total time: 1 second

のように最後に「BUILD SUCCESSFUL」と表示されたら成功です。

何が起こっているか

私も最初そうでしたが、ここまで無事動作したものの、実際に何が起こっているのか、サンプルの動作を理解する次のステップが結構大変なところですね。このサンプルのソースコードは、src\example\Hello.javaのただ1つのクラスだけですが、ソースを開いてみるとわかるように、このクラスはcommons-langとcommons-cliという2つのライブラリーに依存しています。したがって、このクラスを正しくコンパイルして実行するためには、これらのライブラリーのjarファイルが必要となります。
ここで依存性管理を使わずに、Antを使って普通にビルドを行う場合、通常はlibディレクトリーなどjarファイルの格納場所を用意しておき、Antのビルド時のクラスパスにそのjarファイルの場所を追加することになりますが、この考え方はIvyを使う場合もあまり変わりません。ただし、依存関係をビルドスクリプトに直接記述する代わりに、ivy.xmlに以下のように記述します。

<ivy-module version="2.0">
    <info organisation="org.apache" module="hello-ivy"/>
    <dependencies>
        <dependency org="commons-lang" name="commons-lang" rev="2.0"/>
        <dependency org="commons-cli" name="commons-cli" rev="1.0"/>
    </dependencies>
</ivy-module>

基本的には直感的に理解できる内容で、特に難しいことはありません。(Mavenのpomファイルに比べて簡潔でかなりスッキリとしています。)このファイルでは、まずタグでこのモジュールのorganisation*1がorg.apacheで、module名がhello-ivyであることが宣言されています。organisationはMavenで言うところのgroup、moduleはartifactにそれぞれ対応する概念です。次に、タグの中身でこのモジュールが依存するライブラリーが宣言されています。タグのorg(organisation)属性はMavenのpomファイルの要素、name属性は要素、rev属性は要素にそれぞれ対応していると考えてください。
このように、モジュールの依存関係を宣言しておけば、後はAntビルドファイルの任意の場所でタグを記述することで、任意のディレクトリー配下に自動的に依存する(推移的な関連も含めて)jarファイルをダウンロードすることができます。実際、このサンプルプログラムのbuild.xmlファイルでは、

    <target name="resolve" description="--> retreive dependencies with ivy">
        <ivy:retrieve/>
    </target>    
    
 ...

    <target name="run" depends="resolve" description="--> compile and run the project">
        <mkdir dir="${build.dir}" />
        <javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="lib.path.id" />
    	<property name="msg" value="hello ivy !"/>
        <java classpathref="run.path.id" classname="example.Hello">
        	<arg value="-message"/>
        	<arg value="${msg}"/>
    	</java>
    </target>

のように記述されているため、runタスクが実行される前に、resolveタスクが実行され、この中でが実行されています。デフォルトではlibサブディレクトリーにライブラリーが取得されますが、

    <property name="lib.dir" value="lib" />
    <property name="build.dir" value="build" />
    <property name="src.dir" value="src" />

    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
	</path>
    <path id="run.path.id">
        <path refid="lib.path.id" />
        <path location="${build.dir}" />
    </path>

の部分でクラスパスが設定されているため、コンパイルや実行が正しく行われます。
結局、ポイントはivy.xmlでモジュールの定義と依存関係の定義を行い、ライブラリーをで取得するというだけです。Ivyが良いのは第一にこの気軽さであり、これなら既存のAntビルドにも自由に組み込むことが可能なのがお分かりいただけると思います。

Ivyの基本概念について

レポジトリーとキャッシュ

このように、通常はを用いてローカルのディレクトリーにjarファイルをダウンロードしてくることが普通ですが*2、最終的にはMavenと同様に、jarファイルをレビジョンごとに管理したレポジトリーから取得するようになっています。Ivyのレポジトリーを読み込むモジュールはレゾルバーと呼ばれていますが、これがちょうどStrategyパターンになっていて、さまざまな実装をプラグインできるようになっています。ファイルシステム上で管理する実装や、HTTPサーバー上で管理する実装などさまざまなものがあり、また、ディレクトリー構造も細かくカスタマイズができるようになっています。*3
resolvers | Apache Ivy™ Documentation
そして、実際にはデフォルト設定でMavenのセントラルレポジトリーを読み込むレゾルバーが登録されています。(Maven形式のレポジトリーを読み込めるStrategy実装が利用されている)さらに、ここが少し分かりにくいところですが、レポジトリーを何段にも自由に階層化することが可能になっています。よくあるパターンは

  • ローカルPC上のレポジトリー
  • 社内のレポジトリー
  • 社外の公開レポジトリー

のように段階的にレポジトリーを構成しておき、順番に解決させるといった設定が可能です。
なお、Ivyではリポジトリーとは別にキャッシュという概念が存在します。デフォルトではホームフォルダー配下の.ivy2ディレクトリー配下にキャッシュが作成されます。hello-ivyを実行した段階では、以下のようなキャッシュディレクトリーが生成されているはずです。

Mavenの場合は共有されるレポジトリーとローカルのレポジトリーが存在し、ローカルのレポジトリーがキャッシュの役割を兼ねていますが、Ivyの場合キャッシュ専門のディレクトリーが存在する点に注意してください。

ivysettings.xmlを使ったIvyの基本設定のカスタマイズ

デフォルトではIvyのjarファイルの中で定義されている設定ファイルが利用されますが、通常ivysettings.xmlと呼ばれる名前のファイルを作成することで、Ivyの動作をカスタマイズすることができます。たとえば、レポジトリーの階層構造やキャッシュの場所などを設定できます。ivysettings.xmlのリファレンスは以下にあります。
Settings Files | Apache Ivy™ Documentation
ivysettings.xmlを使った設定の簡単な例を試すには、exampleの中で、とりあえずchained-resolversを動かしてみるのが良いと思います。

src\example\chained-resolvers\chainedresolvers-project

サブディレクトリーにcdして、antコマンドを起動してください。hello-ivyの場合と違って、build.xmlファイルの中で以下のようにタグが記述されています。

    <ivy:settings file="${ivy.settings.dir}/ivysettings.xml" />

これによって..\settings\ivysettings.xmlファイルが初期化時に読み込まれます。
そして、以下はivysettings.xmlの中身です。

<ivysettings>
  <settings defaultResolver="chain-example"/>
  <resolvers>
    <chain name="chain-example">
      <filesystem name="libraries">
        <artifact pattern="${ivy.settings.dir}/repository/[artifact]-[revision].[ext]" />
      </filesystem>
      <ibiblio name="ibiblio" m2compatible="true" />
    </chain>
  </resolvers>
</ivysettings>

ここでは、タグの中身で

  • ローカルのファイルシステム上のレポジトリーを読み込むためのfilesystemレゾルバーをlibrariesという名前で登録
  • Mavenのセントラルレポジトリーを読み込むibiblioレゾルバーをibiblioという名前で登録
  • これらを順に解決するためのchainレゾルバーをchain-exampleという名前で登録

というようにレポジトリーに対するレゾルバーが設定されています。そして、タグでchain-exampleをデフォルトレゾルバーとして登録しています。以下のように、ビルド時のログを見ると、test.jarがローカルファイルシステム上のlibrariesから、commons-langがセントラルレポジトリーから読み込まれたことが分かります。(ただし、2回目以降のビルドではキャッシュが利くため、セントラルレポジトリーからのダウンロードは行われません。)

[ivy:retrieve]  found commons-lang#commons-lang;2.0 in ibiblio
[ivy:retrieve]  found org.apache#test;1.0 in libraries
Ivyの依存管理の中心的機能であるコンフィグレーション

前節のsettingsという概念と非常に混同しがち*4なので注意が必要なのですが、Ivyにはコンフィグレーション(configuration)と呼ばれる別の概念があり、Ivyの柔軟な依存管理を行う上での中心的な機能となっています。これは、Mavenで言うところのスコープ(scope)の概念に近いものですが、遥かに柔軟です。Mavenの場合、最初からtest、runtime、compile、providedなどの依存性のスコープが決められています。たとえば、testスコープは単体試験の時に利用されるライブラリーで、compileは本体のソースコードのコンパイルに利用するライブラリーといった具合です。また、これらのスコープにより推移的依存関係の際の動作も決まります。
一方、Ivyのコンフィグレーションは各モジュールのivy.xmlファイルでタグを記述することにより、任意の項目を追加できるようになっています。通常のruntimeやtestといったスコープに加えてweblogic、jbossなど特定のAPサーバー固有の依存関係を定義したり、integration-testのように結合試験の時のみ必要な依存関係を定義したりできます。この概念は最初はちょっと分かりにくいですが、まずはサンプルを動かしてみてください。
example\configurations\jdbc-example\ivy.xmlは以下のように記述されています。

<ivy-module version="1.0">
    <info organisation="org.apache" module="configurations" >
    	<description>
    		This is an example project that aims to demonstrate the usage of the configuration in ivy.
    		This project provide 4 configurations. Each configurations describe the requirement to build or run the project
    	</description>
    </info>
    <configurations>
    	<conf name="compile" description="This is this configuration that describes modules need to build our project"/>
    	<conf name="test" extends="compile" description="This is this configuration that describes modules need to run test on our project"/>
    	<conf name="rundev" extends="compile" description="This is this configuration that describes modules need to execute our project in a dev environement"/>
    	<conf name="runprod"  extends="compile" description="This is this configuration that describes modules need to execute our project in a production environement"/>    	
    </configurations>
    
    <dependencies>
	<!-- this dependency is needed for all configuration -->
        <dependency org="commons-cli" name="commons-cli" rev="1.0" />
        <!-- when launching our app in dev mode we use mckoi db and mckoi jdbc client conf="run.dev->embedded, client"-->
        <dependency org="mckoi" name="mckoi" rev="1.0.2"  conf="rundev->default"/> 
        <!-- when launching our app in production environement we needs other jdbc driver -->
        <dependency org="mm-mysql" name="mm-mysql" rev="2.0.7" conf="runprod->default"/> 
        <!-- junit is only need in the test configuration-->        
        <dependency org="junit" name="junit" rev="3.8" conf="test->default"/> 
    </dependencies>
</ivy-module>

今までのサンプルと違い、が記述されており、この中で複数のタグによって複数のコンフィグレーションが定義されています。実際ここではcompile、testという標準的なコンフィグレーションに加えてrundevとrunprodというコンフィグレーションが定義されている点に注目してください。
さらに、タグの中ではconf属性が記述されていることに注意してください。たとえば、

conf="runprod->default"

という記述はそのライブラリーのrunprodコンフィグレーションにおいて、依存相手のdefaultコンフィグレーションに依存することを示します。慣れないと非常に難しく思われるかも知れませんが、要するに依存関係といっても、目的によってさまざまなものがあるわけですから、その依存関係の種類ごとにコンフィグレーションとして定義しておき、おのおの必要な依存関係を自由に定義できるということに過ぎません。
このようにivy.xmlでコンフィグレーションを定義したら、あとはビルドスクリプト中でタグを記述する際に、どのコンフィグレーションを使うかをconf属性で指定するだけで、目的に応じたjarファイルのみを取得してくることができるわけです。(conf属性を指定しない場合conf="*"と見なされ、全コンフィグレーションの依存関係が取得されます。)
このコンフィグレーション別のretrieve機能を使えば、対象APサーバーごとに別々のコンフィグレーションを定義しておき、warファイルに可能するjarファイルを区別するなどといったことが簡単に行えるようになります。
なお、ivy:retrieveのpattern属性で以下のような書き方をすることで、jarファイルの取得先をコンフィグレーション名ごとのサブディレクトリーに分けることも可能です。

<ivy:retrieve pattern="${ivy.lib.dir}/[conf]/[artifact]-[revision].[ext]"/>
ビルド成果物のパブリッシュ

通常、ビルドした成果物(jarファイルなど)は最終的にパブリッシュという操作を行って、レポジトリーに対してメタ情報(ivy.xml)と共に公開します。パブリッシュを行う対象のモジュールではivy.xmlにてタグを記述します。(Ivyのプロジェクトでは一つのモジュールで複数のartifactをパブリッシュすることもできます。)

    <publications>
      <artifact name="sizewhere" type="jar" conf="core" />
    </publications>

そして、build.xmlにてタグを記述することで、実際にレポジトリーに対してパブリッシュ操作を実行します。詳しくはマニュアルを参照してください。

マルチプロジェクトのビルド

Ivyのような依存性管理が本当に重要になってくるのは複数のプロジェクトから構成されるような大規模なプロジェクトにおいてです。このようなマルチプロジェクトの一括ビルドを行う際にもIvyは便利です。サンプルとしては、

src\example\multi-project

が参考になると思います。ここではポイントだけ説明すると、このサンプルのルートディレクトリーに格納されているbuild.xmlにて

  <target name="buildlist" depends="load-ivy"> 
    <ivy:buildlist reference="build-path">
      <fileset dir="projects" includes="**/build.xml"/>
    </ivy:buildlist>
  </target>
  
  <target name="publish-all" depends="buildlist" 
  			description="compile, jar and publish all projects in the right order">
    <subant target="publish" buildpathref="build-path" />
  </target>

のように記述されている部分で、タグを使って配下のすべてのbuild.xmlからビルドリストを作成します。ここでIvyが自動的に依存関係から適切な順番でリストを作成してくれるところがポイントですね。(Ivyを使わない場合は手動でリストを記述する必要がある)あとは通常のAntでマルチプロジェクトのビルドを行う場合と同様、 タスクを記述してリストの順番にサブプロジェクトのタスクを自動的に呼び出させます。

まとめ

Ivyの基本的な使い方の要点をまとめると以下の通りとなります。

  • モジュール(プロジェクト)ごとにivy.xmlを記述して、依存関係、コンフィグレーション、パブリッシュ対象成果物を定義する。
  • Ivyのグローバルな設定はivysettings.xmlに定義し、タグで読み込む。
  • コンフィグレーションとは独自の依存関係のスコープを定義したものである。
  • レポジトリーとはjarファイルなどのライブラリーをバージョンごとに管理したものである。
  • レポジトリーから読み込むためのレゾルバーの階層を自由に定義することができる。
  • レポジトリーから読み込んだデータは最終的にローカルのファイルシステム上にキャッシュされる。
  • ビルドスクリプトの任意の場所でタグを記述することでjarファイルなどをレポジトリーから取得することができる。
  • ビルドした成果物(アーティファクト)はを実行することでレポジトリーにメタ情報と共にパブリッシュ(公開)される。

ここで紹介した内容は本当に基礎の部分のみです。詳しくは以下のリファレンスを参照してください。
Reference | Apache Ivy™ Documentation
なお、IvyDEというEclipseのプラグインもあります。
Home | Apache IvyDE™
以前のバージョンは結構不具合が多かったのですが、最近は比較的安定して使えるツールになってきているようです。

*1:新しいバージョンではorganizationでも可。Ivyの開発者はフランス人らしいので、もともとはイギリス英語になっている。

*2:タグを利用するとダウンロードなしでキャッシュ上のjarファイルをクラスパスに追加することもできる。

*3:基本的にIvyの思想はこのStrategyパターンによるさまざまな実装方式のプラグインにあるため、この点を理解することが非常に大切です。Strategy大好きのSpringがIvyを利用しているのもちょっと納得できることです。

*4:共に翻訳すると構成とか設定という意味になる。