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!

参考