XML-RPC してみる Part 3

今回も まだまだ引き続き XML-RPC について。

前回 NetBeans 6.9 を使って 簡単なアプリケーションを作成してみたものの...
実は そのアプリケーションには

XML-RPC の実行が終了するまで 何も操作できなくなる
という誰にも言えない問題があったのです。
もし、運悪く XML-RPC がレスポンスを返してくれなかったら 完全にフリーズしてしまいます。

この原因は XML-RPC の実行の仕方にあります。
JavaFX は基本的に 全ての処理を EDT と呼ばれる たった一つのスレッドで 実行しています。
もちろん 全ての処理には 描画処理やイベント処理等も含まれています。
前回のサンプルのように何も考えずにコーディングしてしまったら...
比較的 処理時間の長い XML-RPC が EDT で実行されてしまい、暫くの間 それ以外の処理は全てブロックされ アプリケーションはフリーズしてしまいます。
EDT は XML-RPC の返事をただ待っているだけなのに...
これは XML-RPC に限った話ではありません。
ファイルシステム、データベース、その他の WEBサービス等も同様です。

この問題を解決するのは とっても簡単...

XML-RPC は EDT 以外のスレッドで処理すれば良い
だけです。 方法は
  • XmlRpcClient#execAsync(String, Object[], AsyncCallBack) を使う。
  • javafx.async を使う。
の2つが考えられます。
javafx.async は 過去の日記 にも書きましたが ActionTask を使って とっても簡単に実装できます。
しかし 折角 ライブラリで非同期処理をサポートしているのに 使わない手はありません。
と言うことで 今回は XmlRpCClient#execAsync(String, Object, AsyncCallBack) を使って実装してみることに...

こちらも使い方はとっても簡単です。
前回との違いは buttonAction 関数だけです。
非同期で処理をするために executeAsync(String, Object, AsyncCallback) に 変更しています。
後は XML-RPC の処理が完了した際に呼び出されるコールバック関数として AsyncCallback インターフェースを実装するだけです。
JavaFX の場合 インターフェースの実装は 関数に override を付けるだけです。
更に JavaFX のいいところは 引数や戻り値の型を指定しなくても勝手にコンパイラが推測してくれるところです。

    function buttonAction(): Void {
        client.executeAsync("bookmark.getTotalCount", [ textBox.text ], AsyncCallback {
            override function handleResult(request, result) {
                label.text = "{result} users";
            }
            override function handleError(request, e) {
                e.printStackTrace();    // 今回は何も考えず スタックトレース出力
            }
        });
    }
実は このコードにもまだ問題があります。
JavaFX には忘れてはならないお約束が一つだけあるのですが
それは...
Node の属性は 必ず EDT で変更しよう
です。
このお約束を守らずに作られたアプリケーションは デッドロックを起こして フリーズしてしまいます。
この辺りの話も 既に 過去の日記 に書いてるので、そちらも参考になるかもしれません。

で、結局 buttonAction 関数は こんな感じになりました。
上記との違いは FX.deferAction(function():Void) で label.text の内容を変更しているところです。
この FX.deferAction(...) の引数に渡した関数は EDT で実行されるのです。

    function buttonAction(): Void {
        client.executeAsync("bookmark.getTotalCount", [ textBox.text ], AsyncCallback {
            override function handleResult(request, result) {
                FX.deferAction(function(): Void {
                    label.text = "(result} users";
                });
            }
            override function handleError(request, e) {
                e.printStackTrace();    // 今回は何も考えず スタックトレース出力
            }
        });
    }

上記のように ちょっとだけ注意すれば XML-RPC を利用するのは とっても簡単です。
ライブラリさえあれば 何も知らなくても誰でも利用できそうですね。
Apache XML-RPC には プロキシの仕組みも実装されているようなので、 それを使えば 完全に XML-RPC を意識することなく メソッドを実行できるようになるみたい...
いつか また時間があるときにまとめてみようかな...
最近は 完全に REST に押されている XML-RPC ですが まだまだ 利用できる仕組みだと思います。

実は REST よりも XML-RPC を先に試したのには理由があります。
それは Trac との連携がしたかったから...
自分は 仕事でもプライベートでも毎日のように Trac を利用しているのですが、 WEB のインターフェースはお世辞にも使い易いとは言えません。
それなら TracJavaFX を連携させちゃえばいいじゃんという安易なことを考えていたりして...