Maven2使い方メモ

ずっと避けてたけど、そろそろ避けられなくなってきたので Maven2 の使い方をメモする。
とりあえず、インストールから簡単なコマンドラインプログラムを作るまで。


#環境
##OS
Windows7 64bit

##Maven
2.2.1

#インストール
Maven2 のインストール方法。

##ダウンロード
[ここ](http://maven.apache.org/download.cgi)から `apache-maven-2.2.1-bin.zip` をダウンロード。

##インストール
zip を任意の場所に解凍。
※解凍場所を以後 `%M2_HOME%` と記載する。

`%M2_HOME%` にパスを通す。

##ローカルリポジトリの設定
ローカルリポジトリはデフォルトだと `%ユーザのホームフォルダ%/.m2/repository` に作成される。
嫌な場合は変更する。

`%M2_HOME%/conf/settings.xml` の `localRepository` タグがコメントアウトされているので、コメントアウトを外して任意のパスを指定する。

```xml:settings.xml（リポジトリの設定を変更）
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ~/.m2/repository
  -->
  <localRepository>D:/maven/repo</localRepository>
```

##プロキシの設定
プロキシ環境の場合は、同じく `%M2_HOME%/settings.xml` を編集。

`proxy` タグがコメントアウトされているので、コメントアウトを外して必要な情報を設定。

```xml:settings.xml（プロキシの設定を追加）
  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |
    -->
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
  </proxies>
```

#簡単なプログラムの作成
コマンドラインから実行できる簡単な Java プログラムを Maven2 で作るメモ。
あえて Eclipse は使わない。

##プロジェクトのひな形を作成する
仮に作業フォルダを `D:\tmp` とする。

コマンドプロンプトから、以下のコマンドを実行。

```batch:ひな形の作成
>cd /d D:\tmp

D:\tmp>mvn archetype:create -DgroupId=com.example -DartifactId=sample
```

`D:\tmp\sample` というひな形フォルダが作成される。

```batch:ひな形のフォルダ構成
D:\tmp\sample>tree /f
D:.
│  pom.xml
│
└─src
    ├─main
    │  └─java
    │      └─com
    │          └─example
    │                  App.java
    │
    └─test
        └─java
            └─com
                └─example
                        AppTest.java
```

##実装
App.java と AppTest.java を実装。

```java:App.java
package com.example;

import org.apache.commons.lang3.*;

public class App {
    public static void main( String[] args ) {
        String str = new App().join(args);
        System.out.println(str);
    }
    
    public String join(String[] args) {
        return StringUtils.join(args, ",");
    }
}
```

```java:AppTest.java
package com.example;

import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

public class AppTest {
    
    private App target = new App();
    
    @Test
    public void test() {
        // setup
        String[] args = {"abc", "def"};
        
        // exercise
        String actual = target.join(args);
        
        // verify
        assertThat(actual, is("abc,def"));
    }
}
```

##pom.xml の編集
pom.xml を以下の内容に編集する。

```xml:pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>sample</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>

  <name>sample</name>

  <properties>
    <project.build.sourceEncoding>Shift_JIS</project.build.sourceEncoding>
  </properties>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
          <debug>true</debug>
          <debuglevel>lines,vars,source</debuglevel>
        </configuration>
      </plugin>
      
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        
        <executions>
          <execution>
            <phase>package</phase>
            
            <goals>
              <goal>jar</goal>
            </goals>
            
            <configuration>
              <archive>
                <manifestEntries>
                  <Built-By>anonymous</Built-By>
                </manifestEntries>
              </archive>
            </configuration>
          </execution>
        </executions>
      </plugin>
      
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>appassembler-maven-plugin</artifactId>
        
        <executions>
          <execution>
            <phase>package</phase>
            
            <goals>
              <goal>assemble</goal>
            </goals>
        
            <configuration>
              <repositoryLayout>flat</repositoryLayout>
              <repositoryName>lib</repositoryName>
              
              <programs>
                <program>
                  <mainClass>com.example.App</mainClass>
                  <name>app</name>
                </program>
              </programs>
            </configuration>
          </execution>
        </executions>
      </plugin>
      
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        
        <executions>
          <execution>
            <phase>package</phase>
            
            <goals>
              <goal>single</goal>
            </goals>
            
            <configuration>
              <descriptors>
                <descriptor>src/assemble/distribution.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
      
    </plugins>
  </build>
  
  <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.1</version>
    </dependency>
  </dependencies>
</project>
```

説明は後で。

##Maven Assembly Plugin の設定ファイルを作成する
`src/assemble` に `distribution.xml` というファイルを作成する。
内容は以下。

```xml:distribution.xml
<assembly>
  <id>executable</id>
  <formats>
    <format>zip</format>
    <format>tar.gz</format>
  </formats>
  <fileSets>
    <fileSet>
      <directory>target/appassembler/bin</directory>
      <outputDirectory>/bin</outputDirectory>
    </fileSet>
    <fileSet>
      <directory>target/appassembler/lib</directory>
      <outputDirectory>/lib</outputDirectory>
      <includes>
        <include>*.jar</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>
```

```batch:フォルダ構成
D:\tmp\sample>tree /f
D:.
│  pom.xml
│
└─src
    ├─assemble
    │      distribution.xml
    │
    ├─main
    │  └─java
    │      └─com
    │          └─example
    │                  App.java
    │
    └─test
        └─java
            └─com
                └─example
                        AppTest.java
```

##コンパイル　～　配布用アーカイブの作成
###コンパイルの実行
```batch:コンパイル
D:\tmp\sample>mvn compile
```
`target/classes` 以下に class ファイルが出力される。

###単体テストの実行
```batch:単体テスト
D:\tmp\sample>mvn test
```
テストとして実行されるのは、ファイル名が次のいずれかに合致するファイルのみ。

+ **/Test*.java
+ **/*Test.java
+ **/*TestCase.java

###jarの作成
```batch:jarの作成
D:\tmp\sample>mvn jar:jar
```
`target` フォルダの直下に jar ファイル（`sample-1.0.jar`）が出力される。

###配布用アーカイブの作成
```batch:配布用アーカイブの作成
D:\tmp\sample>mvn package
```
`target` フォルダの直下に zip と tar.gz で出力される（`sample-1.0-executable.zip`, `sample-1.0-executable.tar.gz`）。

アーカイブの中身は、 `target/appassembler` の内容と同じ。

```batch:配布用アーカイブの中身
D:\tmp\sample\target\appassembler>tree /f
D:.
├─bin
│      app
│      app.bat
│
└─lib
        commons-lang3-3.1.jar
        sample-1.0.jar
```

##プログラムの実行
`target/sample-1.0-executable.zip` を解凍すると `sample-1.0` というフォルダができる。
`sample-1.0/bin` にコマンドプロンプトで移動して、以下のコマンドを実行。

```batch:プログラムの実行
D:\tmp\sample\target\sample-1.0\bin>app hoge fuga piyo
hoge,fuga,piyo
```

#説明
##依存ライブラリの dependency タグの書き方を調べる方法

```xml:pom.xmlのdependencyタグ
  <dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.1</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>1.3</version>
        <scope>test</scope>
    </dependency>
  </dependencies>
```

pom.xml の `dependency` をどう記述するかは、以下のいずれかの方法で調べる。

###ライブラリの公式サイトを見る
ライブラリがセントラルリポジトリに登録されている場合は、たいていそのライブラリの公式サイトに Maven2 を使用するときの `dependency` タグの記述方法が説明されている。

[commons lang3 の場合](http://commons.apache.org/proper/commons-lang/)

> \<groupId\>org.apache.commons\</groupId\>
> \<artifactId\>commons-lang3\</artifactId\>
> \<version\>3.1\</version\>

###セントラルリポジトリで検索する
[ここ](http://search.maven.org/#browse)で Web ブラウザを使って検索できる。


##dependency タグの scope タグで参照するタイミングを指定する
```xml:dependencyタグのscopeタグ
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>1.3</version>
        <scope>test</scope> <!-- ★これ -->
    </dependency>
```

`scope` タグで、依存ライブラリをいつ参照するかを指定できる。上記の場合はテストを実行するときにだけ依存ライブラリを参照する。

他には以下の値が指定可能。

|   scope     |   参照のタイミング                                                                       |
|:-------------|:---------------------------------------------------------------------------------|
|  compile   |  デフォルト。常に参照される。                                                    |
|  provided |  コンパイルの時だけ参照される。servlet-api とかが該当する。   |
|  runtime   |  実行時に参照される。テストの時も参照される。                        |
|  test         |  テストの実行時だけ参照される。                                                 |
|  system    |  よくわからない。あまり使わないらしい。                                   |

##コンパイルオプションの指定
```xml:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.7</source>
    <target>1.7</target>
    <debug>true</debug>
    <debuglevel>lines,vars,source</debuglevel>
  </configuration>
</plugin>
```

`configuration` タグの子タグで指定できる。指定できるタグは[ここ](http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html)を参照。


##Application Assembler Maven Plugin を使って起動用スクリプトファイルを作成する
[Application Assembler Maven Plugin](http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/)というプラグインを使うと、プログラムの起動スクリプトが自動生成できる。

```xml:Assemblerの設定
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>appassembler-maven-plugin</artifactId>
  
  <executions>
    <execution>
      <phase>package</phase>
      
      <goals>
        <goal>assemble</goal>
      </goals>
  
      <configuration>
        <repositoryLayout>flat</repositoryLayout>
        <repositoryName>lib</repositoryName>
        
        <programs>
          <program>
            <mainClass>com.example.App</mainClass>
            <name>app</name>
          </program>
        </programs>
      </configuration>
    </execution>
  </executions>
</plugin>
```

`repositoryLayout` と `repositoryName` の設定によって、本体の jar と依存する jar を lib というフォルダの下にまとめている。
`mainClass` はメインメソッドのあるクラスの FQCN を指定していて、 `name` は起動スクリプトのファイル名を指定している。

実行結果は `target/appassembler` の下に出力される。


##Maven Assembly Plugin を使って配布用アーカイブを作成する
[Maven Assembly Plugin](http://maven.apache.org/plugins/maven-assembly-plugin/) を使うと、ビルド結果を任意の形でまとめることができる。

```xml:Assemblyの設定
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  
  <executions>
    <execution>
      <phase>package</phase>
      
      <goals>
        <goal>single</goal>
      </goals>
      
      <configuration>
        <descriptors>
          <descriptor>src/assemble/distribution.xml</descriptor>
        </descriptors>
      </configuration>
    </execution>
  </executions>
</plugin>
```

`descriptor` タグで指定しているファイル（`src/assemble/distribution.xml`）に、具体的な「まとめ方」の定義を記述している。

```xml:distribution.xml
<assembly>
  <id>executable</id>
  <formats>
    <format>zip</format>
    <format>tar.gz</format>
  </formats>
  <fileSets>
    <fileSet>
      <directory>target/appassembler/bin</directory>
      <outputDirectory>/bin</outputDirectory>
    </fileSet>
    <fileSet>
      <directory>target/appassembler/lib</directory>
      <outputDirectory>/lib</outputDirectory>
      <includes>
        <include>*.jar</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>
```

`id` タグで指定した値は、作成されるアーカイブの末尾に追加される（`sample-1.0-executable.zip`）。

`formats` タグで、アーカイブの形式を指定している（zip, tar.gz）。他には tar, tar.bz2, jar, dir, war が指定できるっぽい。

`fileSets` タグの中で、具体的な「まとめ方」を定義している。
`fileSet` タグの子タグに指定できるタグについては、 [ここ](http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html#class_fileSet)を参照。


#ローカルリポジトリに jar を追加する
セントラルリポジトリに無かったり、リポジトリが公開されていないライブラリを使いたい場合は、 jar ファイルを手作業でダウンロードして、コマンドラインからローカルリポジトリに追加する。

```batch:
>mvn install:install-file -Dfile=＜jar ファイルのパス＞ -DgroupId=＜グループID＞ -DartifactId=＜アーティファクトID＞ -Dversion=＜バージョン＞ -Dpackaging=jar
```

ローカルリポジトリにインストールしたら、他のライブラリ同様 pom.xml の dependency で依存関係を追加できるようになる。
その時指定するグループIDやアーティファクトIDはインストールしたときに自分で指定した値を設定する。

#参考
+ [Maven | TECHSCORE(テックスコア)](http://www.techscore.com/tech/Java/ApacheJakarta/Maven/index/)
+ [Eclipse+Mavenでローカルレポジトリの位置を変更する | 情報科学屋さんを目指す人のメモ](http://did2memo.net/2013/04/17/eclipse-maven-move-local-repository/)
+ [Mavenで配布用zipファイルを作成する - Sacrificed & Exploited](http://d.hatena.ne.jp/cnaos/20100102/1262430319)
+ [honeplusのメモ帳 Maven2で生成したMANIFEST.MFにPCのアカウント名が入る](http://honeplus.blog50.fc2.com/blog-entry-45.html)
+ [Maven でアプリケーション実行用バッチファイルを作る - etc9](http://d.hatena.ne.jp/Naotsugu/20101206/1291619754)
+ [Maven2にプロキシを教える | JavaとXMLのマニアな開発：Maven2 入門](http://www.jxpath.com/maven2/step1/proxy.html)