Apache IvyでJavaのライブラリを管理する


## はじめに

Apache IvyでJavaのライブラリを管理する方法を記述します。

## 環境

* CentOS 6.5
* jdk 1.7.0_55
* Apache Ivy 2.4.0
* Apache Ant 1.9.4

## Java及びAntのインストール及び設定

Apache Ivyを利用するには、jdk及びApache Antが必要となるのでインストール及び設定を行っておきます。

今回は、[Apache AntでJavaをビルドする](http://qiita.com/toshiro3/items/6aed479e3cca47352b18)で利用した環境をそのまま使用しています。

## Apache Ivyのインストール

```shell
$ curl -LO http://ftp.tsukuba.wide.ad.jp/software/apache//ant/ivy/2.4.0-rc1/apache-ivy-2.4.0-rc1-bin.tar.gz
$ tar zxvf apache-ivy-2.4.0-rc1-bin.tar.gz
$ cp apache-ivy-2.4.0-rc1/ivy-2.4.0-rc1.jar /path/to/ANT_HOME/lib/
```

## Apache Ivyの動作確認

* サンプルプログラムを実行して動作を確認しておきます。

```shell
$ cd apache-ivy-2.4.0-rc1/src/example/hello-ivy/
$ ant
Buildfile: /path/to/apache-ivy-2.4.0-rc1/src/example/hello-ivy/build.xml

resolve:
[ivy:retrieve] :: Apache Ivy 2.4.0-rc1 - 20140315220245 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/path/to/ant/lib/ivy-2.4.0-rc1.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: org.apache#hello-ivy;working@hadoop-client41
[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] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.0/commons-lang-2.0.jar ...
[ivy:retrieve] ................ (165kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-lang#commons-lang;2.0!commons-lang.jar (1637ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.0/commons-lang-2.0-javadoc.jar ...
[ivy:retrieve] ........................ (467kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-lang#commons-lang;2.0!commons-lang.jar(javadoc) (1686ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-lang/commons-lang/2.0/commons-lang-2.0-sources.jar ...
[ivy:retrieve] ............ (245kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-lang#commons-lang;2.0!commons-lang.jar(source) (999ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0.jar ...
[ivy:retrieve] .. (29kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-cli#commons-cli;1.0!commons-cli.jar (745ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0-javadoc.jar ...
[ivy:retrieve] ... (92kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-cli#commons-cli;1.0!commons-cli.jar(javadoc) (770ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0-sources.jar ...
[ivy:retrieve] .. (48kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-cli#commons-cli;1.0!commons-cli.jar(source) (769ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/commons-logging/commons-logging/1.0/commons-logging-1.0.jar ...
[ivy:retrieve] .. (21kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] commons-logging#commons-logging;1.0!commons-logging.jar (794ms)
[ivy:retrieve] :: resolution report :: resolve 6119ms :: artifacts dl 7432ms
[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   |   3   |   3   |   1   ||   7   |   7   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache#hello-ivy
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  0 artifacts copied, 7 already retrieved (0kB/30ms)

run:
     [java] standard message : hello ivy !
     [java] capitalized by org.apache.commons.lang.WordUtils : Hello Ivy !

BUILD SUCCESSFUL
Total time: 15 seconds
```
## AntベースのプロジェクトへIvyの設定を追加する

* プロジェクトのディレクトリへ移動します。

```shell
$ cd /path/to/projects/sample
```

* build.xmlを修正します。

```xml:build.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- xmlns属性を追加 -->
<project name="sample" basedir="." default="package" xmlns:ivy="antlib:org.apache.ivy.ant">

  <property name="project" value="sample" />
  <property name="version" value="0.0.1" />
  <property name="src.dir" location="src/main/java" />
  <property name="lib.dir" location="/path/to/lib" />
  <property name="build.dir" location="target/classes" />

  <path id="classpath">
    <pathelement location="${lib.dir}/commons-lang3-3.3.2.jar" />
  </path>

  <target name="echo">
    <echo message="Hello, World!" />
  </target>

  <target name="package" depends="compile">
    <jar destfile="${project}-${version}.jar" basedir="${build.dir}" />
  </target>

  <target name="compile" depends="clean">
    <mkdir dir="${build.dir}" />
    <javac includeAntRuntime="false"
      srcdir="${src.dir}"
      destdir="${build.dir}"
      classpathref="classpath"
    />
  </target>

  <!-- resolveターゲットを追加 -->
  <target name="resolve">
    <ivy:retrieve/>
  </target>

  <target name="clean">
    <delete dir="${build.dir}" />
    <delete file="${project}-${version}.jar" />
  </target>

</project>
```
* ivy.xmlを作成します。

ivyでJavaのライブラリを管理するため、プロジェクトが依存するJavaのライブラリをivy.xmlに記述します。

sampleプロジェクトはcommons-langの3.3.2に依存しているため、以下のようになります。

```xml:ivy.xml
<ivy-module version="2.0">
    <info organisation="com.example" module="sample"/>
    <dependencies>
        <dependency org="org.apache.commons" name="commons-lang3" rev="3.3.2"/>
    </dependencies>
</ivy-module>
```

依存関係の具体的な記述内容は、mavenのリポジトリで確認することができます。(Ivyタブの内容)
[Maven Repository: org.apache.commons » commons-lang3 » 3.3.2](http://mvnrepository.com/artifact/org.apache.commons/commons-lang3/3.3.2)


* ivyで依存関係を解決する

```shell
$ ant resolve
Buildfile: /path/to/projects/sample/build.xml

resolve:
[ivy:retrieve] :: Apache Ivy 2.4.0-rc1 - 20140315220245 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/path/to/ant/lib/ivy-2.4.0-rc1.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: com.example#sample;working@hadoop-client41
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  found org.apache.commons#commons-lang3;3.3.2 in public
[ivy:retrieve] downloading http://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2.jar ...
[ivy:retrieve] ................................. (403kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] org.apache.commons#commons-lang3;3.3.2!commons-lang3.jar (1833ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2-sources.jar ...
[ivy:retrieve] ......................... (459kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] org.apache.commons#commons-lang3;3.3.2!commons-lang3.jar(source) (1120ms)
[ivy:retrieve] downloading http://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2-javadoc.jar ...
[ivy:retrieve] ............................... (1049kB)
[ivy:retrieve] .. (0kB)
[ivy:retrieve]  [SUCCESSFUL ] org.apache.commons#commons-lang3;3.3.2!commons-lang3.jar(javadoc) (1115ms)
[ivy:retrieve] :: resolution report :: resolve 5329ms :: artifacts dl 4082ms
        ---------------------------------------------------------------------
        |                  |            modules            ||   artifacts   |
        |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
        ---------------------------------------------------------------------
        |      default     |   1   |   1   |   1   |   0   ||   3   |   3   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: com.example#sample
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  3 artifacts copied, 0 already retrieved (1912kB/24ms)

BUILD SUCCESSFUL
Total time: 10 seconds
```
* ライブラリの取得を確認しておきます。

デフォルトでは、プロジェクト直下のlibディレクトリへライブラリが取得されます。

```shell
$ ls -l /path/to/projects/sample
total 24
-rw-rw-r--. 1 admin admin 1108 Sep 27 13:06 build.xml
-rw-r--r--. 1 admin admin  221 Sep 27 13:34 ivy.xml
drwxrwxr-x. 2 admin admin 4096 Sep 27 13:34 lib
-rw-rw-r--. 1 admin admin 1219 Sep 26 01:26 sample-0.0.1.jar
drwxrwxr-x. 4 admin admin 4096 Sep 25 05:31 src
drwxrwxr-x. 3 admin admin 4096 Sep 26 01:26 target

$ ls -l /path/to/projects/sample/lib
total 1916
-rw-rw-r--. 1 admin admin  412739 Apr  6 21:21 commons-lang3-3.3.2.jar
-rw-rw-r--. 1 admin admin 1074965 Apr  6 21:21 commons-lang3-3.3.2-javadoc.jar
-rw-rw-r--. 1 admin admin  470961 Apr  6 21:21 commons-lang3-3.3.2-sources.jar
```
* Javaのコンパイルを確認します。

ivyによりプロジェクト直下のlibディレクトリへライブラリが取得されるため、クラスパスの修正を行います。
また、antでHelloWorldの実行が行えるように、runターゲットを追加します。

```xml:build.xml
<?xml version="1.0" encoding="UTF-8" ?>
<project name="sample" basedir="." default="package" xmlns:ivy="antlib:org.apache.ivy.ant">

  <property name="project" value="sample" />
  <property name="version" value="0.0.1" />
  <property name="src.dir" location="src/main/java" />
  <!-- パスを修正 -->
  <property name="lib.dir" location="lib" />
  <property name="build.dir" location="target/classes" />

  <!-- クラスパスを修正 -->
  <path id="classpath">
    <fileset dir="${lib.dir}" />
  </path>

  <!-- Java実行時のクラスパスの定義を追加 -->
  <path id="run.classpath">
    <path refid="classpath" />
    <path location="${build.dir}" />
  </path>

  <target name="echo">
    <echo message="Hello, World!" />
  </target>

  <target name="package" depends="compile">
    <jar destfile="${project}-${version}.jar" basedir="${build.dir}" />
  </target>

  <!-- runターゲットを追加 -->
  <target name="run" depends="compile">
    <java classpathref="run.classpath" classname="HelloWorld" />
  </target>

  <!-- resolveターゲットへの依存を追加 -->
  <target name="compile" depends="clean,resolve">
    <mkdir dir="${build.dir}" />
    <javac includeAntRuntime="false"
      srcdir="${src.dir}"
      destdir="${build.dir}"
      classpathref="classpath"
    />
  </target>

  <target name="resolve">
    <ivy:retrieve/>
  </target>

  <target name="clean">
    <delete dir="${build.dir}" />
    <delete file="${project}-${version}.jar" />
  </target>

</project>
```

```shell
$ ant compile
Buildfile: /path/to/projects/sample/build.xml

clean:
   [delete] Deleting directory /path/to/projects/sample/target/classes

resolve:
[ivy:retrieve] :: Apache Ivy 2.4.0-rc1 - 20140315220245 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/path/to/work/ant/lib/ivy-2.4.0-rc1.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: com.example#sample;working@hadoop-client41
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  found org.apache.commons#commons-lang3;3.3.2 in public
[ivy:retrieve] :: resolution report :: resolve 260ms :: artifacts dl 18ms
        ---------------------------------------------------------------------
        |                  |            modules            ||   artifacts   |
        |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
        ---------------------------------------------------------------------
        |      default     |   1   |   0   |   0   |   0   ||   3   |   0   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: com.example#sample
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  0 artifacts copied, 3 already retrieved (0kB/5ms)

compile:
    [mkdir] Created dir: /path/to/projects/sample/target/classes
    [javac] Compiling 1 source file to /path/to/projects/sample/target/classes

BUILD SUCCESSFUL
Total time: 2 seconds
```
* HelloWorldを実行します。

```shell
$ ant run
Buildfile: /path/to/projects/sample/build.xml

clean:
   [delete] Deleting directory /path/to/projects/sample/target/classes

resolve:
[ivy:retrieve] :: Apache Ivy 2.4.0-rc1 - 20140315220245 :: http://ant.apache.org/ivy/ ::
[ivy:retrieve] :: loading settings :: url = jar:file:/path/to/work/ant/lib/ivy-2.4.0-rc1.jar!/org/apache/ivy/core/settings/ivysettings.xml
[ivy:retrieve] :: resolving dependencies :: com.example#sample;working@hadoop-client41
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  found org.apache.commons#commons-lang3;3.3.2 in public
[ivy:retrieve] :: resolution report :: resolve 257ms :: artifacts dl 15ms
        ---------------------------------------------------------------------
        |                  |            modules            ||   artifacts   |
        |       conf       | number| search|dwnlded|evicted|| number|dwnlded|
        ---------------------------------------------------------------------
        |      default     |   1   |   0   |   0   |   0   ||   3   |   0   |
        ---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: com.example#sample
[ivy:retrieve]  confs: [default]
[ivy:retrieve]  0 artifacts copied, 3 already retrieved (0kB/6ms)

compile:
    [mkdir] Created dir: /path/to/projects/sample/target/classes
    [javac] Compiling 1 source file to /path/to/projects/sample/target/classes

run:
     [java] Hello, World!
     [java] * Java version : 24.55-b03
     [java] * OS name : Linux
     [java] * OS version : 2.6.32-431.el6.x86_64

BUILD SUCCESSFUL
Total time: 2 seconds
```


## 参考

* [Apache Ivyの紹介と基本的な使い方](http://d.hatena.ne.jp/ryoasai/20110101/1293904479)
* [Apache Ivy](http://ant.apache.org/ivy/)
* [Apache Ant](http://ant.apache.org/)