saba1024のブログ

どうでも良い思いついた事とかプログラミング関係のメモとか書いていきます。

Java標準の組み込みWebサーバをApache Groovyで利用する

本記事はG* Advent Calendar 2017の18日目の記事です。

@tyamaさんのブログで紹介されていた、@glaforgeさんのこのツイートで初めて、Javaに組み込みWebサーバが存在していることを知りました!

ツイート内のコードだとシングルスレッド(HttpServer#start()を実行したスレッド)で全てのアクセスが同期して処理されるらしいので、事前にExecutorを定義してHttpServer#setExecutor()で渡してあげてマルチスレッドでWebサーバを動かすようにしてみました。

import com.sun.net.httpserver.HttpServer
import com.sun.net.httpserver.HttpExchange
import java.util.concurrent.Executor

class DirectExecutor implements Executor {
    public void execute(Runnable r) {
        // r.run() <--- これを実行すると同期処理にすることも出来る。
        new Thread(r).start()
    }
}

HttpServer.create(new InetSocketAddress(8081), 0).with {
    createContext("/hello") { HttpExchange http ->
    println """
        request method: ${http.requestMethod}
        protocol: ${http.protocol}
        remoteAddress: ${http.remoteAddress}
        headers: ${http.requestHeaders}
        URI: ${http.requestURI}
        body: ${http.requestBody}
    """
        http.responseHeaders.add("Content-type", "text/plain")
        http.sendResponseHeaders(200, 0)
        http.responseBody.withWriter {out ->
            out << "Hello ${http.remoteAddress.hostName}"
        }
    }
    executor = new DirectExecutor()
    start()
}

コレを適当なファイル名で保存しておいて、groovyコマンドで実行するだけでWebサーバの完成です。
これで、

curl -X POST http://localhost:8081/hello?a=b --data "hoge" --data "{a:b, c:d}"

というリクエストを投げると、コンソールには

request method: POST
protocol: HTTP/1.1
remoteAddress: /127.0.0.1:42410
headers: [Accept:[*/*], Host:[localhost:8081], User-agent:[curl/7.35.0], Content-type:[application/x-www-form-urlencoded], Content-length:[15]]
URI: /hello?a=b
body: hoge&{a:b, c:d}

と出力されます。

ちょっとしたツールとかサービスなんかは、古き良き時代(?)のPHPスクリプトのように、Webサーバに結びついていてPHPスクリプトをその場で修正すれば即反映される、というような気軽な感じで作りたいという欲求が合ったので、すでに今回のG* Advent Calendar 2017で投稿したGroovyだけでWebサーバを実装する方法を応用すれば、このJava組み込みWebサーバでGroovyスクリプトを動かせるな〜とちょっとワクワクしています。