AnyEvent::MPRPC から MessagePack-RPC Java の接続

2011/08/08 追記
AnyEvent::MPRPC を修正して頂いた。ver 0.10 では解消済み。


Perl の AnyEvent::MPRPC::Client を使用して MessagePack-RPC Java サーバに接続した際にメソッドコールを行っても何もデータが応答がない。


クライアント側の実装。

#!/usr/bin/env perl
use strict;
use warnings;
use AnyEvent::MPRPC::Client;
use Data::Dumper;

my $client = AnyEvent::MPRPC::Client->new(
    host => '127.0.0.1',
    port => 1985
);
my $d = $client->call('echo', ['foo bar']);

my $res;
eval { $res = $d->recv };
if (my $error = $@) {
    warn Dumper $error;
}
warn Dumper $res;

サーバ側。

package jp.heavenshell
import org.msgpack.rpc.Server;
import org.msgpack.rpc.loop.EventLoop;

public class ServerApp {
    public String echo(String msg) {
        System.out.println(msg);
        return "hello " + msg;
    }
    
    public static void main(String[] args) {
        EventLoop loop = EventLoop.defaultEventLoop();

        Server svr = new Server();
        svr.serve(new ServerApp());
        try {
            svr.listen(1985);

            loop.join();
        } catch (Exception e) {
            e.getStackTrace();
        }
    }
}

で、MessagePack-RPC Java のソースを Eclipse からデバッグ実行をしてみた。
src/main/java/org/msgpack/rpc/transport/RpcMessageHandler.java の handleMessageImpl(MessageSendable channel, MessagePackObject msg) メソッド内にブレークポイントを張って実行する。

private void handleMessageImpl(MessageSendable channel, MessagePackObject msg) {
    MessagePackObject[] array = msg.asArray();

    // TODO check array.length
    int type = array[0].asInt();
    if(type == Messages.REQUEST) {
        // REQUEST
        int msgid = array[1].asInt();
        String method = array[2].asString();
        MessagePackObject args = array[3];
        handleRequest(channel, msgid, method, args);

     } else if(type == Messages.RESPONSE) {
//-snip-
     }

ここの int msgid = array[1].asInt(); にステップオーバした瞬間に落ちた。
array の中に何が入っているかデバッグ実行で表示したら以下の様な値が入っている。

array  MessagePackObject[4]
  [0]  ShortIntegerTypeIMPL
  [1]  RawType
  [2]  RawType
  [3]  ArrayType

これをクライアントが Python の場合以下の場合のようになった。

array  MessagePackObject[4]
  [0]  ShortIntegerTypeIMPL
  [1]  ShortIntegerTypeIMPL
  [2]  RawType
  [3]  ArrayType

MessagePack-RPC の Request の Spec は以下の用に定義されている。

msgid

The 32-bit unsigned integer number. This number is used as a sequence number. The server replies with a requested msgid.

http://wiki.msgpack.org/display/MSGPACK/RPC+specification#RPCspecification-RequestMessage

というわけで [1] に RawType が来ているのが原因っぽい。


Data::MessagePack には Pure Perl の実装があって、$ENV{PERL_ONLY} で判定しているので、export PERL_ONLY=pp として実行すると、[1] ShortIntegerTypeIMPL となって結果が正しく取得できた。

$ export PERL_ONLY=pp
$ perl client.pl
hello foo bar

ということで Data::MessagePack の XS 実装が怪しいことまでわかった。