Eclipseを使ってDropwizardでH2データベースをサーバーモードで利用して、DBViewerで接続できるようになるまで。


DropwizardでH2データベースを立ち上げて利用できるまでやや難しかったので投稿しようと思いました。
流れとしてはEclipseでDropwizardのプロジェクトを作成し、H2のサーバーを立ち上げるクラスを作成し、dropwizardがもつEnvironment のlifecycleにこのクラスを管理させます。そして、起動したH2サーバーに対してDBViewerでアクセスします。

環境

利用したソフトウェアは以下のとおりです。

  • Windows: 10 Pro
  • Eclipse Version: Oxygen.1a Release (4.7.1a)
  • Dropwizard Tools:1.1.1(Eclipseのプラグイン)
  • DBViewer:1.2.2(Eclipseのプラグイン)
  • Maven Version: 3.5.2
  • Java Version: 1.8.0_152

Dropwizardでプロジェクトを作る

まずは、Eclipseでプロジェクトを作りましょう。Eclipseのファイル→新規→Mavenプロジェクトを選択します。

Mavenプロジェクトはフィルターにdropwizardを入力して「io.dropwizard.archetypes」の「java-simple」を選択します。ここでこの項目が出ない場合、「アーキタイプの追加」から追加しましょう。

追加する場合は図のように入力してください。

そうすると一覧に表示されるはずです。

プロジェクトのグループIDとアーティファクトIDは好きな名前にしてください。「アーキタイプで使用可能なプロパティー」の「name」は後程自動で作られるクラスのクラス名に使われます。完了を押すとプロジェクトが作成されます。

pom.xmlにプラグインを追加する

pom.xmlにプラグインを追加します。追加するプラグインは次のとおりです。プラグイン名:グループID:アーティファクトID順で記載します。

  • dropwizard-core:io.dropwizard:dropwizard-core(初めから追加されている)
  • dropwizard-lifecycle:io.dropwizard:dropwizard-lifecycle
  • maven-shade-plugin:org.apache.maven.plugins:maven-shade-plugin
  • h2:com.h2database:h2
  • junit:junit:junit

以下の図のようになることを確認してください。

H2のサーバを立ち上げるクラスを作成

H2のサーバを立ち上げるクラスを作成します。
私はresources以下に作成しました。

作成するときは次のように作成します。

スーパークラスにorg.junit.rules.ExternalResourceを、インターフェースにio.dropwizard.lifecycle.Managedを追加致します。
ExternalResourceはJUnitでテストする際に追加しておくと便利で、ManagedインターフェースはDropwizardのEnvironmentのlifecycleに追加するために継承させます。

このクラスのコードは以下の通りになります。

H2ServerResource.java
package hoge.fuga.resources;

import org.h2.tools.Server;
import org.junit.rules.ExternalResource;

import io.dropwizard.lifecycle.Managed;

public class H2ServerResource extends ExternalResource implements Managed {

    private Server tcpServer = null;
    private Server webConsole = null;

    public H2ServerResource()  {
        // TODO 自動生成されたコンストラクター・スタブ
        super();
    }

    @Override
    public void start() throws Exception {
            try {
                this.before();
            } catch (Throwable e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
                throw new Exception("H2サーバーの起動失敗", e);
            }
        }


    @Override
    public void stop() throws Exception {
        this.after();
    }

    @Override
    protected void before() throws Throwable {
        // tcpでの接続受付とWebコンソール
        if (tcpServer == null) {
            try {
                tcpServer = Server.createTcpServer("-tcpAllowOthers", "-tcpPort", "20020");
                webConsole = Server.createWebServer("-webPort", "20010");
                tcpServer.start();
                webConsole.start();

            } catch (Throwable e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
                throw new Exception("H2サーバーの起動失敗", e);
            }
        }
    }

    @Override
    protected void after() {
        // サーバのシャットダウン
        tcpServer.shutdown();
        webConsole.shutdown();
    }

}

ExternalResourceを継承するとbeforeとafterをオーバーライドした方がいいです。JUnitでいい感じになります。
Managedインターフェースを継承するとstartとstopをオーバーライドしなければなりません。
それぞれ同じ処理なのでどちらかからどちらかを呼び出す関係にしてあります。
ここで注意しなければならないのが、Dropwizard側でstartとstopを呼び出してくれるため、コンストラクタでServerのインスタンスを作らないことです。二重にインスタンスを作ることになるため、エラーを吐きます。
また一応念のため、二重でインスタンスを作成しないためにnullチェックをしてあります。
createTcpServerの引数のtcpAllowOthersはローカルホストからしかアクセスされない場合外しても大丈夫です。

そして、自動で作成されたmainのクラスを変更して以下のようにします。

piyoApplication.java
package hoge.fuga;

import hoge.fuga.resources.H2ServerResource;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

public class piyoApplication extends Application<piyoConfiguration> {

    public static void main(final String[] args) throws Exception {
        new piyoApplication().run(args);
    }

    @Override
    public String getName() {
        return "piyo";
    }

    @Override
    public void initialize(final Bootstrap<piyoConfiguration> bootstrap) {
        // TODO: application initialization
    }

    @Override
    public void run(final piyoConfiguration configuration,
                    final Environment environment) {
        // TODO: implement application
        H2ServerResource h2serverResource = new H2ServerResource();
        environment.lifecycle().manage(h2serverResource);
    }

}

runのところでH2ServerResourceのインスタンスを登録します。
原文を見るとDBの接続とかスレッドプールに使ってねということです。

Managed Objects

Most applications involve objects which need to be started and stopped: thread pools, database connections, etc. Dropwizard provides the Managed interface for this. You can either have the class in question implement the #start() and #stop() methods, or write a wrapper class which does so. Adding a Managed instance to your application’s Environment ties that object’s lifecycle to that of the application’s HTTP server. Before the server starts, the #start() method is called. After the server has stopped (and after its graceful shutdown period) the #stop() method is called.

プログラムは以上になります。ここからコンパイルの作業に入ります。

プログラムのコンパイルと実行

プロジェクトを右クリックし、実行→実行の構成を選択してください。

実行構成のウィンドウが開いたら、Mavenビルドを選択し、新規作成で作ります。

基底ディレクトリにプロジェクトフォルダを選択し、ゴールにpackageかclean packageを入力して、適用し実行を行います。
そうするとビルドされます。

これで実行するとH2サーバーが立ち上がります。
Dropwizardを実行するときに便利なプラグインとしてDropwizard Toolsがあります。

このプラグインはdropwizardを実行するときに必要なserverやconfig.yml等の引数を自動で入力してくれます
インストールしたら、デバッグの構成を開いてください。

デバッグ構成ウィンドウが開いたら、メインクラスを選択します。

そして実行します。
この状態で先程入力した以下のポートにアクセスするとそれぞれDBへのアクセス(20020)とWebコンソール(20010)を開くことができます。

tcpServer = Server.createTcpServer("-tcpAllowOthers", "-tcpPort", "20020");
webConsole = Server.createWebServer("-webPort", "20010");

localhost:20010にアクセスしてみましょう。Webコンソールが開きます。
JDBC URL:にlocalhost:20020を入れてみましょう。
以下のURLでコンソールからアクセスするとプロジェクトフォルダにh2db.mv.dbが作成されます。
jdbc:h2:tcp://localhost:20020/./h2db

Eclipseに戻り、DBViewerから開けるようにします。
DBViewerのウィンドウを開き、登録を押します。

データベース定義ウィンドウが開いたらファイルの追加からh2のドライバを選択します。
mavenのローカルリポジトリのフォルダの中にあるので、探してください。
私の環境では以下のフォルダにありました。
%USERPROFILE%\.m2\repository\com\h2database\h2\1.4.196

そして次へを押します。
接続情報の設定で接続文字列は先程Webコンソールで入力した、
jdbc:h2:tcp://localhost:20020/./h2db
を入力します。
接続ユーザを「sa」にし、接続スキーマを空にします。
そしてテスト接続が行えることを確認してください。

以上でDropwizardでプロジェクトを作るところからDBViewerで接続できるところまでになります。