CLOVER🍀

That was when it all began.

RESTEasy+Vert.x(Embedded Container)で遊ぶ

これは、なにをしたくて書いたもの?

RESTEasyを組み込みサーバー上で動かす方法はいくつかあるのですが、以前にもUndertow、Netty、JDK HTTP Severなどで
やったことがあります。

RESTEasyをJDK付属のHTTPサーバ、Undertowで動かす - CLOVER🍀

UndertowでJAX-RS(RESTEasy)とCDIを使う - CLOVER🍀

RESTEasy+Netty(Netty 3/Netty 4/Netty 4 with CDI)で遊ぶ - CLOVER🍀

今回は、Vert.xを試してみようかなと。Quarkusで使われているJAX-RSのデフォルトのエンジンも、UndertowからVert.xに
なりましたしね。

RESTEasy Vert.x Embedded Container

RESTEasyでの、Vert.xをEmbedded Containerとして組み込む方法は、こちら。

Vert.x

Undertowなど、他のEmbedded Containerを使ったことがあれば、そう難しくはありません。

JAX-RSクライアント側の実装もあるのですが、こちらは今回のお題では問題が出たのでパスしました…。

Vertx Client Engine

とりあえず、使っていってみましょう。

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.7 2020-04-14
OpenJDK Runtime Environment (build 11.0.7+10-post-Ubuntu-2ubuntu218.04)
OpenJDK 64-Bit Server VM (build 11.0.7+10-post-Ubuntu-2ubuntu218.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.7, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.15.0-101-generic", arch: "amd64", family: "unix"

準備

pom.xmlは、以下のように設定。

    <dependencies>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-vertx</artifactId>
            <version>4.5.3.Final</version>
        </dependency>

        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>3.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.6.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.6.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.assertj</groupId>
          <artifactId>assertj-core</artifactId>
          <version>3.16.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
            </plugin>
        </plugins>
    </build>

resteasy-vertxではVert.xへの依存関係はprovidedとして定義されているため、Vert.xに関しては自分で依存関係に加えてあげないと
いけません。

        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-vertx</artifactId>
            <version>4.5.3.Final</version>
        </dependency>

        <dependency>
            <groupId>io.vertx</groupId>
            <artifactId>vertx-core</artifactId>
            <version>3.9.1</version>
        </dependency>

なお、providedに設定されているVert.xのバージョンは、こちらですね。

https://github.com/resteasy/Resteasy/blob/4.5.3.Final/resteasy-dependencies-bom/pom.xml#L34

その他の依存関係(JUnit、AssertJ)は、テストコード用として使います。

では、プログラムを書いていってみましょう。

JAX-RSリソースクラス

まずは、JAX-RSリソースクラスを用意します。簡単な、足し算を行うだけのクラスです。
src/main/java/org/littlewings/resteasy/vertx/CalcResource.java

package org.littlewings.resteasy.vertx;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("calc")
public class CalcResource {
    @GET
    @Path("add")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public int add(@QueryParam("a") int a, @QueryParam("b") int b) {
        return a + b;
    }
}

テストコードの雛形

Vert.xを使ったサーバーの起動および、動作確認はテストコードで行います。

テストコードの雛形は、こちらです。
src/test/java/org/littlewings/reteasy/vertx/ResteasyVertxTest.java

package org.littlewings.reteasy.vertx;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.UriBuilder;

import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServerOptions;
import org.jboss.resteasy.plugins.server.vertx.VertxJaxrsServer;
import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment;
import org.jboss.resteasy.spi.ResteasyDeployment;
import org.junit.jupiter.api.Test;
import org.littlewings.resteasy.vertx.CalcResource;

import static org.assertj.core.api.Assertions.assertThat;

public class ResteasyVertxTest {

    // ここに、テストを書く!!
}

シンプルに使ってみる

最初は、1番シンプルなパターンで使ってみましょう。

こんな感じです。

    @Test
    public void gettingStarted() {
        ResteasyDeployment deployment = new VertxResteasyDeployment();
        deployment.getResources().add(new CalcResource());

        VertxJaxrsServer server = new VertxJaxrsServer();
        server.setDeployment(deployment);
        server.setPort(8080);
        server.setRootResourcePath("");

        server.start();

        try {
            Client client =
                    ClientBuilder.newBuilder()
                            .build();

            int result =
                    client
                            .target(UriBuilder.fromUri("http://localhost:8080/calc/add?a={a}&b={b}").build(5, 3))
                            .request()
                            .get(Integer.class);

            assertThat(result).isEqualTo(8);

            client.close();
        } finally {
            server.stop();
        }
    }

ResteasyDeploymentには、Applicationのサブクラスや、JAX-RSリソースクラスなどを設定します。今回は、作成した
リソースクラスのみです。

        ResteasyDeployment deployment = new VertxResteasyDeployment();
        deployment.getResources().add(new CalcResource());

サーバーを起動するには、VertxJaxrsServerクラスを使用します。こちらで、パスやポートの設定を行い、先ほど作成した
ResteasyDeploymentを使用してJAX-RSサーバーとしての設定を行います。

        VertxJaxrsServer server = new VertxJaxrsServer();
        server.setDeployment(deployment);
        server.setPort(8080);
        server.setRootResourcePath("");

        server.start();

あとは、startするだけ。

終了時には、stopメソッドを呼び出せばOKです。

        } finally {
            server.stop();
        }

確認は、JAX-RSクライアントで。

            Client client =
                    ClientBuilder.newBuilder()
                            .build();

            int result =
                    client
                            .target(UriBuilder.fromUri("http://localhost:8080/calc/add?a={a}&b={b}").build(5, 3))
                            .request()
                            .get(Integer.class);

            assertThat(result).isEqualTo(8);

            client.close();

まずは、これで確認できました、と。

Vert.xの設定を行う

次に、もうちょっと細かくVert.xの設定を行ってみましょう。

こちらです。

    @Test
    public void customizeVertx() {
        ResteasyDeployment deployment = new VertxResteasyDeployment();
        deployment.getResources().add(new CalcResource());

        VertxOptions vertxOptions = new VertxOptions();
        vertxOptions.setEventLoopPoolSize(Runtime.getRuntime().availableProcessors() * 2);  // default
        vertxOptions.setWorkerPoolSize(30);

        HttpServerOptions serverOptions = new HttpServerOptions();
        serverOptions.setMaxHeaderSize(8192);
        serverOptions.setPort(8080);
        serverOptions.setReuseAddress(true);

        VertxJaxrsServer server = new VertxJaxrsServer();
        server.setDeployment(deployment);
        // server.setPort(8080);
        server.setRootResourcePath("");
        server.setVertxOptions(vertxOptions);
        server.setServerOptions(serverOptions);

        server.start();

        try {
            Client client =
                    ClientBuilder.newBuilder()
                            .build();

            int result =
                    client
                            .target(UriBuilder.fromUri("http://localhost:8080/calc/add?a={a}&b={b}").build(5, 3))
                            .request()
                            .get(Integer.class);

            assertThat(result).isEqualTo(8);

            client.close();
        } finally {
            server.stop();
        }
    }

スレッド数の設定などは、VertxOptionsで行います。

        VertxOptions vertxOptions = new VertxOptions();
        vertxOptions.setEventLoopPoolSize(Runtime.getRuntime().availableProcessors() * 2);  // default
        vertxOptions.setWorkerPoolSize(30);

また、HTTPサーバーとしての設定は、HttpServerOptionsで行います。

        HttpServerOptions serverOptions = new HttpServerOptions();
        serverOptions.setMaxHeaderSize(8192);
        serverOptions.setPort(8080);
        serverOptions.setReuseAddress(true);

こちらを、VertxJaxrsServerに設定します。

        VertxJaxrsServer server = new VertxJaxrsServer();
        server.setDeployment(deployment);
        // server.setPort(8080);
        server.setRootResourcePath("");
        server.setVertxOptions(vertxOptions);
        server.setServerOptions(serverOptions);

VertxOptionsやHttpServerOptionsは、Vert.x自体が提供するクラスです。

VertxJaxrsServer#setPortなどは、実はVertxJaxrsServerが内部的に持っているHttpServerOptionsへ設定しているだけなので、
直接HttpServerOptionsを使う時は、設定はこちらに任せた方がよいのかもしれません。

JAX-RSクライアントを使った確認は、先ほどと同じなので省略。

あと、今回はRESTEasyを動かすためのEmbedded ContainerとしてVert.xを使用しましたが、Vert.xにRESTEasyを組み込む
という方法もあるようです(パスしましたが)。

クライアント側は、今回の確認パターンでは問題があったので…ちょっとなんとかしたいですね。