VertxでVerticleを起動させるメモ

## はじめに
最近は関数型言語が流行りつつあるので、僕も乗り遅れまいと（すでに乗り遅れている感じが否めないが）Vertxを学んでみる。
ちなみにVertxとは何か・・・というと僕は正確な答えを持ってない。
僕のイメージでは`負荷分散プログラム`のフレームワークというイメージ。

とりあえず、僕のイメージで`Vertx`を語ってみる。（間違ってるかもしれないので、鵜呑みにしないように！w）

## Vertxって？
プログラムの最小単位を`Verticle`と定めて、`Verticle`単位でプログラムを動かす事を目的としている。
例えば`ServerVerticle`という`HTTPリクエスト`を待ち受けるプログラムを書いたとした場合に、リクエストを受けるのは`ServerVerticle`だが実際の処理は`UserVerticle`に任せる場合は以下のようになる。

```
HTTPリクエスト → ServerVerticle → UserVerticle → HTTPレスポンス
```

これだけだと何が良いのかわからないと思う。

Vertxの特徴は`Verticle`単位でプログラムが動くため、ServerVerticleとUserVerticleは別々のメモリ空間で動作している。
そのVerticle間のやりとりはメッセージで行うことによって疎結合を実現しているのだ。
なので、プログラム単位に割くメモリを割り当てる事ができて負荷が重いプログラムにはメモリを多く割り当てるなどを`動的`に行えるのだ！

動的にメモリを割り当てる（正確にはVerticle数を増やしたり減らしたりできる）というのは、あるプログラムの負荷が上がった際に局部的にメモリを増やせるということだ。
通常のアプリケーションの場合は、サーバー台数を増やしたりしなければならないところをプログラム単位で増強できればコスト削減にも繋がるし高負荷時の対応も即時に行える。

プログラムが自動的にVerticleの数を制御してくれれば突然高負荷になっても何も対応しないで済むかもしれないのだ！
・・・と書いてますが、僕は実際に検証したわけではありません。（汗

## Verticleって？
`Verticle`はVertx上のでプログラム最小単位です。（最大単位と書いても合ってる気がする・・・。）
上記にも記載した通りで、Vertxは`Verticle単位`でメモリ空間を確保してます。
なので、`Verticle同士の干渉`はメッセージのやり取りだけで行います。

ということは・・・状態をサーバー側で持てない事を示してます。
すなわち副作用のない関数を書く必要があります。
（Vertxではサーバーを跨いでデータを扱えるSyncMapがあります。また、DBへのアクセスなどもあるのでこの表現は間違ってますが説明上このように書いてます。）

「副作用がない・状態を保持しない」プログラムと言うと、オブジェクト指向をずっと使ってた人には若干とっつきにくそうです。
というか、僕はとっつきにくかったです。
しかし、この概念があるため`Vertx`は以下の恩恵があります。

* Verticle単位でプログラムの数を変更できる。
* メインループが専有されて他のプログラムに影響することがない。（重い処理をVerticleに記載してはいけない。）
* Verticle内のプログラム言語を自由に選べる。（インターフェースが決まっているため）

これは、素早いレスポンスを要求される`WebSocket`などで大きな威力を発揮します。

## Vertxのインストール
とりあえず、イメージをつかむために動かしてみましょう！
まずはJava8をインストールしてください。
僕は`1.8.0_31`をインストールします。
また、以下の説明はMacで行いますが特にプラットフォームには依存しないのでWindowsでも動きます。

### Vertx3をインストールする。
[vertx](http://vertx.io/)のホームページより本体をダウンロードしてください。
僕は[ここ](https://bintray.com/vertx/downloads/distribution/3.0.0/view)から`vert.x-3.0.0-full.zip`をダウンロードして解凍しました。
※パスを通すため全角文字や空白が含まれていないフォルダに解凍すると余計な障害に見舞われません。

### Pathを通します。
僕は`.bash_profile`に以下のように記載しました。

```.bash_profile
PATH="$PATH":[解凍フォルダのパス]/vert.x-3.0.0/bin
```

パスを読み込みます。（Windows用に`vertx.bat`も用意されてました。未確認ですが、多分Windowsでも動きます。）

```
$> source .bash_profile
```

### インストールの確認をします。

```
$> vertx
Listening for transport dt_socket at address: 8000
....
```

と表示されればvertxの設定は完了です。

## 動かしてみる。
設定が終わったら動かしてみましょう。

### Java編
以下のファイルを適当なフォルダに作成してください。

```JavaVerticle.java
import org.vertx.java.core.Handler;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.platform.Verticle;

public class JavaVerticle extends Verticle {

  public void start() {
    vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
      public void handle(HttpServerRequest req) {
        req.response().headers().set("Content-Type", "text/plain");
        req.response().end("Hello Java!");
      }
    }).listen(8080);
  }
}
```

同フォルダでvertxを起動します。

```
$> vertx run JavaVerticle.java
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle
```

と表示されればOKです。
`localhost:8080`をブラウザで見てもらえると`Hello Java!`と表示されているはずです。

### Groovy編
Javaと同様にGroovyでも動かしてみましょう。
Groovyを動かすために何か必要なものはありません。

```GroovyVerticle.groovy
import org.vertx.groovy.platform.Verticle

class GroovyVerticle extends Verticle {
    @Override
    def start() {
        vertx.createHttpServer().requestHandler { request ->
            request.response.putHeader("Content-Type", "text/plain")
            request.response.end("Hello Groovy!")
        }.listen(8070)
    }
}
```

動かしてみましょう。

```
$> vertx run groovy:GroovyVerticle
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle 
```

Groovyの起動では`groovy:`が必要です。代わりにファイル拡張子は不要です。指定すると落ちます。
`localhost:8070`をブラウザで見てもらえると`Hello Groovy!`と表示されているはずです。

### 両方同時に動かしてみましょう
先ほど`Verticle`は自由に増やしたりできると書きました。
実際に複数のVerticleを起動してみましょう。

```App.groovy
container.deployVerticle('groovy:GroovyVerticle')
container.deployVerticle('JavaVerticle.java')
```

こちらのファイルを作成します。

```
$> vertx run App.groovy 
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle 
```

上記のファイルを実行すると`Verticle`が二つ起動されます。
試しに`localhost:8080`と`localhost:8070`へアクセスしてみてください。
両方のVerticleが動作していることを確認できると思います。
※なぜかここは`groovy:`を書かなくても動く。Verticleを起動するときだけ必要なのかもしれない。（汗

```App.groovy
container.deployVerticle('groovy:GroovyVerticle', 10)
container.deployVerticle('JavaVerticle.java', 15)
```

上記のように設定すると`GroovyVerticle`を10個、`JavaVerticle`を15個起動させることができます。
（多分w。確認はしてませんが、動きました・・・。）

また、外部からverticleの数を変えることも出来ますが・・・やり方をメモったファイルを紛失してしまったので本記事では割愛します。（汗

## 最後に説明
とりあえず、`Verticle`の起動方法は分かったかと思います。
コードを見ていただければ分かると思いますが、`Verticle`が起動すると`start`メソッドがまず呼び出されます。
ここでVerticleの初期処理を行います。

上記の例ではHTTPの待ち受けを行ってますが、他では以下のことを行ったりします。

* WebSocketの待ち受け
* イベントハンドラ(vertx.eventBus)の登録

・・・って、書いておきながら僕は上記の2点くらいしかしたことがなかったです。はい。
長くなってきたのでVerticle同士のメッセージやりとりをするイベントハンドラについては別記事で記載します。
また、その際にSyncMapについても書こうと思います。

ReactiveがVertx3で使えるようになったので、こちらについても調べたいのですが・・・ここまで調べれるかどうかは疑問です・・・。
（というのも、Vertxは業務で使用しているわけではないので・・・）

## おまけ
本当はWebSocketの通信方法を書きたかったのですが、検証が面倒なのでここでの題材にあげませんでした。

が！
興味のある方もいると思いますので、Groovyのコードだけ貼り付けておきます。
※Vertx2で動かしていたコードです。説明はしませんw

```WsServerVerticle.groovy
import org.vertx.groovy.core.buffer.Buffer
import org.vertx.groovy.core.eventbus.Message
import org.vertx.groovy.core.http.ServerWebSocket
import org.vertx.groovy.platform.Verticle
import org.vertx.java.core.impl.VertxInternal

import org.vertx.java.core.json.JsonArray
import org.vertx.java.core.spi.cluster.ClusterManager

class WsServerVerticle extends Verticle {
    @Override
    def start() {
		// スタックオーバーフローでは下記のように取得していた。
		// http://stackoverflow.com/questions/12299132/clustering-and-shared-data-in-vert-x
        // ClusterManager clusterManager = ((VertxInternal)vertx).clusterManager()
        // Map map = clusterManager.getSyncMap("mapName");
		// 実際は以下のように取ってた。（以下のコードはこのサンプルでは使ってません。）
        ClusterManager clusterManager = ((VertxInternal)vertx.toJavaVertx()).clusterManager()
        Map map = clusterManager.getSyncMap("mapName");

        // WebSocketを起動
        vertx.createHttpServer().websocketHandler {ServerWebSocket ws ->
            onOpen(ws)
        }.listen([ポート番号], [アドレス(0.0.0.0)])
    }

    @Override
    def stop() {
    }
    
    // WebSocketのコネクションが開かれた場合の処理
    private def onOpen(ServerWebSocket ws) {
        println "open"
        // クライアントへ書き込む関数
        def writeHandler = { Message message ->
			// wsインスタンスをキャプチャーしてる。（上の説明で状態を持たないって書いてたが、こういう場合もある。）
            ws?.writeBinaryFrame(new Buffer((byte[])message.body))
        }

        // 他のVerticleからもクラアントへ書き込めるようにする。
        vertx.eventBus.registerHandler([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], writeHandler)

        // WebScoketへ通知があった場合の処理
        ws.dataHandler { data ->
            onMessage(data)
        }

        // WebSocket切断処理
        ws.closeHandler {
            // 作成したイベントバスを削除しておく。
            vertx.eventBus.unregisterHandler([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], writeHandler)
            println "close"
        }
    }

    // WebSocketのデータ受信ハンドラの定義
    private def onMessage(Buffer data) {
        // 受け取ったメッセージの処理を行う。

        // 実際の処理を行うVerticleを呼び出す。
        vertx.eventBus.send([他のVerticleで登録したイベントバスを呼び出す。], data) { Message msg ->
            // 結果をクライアントへ通知する
            vertx.eventBus.send([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], (JsonArray)msg.body)
        }
    }
}

```

## 参考にしたサイト
[Vert.x がいいね！](http://acro-engineer.hatenablog.com/entry/2013/08/10/131203)

## Vertx2のメモ
僕用のメモです。
Vertx2で使ってた設定をメモに残しておきます。

読者の方は読み飛ばしてください。

### デバッグ
Vertx3では未確認ですが、Vertx2では以下の設定を`[解凍フォルダのパス]/vert.x-3.0.0/bin/vertx`に記載しました。

```
JVM_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
```

### mod.jsonはどこに・・・？
Vertx3でも同じ構成なのだろうか？？

Vertx2では以下の場所に配置されていたが・・・。
[https://github.com/vert-x/vertx-gradle-template/tree/master/src/main/resources](https://github.com/vert-x/vertx-gradle-template/tree/master/src/main/resources)

Vertx3ではなくなってる・・・。
ってか、別にテンプレートがあるのか？？？
[https://github.com/vert-x3/vertx-examples/tree/master/gradle-simplest](https://github.com/vert-x3/vertx-examples/tree/master/gradle-simplest)

### Gradleの設定が大きく変わってないか？？
Vertx2
[https://github.com/vert-x/vertx-gradle-template/blob/master/build.gradle](https://github.com/vert-x/vertx-gradle-template/blob/master/build.gradle)

Vertx3
[https://github.com/vert-x3/vertx-examples/blob/master/gradle-simplest/build.gradle](https://github.com/vert-x3/vertx-examples/blob/master/gradle-simplest/build.gradle)

僕はGradleに明るくないけど、`Vertx3`では`Main-Class`で初期処理をする`Verticle`を指定できるようになったのかな？
`Vertx2`では以下のコマンドで起動してた。

```
$> CLASSPATH=[先に読み込みたいライブラリ]/lib/*:. vertx run [起動したいVerticle] -cluster -cp build/classes/main -conf [読み込みたいConfig]
```

`[VERTX_HOME]/conf/langs.properties`もなくなってる・・・。