Google App Engine [Java] でMavenによる開発環境構築

最近、GAE(Google App Engine)を初めて使ってみたのですが、初期プロジェクト構築でハマるところがあったので記事にしました。Mavenでビルド、デプロイができるようになるまでが本記事の目標です。

## 本記事が対象とする開発環境
本記事では以下を開発環境の前提とします。

- GAEはスタンダード環境を利用
- 初期プロジェクト構築、ビルド、デプロイはJava + Mavenを使用
- 開発用エディタはEclipseを使用

## 初期プロジェクト構築
クラウド側のアカウント登録とプロジェクト作成は済ませてあることとします。
まずMavenで初期プロジェクトを作成します。
[GAEのドキュメント](https://cloud.google.com/appengine/docs/standard/java/tools/maven?hl=ja)によると、以下を実行すればよいです。

```
 mvn archetype:generate -Dappengine-version=1.9.71 \
  -Djava8=true -DCloudSDK_Tooling=false \
  -Dapplication-id=your-app-id \
  -Dfilter=com.google.appengine.archetypes:
```
your-app-idにはデプロイ先のGAEのプロジェクトIDを指定します。私は何も考えずに上記をそのまま実行してしまい、後でハマりました。尚、プロジェクトIDを間違えても後から修正できます。

```
1: remote -> com.google.appengine.archetypes:appengine-flexible-archetype (A basic Java application with Google App Engine flexible.)
2: remote -> com.google.appengine.archetypes:appengine-skeleton-archetype (A skeleton application with Google App Engine)
3: remote -> com.google.appengine.archetypes:appengine-standard-archetype (A basic Java application with Google App Engine Standard)
4: remote -> com.google.appengine.archetypes:endpoints-skeleton-archetype (A skeleton project using Cloud Endpoints Frameworks with Google App Engine Standard)
5: remote -> com.google.appengine.archetypes:guestbook-archetype (A guestbook application with Google App Engine)
6: remote -> com.google.appengine.archetypes:hello-endpoints-archetype (A simple starter application using Cloud Endpoints Frameworks with Google App Engine Standard)
7: remote -> com.google.appengine.archetypes:skeleton-archetype (Archetype with a README about Google App Engine archetypes)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): :
```

archtypeを聞いてきますが、私はスタンダード環境なので3:appengine-standard-archetypeを選択しました。2:appengine-skeleton-archetypeも3と殆ど同じ内容です。4:endpoints-skeleton-archetypeを選択するとRESTアプリっぽいものができるようです。

groupId, artifactId, packageなどを聞いてくるので、適時入力していくとMavenプロジェクトが作成されます。

## pom.xmlの修正
### プロジェクトIDとバージョンの修正
プロジェクトIDを修正する場合は、\<build\>\<plugins\>以下にある\<appID\>を修正します。下の{your-app-id}の部分です。これが正しい値に設定できてないとデプロイに失敗します。バージョンは\<version\>に指定します。

```
<plugin>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>1.9.71</version>
  <configuration>
    <appId>{your-app-id}</appId> <!-- Override appengine-web.xml <project> -->
    <version>1</version>
    ...
  </configuration>
</plugin>
```
### ライブラリ追加
必要となるライブラリを追加します。私はgcs(Google Cloud Storage)を利用するため以下を追加しました。gcs-clientは依存するライブラリが多いので、Mavenでやると助かります。

```
<dependency>
  <groupId>com.google.appengine.tools</groupId>
  <artifactId>appengine-gcs-client</artifactId>
  <version>0.8</version>
</dependency>
```
## EclipseへGoogle Cound Toolsをインストール
Eclipse MarketplaceからGoogle Cloud Tools for Eclipseをインストールしておきます。

## Eclipseへのインポート

EclipseのFile->Import->Existing Maven Projectsから、作成したMavenプロジェクトをインポートします。
mvn eclipse:eclipseとかやってもうまくできないのでご注意ください。

## appengine-web.xmlの修正
GAE関連の記事を探すと、アプリケーションの設定はapp.yamlに記載する、と書いてあるものが多いですが、GAEスタンダード環境でJavaを使う場合は、appengine-web.xmlに記載するのが一般的のようです。
私は以下の項目を修正しました。

|項目|説明|
|---|---|
|ssl-enabled|httpsのみとする場合trueに設定する。|
|static-files|静的ファイルを指定する。(静的ファイルへのリクエスト処理はインスタンス時間を消費しない)|
他に、スケーリングに関する設定項目などがあります。詳しくは[appengine-web.xml リファレンス](https://cloud.google.com/appengine/docs/standard/java/config/appref?hl=ja)を見てください。

## ローカル環境での実行
以下を実行すると、ローカル環境でアプリが実行されます。

```
mvn appengine:run
```
以下では、ローカル環境で実行時の注意点を記載します。
### appengine-api-1.0-sdkのprovidedを一時的にコメントアウト
gaeのAPIを利用する場合にappengine-api-1.0-sdkが使われますが、pom.xmlには\<scope\>provided\</scope\>と書かれており、アプリ本体には含まれません。ローカル環境ではappengine-api-1.0-sdkが共通ライブラリに存在しないため、アプリ本体に含める必要があります。このため一時的に\<scope\>provided\</scope\>をコメントアウトします。デプロイ時にはコメントアウトを元に戻す必要があるので注意が必要です。

### 開発者用コンソール
http://localhost:8080/_ah/admin にアクセスするとローカルで動作するGoogle Cloud Storage(エミュレーション)等の状態を確認することができます。(ポート番号は各自の環境に合わせて変更してください)
本記事執筆時では、データの閲覧のみで修正はできませんでした。

## デプロイ
以下でGAEへのデプロイを実行できます。
```
mvn appengine:deploy
```
アカウントとの紐付けができていない場合は、ブラウザが開いてGoogleへのログインを実施し、表示されるトークンを上記コマンド実行中のコンソールに入力する必要があります。

## 参考

- [Apache Maven と App Engine プラグインの使用（App Engine SDK ベース）](https://cloud.google.com/appengine/docs/standard/java/tools/maven?hl=ja)
- [appengine-web.xml リファレンス](https://cloud.google.com/appengine/docs/standard/java/config/appref?hl=ja)