Playframework1.2系 公式ドキュメント読解・写経 1.主要な概念:クラス拡張

公式ドキュメントの読解及び写経再開。形式的には各ドキュメントを順次読み進めて行って、気になる所を横展開・深堀りしていければ。

主に公式ドキュメントを読解対象とする予定ですが、関連キーワードで漁って見つかった内容や、下記書籍『Play Framework Cookbook』等の該当項目も適宜参照して行ければと思います。必要とあらば書籍の適当訳・写経等もガンガン盛り込む方向で。

Play Framework Cookbook: Over 60 Incredibly Effective Recipes to Take You Under the Hood and Leverage Advanced Concepts of the Play Framework

Play Framework Cookbook: Over 60 Incredibly Effective Recipes to Take You Under the Hood and Leverage Advanced Concepts of the Play Framework

クラス拡張とは?

当エントリではこちら、『クラス拡張』について。

翻訳されたドキュメントを一読してみる…がしかし、いまいちストンと理解が来ない。( ̄〜 ̄) 同じバージョンの原典を見てみる。こちらでは『Class enhancement』となっている。"クラスの強化"?

いずれにしても、Playframeworkには既存内容にPlugin形式で機能を追加・付与する仕組みが提供されているようだ(という理解)。


ドキュメントで言及されているPlayPluginのAPIを覗いて見る。サブクラスには以下のようなクラスがある模様。Javadoc APIに記載されている内容で概要レベルで有用そうな情報が書かれているものについては併せて記載してみた。用途に応じて色々な拡張ポイントがあるようです。

Plugin that reads list of plugins to disable from application.conf To disable plugins, specify it like this in application.conf:
plugins.disable=full-plugin-class-name plugins.disable.0=full-plugin-class-name plugins.disable.1=full-plugin-class-name plugins.disable.whatever=full-plugin-class-name
Plugin used for core tasks
Handles migration of data. Does only support the default DBConfig
Creates temporary folders for file parsing, and deletes it after request completion.
Simple HTTP client to make webservices requests.

Get latest BBC World news as a RSS content

    HttpResponse response = WS.url("http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml").get();
    Document xmldoc = response.getXml();
    // the real pain begins here...
 
Search what Yahoo! thinks of google (starting from the 30th result).

    HttpResponse response = WS.url("http://search.yahoo.com/search?p=%s&pstart=1&b=%s", "Google killed me", "30").get();
    if( response.getStatus() == 200 ) {
       html = response.getString();

Enhancerって?

PlayframeworkとEnhancer/EnhancementあたりのキーワードでWebを漁ってたら上記のページがヒットした。まだ内容は読んでない。

上記ページなりパッケージのクラスをパッと見る感じでは、Pluginの仕組みを使えば色々拡張が出来て、そこでenhancer/enhancementというものを使ってそれら機能を実現してる…みたいな感じなのかな?どうなんだろ。

クラス拡張→Moduleという概念

『Playframework + プラグイン』というキーワードだと、以下のエントリ等がヒットする。がしかし、情報が端折られているのか一番上のエントリ内容ではゴール(アプリケーションアクセスの際に文字列出力)にまで辿り着けず。


書籍『Playframework Cookbook』を見てみると、そのものズバリで詳細解説を行っている章が存在したので、当エントリではその部分を適当訳しつつ、ひとまずのゴールまでの道のりをメモして行こうと思います。

Chapter 5: Introduction to Writing Modules(モジュール作成入門)
    Introduction(はじめに)
    Creating and using your own module(独自のモジュール作成・利用)
    Building a flexible registration module(柔軟な登録モジュールの実装)
    Understanding events(イベントの理解)
    Managing module dependencies(モジュール依存管理)
    Using the same model for different applications(異なるアプリケーションで同じモデルを使う)
    Understanding bytecode enhancement(バイトコード拡張の理解)
    Adding private module repositories(リポジトリへのプライベートモジュールの登録)
    Preprocessing content by integrating stylus(スタイラス統合によるコンテンツの前処理)
    Integrating Dojo by adding command line options(コマンドラインオプションの追加によるDojoの統合)

『Playframework Cookbook』適当訳&写経 Chapter 5:
Introduction to Writing Modules - Creating and using your own module
(モジュール作成入門 - 独自のモジュール作成・利用)

適当訳っつうか流れをカバーする為の文言をGoogle先生にカバーしてもらいながら超〜適当に書き殴ってるだけなのでその辺ご容赦を。

環境はWindows7/Java JDK7/Eclipse4.2/Play1.2.5。パスとかは適宜読み替えてください。

モジュール作成:play new-module

まずは新規モジュール作成【play new-module】。書籍の内容にならいモジュール名は【firstmodule】とする。

C:\eclipse4.2\workspace>play new-module firstmodule
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ The new module will be created in C:\eclipse4.2\workspace\firstmodule
~
~ OK, the module is created.
~ Start using it by adding this line in the application.conf modules list:
~ module.firstmodule=C:\eclipse4.2\workspace\firstmodule
~
~ Have fun!
~

C:\eclipse4.2\workspace>
Ant実行環境の導入

そのままモジュールのビルド【play build-module】を実行してみる。所定の場所にzipファイルは出来るものの、途中でant実行に関するエラーが出ている。どうやらAnt実行環境も必要なようです。

C:\eclipse4.2\workspace>play build-module firstmodule
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ What are the playframework versions required?
~
~ Building...
~
'ant' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
~
~ Packaging firstmodule-0.1 ...
~
~ Done!
~ Package is available at C:\eclipse4.2\workspace\firstmodule\dist\firstmodule-0.1.zip
~

C:\eclipse4.2\workspace>

Ant公式からアーカイブファイル(Zip)を入手→解凍、ANT_HOMEとPATHにそれぞれパスを通しバージョンが表示される所までざっくり確認。

※ANT_HOME C:\apache-ant-1.8.4 (新規追加)
※PATH %ANT_HOME%/bin          (既存追記)
--
C:\>ant -version
Apache Ant(TM) version 1.8.4 compiled on May 22 2012


再度【play build-module】を実行し、antに関するエラーが出ない事を確認。このコマンドは後ほど改めて実行する事になります。

モジュール取り込み元のプロジェクト作成・諸設定

今度は取り込む側のプロジェクトを作成。プロジェクト名は【playfw】としてみる。以下のコマンドでプロジェクトを作成し、Eclipseで取り込む。

C:\eclipse4.2\workspace>play new playfw
C:\eclipse4.2\workspace>play deps playfw
C:\eclipse4.2\workspace>play ec playfw

conf/dependencies.ymlに、以下の内容を追記。

# Application dependencies

require:
    - play
    - customModules -> firstmodule  【←当該行追記】

repositories:                       【←repositories以下追記】
    - playCustomModules:
        type:    local
        artifact:    "C:\\eclipse4.2\\workspace\\firstmodule"
        contains:
            - customModules -> *


取り込み元プロジェクト内で依存性解決【play deps】実施。モジュールが取り込まれているのが確認出来る。

C:\eclipse4.2\workspace>play deps playfw
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ Resolving dependencies using C:\eclipse4.2\workspace\playfw\conf\dependencies.yml,
~
~       customModules->customModules -> (from playCustomModules)
~
~ Installing resolved dependencies,
~
~       modules/firstmodule -> C:\eclipse4.2\workspace\firstmodule
~
~ Done!
~

C:\eclipse4.2\workspace>
モジュール取り込み対象のプロジェクトで必要なクラスを作るなど

今度は取り込み対象のプロジェクトにてJavaクラスを作成。PlayPluginクラスを拡張して以下のようなクラスを作成。アプリ初回起動時(デバッグモードでは起動後の初回ブラウザアクセス時)に動く部分にひとつ噛ませてみる。

package play.modules.firstmodule;

import play.PlayPlugin;

public class MyPlugin extends PlayPlugin {
	public void onApplicationStart() {
		System.out.println("Yeeha, firstmodule started!");
	}
}

クラス作成に併せて、src/play.pluginsファイルに以下の記載を追加。数字は優先順位だったと思うが値は適当で(良かったはず)。

1000: play.modules.firstmodule.MyPlugin
モジュールのビルド実施:play build-module

ディレクトリを移動してビルドコマンドを実行【play build-module】。(もしくはモジュールプロジェクト名付加で実行)
ビルドを行う事でzipファイルが作成される。またビルドの結果、モジュールプロジェクト内のlib/フォルダにjarファイルが生成されている事も確認出来る。

C:\eclipse4.2\workspace\firstmodule>play build-module
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ What are the playframework versions required?
~
~ Building...
~
Buildfile: C:\eclipse4.2\workspace\firstmodule\build.xml

check:

compile:
    [mkdir] Created dir: C:\eclipse4.2\workspace\firstmodule\tmp\classes
    [javac] C:\eclipse4.2\workspace\firstmodule\build.xml:44: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable b
uilds
    [javac] Compiling 1 source file to C:\eclipse4.2\workspace\firstmodule\tmp\classes

build:
     [copy] Copying 1 file to C:\eclipse4.2\workspace\firstmodule\tmp\classes
      [jar] Building jar: C:\eclipse4.2\workspace\firstmodule\lib\play-firstmodule.jar  【←jar作成】
   [delete] Deleting directory C:\eclipse4.2\workspace\firstmodule\tmp

BUILD SUCCESSFUL
Total time: 4 seconds
~
~ Packaging firstmodule-0.1 ...
~
~ Done!
~ Package is available at C:\eclipse4.2\workspace\firstmodule\dist\firstmodule-0.1.zip
~

C:\eclipse4.2\workspace\firstmodule>
動作確認

取り込み元で再度依存性解決を行い、

C:\eclipse4.2\workspace>play deps playfw
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ Resolving dependencies using C:\eclipse4.2\workspace\playfw\conf\dependencies.yml,
~
~       customModules->customModules -> (from playCustomModules)
~
~ Installing resolved dependencies,
~
~       modules/firstmodule -> C:\eclipse4.2\workspace\firstmodule
~
~ Done!
~

C:\eclipse4.2\workspace>

アプリ起動→ブラウザにて http://localhost:9000/ にアクセス。ブラウザアクセス時点で文言が出力されている(=プラグイン連携が上手く行った)事が確認出来ました♪ヽ(′∀`)ノ

C:\eclipse4.2\workspace>play run playfw
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \| |/ _' | || |_|
~ |  __/|_|\____|\__ (_)
~ |_|            |__/
~
~ play! 1.2.5, http://www.playframework.org
~
~ Ctrl+C to stop
~
CompilerOracle: exclude jregex/Pretokenizer.next
Listening for transport dt_socket at address: 8000
XX:XX:XX.XXX INFO  ~ Starting C:\eclipse4.2\workspace\playfw
XX:XX:XX.XXX INFO  ~ Module firstmodule is available (C:\eclipse4.2\workspace\firstmodule)
XX:XX:XX.XXX WARN  ~ You're running Play! in DEV mode
XX:XX:XX.XXX INFO  ~ Listening for HTTP on port 9000 (Waiting a first request to start) ...
Yeeha, firstmodule started!  【←ログ出力確認!】
XX:XX:XX.XXX INFO  ~ Application 'playfw' is now started !


ざっくり手順の流れをまとめるとこんな感じか。

※Play,Ant実行環境を事前に用意
(1).play new-moduleでモジュール枠作成
(2).1で作ったプロジェクトにPlugin拡張クラスを作成  (取り込み対象プロジェクト)
(3).play.pluginsファイルに定義を追加               (取り込み対象プロジェクト)
(4).(念の為)モジュールプロジェクト上でビルド確認   (取り込み対象プロジェクト)
(5).取り込み対象プロジェクトのconf/dependencies.ymlに定義を追加   (取り込み元プロジェクト)
(6).依存性解決コマンド実行(play deps)                             (取り込み元プロジェクト)
(7).アプリケーション起動、動作確認                                (取り込み元プロジェクト)

なお、手順(4)の確認時にmoduleプロジェクト上で単独でantコマンド実行したら、"プロパティ指定"が必要だとか

C:\eclipse4.2\workspace\firstmodule\build.xml:6: Please specify Play framework path using -Dplay.path=/path/to/framework/home

libフォルダが無いとか

C:\eclipse4.2\workspace\firstmodule\build.xml:44: C:\eclipse4.2\workspace\firstmodule\lib does not exist.

言われるかも。前者の方は【play build-module】コマンド実行時に特に何も言われなかったからきっと【play build-module】コマンド打つ時は意識しないで済むような構成なのかも。というかきっとそうなんだろう。libフォルダの件についてはもしかしたら怒られるかもしれないのでその時は適宜フォルダ追加してください。


書籍には拡張可能なポイント?メソッドの一覧及び解説もなされていたのでひとまずメソッド名だけ列挙。一つ一つ読み解いて行きたい所だがその辺は時間を見て追々という事で。

  • onLoad()
  • bind()
  • getStatus(), getJsonStatus()
  • enhance()
  • rawInvocation()
  • serveStatic()
  • loadTemplate()
  • detectChange()
  • onApplicationStart()
  • onApplicationReady()
  • afterApplicationStart()
  • onApplicationStop()
  • onInvocationException()
  • invocationFinally()
  • beforeActionInvocation()
  • onActionInvocationResult()
  • onInvocationSuccess()
  • onRoutesLoaded()
  • onEvent()
  • onClassesChange()
  • addTemplateExtensions()
  • compileAll()
  • routeRequest()
  • modelFactory()
  • afterFixtureLoad()