Playframework2で自作プラグインを作る

Playframeworkのプラグイン*1とは?

Playframeworkはプラグインにより機能拡張できるのですが、Playframeworkにおけるプラグインって何なん?というのは僕の中でも結構フワフワしています。
結局のところただのライブラリっぽいのですが、ライブラリではなくプラグインとして組み込むことの利点は、フレームワークの起動時、及び終了時に、フレームワークに任意の処理を実行してもらえるところですかね?
故に、何らかのデータストアへアクセスしたり、テンプレートエンジンを履き替えたりといった「何らかの初期化処理がないと使えないんだけど、アプリ内からそういうのに感心を持ちたくない」ようなモノがプラグイン化に値するのかなーと思ってます。

プラグインを作るには

Playアプリに組み込む際にはjarになっててクラスパスに入ってれば何でもいい*2ので、mavenで作ろうが、sbtで作ろうがgradleで作ろうが自由です。
僕は後者2つが勉強不足でよく分からなかったのでmavenで作りました。

pom.xml

<repositories>
	<repository>
		<id>typesafe</id>
		<url>http://repo.typesafe.com/typesafe/releases/</url>
	</repository>
</repositories>

上のリポジトリを追加し、更に

<dependency>
	<groupId>play</groupId>
	<artifactId>play_2.10</artifactId>
	<version>2.1.0</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>play</groupId>
	<artifactId>play-java_2.10</artifactId>
	<version>2.1.0</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>play</groupId>
	<artifactId>play-test_2.10</artifactId>
	<version>2.1.0</version>
	<scope>test</scope>
</dependency>

な依存性を追加します。Playのバージョンはお使いのPlayのバージョンに合わせてください。
scalaで書く場合はplay-javaは必要ありませんが、javaで書く場合は必要です。play_x.xxはplay-java_x.xxの依存性にひっついてきてるのでplay-javaを指定した場合は必要ないかもしれません。
テストを書く場合はplay-testが必要です。

作成

これで、プラグインを作るのに必要なクラス群が手に入ったので、いよいよプラグインを作成します。と言っても、最低限の枠組みしか用意されてないので、やるべきことはほとんどありません。

javaの場合、play.Pluginを継承した以下の様なクラスを作ります

package hoge;

import play.Application;
import play.Plugin;

public class HogePlugin extends Plugin {

	public HogePlugin(Application app) {
	}

	@Override
	public boolean enabled() {
	}

	@Override
	public void onStart() {
	}

	@Override
	public void onStop() {
	}

	public void hello() {
		System.out.println("hello!!!!!!!");
	}
}

Applicationを引数とするコンストラクタは必須ですが、各メソッドのオーバーライドは任意です。
フレームワーク起動時に

  1. コンストラク
  2. enabled
  3. onStart

の順でコールされます。
enabledがtrueを返すとこのプラグインは有効化されていると判断され、フレームワークはコンストラクタで生成したプラグインクラスのインスタンスを保持します。
保持されたインスタンスはアプリ側からは以下のようにして取得して利用できます。

HogePlugin plugin = Play.application().plugin(HogePlugin.class); //enabledがfalseを返した(プラグインが無効化されている)場合、nullが返る
plugin.hello();

onStopはフレームワーク終了時に呼ばれます。

と、枠組みとしてあるのはホントにこの程度のものなので、あとはいい感じにしてください、と言う感じ。
例えば、あるデータストアに接続するプラグインならapplication.confに特定のキーで接続情報やプラグイン有効化フラグを記述するような決まりにしておいて、コンストラクタかenabledメソッドで設定情報を取得、プラグインの有効無効を判断*3インスタンスメソッドで機能を提供、という感じになると思います。


このエントリ書くのに、練習がてら作ってみたプラグイン置いておきます(Play2.1用です)
https://github.com/kamekoopa/play-thymeleaf-plugin

ところで

プラグインクラスのインスタンスを取得するのに

Play.application().plugin(HogePlugin.class);

これ、面倒じゃないですかね?

public static void doHello() {
	Play.application().plugin(HogePlugin.class).hello();
}

プラグインクラスにこういう感じで書けば、アプリ内で使うときには

Hoge.doHello();

こういう感じでかけて楽だと思うんですが*4、流儀的にはどうなんでしょうか…?


*1:このエントリではplayコンソール系のプラグインについては扱いません

*2:Build.scalaに依存性追加するなり、libディレクトリに直接jar突っ込むなり

*3:これらの処理ってコンストラクタとenabledメソッド、どちらに書くのが妥当なんですかね?

*4:上で公開してるプラグインがそういう感じの実装になってます