herokuでjavaからmysql(mariadb)の接続まで

# 前回までの手順
http://qiita.com/gosshys/items/112bcc6e24718af895d0

# herokuのjavaのサンプルプロジェクト
herokuのGetting Started with Java on Herokuの手順で作成された「java-getting-started(helloworld)」プロジェクトでは、デフォルトでpostgresqlが利用できるようになっている。
これを既存のmysql（実際にはmariadb）に接続する。

# 手順

## 手順１：Run the app locally
まず、以下のherokuの手順にしたがって、組み込みのJavaサーバーのJettyが起動することを確認する。
https://devcenter.heroku.com/articles/getting-started-with-java#run-the-app-locally

![image](https://qiita-image-store.s3.amazonaws.com/0/38174/0c86d8b8-4057-99a7-70d5-c16bf2fa99df.png)

`foreman start web`の前に、`mvn clean install`を実行しないとアプリケーションが起動しないので注意する。
`foreman`は、herokubeltに同封されているProcfileにしたがって複数プロセスを起動することができるツールらしい。
http://qiita.com/7kaji/items/6a59977d2ad85604e7fd

サーバーが起動したら、`http://localhost:5000/`へアクセスして、`Hello from Java!`が表示されればOK。
そしたら、foremanは、Ctrl+cで閉じます。

## 手順２：IntelliJで開く
IDEを使って開発したいため、IntelliJでherokuのサンプルプロジェクトを開きます。

![image](https://qiita-image-store.s3.amazonaws.com/0/38174/5ea48fb7-2b06-b7a1-41fc-6b8b0e5f4dd4.png)

「Open」を選択して、「Open File or Project」ウィンドウを開きます。
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/f17a4336-e86e-8649-ca0a-1f9a94b75c48.png)

herokuのサンプルプロジェクト「java-getting-started」を選択。
IntelliJが適当にプロジェクトの設定を追加してくれます。
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/089a2d27-8b0b-19fb-5009-04f511de4355.png)

## 手順３：IntelliJ上でMainクラスを起動
IntelliJからMainクラスを実行します。Mainクラスを右クリックから「Run Main.main()」を選択
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/134b3118-b0cd-196e-d8f7-5cee9424a8b1.png)

起動に失敗します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/7b4956f5-d425-00b8-8fb7-cc34ece3762b.png)

```
Exception in thread "main" java.lang.NumberFormatException: null
	at java.lang.Integer.parseInt(Integer.java:542)
	at java.lang.Integer.valueOf(Integer.java:766)
	at Main.main(Main.java:65)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
```

Main.javaの65行目を見ます。
```
  public static void main(String[] args) throws Exception {
    Server server = new Server(Integer.valueOf(System.getenv("PORT")));
```
`System.getenv("PORT")`で値が取れていないようなので、IntelliJのメニューから「Run」-「Edit Configurations」から環境変数を設定します。
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/0b265119-912d-3ac2-7465-cefa44f87f5e.png)
「Environment variables」が環境変数の指定になります。コードが`System.getenv()`なので、「VM Option」（起動引数）の`-D`オプションではダメでした。
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/7fc8fb5a-d0b4-0501-ab0f-66e4b86405d0.png)
とりあえず、`PORT`に5000を設定。(これはforemanのコマンド１つ目のデフォルトポート番号らしいです)
「OK」を押して、 ウィンドウを閉じて、再度、MainクラスをRunする。

```
2015-04-25 19:04:59.303:INFO::main: Logging initialized @177ms
2015-04-25 19:04:59.412:INFO:oejs.Server:main: jetty-9.2.10.v20150310
2015-04-25 19:04:59.458:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@3ada9e37{/,null,AVAILABLE}
2015-04-25 19:04:59.479:INFO:oejs.ServerConnector:main: Started ServerConnector@490d6c15{HTTP/1.1}{0.0.0.0:5000}
2015-04-25 19:04:59.480:INFO:oejs.Server:main: Started @357ms
```

こんな感じで起動するので、`http://localhost:5000/`にアクセスする。
おなじみの`hello`メッセージが表示されるはずです。

また、以下のように`java.net.BindException: Address already in use`のようなエラーがでる場合は、他のプロセスで`5000`番ポートを利用しているので、探しだしてkillするか、IntelliJの環境変数の`PORT`の番号をずらしましょう。

```
2015-04-25 19:06:30.342:INFO:oejs.Server:main: jetty-9.2.10.v20150310
2015-04-25 19:06:30.381:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@3ada9e37{/,null,AVAILABLE}
2015-04-25 19:06:30.393:WARN:oejuc.AbstractLifeCycle:main: FAILED ServerConnector@5f5a92bb{HTTP/1.1}{0.0.0.0:5000}: java.net.BindException: Address already in use
java.net.BindException: Address already in use
	at sun.nio.ch.Net.bind0(Native Method)
	at sun.nio.ch.Net.bind(Net.java:436)
	at sun.nio.ch.Net.bind(Net.java:428)
	at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:214)
	at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
	at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:321)
	at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
	at org.eclipse.jetty.server.ServerConnector.doStart(ServerConnector.java:236)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.server.Server.doStart(Server.java:366)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at Main.main(Main.java:70)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
```

## 手順４：mysqlに接続してみる
デフォルトのpostgresqlを利用するのではなく、現行稼働しているmysql(実際はmariadb)に接続してみます。
サンプルプログラムを流用して、自前で用意したmysqlへ接続します。

### pomファイルにmariadbのコネクタのライブラリを設定
すみません、mysqlの方は読み替えてください。
mariadbの最新のコネクタライブラリを探す。

googleで検索すると以下のページが引っかかるので参考にします。
http://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/1.1.8

以下の設定をpom.xmlに追記します。postgresqlの設定は消しても大丈夫です。

```
<dependency>
	<groupId>org.mariadb.jdbc</groupId>
	<artifactId>mariadb-java-client</artifactId>
	<version>1.1.8</version>
</dependency>
```

### mariadbへの接続設定を環境変数に設定
herokuのサンプルでは、`heroku config`の設定情報からpostgresqlのホスト、ユーザー、パスワードを取得してデータベースコネクションを取得しています。
heroku configの例

```
~/D/g/java-getting-started ❯❯❯ heroku config
=== dry-bayou-2092 Config Vars
DATABASE_URL:                postgres://xxxxxxxxxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyy@ec2-99-999-999-99.compute-1.amazonaws.com:5432/zzzzzzzzzzzzzz
HEROKU_POSTGRESQL_MAUVE_URL: @ref:aaaaaaaa-bbbbbbb-9999:url
JAVA_OPTS:                   -XX:+UseCompressedOops
```

- xxxxxxxxxxxxxx ユーザーID
- yyyyyyyyyyyyyyyyyyyyyyyyyy パスワード
- ec2-99-999-999-99.compute-1.amazonaws.com ホスト
- 5432 ポート番号
- zzzzzzzzzzzzzz データベース

postgresqlの設定を参考にして、環境変数に以下を設定します。

```
mariadb://userid:pasword@localhost:3306/database
```

「Run」-「Edit Configurations」の「Environment Variables」に環境変数「DB_URL」を追加
![image](https://qiita-image-store.s3.amazonaws.com/0/38174/eb8460ef-3cdf-9ca2-074d-c1dc2b4ac5f1.png)

*userid、pasword、database等は自分の環境に合わせて変更してください*

### mariadbへ接続するようにJavaコードを変更
サンプルコードの`getConnection`メソッドの`DATABASE_URL`を`DB_URL`に、`postgresql`を`mariadb`に変更します。

```java:Main.java(変更後)
  private Connection getConnection() throws URISyntaxException, SQLException {
    URI dbUri = new URI(System.getenv("DB_URL"));

    String username = dbUri.getUserInfo().split(":")[0];
    String password = dbUri.getUserInfo().split(":")[1];
    int port = dbUri.getPort();

    String dbUrl = "jdbc:mariadb://" + dbUri.getHost() + ":" + port + dbUri.getPath();

    return DriverManager.getConnection(dbUrl, username, password);
  }
```

## 手順５：DB接続を確認
Mainクラスを再度実行して、今度は、`http://localhost:5000/db`にアクセスします。
Servletでmariadbへの接続がうまくいけば、`ticks`テーブルが作成され、`INSERT INTO ticks VALUES (now())`で現在時刻がテーブルに登録されます。
その結果がWebページに表示されれば成功です。

![image](https://qiita-image-store.s3.amazonaws.com/0/38174/ebc0ed04-f98e-a08b-332f-877b07b62fcb.png)


# herokuにデプロイする前に
herokuの環境変数にmaridadbの接続設定を追加します。

```
heroku config:set DB_URL=mariadb://userid:pasword@localhost:3306/database
```