Javaで動的にプラグインを読むシステムを実現する方法について考えようとした結果Jabotなるものが出来た
r7kamura/ruboty · GitHub のJava移植版
Jabot/Rubotyについて
凡そRubotyについての説明になるが、プラガブルなChat専用Botである
+------+ +---------+ +---------+ +-------+ | User | <==> | Adapter | <==> | Handler | <==> | Brain | +------+ +---------+ +---------+ +-------+
Userのチャットに対しAdapterが会話を受信したり送信したりする機能を持つ。Adapterにはシェル上で対話機能を実現するShellAdapterや、Slackでのメンションを受信するSlackAdapterなどが存在する。受信したメッセージは複数のHandlerを経由し、Handler毎に定義されたアクションを行う。例えば、PingHandlerには、PING
というメッセージがあればPONG
を返すのようなものが定義されている。また永続化層としてBrainが用意されており、これを利用すると特定の語を違う語に置き換えるルールを保存すると、適宜後続のHandlerに変換されたメッセージを送ったり出来るReplaceHandlerなどが作れる。
まさにこのRubotyが持つプラグインシステムが今回試したかったものだった。
プラグインシステム
Adapter, Handler, BrainをまとめてPluginと呼ぶと、利用したいPluginだけを用意・宣言しておいて使い分けたくなる。Rubotyでは必要なHandlerなどをGemfileに記述するだけで、クラスが定義される際にRuboty本体へ情報が保存されるようになっている。Jabotでは、以下のようなplugins.yml
を利用する事でプラグインシステムを成立させるようにした。プラグイン毎に必要なoptionなどもまとめて記述出来るのでわりと理に適っているように思う。
name: jabot adapter: # require one adapter plugin: com.krrrr38.jabot.plugin.adapter.ShellAdapter namespace: shell-adapter options: prompt: "> " handlers: - plugin: com.krrrr38.jabot.plugin.handler.HelpHandler namespace: help-handler - plugin: com.krrrr38.jabot.plugin.handler.PingHandler namespace: ping-handler brain: plugin: com.krrrr38.jabot.plugin.brain.InmemoryBrain namespace: inmemory-brain
Java側で動的にプラグインを読む仕組みとして、今回はgitbucketを参考にした。gitbucketではデフォルトパッケージにPluginというクラスを予め用意する事で様々なPluginを読み込んでいる。今回は設定ファイルがあるので、特に気にする事なくパッケージ名から情報を記述するようにし、起動時に必要なPluginを読み込みようにした。
新しいPluginを作成するには、予め抽象クラスでAdapter
、Handler
、Brain
が用意されているので、それらに合うような実装をし、classpathの通る所にjarを入れた上でplugins.ymlに必要な情報を追記すれば良い。例えば新しいAdapter
を作る際には、どのようにしてデータを受信するのか、どのようにして送信するのか、接続時のアクションなどを定義すれば完成である。
appassembler-maven-plugin / Jabotの使い方
Javaの制約として、コマンドラインツールの作りにくさが挙げられる。Jabotを試したいのならGitHubのReleaseページにある最新のものからjabot-app-*-executable.zip
をダウンロードし、解凍した後そのディレクトリでbin/jabot
と打てば実行出来る。
これが出来たのはappassembler-maven-plugin
が以下のような構造でzipやtar.gzを作ってくれるためである。bin以下のファイルは定義しておいたMainClassを実行するのに十分なクラスパスなどを記述したシェルスクリプトになっている。
├── plugins.yml ├── bin │ ├── jabot │ └── jabot.bat └── lib ├── jabot-echo-handler.jar ├── jabot-shell-adapter.jar └── ... (more custom plugin jar)
まぁ
jabot-handler-pluginだけを使って独自のHandlerを作って欲しかったりと、そんな利用もありーのpluginをmavenのモジュールとかで作ったせいで、リリース作業でmavenに10数個完成物投げたりしたのは面白かった
基本的にはRubotyを移植しただけなんで2日程しか手つけてないし、
ちょっとjava書きたくなった結果Rubotyパクったもの出来たけどもうモチベーション消えた
— かる (@krrrr38) August 16, 2015
だそうだ。