2014年3月9日日曜日

IntelliJ IDEA メモ

開発環境として、IntelliJ IDEA を使っています。新しい環境に IntelliJ をインストールする際の設定や利用時のメモを記述していきます。なお、OS のバージョンは Fedora19、IntelliJ のバージョンは IDEA 13 の有償版(Ultimate Edition)を利用しています。

キーマップ

以前は Eclipse 風のキーマップに変更していましたが、以下の観点からデフォルトのキーマップにしています。
  • ググって出てくる公式の情報はデフォルトのキーマップであること
  • IntelliJ 起動時の Tips ももちろんデフォルトのキーマップであること
ここで自分好みに変えてしまうと、遅かれ早かれ既存のキーマップとバッティングし、知らず知らずのうちに上書きしてしまうことになります。以前は気にしなかったのですが、IntelliJ の記事を読んでいるうちに、いろいろ便利なショートカットがあるなあ、せっかくだし試さないのもなーと揺らいだため、現在はデフォルトに戻しています。

以下によく使うキーを列挙します。

  • ファイル検索
    • Ctrl + Shift + N
    • Shift 2 回
      • ただし自分の環境だと不安定
  • メンバ表示(Eclipse でいうアウトライン)
    • Ctrl + F12
  • ブックマーク

テンプレート

以下を参考に設定。(JUnit 実践入門風のもの)

Intellij IDEAにJUnitのLive templateを追加する

プラグイン

Eclipse に負けず劣らず、IntelliJ はプラグインが豊富に用意されています。ここでは、よく使うものを列挙します。
  • IntelliJ Configuration Server plugin
    • 複数端末にインストールされた IntelliJ の設定を同期します。
    • JetBrains アカウントが必要です。
  • FindBugs-IDEA
    • 静的バグ解析
  • lombok-intellij-plugin
    • もはや定番ともいえる lombok のプラグイン。Java Beans がすっきりするので、JPA における Entity や JSF の Backing Bean などで利用しています。

アプリケーションサーバの追加

WildFly

  1. 上部メニューの [Run]
  2. [Edit Configurations...]
  3. [+] マーク
  4. [JBoss Server]
    • 表示されていない時は、(28 more items) をクリック
  5. [Local]
  6. [Name]に適当な名前をつける
  7. [Server]タブの[Configure...]をクリック、[JBoss Home:]に WildFly のインストールディレクトリを選択
ここまででサーバの基本的な設定は完了。
アプリケーションをデプロイする場合は、
  1. [Deployment]タブを選択
  2. [+] マーク
  3. [Artifact...]
  4. デプロイするアプリケーションを選択
これで standalone ディレクトリをベースに、standalone.sh で起動する。ベースディレクトリや standalone.xml 以外のプロファイルを利用したい場合は、[Startup/Connection]タブの内容を編集する。

2014年1月31日金曜日

Entering Undertow Web server 和訳

本エントリは以下の和訳です。お手元に WildFly をぜひご用意ください。

Entering Undertow Web server

Java EE 7 のリリースへの対応と、 Web Sockets API や HTTP upgrades(例: HTTP 経由の EJB) といった先進的な機能を実現するため、WildFly の開発チームは重大な決断をしました。Apache Tomcat からフォークされた JBoss Web Server の長きにわたるコミットメントを経て、WildFly では新しい Web サーバ、その名も Undertow を基盤に据えています。

Undertow は 柔軟性に富み、高速な Java 製の Web サーバであり、J2SE New Input Output(NIO) API をベースにしています。Undertow はコンポジジョンベースのアーキテクチャを持ち、ハンドラと呼ばれる小さな単一のコンポーネントを組み合わせることで、Web サーバとして完全な機能を構築できます。これらハンドラは、Java EE Servlet 3.1 コンテナの完全な機能の実現であったり、ユーザのコード中に埋め込まれたシンプルな HTTP を処理するハンドラを実行するためにチェーンされます。

以下の図のように、ハンドラチェーンは様々な個々のハンドラからなり、最終的に Servlet レスポンスやエラー(例: リクエストされたパスが存在しない)を生成します。

Undertow Web サーバはまた、タスクを処理するためにノンブロッキング非同期ハンドラにするか、スレッドプールで管理されるブロッキングハンドラに処理を委譲するか選択できる柔軟性を持っています。

Undertow の設定内容を確認するために、設定ファイル(standalone*.xml もしくは domain.xml)を見てみましょう。そして、"undertow" サブシステムのところまで移動してください。デフォルトでは以下のようになっています。

<subsystem xmlns="urn:jboss:domain:undertow:1.0">
   <buffer-caches>
      <buffer-cache buffer-size="1024" buffers-per-region="1024" max-regions="10" name="default">
   </buffer-cache></buffer-caches>
   <server name="default-server">
      <http-listener max-post-size="10485760" name="default" socket-binding="http">
      <host alias="localhost" name="default-host">
         <location handler="welcome-content" name="/">
      </location></host>
   </http-listener></server>
   <servlet-container default-buffer-cache="default" name="default" stack-trace-on-error="local-only">
      <jsp-config>
      <persistent-sessions path="persistent-web-sessions" relative-to="jboss.server.data.dir">
   </persistent-sessions></jsp-config></servlet-container>
   <handlers>
      <file directory-listing="true" name="welcome-content" path="${jboss.home.dir}/welcome-content">
   </file></handlers>
</subsystem>

Undertow の設定のうち1つ重要な要素として Buffer Caches があります。バッファは原則として、データを書き込み及び、後で読み込むことのできるメモリのブロックです。メモリブロックは NIO Buffer オブジェクトにラップされ、メモリブロックを簡単に扱うことのできるメソッド郡を提供します。バッファを利用することの大きな利点として、物理アクセスよりも高速であることが挙げられます。
Java NIO に加え、WildFly は XNIO(http://www.jboss.org/xnio)を活用しています。XNIO は低レベル I/O レイヤを提供し、NIO API をシンプルに扱うことができるようになります。XNIO は NIO セレクタを利用することによる複雑さの解決、NIO に不足しているマルチキャストやシリアルポートのような非ソケット I/O へのサポートを提供します。また、NIO が持つ機能は全てそのまま利用できます。
Undertow を管理するために、管理コンソール上で Profile タブの Web パネルを見てください。以下のリストが含まれています。
  • Web Services: WSDL ホストやポートといった Web サービスの設定を行えます
  • Servlets: JSP の一括リロードができる開発モードを利用するかどうかの設定を行えます(デフォルト: false)
  • HTTP: HTTP コネクタの設定(例: IO リソースプールの設定)を行えます
  • Undertow Core: ハンドラとフィルタを HTTP コネクションと関連付ける設定を行えます

Web サーバのプールの設定

ここは JBoss AS 7 の設定から変わったところです。以前のバージョンでは Web サーバのスレッドプールをチューニングするために、Thread Executor を参照していました。一方 WildFly 8 では、IO サブシステム中で作成される Worker 要素を参照する必要があります。やり方を見てみましょう。左にあるメニューのツリーから Core を開いて、以下の図のように "IO" を選択してください。
メインのパネルから "Worker" パネルを選択してください。すでに "default" ワーカが存在していることがわかると思います。Add/Remove ボタンをクリックすることで、いつでも新しいワーカを作成、削除することができます。また、"Edit" リンクをクリックすることで、default ワーカのスレッド数を変更することができます。リンクをクリックすると以下のように属性を編集できます。
最初の Stack size は Web サーバのスレッドのスタックサイズです。スレッドのスタックサイズを大きくすると Web サーバはより多くのリソースを処理できます。よって、少数のユーザ向けです。Task keepalive は同じクライアントからのリクエストに対するコネクションを何秒維持するか設定できます(デフォルト: 60)。Keep-Alives を利用するとブラウザは初回リクエスト時に確立したコネクションを全てのリクエストに対して使いまわすため、通常、ページのロード時間が半減します。

Io threads  Web サーバが利用できるスレッド数です。これは Web アプリケーションが高負荷を受けるようになるにつれて増やす必要のある、チューニングすべき重要なパラメータです。Task Max Threads は同時に処理できるリクエスト数です。IO ワーカの設定が終わったら Save をクリックしてください。

ワーカの設定をしたので、Web サーバからこのワーカを参照させる必要があります。左にあるメニューのツリーから Web サブシステムを開いて HTTP を選択してください。HTTP サーバに関する見慣れない項目があり、設定することができます。
表中の "default" 要素をクリックし、Worker 要素が先ほどの IO ワーカと関連づけられていることを確認してください。ワーカを利用するためには enabled である必要があります。次に、HTTP リスナと Socket binding(左のメニューの General Configuration にある Socket Binding から、利用できるソケットバインディング設定を確認できます) を関連付ける必要があります。最後に、HTTP サーバを Java NIO Buffer Pool の実装を設定します。これについては、次のセクションで説明します。

HTTP のワーカ設定が完了すると、Web サーバのワーカスレッドの名前は [worker name]-[worker-id] という形式になります。以下の図では、ワーカの名前を "custom" と定義し、JDK に同梱されている JConsole を利用してスレッドを監視しています。

Web サーバのバッファプールの設定

すでに述べたとおり、Undertow は Java NIO API に基づいており、J2SE のプールを利用します。

バッファするためには java.nio.ByteBuffer が必要です。
バッファはオブジェクトであり、読み書き可能なデータを含みます。NIO におけるバッファオブジェクトの追加が、この新しいライブラリと元々の I/O との大きな違いです。ストリーム指向の I/O では、データの読み書きに直接ストリームオブジェクトを操作していました。NIO ライブラリでは、全てのデータは Buffers を介して操作されます。データが読み/書き込まれるとき、バッファに対して読み/書き込まれます。NIO においてデータアクセスする際は、バッファから取り出すことになります。
Undertow における IO バッファプール の設定は、以下の図のように左のメニューの Core | IO を選択し、Buffer Pools から行います。
表中の "default" 行をクリックすると、以下要素を設定できます。

Buffers per slice バッファの分割数を設定します。大きなバッファを分割して操作し、バッファ全体を処理する際のオーバヘッドを回避します。
Direct buffers バッファがダイレクトバッファとして設定されるかどうかを選択します。ダイレクトバッファは Java ヒープ外の領域に割り当てられ、バッファの存続期間中はメモリアドレスが固定されます。メモリアドレスを順番に固定することで、カーネルが安全にメモリに直接アクセスできるため、ダイレクトバッファによって I/O 操作がより効率的になります。
Buffer size java.nio.ByteBuffer のサイズを設定します。ダイレクトバッファが有効な場合、デフォルトの 16kb は最大パフォーマンスを提供するのに最適な値です(この値は Linux でのデフォルトのソケットバッファサイズと一致します)。

この記事は "WildFly 8 Book" からの引用です。この本はもっとも有名なオープンソースの Java アプリケーションサーバである JBoss WildFly(JBoss AS から改称)の実践的でわかりやすいガイドです。この本は新しくエキサイティングな WildFly の運用管理面の詳細を網羅しています。管理機能にフォーカスし、最新のアーキテクチャとパフォーマンスの変化を学べます。基本的な設定からクラスタリングや JDBC コネクティビティ、ロギングなど高度な設定まで順を追って習得できます。

2013年12月23日月曜日

Spring の JMS サンプルを試す

この記事は Spring Framework Advent Calendar 2013 の 12/23 の記事です。 

このエントリでは、Spring Guide で紹介されている JMS サンプルを試してみたいと思います。
# なんども掲載日を変更してしまい、すみません。
# 本当は WildFly/HornetQ で何かしら動かしてみたかったのですが、次回リベンジします。。

Spring では Guides として、用途別にたくさんのサンプルを載せています。

http://spring.io/guides

その中で JMS を利用したメッセージングのサンプルがあったので、試してみました。

http://spring.io/guides/gs/messaging-jms/

サンプルを clone し、内容を確認してみます。
$ git clone https://github.com/spring-guides/gs-messaging-jms.git
$ cd gs-messaging-jms
$ tree --dirsfirst
.
# 完成形
├── complete
│   ├── gradle
│   │   └── wrapper
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── hello
│   │               ├── Application.java
│   │               └── Receiver.java
│   ├── build.gradle
│   ├── gradlew
│   ├── gradlew.bat
│   └── pom.xml
# 最初の状態
├── initial
│   ├── gradle
│   │   └── wrapper
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── hello
│   ├── build.gradle
│   ├── gradlew
│   ├── gradlew.bat
│   └── pom.xml
# その他
├── test
│   └── run.sh
├── LICENSE.code.txt
├── LICENSE.writing.txt
├── README.adoc
├── SIDEBAR.ftl.md
└── SIDEBAR.md

complete に完成済みの答えが格納されています。initial はある程度の構成ができてここからソースや少々の設定を加えて complete に近づけていく、という形になっています。
今回作成する必要があるのは、
  • Application.java
  • Receiver.java
ですね。あとは Maven を利用するならば pom.xml を、Gradle であれば build.gradle を一部追記しておしまいです。では、ガイド に沿って、initial 以下を編集作成していきたいと思います。

Receiver.java

hello パッケージに Receiver.java を作成します。
MDB ? と見まごうばかりですが、これは Message Driven Pojo(MDP) であり、javax.jms.MessageListener を実装する必要はありません。onMessage ではなく、任意の名前のメソッドを作成し、メッセージコンシューマの実装を記述していきます。
最後の FileSystemUtils.deleteRecursively(new File("activemq-data")); で組込 ActiveMQ のデータを削除しています。

Application.java

hello パッケージに Application.java を作成します。

まず目をひくのが、Class 宣言のところにある @Configuration と @EnableAutoConfiguration ですね。このプロジェクトは、Spring Boot というスタンドアロンなアプリケーションを迅速につくる仕組みを利用しており、この 2 つの設定のおかげで、だいたい Spring が設定をよきにはからってくれるというもののようです。確かに、プロジェクト中に applicationContext.xml などは見当たりません。すごい。

Spring Boot - AutoConfigure

とはいえ、自分で設定するところも必要です。

L27 - 30 では先ほど作成した Receiver を Bean 定義しています。Java クラス中に定義できてしまうんですね。
L32 - 39 では、メッセージ受信時に実行されるメソッドが定義するために、Receiver#receiveMessage をリスナ用メソッドに指定しています。Receiver が MDP でいられるのはこういった設定ができるからなんですねえ。
L41 - 52 では、SimpleMessageListenerContainer を返す container メソッドを定義しています。ここで MDP の設定はひと通り定義しています。

main() メソッドが、送信クライアントになっています。JmsTemplate を使っているので、かなりコードが短いですね。
# 送信に関しては、JMS2.0 もかなりシンプルに使える API ですので、EE 7 が待ち遠しいですね。

アプリケーションのビルド・実行

initial にある pom.xml/build.gradle に plugin を追加して、実行可能な jar を作成できるようにします。pom.xml の場合は spring-boot-maven-plugin プラグインを追加し、build.gradle の場合は dependencies と apply plugin を追加します。

Maven の場合


Gradle の場合


こう並べてみると Gradle は記述がさっぱりしていて、ぐらついてしまいますねえ。。

これでビルドできるようになったので、Maven または Gradle を使ってビルドします。

Maven の場合

$ mvn clean package

Gradle の場合

$ ./gradlew build

ビルドが完了したら実行します。

Maven の場合

$ java -jar target/gs-messaging-jms-0.1.0.jar

Gradle の場合

$ java -jar build/libs/gs-messaging-jms-0.1.0.jar

実行結果

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v0.5.0.M6)

[...]
Sending a new message.
Received <ping>
[...]

Spring + JMS いい感じ

Spring の JMS クライアントはかなりいい感じということがわかりました。純粋に jms クライアントを書くよりシンプルに記述できますね。
また、MDP を使うことで EJB なしで非同期受信ができるのは特筆すべき点と思います。

今回の JMS プロバイダは組込みの ActiveMQ でしたが、今後は WildFly の JMS プロバイダである HornetQ を利用するなどもしてみようかと思います。

2013年12月13日金曜日

Brunch を使ってみる

今ちまちまと作っているブログアプリケーションである MoreCat ですけれども、フロントエンドの開発に Brunch というフレームワークを使おうと考えています。名前は前から聞いていたのですが実際に触るのは初めてなので、メモがてら練習してみます。
なお、おれの JavaScript 力(ジャバスクリプトちから)は皆無に等しいので、JS もこれからがんばります。
利用環境は Fedora 19 です。

Brunch ってなんじゃい

Brunch is an ultra-fast HTML5 build tool
だそうです。CoffeScript や Backbone.js、Stylus など、いろいろなフレームワークを組み合わせたフレームワーク + ビルド環境って感じでしょうか。

Brunch の導入

とりあえずトップページの Getting Started に沿ってやってみます。

Node.js/npm のインストール


brunch のインストールに必要です。
$ sudo yum install npm
$ npm -v              
1.3.6

Bower のインストール


あとで必要になるので Bower もインストールしておきます。
$ sudo npm install -g bower 
$ bower -v
1.2.8

Brunch のインストール

$ sudo npm install -g brunch

スケルトンからプロジェクトを作成

$ brunch new gh:paulmillr/brunch-with-chaplin brunch-practice

スケルトンはいろいろあるようですが、とりあえず一番メジャーそうなものを選びました。brunch new <skeleton-URL> [optional-output-dir] の書式で作成します。[optional-output-dir] を指定しない場合は、カレントディレクトリに資材が展開されます。資材は以下のような内容です。
$ cd brunch-practice
$ tree -L 1 --dirsfirst
.
├── app
├── bower_components
├── generators
├── node_modules
├── public
├── README.md
├── bower.json
├── brunch-config.coffee
└── package.json

スケルトンをそのまま動かしてみて、ちょっといじる

何も変更せずにそのまま動かしてみました。
$ cd brunch-practice
$ brunch watch --server
12 Dec 23:30:19 - info: application started on http://localhost:3333/
12 Dec 23:30:20 - info: compiled 29 files and 1 cached into 3 files, copied index.html in 769ms
localhost:3333 でリスンしてるよ、と表示されるのでブラウザで確認してみます。
このページは app/assets/index.html のようなので、適当に body 要素に hogehoge と書いてみました。すると変更を検知して自動的にビルドしてくれます。
12 Dec 23:33:35 - info: copied index.html in 68ms
再度 localhost:3333 にアクセスすると、変更が反映されていることがわかります。しかもブラウザも勝手に更新されてました。すごい。こうやって開発を進めていくわけですね。

プロダクション環境のビルド

以下のコマンドで、プロダクション環境のビルドが行われ、public ディレクトリに出力されます。デフォルトで js は全てミニファイされています。
brunch build --production

Brunch, 使ってみよう

自分が JavaScript の周辺フレームワークに疎いため、ひとつひとつを理解するのに時間がかかりそうですが、開発そのものはすごくスムーズに行えそうです。がんばるぞ。

2013年12月9日月曜日

WildFly の Web 基盤、Undertow の紹介

この記事は JavaEE Advent Calendar 2013 の 12/9 の記事です。

昨日は @n_agetsu さんの CDIでアプリケーション設定をインジェクション でした。
明日は @sk44_ さんの JSF で日本語ファイル名のファイルダウンロード? です。

このエントリでは、WildFly の Web コンテナである、Undertow のご紹介をしたいと思います。

WildFly って何?

WildFly は、OSS の Java EE アプリケーションサーバです。2013-12-09 時点でのリリースバージョンは 8.0.0.Beta1 であり、Java EE 7 の仕様がひと通り実装されています。
以前は JBoss Application Server(JBoss AS) と呼ばれていたものですが、商用サポート版である JBoss Enterprise Application Platform(JBoss EAP)と区別がつきづらいことや、JBoss を冠するプロダクトが複数あることから、アプリケーションサーバのランタイム固有の名称として WilfFly と改名されました。JBoss AS としての最後のメジャーバージョンが 7 であったため、WildFly はその数字を引き継いで 8 から始まっていて、基本的なアーキテクチャはそのまま踏襲されています。

その他 WildFly については @nekop さんの JBoss / WildFly (全部俺) Advent Calendar 2013 をご参考ください。全部俺て。

Undertow って何?

今回の本題の Undertow ですが、WildFly の Web サブシステムです。JBoss AS 7 から、Web や EJB、データソースなどはサブシステムという単位で設定を行うようになっています。JBoss AS 7 では 7 より前の JBoss の通り、Web サブシステムは JBossWeb という Tomcat ベースの Web/Servlet コンテナ実装を利用していました。WildFly では新たに Undertow を Web サブシステムの実装に利用しています。また、設定上も Web サブシステムから Undertow サブシステムと名称が変わっています。

Undertow の特徴

Undertow は Java で実装されたフレキシブルで高パフォーマンスな Web サーバであり、NIO ベースのブロッキング/ノンブロッキング API を提供します。 
Undertow はコンポジションベースのアーキテクチャを持ち、小さく単一な用途のハンドラと結びつけることで Web サーバを構築できます。このことにより、完全な Java EE の Servlet 3.1 コンテナ、低レベルなノンブロッキングハンドラ、またはその中間の何か、といった選択ができるような柔軟性を持っています。
Undertow はビルダ API を利用することで簡単に組み込めるよう設計されています。Undertow のライフサイクルは組込先のアプリケーションで完全にコントロールすることができます。
Undertow は JBoss によりスポンサードされており、WildFly アプリケーションサーバのデフォルトの Web サーバです。
ノンブロッキング I/O ということで、よりスケーラブルになっています。また、簡単に Web サーバを構築でき、ビルダ API を利用することでアプリケーションへの組み込みも簡単とのこと。Jetty のような使い方もできそうですね。
次に Why Undertow ということで特徴をまとめています。

  • 軽量
    • Undertow は軽量で、Undertow Core の jar のサイズは 1MB 以下です。ランタイムとしても軽量であり、シンプルな埋込みサーバであれば、ヒープサイズは 4MB 以下で動きます。
  • HTTP Upgrade のサポート
    • HTTP Upgrade をサポートしており、複数のプロトコルを HTTP ポートを介して利用することができます。
  • Web Socket のサポート
    • JSR-356 を含む、Web Socket をフルサポートしています。
  • Servlet 3.1
    • 埋込み Servlet を含む、Servlet 3.1 をサポートしています。また、同じデプロイ資材に対して Servlet とネイティブな Undertow のノンブロッキングハンドラを組み合わせることも可能です。
  • 埋め込み可能
    • 少ないコード量でアプリケーションに Undertow を埋め込むこともできますし、スタンドアロン実行することも可能です。
  • 柔軟性
    • Undertow サーバはハンドラにより設定が変更可能です。必要な機能を任意に追加可能で、利用しないものに対して注意を払う必要がありません。
HTTP Upgrade をサポートしており、このおかげで WildFly では最終的に HTTP の 8080 と管理用の 9990 の 2 つのポートのみしか利用しなくなる予定[1]です。EJB や JMS などで利用するプロトコルも、HTTP Upgrade されて利用されます。

[1]https://community.jboss.org/wiki/WildFly800Beta1ReleaseNotes

トップページの最後に Show me the code として、Hello World を返すだけの、しかし非同期 IO であるサーバを実行するコード例がありますので、試してみましょう。

以下にサンプルを作っています。

https://github.com/emag/undertow-practice

依存ライブラリは、undertow-core のみです。

  io.undertow
  undertow-core
  1.0.0.Beta25


サーバのコードとして、以下を作成します。
public class HelloWorldServer {

    public static void main(String[] args) {

        Undertow server = Undertow.builder()
            .addListener(8080, "localhost")
            .setHandler(new HttpHandler() {
                @Override
                public void handleRequest(final HttpServerExchange exchange) throws Exception {

                    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                    exchange.getResponseSender().send("Hello World");

                }
            }).build();
        server.start();
        System.out.println("HelloWorldServer is running!");
    }

}

非常にわかりやすいですね。localhost:8080 でリスンし、何をするかをハンドラとして設定します。ここでは Content-Type: text/plain として Hello World という内容のレスポンスを返します。
では、実際に実行してみます。
$ git clone https://github.com/emag/undertow-practice
$ cd undertow-practice
$ mvn clean compile exec:java -Dexec.mainClass=org.emamotor.undertow.practice.HelloWorldServer
[...]
HelloWorldServer is running!

サーバが立ち上がりました。リクエストしてみます。
$ curl localhost:8080 -v                           
* About to connect() to localhost port 8080 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
> 
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: text/plain
< Content-Length: 11
< 
* Connection #0 to host localhost left intact
Hello World%

おお、ちゃんと Hello World が返ってきています。Hello World しか返せませんが、これは確かに Web サーバです。API もわかりやすいですし、10数行程度でこれはすごいですね。残念ながら自分の環境では非同期 I/O なのかを確認するには至っていないので、いずれ高負荷時にどうなるのか確認してみたいです。
また、興味がある方は main メソッドからデバッグしてみるのも良いかと思います。依存関係からもわかるように、Undertow は XNIO という JBoss プロジェクトの 1 つを基盤として利用して I/O を処理しています。XNIO は NIO を補完するような低レイヤの API を提供しているようです。なんだか難しいフレームワークのようで、がんばって理解したいところです。。

この他にも、Undertow のリポジトリにサンプルが何種類か用意されていますので、お試しいただければと思います。Undertow 1台をリバースプロキシにして、他の Undertow サーバ 3 台をロードバランスする例などもあり、おもしろいですね。定番の WebSocket による Chat サンプルもあります。

Undertow Examples

また、Undertow にはいくつかのドキュメントもあります。いくつかは本ブログで和訳もしているので、ご参考いただければと思います。

http://undertow.io/documentation/index.html

WildFly と Undertow

ここまでは Undertow 単体の内容を見てきましたが、実際には Undertow 単体というよりは、WildFly の Web コンテナとして利用が主かと思いますので、最後にいくつか設定を見ていきたいと思います。

まず、以下より WildFly をダウンロードします。

http://wildfly.org/downloads/

現在(2013-12-09)時点では 8.0.0.Beta1 が最新版です。ダウンロードした wildfly-8.0.0.Beta1.zip を適当なディレクトリに展開すればインストール完了です。

 以下を実行し、WildFly をスタンドアロンモードで起動します。標準出力に起動ログが出力されますが、以下では Undertow に関連してそうなところのみ抜き出しました。
$ cd <WildFly のインストールディレクトリ>/bin
$ ./standalone.sh 
=========================================================================

  JBoss Bootstrap Environment

  JBOSS_HOME: /home/wildfly/wildfly-8.0

  JAVA: java

  JAVA_OPTS:  -server -XX:+UseCompressedOops -Xms1g -Xmx1g -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true

=========================================================================

[...]
06:12:02,534 INFO  [org.jboss.as] (MSC service thread 1-6) JBAS015899: WildFly 8.0.0.Beta1 "WildFly" starting
[...]
06:12:03,319 INFO  [org.xnio] (MSC service thread 1-10) XNIO version 3.1.0.CR7
06:12:03,325 INFO  [org.xnio.nio] (MSC service thread 1-10) XNIO NIO Implementation Version 3.1.0.CR7
[...]
06:12:03,425 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-2) JBAS017502: Undertow 1.0.0.Beta17 starting
06:12:03,431 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 49) JBAS017502: Undertow 1.0.0.Beta17 starting
[...]
06:12:03,529 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-15) JBAS017525: Started server default-server.
06:12:03,549 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 49) JBAS017527: Creating file handler for path /home/wildfly/wildfly-8.0/welcome-content
06:12:03,561 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-13) JBAS017531: Host default-host starting
06:12:03,591 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-11) JBAS017519: Undertow HTTP listener default listening on /127.0.0.1:8080
[...]
06:12:03,867 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.0.0.Beta1 "WildFly" started in 1856ms - Started 183 of 220 services (63 services are lazy, passive or on-demand)

WildFly が立ち上がったら、管理 CLI を起動します。プロンプトが変われば管理対象サーバ(localhost:9990)に接続できています。
$ cd <WildFly のインストールディレクトリ>/bin
$ ./jboss-cli.sh -c
[standalone@localhost:9990 /]

余談ですが、JBoss AS7 では CLI 接続に 9999 ポートを指定していましたが、上述したポート削減のため 9990(http-remoting) をデフォルトで利用するようになっています。なお、Beta1 の時点ではまだ 9999 でも接続することが可能です。9999 ポートを利用したい場合は以下のように、明示的にプロトコル(remote)を指定する必要があります。
$ ./jboss-cli.sh -c --controller=remote://localhost:9999
[standalone@localhost:9999 /]

全体設定


CLI に接続し、以下コマンドを実行します。
[standalone@localhost:9990 /] /subsystem=undertow:read-resource
{
    "outcome" => "success",
    "result" => {
        "default-server" => "default-server",
        "default-servlet-container" => "default",
        "default-virtual-host" => "default-host",
        "instance-id" => undefined,
        "buffer-cache" => {"default" => undefined},
        "configuration" => {
            "filter" => undefined,
            "handler" => undefined
        },
        "error-page" => undefined,
        "server" => {"default-server" => undefined},
        "servlet-container" => {"default" => undefined}
    }
}

以前の AS7 までの web サブシステムと、設定項目が変わっています。WildFly がベースになるであろう EAP 7 を利用する場合は設定の見直しが必要になると考えられます。
なお、AS 7.1.1.Final の web サブシステムは以下です。
[standalone@localhost:9999 /] /subsystem=web:read-resource
{
    "outcome" => "success",
    "result" => {
        "default-virtual-server" => "default-host",
        "instance-id" => undefined,
        "native" => "false",
        "configuration" => {
            "container" => undefined,
            "static-resources" => undefined,
            "jsp-configuration" => undefined
        },
        "connector" => {"http" => undefined},
        "virtual-server" => {"default-host" => undefined}
    }
}

また、先日リリースされた商用版である EAP 6.2.0(AS 7.3.0.Final-redhat-14)では以下です。
[standalone@localhost:9999 /] /subsystem=web:read-resource                
{
    "outcome" => "success",
    "result" => {
        "default-virtual-server" => "default-host",
        "instance-id" => undefined,
        "native" => false,
        "configuration" => {
            "container" => undefined,
            "static-resources" => undefined,
            "jsp-configuration" => undefined
        },
        "connector" => {"http" => undefined},
        "valve" => undefined,
        "virtual-server" => {"default-host" => undefined}
    }
}

valve 設定が増えていますね。

Handler


Undertow サブシステムには Filter や Handler という見慣れない設定が存在しています。ここでは Handler について少しだけ見てみます。
[standalone@localhost:9990 /] /subsystem=undertow/configuration=handler/
file           reverse-proxy

handler として file と reverse-proxy という設定が用意されています。file では localhost:8080 でアクセスしたときのウェルカムファイルの設定が行われています。
変わり種は reverse-proxy ですね。Undertow 単体で reverse-proxy の設定ができるようになっています。今後別エントリで試してみたいと思います。すぐに試してみたい方は、以下のビデオで設定が載っていましたので、ご覧ください。

  • Dive Into WildFly 8
    • Reverse Proxy については 45:05 くらいから言及されています。

アクセスログの設定


アクセスログの設定も以前とパラメータが変わっています。設定後は反映に再起動が必要です。
[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/host=default-host/setting=access-log:add
[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/host=default-host/setting=access-log:read-resource
{
    "outcome" => "success",
    "result" => {
        "directory" => expression "${jboss.server.log.dir}",
        "pattern" => "common",
        "prefix" => "access_log",
        "rotate" => true,
        "worker" => "default"
    }
}
[standalone@localhost:9990 /] :reload

最後に

Java EE アプリケーションサーバにとって、Web コンテナはその根幹をなす非常に大切なものです。今まで JBoss AS は、Tomcat という伝統ある Web コンテナをベースにしてきましたが、WildFly にて刷新されました。刷新の理由はノンブロッキング API であったり、HTTP Upgrade のためだったりと様々ですが、近年の Web に対応するために色々な需要を取り込んでいることが伺えます。
今後、WildFly が正式リリースされるまでにどう仕上がっていくか楽しみですね。

参考

  • WildFly 8 Webinar Recording
    • Undertow について、30:05 くらいからスペックリードの  Stuart Douglas 氏が解説しています。

2013年12月1日日曜日

WildFly に Byteman をアタッチさせる

WildFly に Byteman をアタッチさせる手順メモ。
環境はスタンドアロンを想定しています。

Byteman のダウンロードとインストール

個人的な趣味で恐縮ですが /opt 以下にインストールし、byteman とエイリアスをさせます。ダウンロードする URL やファイル名が変わらない限りは、BYTEMAN_VERSION を変更するだけで動作すると思います。
BYTEMAN_VERSION="2.1.3"
BYTEMAN_BINARY="byteman-download-$BYTEMAN_VERSION"
BYTEMAN_DOWNLOAD_URL="http://downloads.jboss.org/byteman/$BYTEMAN_VERSION/byteman-download-$BYTEMAN_VERSION-bin.zip"
cd /opt
wget -qO- -O tmp.zip $BYTEMAN_DOWNLOAD_URL && unzip tmp.zip && rm -f tmp.zip && ln -s $BYTEMAN_BINARY byteman

WidlFly 起動時に Byteman をアタッチ

以下の JVM 起動オプションを <WildFly のインストールディレクトリ>/bin/standalone.conf に追記します。
BYTEMAN_HOME=/opt/byteman
BYTEMAN_RULE=/path/to/somerule.btm
BYTEMAN_OPTS="-javaagent:$BYTEMAN_HOME/lib/byteman.jar=listener:true,boot:$BYTEMAN_HOME/lib/byteman.jar"
if [ "x$BYTEMAN_RULE" != "x" ]; then
  BYTEMAN_OPTS="${BYTEMAN_OPTS},script:$BYTEMAN_RULE"
fi
BYTEMAN_OPTS="$BYTEMAN_OPTS -Dorg.jboss.byteman.transform.all
-Dorg.jboss.byteman.debug"
JAVA_OPTS="$BYTEMAN_OPTS $JAVA_OPTS"
後は BYTEMAN_RULE で指定しているパスを適宜適用したいルールのファイルを設定すれば完了です。試しに WildFly の起動/終了時にログを出させるルールを wildfly-begin-end.btm 等として適用してみます。ルールの内容は以下です。WildFly の起動と停止メソッドの終了に合わせてログを出力しています。

起動および停止を行うと、以下のようなログが出力されます。
# 起動時
[...] ...
[...] INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.0.0.Beta1 "WildFly" started in 2058ms - Started 181 of 218 services (62 services are lazy, passive or on-demand)
[...] INFO  [stdout] (Controller Boot Thread) Default helper activated
[...] INFO  [stdout] (Controller Boot Thread) Installed rule using default helper : WILDFLY_STARTED
[...] INFO  [stdout] (Controller Boot Thread) WildFly started with Byteman!

# 停止時
[...] ...
[...] INFO  [org.jboss.as] (MSC service thread 1-2) JBAS015950: WildFly 8.0.0.Beta1 "WildFly" stopped in 18ms
[...] INFO  [stdout] (MSC service thread 1-2) Installed rule using default helper : WILDFLY_STOPPED
[...] INFO  [stdout] (MSC service thread 1-2) WildFly stopped with Byteman!

参考