EclipseのWTPでTomcatのcontext.xmlを切り替える方法

# はじめに
Tomcatが提供するデータソースをWebアプリケーションから使用する際は、context.xmlにデータソースの設定を記述します。本稿では、EclipseのWTP(Web Tools Plugin)を使ってTomcatを起動して開発している時に、開発者ごとにcontext.xmlをうまく切り替える方法を紹介します。

「やり方を早く知りたい！」という方は、[切り替え方法](#切り替え方法)からご覧ください。

# context.xml の切替がなぜ必要なのか

context.xmlの配置場所には大きく二通りがあります。

1. Webアプリケーション配下の ```META-INF/context.xml```
2. Tomcatインストールディレクトリ配下の ```$CATALINA_BASE/conf/context.xml```

(参考：[Apache Tomcat 8 Configuration Reference (8.5.32) - The Context Container](https://tomcat.apache.org/tomcat-8.5-doc/config/context.html#Defining_a_context))

それぞれ、以下のような特徴がありますが、一長一短です。

#### **1. Webアプリケーション配下**

- contex.xmlをwarファイルに含めてそのままデプロイできるため、簡単。
- context.xml も構成管理対象としてしまう。(DB接続情報を構成管理対象とすることの可否はさておくとして)
- 本番環境、テスト環境等の接続情報切替は、Mavenのリソースフィルタ等を使ってビルド時(=war作成時)に切り替える。
- 開発者がローカル環境でテストするときは毎回Mavenでビルドするわけにいかないため、```META-INF/context.xml``` を**手作業で修正、誤ってコミットしてしまう事故が多発**する。
 
#### **2. Tomcatインストールディレクトリ配下**

- データソースはアプリケーションサーバが提供するもの、という思想に基づくならこちら。
- context.xmlは構成管理対象にしない。
- その代わり、本番環境、テスト環境、各開発者のローカル環境等に合わせてそれぞれ用意しなければならない。


特に開発中に開発者がそれぞれ自分の開発用データベースを使用しながらEclipse上でTomcatにデプロイしながら開発する時に、context.xmlを構成管理対象にしつつ、環境に合わせて切り換えられるようにする方法を紹介します。

# 切り替え方法
## 基本アイデア

開発者毎のデータソース設定を記述したファイルをすべてGit管理としておき、シンボリックリンクを使って切り替えます。シンボリックリンクはWTPの設定で、META-INF配下にデプロイするようにします。

開発者毎のデータソース設定を記述したcontext.xmlは、```context_ログインユーザ名.xml```というファイル名で```context/user```ディレクトリ配下に配置します。これはGit管理対象とします。ログインユーザ名はWindowsのログインユーザ名(```%USERNAME%```環境変数)とします。以下の例では、alice、bob、charlieが開発者のログインユーザ名です。このように、開発者の数だけファイルを作成しておきます。

各開発者は、自分用の```context_ログインユーザ名.xml```へのシンボリックリンクを```context/META-INF/context.xml```として作成することで、データソース設定の切替を実現します。

## Eclipseプロジェクトのディレクトリ構成
Eclipseのプロジェクト配下に、```context/META-INF```と```context/user```ディレクトリを新しく作成します。

```context/META-INF``` の内容は後述の設定によってウェブアプリケーション内の ```META-INF``` 配下にデプロイされます。

```context/user``` 配下に前述の開発者毎の ```context_***.xml```を配置します。また、シンボリックリンク作成用のバッチファイル(後述)も配置します。

```
(プロジェクトルートディレクトリ)
┊ 
├ context
│  ├ META-INF
│  │  ├ .gitignore
│  │  └ context.xml ← <setup-context.bat が作成するシンボリックリンク。Git管理対象外>
│  │
│  └ user
│     ├ setup-context.bat ← <シンボリックリンク作成用バッチファイル(後述)>
│     ├ context_alice.xml   ← <aliceのデータソース設定を記述したcontext.xml>
│     ├ context_bob.xml     ← <bobのデータソース設定を記述したcontext.xml>
│     └ context_charlie.xml ← <charlieのデータソース設定を記述したcontext.xml>
┊
```

```context_***.xml``` の内容は、以下のような ```context.xml``` そのもので、接続先だけ開発者に合わせて変更しておきます。(以下はMySQLでの例です)

```xml:context_***.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/webapp" docBase="webapp" crossContext="true" reloadable="true" debug="1">
	<Resource name="jdbc/mysql" auth="Container" type="javax.sql.DataSource"
                  driverClassName="com.mysql.jdbc.Driver"
                  url="jdbc:mysql://ホスト:3306/データベース名"
                  username="ユーザ名" password="パスワード"
                  maxIdle="10" defaultAutoCommit="false" />
</Context>
```

## シンボリックリンクの作成

```setup-context.bat```はシンボリックリンクを簡単に作成するための作成するためのバッチファイル。開発者はプロジェクトをクローンしたのち、このバッチファイルを実行します。```setup-context.bat```は、```%USERNAME%```を参照して、```context_ログインユーザ名.xml``` へのシンボリックリンクを```context/META-INF/context.xml```として作成してくれます。

開発者毎に変わるファイルはこのシンボリックリンクだけです。このシンボリックリンクはこのあと説明するようにGit管理外にするため、コンフリクトを起こすことがありません。

## シンボリックリンクをGitの管理対象外に設定する

Gitの仕様上、シンボリックリンクはその実体がリポジトリに登録されてしまうため、```context/META-INF/context.xml``` をGit管理対象外とします。このため、```context/META-INF/.gitignore``` を以下のように作成しておきます。


```:.gitignore
/context.xml
```

## Eclipse のプロジェクト設定
Eclipseで以下のようにプロジェクトを設定します。これにより、WTPでTomcatを起動したとき、```context/META-INF/```配下のファイルがWebアプリケーションの ```META-INF``` 配下にコピーされます。

1. Eclipseでプロジェクトのプロパティを開き、「デプロイメント・アセンブリー」を開きます。

2. 「追加...」ボタンを押し、新規アセンブリー・ディレクティブで「フォルダ」を選択します。![assembly.png](https://qiita-image-store.s3.amazonaws.com/0/222989/f9fd17aa-27f9-bffb-c91e-0a29d77e6b74.png)

3. ```context/META-INF```ディレクトリを選択し、「デプロイ・パス」に ```META-INF/```を指定して、設定を保存します。
![context.png](https://qiita-image-store.s3.amazonaws.com/0/222989/653edda8-ffb7-9f03-3238-f0e324a5b341.png)

これでWTPを使ってTomcatを起動すれば、開発者に応じた ```context.xml```(実体は```context_***.xml```) が ```WEB-INF/``` 配下にデプロイされ、データソースの設定切替が実現できます。


## シンボリックリンク作成用のバッチファイル
```setup-context.bat```は以下の内容で作成してください。本質的には ```mklink```コマンドでシンボリックリンクを作成しているだけです。シンボリックリンクが既に存在する場合、確認を促した上で上書きします。

```:setup-context.bat
@echo off

set CONTEXT_DIR=..\META-INF
set CONTEXT_FILE=context.xml

%~d0
pushd %~p0

set USER_CONTEXT_DIR=%~p0

for %%I IN ( %USER_CONTEXT_DIR:~0,-1% ) do set "USER_CONTEXT_DIR=%%~nI"

cd %CONTEXT_DIR%

if not exist %CONTEXT_FILE% goto :MAKELINK

set /P INPUT="[WARNING] %CONTEXT_FILE% が存在します. 削除してもよろしいですか? (y/n)"
if not %INPUT%==y goto :END

del %CONTEXT_FILE%

:MAKELINK
mklink %CONTEXT_FILE% ..\%USER_CONTEXT_DIR%\context_%USERNAME%.xml

:END
popd

pause
```

# 運用方法
これで、以下のような流れで運用することができます。

1. 開発者が増えたら、その開発者用のデータベースを用意し、そこに接続するための ```context_<開発者ユーザ名>.xml```を作成して、```context/users/```配下に配置してコミットする。
2. 開発者はプロジェクトをクローンして、Eclipseにインポートする。
3. 開発者は ```context/user/setup-context.bat``` を実行する。[^permission]
4. ```context/META-INF/context.xml``` がシンボリックリンクとして作成される。
5. Eclipseのパッケージ・エクスプローラーでF5キーを押して更新。```context/META-INF/context.xml``` が表示されていることを確認する。
6. WTPを使ってTomcatを起動すると、Eclipseのプロジェクト設定に従って ```context/META-INF/context.xml``` がWebアプリケーションの ```META-INF``` 配下にコピーされ、データソースの設定として有効になる。

[^permission]: このとき、「この操作を実行するのに十分な特権がありません。」と表示された時は、バッチファイルを管理者権限で実行してください


いまどきTomcatのデータソースを直接使うような開発プロジェクトは少ないかもしれませんが、これで少しは現場のストレスが減るかもしれません。