Gradle で GAE/J 開発

# Gradle App Engine plugin

Java で Google App Engine (GAE) 開発するなら Eclipse の[プラグイン](https://developers.google.com/eclipse/docs/getting_started)でお手軽に始められるが、チーム開発や CI との連携を考えるとやはり Gradle などのビルドツールを使いたい。

Google のドキュメント的には Maven を推奨しているようだが、Gradle 用のプラグインも Google 公式 GitHub のほうで公開されている。

* **Gradle App Engine plugin**  
  https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

Gradle App Engine plugin （以降 GAE プラグイン）は、アプリのビルド、ローカルサーバ実行、テスト、デプロイなど Google App Engine SDK （以降 SDK）で行う一連の作業を Gradle タスクとして定義している。

しかし使う人が少ないのかネット上にあまり情報は見つからない。
そもそも GAE/Java 開発自体が Go などにおされてトレンドから外れているのか、古い資料ばかりで参考にならないものが多い。

とはいえ、 依然 GAE は進化を続けており、GAE/Java SDK も頻繁に更新されている。
2014年は Managed VM サービスの登場があり、Java Runtime の自由度が高まった。
Android Studio も正式版がリリースされ、そのプロジェクトは Gradle ベースになっており、統合されたバックエンド開発にはこの GAE プラグインが組み込まれている。
GAE の Java 開発はネタ的にも盛返しの機運があるということで、技術情報や書籍なども今年あたりからまた出てくるだろう。

それまでのつなぎとして、現状を調べた情報のメモをまとめておく。
いまいち整理しきれていないが、取っ掛かりを拾う参考にはなるだろう。
間違いやタイプミスがあれば教えてほしい。

## build.gradle

試行錯誤の結果、以下の build.gradle に落ち着いた。

```groovy:build.gradle
buildscript {
    ext { 
        // Gradle App Engine plugin version
        gaePlunginVersion = '1.9.19' 
    }
    repositories { jcenter() }
    dependencies {
        classpath "com.google.appengine:gradle-appengine-plugin:${ gaePlunginVersion }"
    }
}

// プラグイン
apply plugin: 'war'
apply plugin: 'appengine'  // Gradle App Engine plugin


// プロジェクト設定
sourceCompatibility = '1.7'
targetCompatibility = '1.7'

//group = 'com.hoge.aaa'
//version = '1.0'

// GAE プラグイン設定
ext {
    // Google App Engine SDK Version
    sdkVersion = '1.9.19'  // = gaePlunginVersion
}
appengine { 
    downloadSdk = true
    appcfg {
        // oauth2 = true  // OAuth2 で認証する
    }
}

// 依存管理
repositories { jcenter() }
dependencies {
    compile     'org.slf4j:slf4j-api:1.7.7'
    testCompile 'junit:junit:4.11'

    providedCompile 'javax.servlet:servlet-api:2.5'

    // Google App Engine SDK for Java
    // appengine.downloadSdk = true のときに、必要
    appengineSdk "com.google.appengine:appengine-java-sdk:${ sdkVersion }"

    //  Google App Engine API
    compile      "com.google.appengine:appengine-api-1.0-sdk:${ sdkVersion }"
    compile      "com.google.appengine:appengine-api-labs:${ sdkVersion }"
    testCompile  "com.google.appengine:appengine-api-stubs:${ sdkVersion }"
    testCompile  "com.google.appengine:appengine-testing:${ sdkVersion }"

    // Memcache サポート
    compile      'net.sf.jsr107cache:jsr107cache:1.1'
    compile      "com.google.appengine:appengine-jsr107cache:${ sdkVersion }"

}

/*　JPA/JDO を使う場合はこのコメントを外す
// Persistence サポート
appengine {
    enhancer {
        version     = 'v2'       // DataNucleusのバージョン
        api         = 'jpa'      // Persistence API 'jpa', 'jdo'
        enhanceOnBuild = true    // build 時にエンハンス処理を行う
    }
}
dependencies {
    compile 'org.ow2.asm:asm:4.0'
    compile 'org.datanucleus:datanucleus-api-jpa:3.1.3'
    compile 'org.datanucleus:datanucleus-api-jdo:3.1.3'
    compile 'com.google.appengine.orm:datanucleus-appengine:2.1.2'
    compile 'org.datanucleus:datanucleus-core:3.1.3'
    compile 'org.apache.geronimo.specs:geronimo-jpa_2.0_spec:1.0'
    compile 'javax.jdo:jdo-api:3.0.1'
    compile 'javax.transaction:jta:1.1'
}
*/

/* Google Cloud Endpoints を使う場合はこのコメントを外す
// Endpoints サポート
{    
    endpoints {
        getDiscoveryDocsOnBuild = true
        getClientLibsOnBuild    = true
    }
}
dependencies {
    "compile com.google.appengine:appengine-endpoints:${ sdkVersion }"
    "compile com.google.appengine:appengine-endpoints-deps:${ sdkVersion }"
}
*/
```

## プロジェクトの作成

Gradle はプロジェクト生成やテンプレート機能が弱いので少し作業がいる。

まずはプロジェクトディレクトリで ```gradle init``` する。
生成された build.gradle ファイルの中身を上記スクリプトで置き換える。
./gradlew コマンドも組み込まれるので以降こちらを使う。

Gradle Java プロジェクトのディレクトリ規約はいわゆる Maven レイアウトに従うが、Gradle はあまり面倒をみてくれない。
init タスクに Java 用のオブションがあるにはあるが中途半端だ。

以下のタスクを build.gradel に一時的にコピペして layout タスクを走らせればソースディレクトリを作成できる。
後で git に空ディレクトリを捨てられたりするので、とっておいてもいい。

```groovy
task layout << {
    sourceSets*.allSource.srcDirs*.each { it.mkdirs() }   // *. は Spread Operator という groovy の演算子
    new File(sourceSets.main.resources.srcDirs[0], 'META-INF').mkdirs()
    new File(webAppDir, 'WEB-INF').mkdirs()
}
```

動作検証用にサンプルソースが欲しいところだ。
Maven 用なら guestbook-artifact というひな形があるのだが、Gradle にこれを単純に流用することはできないようだ。
SDK の demos ディレクトリ配下にもサンプルプロジェクトがいくつか（guestbookも）あるので、ここから適当に拾うのもいいだろう。
だだし Eclipse 用のプロジェクト構成になっているで、ソースファイルや設定を適切なでディレクトリに手作業で移動する必要がある。

demos/guestbook の場合、以下の様な配置にする。

```bash
$ tree
.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── endpointsSrc
    │   └── resources
    ├── functionalTest
    │   ├── java
    │   └── resources
    ├── main
    │   ├── java
    │   │   └── guestbook
    │   │       ├── GuestbookServlet.java
    │   │       └── SignGuestbookServlet.java
    │   ├── resources
    │   │   └── META-INF
    │   └── webapp
    │       ├── WEB-INF
    │       │   ├── appengine-web.xml
    │       │   ├── logging.properties
    │       │   └── web.xml
    │       ├── guestbook.jsp
    │       └── stylesheets
    │           └── main.css
    └── test
        ├── java
        └── resources
```


```./gradlew build``` してエラーがでなければ OK。
初回の実行では、Gradle、SDK、依存関係の jar などがダウンロードされるので時間と通信量がかかる。
おそらく 300MB 以上の通信量になるので、スタバでテザリングをしている人は月末の実行を避けたほうがいいだろう。
ホームディレクトリをみると 500MB ほど膨らむようだ。

## ローカル動作確認

appengineRun タスクでローカル開発サーバを起動する。

```
$ ./gradlew appengineRun

```

デフォルトではサーバがフォアグラウンドで起動され、http://localhost:8080/ で Web アプリにアクセスできるようになる。

最初は一通りの動作確認をなるべくしっかりやっておいてほしい（後述）。

管理画面 http://localhost:8080/_ah/admin も確認しておこう。
Datastore の内容などが確認できる。

ローカル開発サーバを停止するには ```appengineStop``` タスクを使う。
（自分は別ターミナルを開くのが面倒なので Ctrl+C することが多い）

## 初めてのデプロイ

アプリの動作に問題なければ GAE のクラウドサーバへデプロイしてみよう。

その前にいくつか仕込みがいる。

###・ アプリケーション ID の設定

言うまでもなく [Google Developers Console](https://console.developers.google.com/project) で GAE プロジェクトを作成しておく必要がある。

作成したプロジェクトの「プロジェクト ID」が SDK では「アプリケーション ID」と呼ばれる（ややこしい）。

アプリケーション ID の設定項目はなぜか build.gradle には存在しない。
appengine-web.xml のほうを編集する必要がある。

```xml:src/main/webapp/WEB-INF/appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>my-application-id</application>
    <version>v1</version>
    <!-- TODO review code for thread-safety. -->
    <threadsafe>false</threadsafe>

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
</appengine-web-app>
```
application 要素にアプリケーション ID を記述する。
version 要素は英数字の任意の文字列でよい。

###・ Datastore インデックスの確認

Datastore を使う場合（guestbookは使う）、各エンティティ用に追加するインデックスを定義する必要がある。
それを怠ると、ローカルサーバ環境では問題なくても、AGE 本番サーバでは 500 ステータス（DatastoreNeedIndexException）のエラーが返されてしまう。

インデックス定義は自分で設定ファイルに記述しなくても、以下のファイルとして自動生成されるので当面はとりあえずそのままで OK だ。

```bash
build/exploded-app/WEB-INF/appengine-generated/datastore-indexes-auto.xml
```

しかしこのファイルは build するだけでは作成されない。

appengineRun でローカル開発サーバを起動後、Datastore API にアクセスするロジックを通った時に初めて生成される。
ローカル開発サーバ稼働中に Datastore スタブがエンティティに対するクエリを見ているようで、それから適切なインデックス定義を生成し、上記XMLファイルに追加される。

アクセスしなかった Entity のインデックス定義は追加されないので、最初のローカル動作確認ではすべての エンティティ に通るよう念入りにやっておきたい。
Function Test での自動化も TODO に入れておこう。

また、新規に追加されたインデックスは、デプロイ後クラウドサーバ上で有効になるまで数分かかることがあるので、すぐにアクセスしてエラーになっても慌てないように。

###・ 認証方法を決める

GAE サーバへの認証はデフォルトでパスワード認証となっている。
プロジェクト管理者の Google アカウントの Gmail アドレスとパスワードで認証できるはずなのだが、現在はまずもって成功しない。

それは GAE 側の問題ではなく、Google の認証基盤のセキュリティポリシーが厳しくなった影響だ。
普通にパスワード認証を試みると、ブロックしましたという通知メールがくる。

解決策としては、以下の３つが考えられる。

**A.** ２段階認証を有効にして、[アプリ パスワードを発行](https://support.google.com/accounts/answer/185833?hl=ja)する
**B.** 「[安全性の低いアプリを許可](https://support.google.com/accounts/answer/6010255?hl=ja)」し、アカウントのセキュリティレベルを下げる
**C.** パスワードではなく OAuth で認証する

上の**A.** **B.**２つの案は Google アカウント設定の変更になり、今後の Google 生活に与える影響を判断しなければならない。
その判断は今やりたいことではない。
ここでは、**C.** 案の OAuth を使うようにする。

build.gradle で ```appengine.appcfg.oatuh2=true``` を追加する（コメントアウトを外す）と OAuth2 認証が有効になる。

```groovy:build.gradle
：
appengine {
    downloadSdk = true
    appcfg {
        oauth2 = true
    }
}
：
```

デフォルトでは認証情報がキャッシュされ、以降のアクセスでは認証入力が省略できる。
それを避けたい理由があるのなら、```appengine.appcfg.noCookies=true``` を追加しておく。

> **追記** SDK 1.9.19 から、OAuth2 でないと、warning が出るようになったらしい。
> 1.9.20 からは OAuth2 がデフォルトの認証になる。
> https://code.google.com/p/googleappengine/wiki/SdkReleaseNotes

### デプロイタスク実行

デプロイのタスク名は deploy ではなく、upload でもなく、ましてや push でもない update だ。

```
$ ./gradlew appengineUpdate
```

Gradle スクリプトの実行の途中でWebブラウザが立ち上がり、OAuth 認証を求められる。

![0auth2.png](https://qiita-image-store.s3.amazonaws.com/0/21239/5e6b0d8f-6621-66be-c932-6db05e21b512.png)

認証後に表示される認証トークンをコピーし、入力待ちしている Gradle ターミナルにぺーストする。
するとタスクスクリプトが続行し、GAE クラウドサーバへのデプロイが完了する。

公開されたアプリは、```https://<my-application-id>.appspot.com/``` でアクセスできる。
ただし、Datastore にアクセスするリクエストでは、最初の数分は 500 エラー応答で待たされる。
前に触れたように、インデックス登録が完了するまで時間がかかるからだ。
エラー内容は Developers コンソールのログ画面で参照できるので確認してみてほしい。

## 最初のコミット

最初のデプロイがうまく行ったなら、ここらでソース管理しておきたい。
もちろん Git を使う。

```bash

$ ./gradlew clean
$ git init
$ vi .gitignore
.gradle
build
local.properties

$ git add .
$ git status 
$ git commit -m "Kick start !"

```

ソースを開発メンバーと共有するために GitHub などのリモートレポジトリに上げたい。
Google Cloud にも プロジェクト専用の Git レポジトリ（Cloud レポジトリという）が用意されるので今回それを使ってみる。

Developer コンソールではプロジェクト管理の「ソースコード」＞「閲覧」でプロジェクトのレポジトリ内容が参照できる。　
初期段階ではブランチもない空のレポジトリ状態で、初期設定の説明画面に誘導される。

![start.png](https://qiita-image-store.s3.amazonaws.com/0/21239/bad3fb3e-dcff-ec91-b6f9-391d3bf170fe.png)


![select.png](https://qiita-image-store.s3.amazonaws.com/0/21239/bd363b1d-48ba-2abe-ed64-d9e468ef8319.png)


ここで3パターンの手順が提示される。

最初のは、Cloud レポジトリを GitHub や Bitbucket にある既存のプロジェクトと同期させる方法。
2番目はローカルレポジトリを push してリモートレポジトリを作成する方法。
3番目は最初に空のレポジトリをリモートに作成し、ローカルに clone させる方法。

今ローカルレポジトリを作ったばかりなので、ここは２番目の方法でいくことにする。

![local.png](https://qiita-image-store.s3.amazonaws.com/0/21239/b3b9058c-4f76-25c1-18ab-9bf803b33cc0.png)


すると手順の最初でいきなり Google Cloud SDK のインストールを要請される。
それに含まれる glcoud コマンドは Google Cloud ツール共通の自動認証環境を提供するらしい。
詳細は以下が参考になる。

* [ハンズオン : Google Cloud SDK 基本と認証 - Qiita](http://qiita.com/yuko/items/1c4ee5b081c5b6a3ac8a)

今回は開発者にできるだけ環境構築をさせてない方針で、 Gradle と Git だけで完結させたいので gcloud コマンドを使わない方法で行く。

代わりにパスワード認証でリモートレポジトリにアクセスする。
アカウント名は Google アカウントのメールアドレスをそのまま使うが、パスワードがこれまた異なる。
GAE と Git サーバは認証基盤が統合されていないらしい。

手順を飛ばして説明画面の文中下部にある「こちらのリンクに沿って 」（赤丸）というリンクを開くと、OAuth の認証トークンの文字列が得られる。


![pass.png](https://qiita-image-store.s3.amazonaws.com/0/21239/85f89c47-7146-cfed-a800-c73ebf1bf4b3.png)

このトークンを Git パスワードとして入力する。

画面ではパスワード入力を省略できるよう .netrc へのコピペ用テキストも表示されるが、もちろん今日日パスワードを平文で運用するのはあり得ない。
この文字列を暗記する自信がなければ Git にキャッシュさせることもできる。

* [git を https 経由で使うときのパスワードを保存する - Qiita](http://qiita.com/iorionda/items/88d6329af997b5c5e748)

リモートレポジトリの URL は以下のようになる。
```
https://source.developers.google.com/p/<my-application-id>
```

ちなみに gcloud コマンドを使うと以下のようなパスを追加した URL で登録されるが、今のところ同一のレポジトリを指しているようなので気にしない。
```
https://source.developers.google.com/p/<my-application-id>/r/default
```

リモートレポジトリを登録して最初のコミットを push する。
```
$ git remote add origin https://source.developers.google.com/p/my-application-id
$ git push origin master
```

Developer コンソール で再度確認すると、今度は master ブランチのソースツリーが表示されているはず。
ソースや diff を参照できるだけでなく、ブラウザ上でファイルを編集してそのままコミットすることもできるので、ちょっとした値の変更などに重宝するだろう。
また、やり直したくなったらレポジトリをまるごと削除することも可能だ。

別環境で clone してみて ```./gradlew build``` が通れば OK だ。 

さて、なにを作ろうか。

# メモ

## GAE プラグインと SDK

GAE プラグインは buildscript で依存関係を定義し appengine を apply するだけで使用できる。
war の apply も必要。（war があれば java は不要なはず。）

GAE プラグインのバージョンは SDK と同期しているので共通になる。
頻繁に更新されるのでバージョンをグローバル定数にしておきたいが、buildscript ブロックは変数のスコープが違うようで、ちょっと単純には行かない。

GAE プラグインは SDK (Google App Engine SDK for Java) のコマンドアクションをタスク化したものと言えるが、SDK そのものは同梱されていない。

dependencies.appengineSdk 構成で SDK を Gradle の依存管理に含めることができて、appengine.downloadSdk に true にすると appengineDownloadSdk タスクにより SDK がダウンロード・展開される。

マニュアルでインストールした既存 SDK のパスを環境変数などでプラグインに教える手段もあるのだが、開発メンバーの負担になるのでローカル環境に依存させないようできるだけ Gradle で完結させておきたい。


## アプリケーション ID

アプリケーション ID やアプリバージョンを設定するプロパティなりタスクなりがあってもいいと思うのだが、GAE プラグインには用意されない。

調べると appengine.appcfg.app.id という、いかにもそれっぽい設定項目があるにはあるが、これは サーバからローカルにアプリをダウンロードするという appengineDownloadApp タスク専用でデプロイ時には参照されない。

どうしても build.gradle 側で管理したければ以下のような奥の手もある。

```groovy:build.gradle

ext {
    appId      = 'my-application-id'
    appVersion = 'v1'
}

appengine {
    appcfg {
        extraOptions = ["--application=${ appId }", "--version=${ appVersion }"]
    }
}
```
 
extraOptions に記述した配列は SDK の appcfg コマンドの引数として付加されるので、appcfg コマンドにある下記オプションを渡せば appengine-web.xml の内容を無視して差し替えできるのだ。

```bash
$ $APPENGINE_SDK/bin/appcfg.sh help update
 :
 :
  -A APP_ID, --application=APP_ID
                        Override application id from appengine-web.xml or app.yaml
  -M MODULE, --module=MODULE
                        Override module from appengine-web.xml or app.yaml
  -V VERSION, --version=VERSION
                        Override (major) version from appengine-web.xml or app.yaml
 :
```

## 認証設定

デプロイ時などの GAE への認証は、パスワードか OAuth を選べる。
認証用に以下のような設定項目があり、全て省略するとデフォルトでパスワード認証になる。

```groovy:build.gradle
appengine {
    appcfg {
        email        = 'hoge.admin@gmail.com'  // Google アカウント
        password     = 'XXXXXX'     // 省略すると実行時に入力
        noCookies    = true         // 認証情報をキャッシュしない。
        passIn       = false        // パスワード入力必須にする。
        oauth2       = false        // OAuth で認証する。ブラウザが起動する。
    }
}
```

アカウント情報を build.gradle に埋め込むこともできるが、チーム開発での共有を前提とするとそれは避けたい。
OAuth にするのが無難だが、Jenkins のような CI サーバからの使用も想定に入ると、Web を経由させるのが苦しい。

できれば認証設定は build.gradle から外出しにしたい。

ちなみにパスワードだけは gradle.properties ファイルに外出しできるようになっているが、平文で保存するのは不安がある。

```properties:~/.gradle/gradle.properties
appenginePassword=XXXXXXXX
```

build.gradle は外部からプロパティやスクリプトを取り込めるので、それをJenkins から与えるのが無難なところだろう。

## JPA/JDO サポート

build.gralde にあるコメントアウトを外せば、JPA や JDO が使えるようになる。

JPA の persistence.xml、JDO の jdoconfig.xml は src/main/resouces/MATA-INF 配下に配置する。

GAE は JPA/JDO の実装として [DataNucleus](http://www.datanucleus.org/) を使用する。
SDK には v1 系と v2 系の２つのバージョンが同梱されており、サポートする JPA/JDO の API バージョンが違う。
過去のしがらみがなければ v2 を選んでおいて問題ない。

Google のドキュメントを見ると、新しい v2 を使えるようにするために、何か設定ファイルにややこしい編集をする必要があるようなことが書いてあるが、そんなことをせずに Eclipse でも Gradle でもそのまま利用できた。
おそらくその辺の仕組みはすでに改善されているのだが、ドキュメントが追い付いていないようだ。
DataNucleus のバージョンも 2.x とあるが実際は 3.x を使っているようだ。

dependencies に追加する jar は SDK 同梱のものから判断するしかない。
ところが、SDK 同梱の jar を検索すると同じような jar がたくさん引っかかってどまどう。
lib/opt/user ディレクトリ配下にまとめられている jar がどうもそれのようだ。

```
$ cd  ~/.gradle/appengine-sdk/appengine-java-sdk-1.9.17/lib/opt/user
$ ls
appengine-api-labs	datanucleus
appengine-endpoints	jsr107
$ tree datanucleus
datanucleus
├── v1
│   ├── datanucleus-appengine-1.0.10.final.jar
│   ├── datanucleus-core-1.1.5.jar
│   ├── datanucleus-jpa-1.1.5.jar
│   ├── geronimo-jpa_3.0_spec-1.1.1.jar
│   ├── geronimo-jta_1.1_spec-1.1.1.jar
│   └── jdo2-api-2.3-eb.jar
└── v2
    ├── asm-4.0.jar
    ├── datanucleus-api-jdo-3.1.3.jar
    ├── datanucleus-api-jpa-3.1.3.jar
    ├── datanucleus-appengine-2.1.2.jar
    ├── datanucleus-core-3.1.3.jar
    ├── geronimo-jpa_2.0_spec-1.0.jar
    ├── jdo-api-3.0.1.jar
    └── jta-1.1.jar

2 directories, 14 files

```

dependencies の設定により、リモートレポジトリからダウンロードした jar がクラスパスに追加され、SDK 同梱の jar は使われない。
また、本来 runtime には不要な jar もいくつか war に入ってしまう。
細かい jar バージョンの追随性や重複ファイルによるディスク容量が気になるなら、SDK の jar ファイルを直接参照する記法もある。

```groovy:build.gradle
dependencies {
  ・
  ・
  // JPA/JDOサポート
    def sdkDir = new File(gradle.gradleUserHomeDir, "appengine-sdk/appengine-java-sdk-${ sdkVersion }")
    compile fileTree(dir: sdkDir, include: 'lib/opt/user/datanucleus/v2/*.jar')
}

```

ただし、Gradle の依存性管理から外れるので、別の依存とコンフリクトを起こすかもしれない。

JPA/JDO に対応したエンティティクラスは、コンパイル後の class ファイルにアノーテーションに従った後処理が施される(Enhance)。
これを行うのが エンハンサー(Enhancer)で、appengine.enhancer には、実行すべきエンハンサーの API (JDP or JPA) とバージョン（v1 or v2）を指定し、build 時の依存タスクに appengineEnhance タスクを追加するよう設定する(enhanceOnBuild = true)。

エンハンサーは全てのクラスをスキャンして、アノーテーションしたエンティティクラスを自動検出する。
SDK 付属のエンハンサーには処理対象となるディレクトリを渡せるはずなのだが、GAE プラグインに設定項目は用意されていない。

JPA/JDO のプロバイダも、クラスファイルをスキャンし、エンティティクラスを自動検出するので、persistence.xml や jdoconfig.xml でのクラス指定は省略できるはずだ。

しかし エンティティクラスを指定した方がいい状況もある。
JPA の仕様的に Java SE 環境で実行された場合、自動検出は行われずエンティティクラス指定は省略できなかったはずだ。
Java SE な環境とは Java EE コンテナを使わないスタンドアローンでの実行を意味し、今回の GAE 開発の環境では、JUnit を使った エンティティの単体テストの実行がそれにあたる。
Datanucleusの実装にもよるが、もしエンティティの単体テストをきっちりやりたいのなら、クラス指定もしておいたほうがいいだろう。

ここまで JPA/JDO が面倒だと思ったなら、代わりに Google 謹製の Objectify を使うという選択肢もある。
ただし Datastore 限定になるが。

*  objectify-appengine  
https://code.google.com/p/objectify-appengine/

```groovy
appengine {
    enhancer {
        enhanceOnBuild = false    // エンハンス不要
    }
}
dependencies {
    compile 'com.googlecode.objectify:objectify:5.0.3'
}

```

## Memcache

省略。

## Google Cloud Endpoints サポート

省略。

## App Engine Modules サポート

パス。

## Managed VM サポート

そのうち。

## Eclipse サポート

うーむ、どーしてくれよう。

# 資料

## 規約

GAE プラグインで定義している設定項目とそのデフォルト値。
大体あっているはず。

```groovy
appengine {
    httpAddress = 'localhost'
    httpPort    = '8080'
    daemon      = false
    warDir      = 'build/exploded-war'
    disableUpdateCheck    = false
    jvmFlags    = null    // []
    downloadSdk = false

    appcfg {
        email        = null     //'google.account@gmail.com'
        password     = null     // <-- ~/.gradle/gradle.prpoperties#appenginePassword
        server       = 'appengine.google.com'
        noCookies    = false
        passIn       = false
        oauth2       = false
        host         = null
        httpProxy    = null
        httpsProxy   = null
        extraOptions = []
    
        // appengineDownloadAppタスク用設定
        app {
            id              = null      // 'my-app-id'
            version         = null      // 省略時にはデフォルトバージョンとなる
            outputDirectory = 'build/downloaded-app'
        }

        // appengineLogsタスク用設定
        logs {
            numDays     = 1         // 0 ならすべての過去ログ
            severity    = 1         // 4:CRITICAL, 3:ERROR, 2:WARNING, 1:INFO, 0:DEBUG
            append      = false     // 追記モードにする
            includeAll  = false     // 処理時間などの詳細な情報も出力する（コンソールのログ画面の出力）
            outputFile  = null      // ex. file('my-app.log')
        }

        // appengineUpdateタスク用設定
        update {
            useJava7    = false     // Java 7 互換フラグ。　使用していない???
        }
    }

    enhancer {
        version     = null        // 'v1', 'v2'
        api         = null        // 'jpa', 'jdo'
        enhanceOnBuild  = false
    }

    endpoints {
        discoveryDocFormat    	= ['rpc', 'rest']
        serviceClasses          = null
        getDiscoveryDocsOnBuild = false
        getClientLibsOnBuild    = false
        exportClientLibsOnBuild = false
        installClientLibsOnBuild    = false
        clientLibJarOut         = null
        clientLibSrcJarOut      = null
        googleClientVersion     = '1.19.0'
    }
}

```

## タスク

GAE プラグインは32個のタスクを定義している。

今更何だが、タスク名の入力は単語ごとの前方一致でかなり省略できる。

```bash
$ ./gradlew appengineUpdate
$ ./gradlew appUpdate
$ ./gradlew appUp
$ ./gradlew aU
```

省略しすぎて、他のプラグインタスクとかち合あわないように。


### バージョンの確認

* **appengineVersion**: SDKのバージョン、Java実行環境情報が出力される。 GAE プラグイン自体のバージョンは出力されない。

```
$ ./gradlew appVersion
:appengineVersion
Release: 1.9.17
Timestamp: Sat Nov 15 14:05:30 JST 2014
API versions: [1.0]

java.vm.vendor: Oracle Corporation
java.vm.version: 24.71-b01
java.version: 1.7.0_71
os.name: Mac OS X
os.version: 10.9.5
```

### 開発系タスク

* **appengineDownloadSdk**: ```dependencies.appengineSdk``` で指定した Google App Engine SDK for Java をレポジトリからダウンロードしインストール（ZIP展開）する。
```appengine.dowonloadSdk``` フラグが false でも単独で実行できる。
インストールパスは、　~/.gradle/appengine-sdk/appengine-java-sdk-1.9.17 のように gradleホーム配下に展開される。
SDK バージョンを更新するごとに、ダウンロードZIPと展開されたSDKで350MBほどのディスク容量を消費する。

* **appengineEnhance**: JSO/JPA 用のエンハンサーを実行し、エンティティクラスのコンパイル済み class ファイルに永続化のための後処理を加える。
エンハンサーの実装は SDK 同梱の方を使っているはず。
```appengine.enhancer.enhanceOnBuild``` が true にすると build のタスクツリーに追加される。

* **appengineRun**: ローカル開発サーバ（Jetty）を起動し、アプリを稼働させる。
デフォルトのポートは 8080、```appengine.httpPort```で変更できる。
デフォルトではサーバがフォアグラウンドで実行され、停止するには、Ctrl+C するか別ターミナルから appengineStop タスクを実行する。
開発サーバをバックグラウンドで実行させることもできる。
その場合、 ```appengine.deamon``` フラグに true をセットし、本タスクを Gradle のデーモンモード ``` ./gradlew --daemon appRun ``` で実行する。
デーモンを停止するには appengineStop タスクを実行するか、あるいは ```./gradlew --stop``` して Gradle ごと落としてもよい。
まめに停止しないとポートを占有するので、build 時などの失敗の原因となる。

* **appengineStop**: 稼働中のローカル開発サーバを停止させる。

* **appengineExplodeApp**: war を build/exploded-app 配下に展開する。 
ローカル開発サーバはこの展開済アプリを実行する。

* **appengineFunctionalTest**: 機能テストを実行する。
依存タスク```appengineRun```でアプリを起動してリクエストレベルのテストを行う。
テストコードは src/functionalTest 配下に配置されたものを実行する。
（サンプルが見当たらないので使い方がよくわからない）

* **appengineUpdate**:　アプリをGAE クラウドサーバにデプロイする。
アプリケーションIDとアプリバージョンを指定は appengine-web.xml に記述する。
モジュール(module)も指定できるはず。

* **appengineRollback**: アプリのデプロイ（update）に何らかの理由で失敗し中途半端な状態になることがあるらしい。
万一そうなったら update をやり直しても回復はしないので、いったん rollback して直近の update をなかったことにする。

* **appengineDownloadApp**: GAE サーバに上がっているアプリをダウンロードする。
ダウンロードするアプリは appengine.appcfg.app で指定できる。
（どういう状況で使うのかはよくわからない）

### App Engine Backends 用タスク

非推奨。
App Engine の Backends は　Modules に取って代わられた。

* **appengineConfigureBackends**:
* **appengineDeleteBackend**: 
* **appengineRollbackBackend**: 
* **appengineStartBackend**:
* **appengineStopBackend**:
* **appengineUpdateAllBackends**:
* **appengineUpdateBackend**:
* **appengineListBackends**:
* **appengineUpdateAll**:

### Google Cloud Endpoints クライアントライブラリ用タスク

* **appengineEndpointsGetClientLibs**: Download Endpoints client libraries. (this makes network calls)
* **appengineEndpointsGetDiscoveryDocs**: Download Endpoints discovery docs, you should run appengineExplodeApp with this to ensure the discovery docs are copied into the project after download. (this makes network calls)
* **appengineEndpointsInstallClientLibraries**: Install client libraries to the local maven repo.
* **appengineEndpointsExportClientLibraries**: Export client libraries to user-defined destination.

### 運用系タスク

* **appengineCronInfo**: Verifies and prints the scheduled task (cron) configuration.
* **appengineUpdateCron**: Updates the schedule task (cron) configuration for the app, based on the cron.xml file.
* **appengineUpdateDos**: Updates the DoS protection configuration for the app, based on the dos.xml file.
* **appengineUpdateIndexes**: Datastore インデックスを更新する。新たに追加されたインデックス定義のみが反映されるということらしい。
* **appengineVacuumIndexes**: Deletes unused indexes in App Engine server.
* **appengineUpdateQueues**: Updates the task queue configuration (queue.xml) in App Engine.
* **appengineUpdateDispatch**: Modules 間のルーティングを定義した dispatch.xml の内容で、ディスパッチ設定を更新する。
* **appengineLogs**: GAE サーバに蓄積されているログをローカルにダウンロードする。
出力先ファイルや、フィルタリング等のパラメータ指定は '''appengine.appcfg.logs で行う。


# 参考

* Gradle App Engine plugin 
  https://github.com/GoogleCloudPlatform/gradle-appengine-plugin

* Gradle Tutorial : Part 5 : Gradle App Engine Plugin
  http://rominirani.com/2014/08/15/gradle-tutorial-part-5-gradle-app-engine-plugin/

* Gradle 日本語ドキュメント 
  http://gradle.monochromeroad.com/docs/

* [Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築](http://www.amazon.co.jp/Gradle%E5%BE%B9%E5%BA%95%E5%85%A5%E9%96%80-%E6%AC%A1%E4%B8%96%E4%BB%A3%E3%83%93%E3%83%AB%E3%83%89%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E8%87%AA%E5%8B%95%E5%8C%96%E5%9F%BA%E7%9B%A4%E3%81%AE%E6%A7%8B%E7%AF%89-%E7%B6%BF%E5%BC%95-%E7%90%A2%E7%A3%A8/dp/4798136433) 綿引琢磨他　翔泳社

* [Java - Gradle使い方メモ - Qiita](http://qiita.com/opengl-8080/items/4c1aa85b4737bd362d9e)

* [GoogleCloudPlatform - 既存のGitローカルレポジトリをGoogle Cloud RepositoriesにPushする。 - Qiita](http://qiita.com/soundTricker/items/3a77f1053b24cca3ecec)