バグだらけのWebアプリケーションをKotlinで実装してみました

## 概要

[以前紹介した](https://qiita.com/tamura__246/items/c8229d68ef199890827b)バグだらけのWebアプリケーション[「EasyBuggy」](https://github.com/k-tamura/easybuggy/blob/master/README.jp.md)のSpring Bootベースのクローン[「EasyBuggy Boot」](https://github.com/k-tamura/easybuggy4sb/blob/master/README.jp.md)を、Kotlinで再実装してみました([「EasyBuggy Bootlin」](https://github.com/k-tamura/easybuggy4kt/blob/master/README.jp.md))。

[このページ](https://github.com/k-tamura/easybuggy4kt/releases/latest)からダウンロードして、以下のコマンドで起動できます。

```bash
java -jar ROOT.war
```

<table width="100%"><tr><td>:writing_hand_tone1: 起動するにはJava 8以上が必要です。`java -jar ROOT.war --port=9000`とすると9000番ポートで起動します。</td></tr><table>

次のようにJavaオプションを付加すれば、ログ出力やデバッグ、JMXによる監視ができます。また、最大メモリ使用量を制限しているので、OutOfMemoryErrorなどの問題がより発生しやすくなります。

```bash
java -Xmx256m -XX:MaxPermSize=64m -XX:MaxDirectMemorySize=90m -XX:+UseSerialGC -Xloggc:logs/gc.log -XX:+PrintHeapAtGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M -XX:GCTimeLimit=15 -XX:GCHeapFreeLimit=50 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/ -XX:ErrorFile=logs/hs_err_pid%p.log -agentlib:jdwp=transport=dt_socket,server=y,address=9009,suspend=n -Dderby.stream.error.file=logs/derby.log -Dderby.infolog.append=true -Dderby.language.logStatementText=true -Dderby.locks.deadlockTrace=true -Dderby.locks.monitor=true -Dderby.storage.rowLocking=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7900 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -ea -jar ROOT.war
```

以下のようなメッセージが表示されたら、Webアプリケーションの起動は完了しています。

```
2017-10-19 16:36:01.065  INFO 5304 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8081 (http)
2017-10-19 16:36:01.075  INFO 5304 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2017-10-19 16:36:01.242  INFO 5304 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-10-19 16:36:01.249  INFO 5304 --- [           main] o.t.e.Easybuggy4ktApplicationKt          : Started Easybuggy4ktApplicationKt in 37.355 seconds (JVM running for 38.916)
```

http://localhost:8080 にアクセスすると、メインページが表示されます。

![demo_ebk_ja_startup.gif](https://qiita-image-store.s3.amazonaws.com/0/43869/873bf9ae-61a6-7c87-259e-a88e4f3174c6.gif)

起動がちょっと遅いです(15秒ほど。EasyBuggyは3秒で起動するんですが...)

### 上記以外の起動方法

`git clone`して、`gradle bootRun`しても起動できます。

```bash
$ git clone https://github.com/k-tamura/easybuggy4kt
$ cd easybuggy4kt
$ gradle bootRun
```

<table width="100%"><tr><td>`src/main/resources/application.properties`の`server.port=${port:8080}`の行を`server.port=9000`にとすると9000番ポートで起動します。</td></tr><table>

また、Tomcat 8.5などのJavaコンテナにROOT.warをデプロイしても同様に動作します。

## このアプリの用途

「EasyBuggy」や「EasyBuggy Boot」と同様に、様々な障害を再現させて、解析し、理解を深めることが目的です。なぜKotlinで再実装したかというと、次のことを知りたかったからです。

 - Kotlinで実装されたアプリにも脆弱性やリソースリークをつくり込むことはできるか
 - Javaで実装されたアプリをKotlinで再実装する上で必要な作業は何か
 - Javaで実装されたアプリをKotlinで再実装することで可読性は向上するか

## デモ

以下はメモリリークが発生するページに何度もアクセスして、メモリがリークしている状態を観測したデモです。

![demo_ebk_ja_memleak.gif](https://qiita-image-store.s3.amazonaws.com/0/43869/8a95c10d-2d46-984d-066d-0dbf92c7e680.gif)

## 構成の相違点

「EasyBuggy」、「EasyBuggy Boot」、「EasyBuggy Bootlin」の主な構成の相違点は以下の通りです。

|相違点|EasyBuggy|EasyBuggy Boot|EasyBuggy Bootlin|
--------|--------|--------|--------
|言語|Java|Java|Kotlin|
|ベースとなる技術|Servlet 3.0.1|Spring Boot 1.5.6 (Servlet 3.0.1)|Spring Boot 1.5.7 (Servlet 3.0.1)|
|プレゼンテーション層|未使用 (一部 JSP 2.2 + JSTL 1.2)|Thymeleaf 2.1.5 (一部 JSP 2.3 + JSTL 1.2)|Thymeleaf 2.1.5 (一部 JSP 2.3 + JSTL 1.2)|
|サーブレットコンテナ|Tomcat 7.0.37|Tomcat 8.5.16|Tomcat 8.5.20|
|DBクライアント/サーバー|JDBC / Derby 10.8.3.0|Spring JDBC 4.3.9 / Derby 10.12.1.1 (Java 7の場合)、または10.13.1.1 (Java 8の場合)|Spring JDBC 4.3.11 / Derby 10.13.1.1|
|LDAPクライアント/サーバー|Apache DS Client API 1.0.0 / Server 1.5.5|Spring LDAP 2.3.1 / unboundid-ldapsdk 3.2.1|Spring LDAP 2.3.1 / unboundid-ldapsdk 3.2.1|
|メール|JavaMail 1.5.1|JavaMail 1.5.1 (Spring Boot Mailで導入されるJavaMail 1.5.6をオーバーライド)|JavaMail 1.5.1 (Spring Boot Mailで導入されるJavaMail 1.5.6をオーバーライド)|
|開発ツール|無し|Spring Boot Developer Tools 1.5.6|Spring Boot Developer Tools 1.5.7|
|ビルドツール|Maven|Maven|Gradle|
|Java|Java 6以上をサポート|Java 7以上をサポート|Java 8以上をサポート|

## ビルドの方法

以下のコマンドで、実行可能かつデプロイ可能なwarファイルを作成することができます。

```bash
$ gradle clean build
```

## 開発の方法

EasyBuggy Bootlinの開発には、Kotlinを開発したJetBrains社のIntelliJ IDEAを使用しています。JavaのプログラムをKotlinのプログラムに変換するような役立つ機能があったので、STSではなくIntelliJを選択しました。IntelliJのおかげで、かなり短時間にこのアプリが開発できました。

開発を高速にするためには、`gradle build --continuous`で継続的にビルドしながら、`gradle bootRun`でEasyBuggy Bootlinを起動するといいです。この方法であれば、ソースコードを修正すると、Spring Boot DevToolsにより自動的にリロードされて、修正が反映されます。

![demo_ebk_ja_devtool.gif](https://qiita-image-store.s3.amazonaws.com/0/43869/80d155da-4ccc-5731-393e-2952a2a6955e.gif)