MessagePack-RPCでJavaとPythonで連携してみる

# 前書き
JavaとPythonで作ったシステムを統合したい，Javaで実装したシステムをPythonスクリプトで気軽に操作できるようにしたい，という必要に迫られて実験．
最初は自分で適当にプロトコル決めるかなーとか思っていたけど，MessagePack-RPCがとっても便利そうだったのでのっかることに．

# やってみたこと
要は，Java側のメソッドをPythonから呼ぶ，Python側のメソッドをJavaから呼ぶというのがしたいこと．もちろん，引数や返り値も扱えないといけない．
というわけで，今回は，

- 文字列を渡してとHelloつきの文字を返してもらう(hello)
- 2つの引数を渡して足した値を返してもらう(add)
- 数の配列を渡して合計値を返してもらう(sum)
- 数の配列を渡して，matplotlibで作った折れ線グラフイメージを返してもらう(make_graph)

というのをやってみます．サーバー側がPython，クライアント側がJavaです．

# コード
## Python側のコード

``` server.py
import msgpackrpc
import matplotlib.pyplot as plt
from PIL import Image

class TestServer(object):

    def hello(self, mesg):
        print(mesg)
        return ("Hello, " + mesg.decode()).encode()

    def add(self, a, b):
        return a + b

    def sum(self, d):
        return sum(d)

    def make_graph(self, d):
        plt.plot(d)
        plt.savefig('hoge.png')
        f = open('hoge.png', 'rb')
        d = f.read()
        f.close()
        return d

server = msgpackrpc.Server(TestServer())
server.listen(msgpackrpc.Address("localhost", 1985))
server.start()
```

## Java側のコード

``` TestClient.java
import org.msgpack.rpc.Client;
import org.msgpack.rpc.loop.EventLoop;
import org.msgpack.type.Value;

import java.io.*;
import java.util.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.*;

public class TestClient {

    public static void main(String[] args) throws Exception {

        EventLoop loop = EventLoop.defaultEventLoop();
        Client client = new Client("localhost", 1985, loop);
                int v;

        System.out.println(" --- hello ---");
        Value result = client.callApply("hello", new Object[]{"miyo"});
        System.out.println("Result type:" + result.getType());
        String s = new String(result.asRawValue().getByteArray());
        System.out.println(s); // Hello, miyo
        System.out.println();

        System.out.println(" --- add --- ");
        result = client.callApply("add", new Object[]{100, 10}); // 110
        System.out.println("Result type:" + result.getType());
        v = result.asIntegerValue().getInt();
        System.out.println("result = " + v + " :" + (v == 110));
        System.out.println();

        System.out.println(" --- sum --- ");
        result = client.callApply("sum", new Object[]{new int[]{1, 2, 3, 4, 5}}); // 15
        System.out.println("Result type:" + result.getType());
        v = result.asIntegerValue().getInt();
        System.out.println("result = " + v + " :" + (v == 15));
        System.out.println();

        System.out.println(" --- make graph ---");
        result = client.callApply("make_graph",
                                  new Object[]{new int[]{1,2,4,8,10,3,6,8,9,-1}});
        System.out.println("Result type: " + result.getType());
        byte[] raw = result.asRawValue().getByteArray();
        BufferedImage img = ImageIO.read(new ByteArrayInputStream(raw));
        System.out.println(img);
        Icon icon = new ImageIcon(img);
        JOptionPane.showMessageDialog(null,
                                      "",
                                      "image",
                                      JOptionPane.PLAIN_MESSAGE,
                                      icon);
        client.close();
        loop.shutdown();
    }
}

```

# 実行結果
実行したターミナルの様子はこんな感じ
![result_console.PNG](https://qiita-image-store.s3.amazonaws.com/0/25342/b861a491-269b-8e7e-a9b3-fb4c2c7000e5.png)

Pythonで生成したグラフもちゃんと表示できた
![result_graph.PNG](https://qiita-image-store.s3.amazonaws.com/0/25342/df3d181d-2dec-172e-73bf-668b0121e0b7.png)

# で
いやー，便利だわ!!

# 参考
いろいろ参考にしすぎてメモしそこねた...
- https://github.com/msgpack/msgpack-java/wiki/QuickStart
- http://grepcode.com/file/repo1.maven.org/maven2/org.msgpack/msgpack/0.6.4/org/msgpack/type/Value.java#Value
- https://github.com/msgpack-rpc/msgpack-rpc
- https://github.com/msgpack-rpc/msgpack-rpc-java
- https://github.com/msgpack-rpc/msgpack-rpc-python
- http://www.ne.jp/asahi/hishidama/home/tech/java/image.html
- http://d.hatena.ne.jp/heavenshell/20110802/1312277616