Mavenでwarと実行可能jarを同時にビルドする


Webアプリで実装したロジック層をバッチ処理でも利用したい場合に、warとjarを同時に作りたい事ってよくあると思います。

しかも、依存ライブラリも一緒のjarに固めて、名前もカスタマイズしたい(個人的にxxx-with-dependencies.jarは長いからイヤです)。そんな時のpom.xmlの書き方を紹介します。

## 環境
* Java 8
* Maven2
* logback 1.1.3

## サンプル
サンプルコードは、[こちら](https://github.com/t-mochida/sample-war-jar "github")

## プロジェクト構成
```
project
 └ src
    └ main
       └ assembly
          └ executable-jar.xml
          └ logback.xml
       └ java
       └ resources
          └ logback.xml
          └ sample.properties
       └ webapp
          └ WEB-INF
             └ web.xml
 └ pom.xml  
```

assemblyディレクトリ配下のファイルはjarをつくるためのファイルです。

- executable-jar.xmlにjarの構成を記述します。
- logback.xmlは、jar用のlogback用の設定ファイルです。
（warとjarでログの出力場所を変えたい場合ってありますよね）

## pom.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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.com</groupId>
  <artifactId>sample-war-jar</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>sample-war-jar Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <!-- プロファイルの設定 -->
  <profiles>
    <profile><!-- ローカル環境用 -->
      <id>Local</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <msg.hello>Hello! World in local.</msg.hello>
      </properties>
    </profile>
    <profile>
      <id>Product</id><!-- 本番環境用 -->
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <properties>
        <msg.hello>Hello! World.</msg.hello>
      </properties>
    </profile>
  </profiles>

  <dependencies>
    <dependency><!-- サーブレット用 -->
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>

    <dependency><!-- Logback用 -->
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.12</version>
    </dependency>

    <dependency><!-- Logback用 -->
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.3</version>
    </dependency>
  </dependencies>

  <!-- ビルド設定 -->
  <build>
    <finalName>sample</finalName>

    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>

    <plugins>
      <!-- war作成用 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <executions>
          <execution>
            <id>make-war</id>
            <phase>package</phase>
            <goals>
              <goal>war</goal>
            </goals>
            <configuration>
              <failOnMissingWebXml>false</failOnMissingWebXml>
              <webResources>
                <resource>
                  <directory>src/main/webapp</directory>
                </resource>
              </webResources>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- jetty起動用 -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
        </configuration>
      </plugin>

      <!-- jar作成用 -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>make-jar</id>
            <phase>compile</phase><!-- packageじゃなくて、compileを指定 -->
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptors><!-- 独自定義ファイルの指定 -->
            <descriptor>src/main/assembly/executable-jar.xml</descriptor>
          </descriptors>
          <finalName>sample</finalName>
          <appendAssemblyId>false</appendAssemblyId>
          <archive>
            <manifest>
              <mainClass>com.sample.warjar.batch.Main</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>
```

サンプルは、サーブレットからロジック層の処理を呼び出し、プロパティーファイルを読み込んで表示するだけのものです。jarも同様にロジック層を呼び出してテキストを表示します。

pluginの記述は、順に、war作成用とjetty起動用※とjar作成用です。

ポイントは、「maven-assembly-plugin」の記述です。
「phase」のところで、compileを指定しています。（packageだと、なぜか、作成後のjarのMainクラスの呼び出しに失敗しました）

そして、「descriptor」のところで、独自定義ファイルを指定しています。
ここで指定するディレクトリやファイル名は任意で実行可能ですが、デフォルトのディレクトリ名は、「src/main/assembly」らしいです。

※ `mvn jetty:run`でWebアプリを直接起動でき、localhost:8080/myappでアクセスできます。

## descriptorファイルの用意
```executable-jar.xml
<assembly
  xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">

  <id>make-jar</id>
  <formats>
    <format>jar</format>
  </formats>

  
  <fileSets>
    <fileSet>
      <directory>${project.basedir}/src/main/assembly</directory>
      <outputDirectory>/</outputDirectory>
      <includes><!-- jarに含めたいファイルの定義 -->
        <include>logback.xml</include>
      </includes>
      <excludes>
        <exclude>executable-jar.xml</exclude>
      </excludes>
    </fileSet>
  </fileSets>

  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <!-- 依存ライブラリ等を解凍する指定 -->
      <unpack>true</unpack>
      <unpackOptions>
        <excludes><!-- 解凍時に除外するファイルを指定 -->
          <exclude>**/logback.xml</exclude>
        </excludes>
      </unpackOptions>
      <scope>runtime</scope>
    </dependencySet>
  </dependencySets>
</assembly>
```

ポイントは２箇所あります。
「fileSet」の記述で、jarに含みたいlogback.xmlファイルを指定し、「unpackOptions」の記述で、logback.xmlを除外しています。

これで、warに含まれるWebアプリ用のlogback.xmlを省きつつ、バッチ処理用のlogback.xmlの定義ファイルを取り込むことを実現しています。

一方、プロパティーファイルがwarと同じように取り込まれていることは、サンプルを実行すると確認できます。

作成したい状況に合わせてここら辺をカスタマイズしてください。

## warとjarを作成する 
Mavenコマンド`mvn package`一発でwarもjarも生成されます。

## 参考URL

* [Advanced Assembly-Descriptor Topics](http://maven.apache.org/plugins/maven-assembly-plugin/advanced-descriptor-topics.html)
* [Logbackでファイルにログを吐く時の基本設定](http://qiita.com/joe_hrmn/items/356f1e2b05cb90241414)