主要な概念
MVC アプリケーションモデル
Play アプリケーションは web に適用された MVC アーキテクチャパターンに従います。
このパターンはアプリケーションを別々の層: Presentation 層 と Model 層 に分割します。Presentation 層 はさらに View 層 と Controller 層 に分けられます。
- Model は、アプリケーションが扱う情報をドメインに特化して表現したものです。ドメインのロジックは生のデータに ‘意味’ (例えば、今日がユーザの誕生日かとか、あるいはショッピングカートの合計や税金や送料などを計算して) を追加します。ほとんどのアプリケーションが、データを保存するためにデータベースなどの永続的なストレージを使用します。Model によって隠蔽されるかカプセル化されることが分かっているので、MVC ではデータアクセス層について明確には言及しません。
- View は、通常はユーザインタフェースである双方向のやり取りに適した形式にモデルをレンダリングします。異なる目的に応じて、ひとつのモデルに対して複数のビューが存在することもあります。Web アプリケーションでは、通常、ビューは HTML、XML または JSON のような ‘Web フォーマット’ としてレンダリングされます。しかし、例えば動的にレンダリングされたチャートダイヤグラムのようにバイナリ形式としてビューを表現する場合もいくつかあります。
- Controller は、イベント (通常はユーザのアクション) に反応してそれらを処理します。このとき、モデルの変更も実行するかもしれません。Web アプリケーションでは、通常、イベントは HTTP リクエストです: コントローラは HTTP リクエストを待ち受けて、‘イベント’ からクエリ文字列パラメータやリクエストヘッダ… と言った関連データを抽出します。そして、下層のモデルオブジェクトに変更を適用します。
Play アプリケーションでは、これらの 3 つの層は app
ディレクトリの中に、それぞれ別々の Java パッケージとして定義されます。
app/controllers
コントローラは、public かつ static なメソッドはいずれも action となるクラスです。アクションは HTTP リクエストが受信されたときに起動される Java のエントリポイントです。コントローラクラスの Java コードはまったくオブジェクト指向的ではありません: 主に手続き型のコードです。アクションメソッドは、HTTP リクエストから関連データを抽出して、モデルを検索するか更新して、HTTP レスポンスにラップされた結果を返します。
app/models
ドメインモデルオブジェクト層は、Java 言語から利用可能なすべてのオブジェクト指向特徴を使用する Java クラスの集合です。ドメインモデルオブジェクト層はアプリケーションが扱うデータ構造と操作を含んでいます。モデルオブジェクトを永続的なストレージに保存する必要がある場合は、ドメインモデルオブジェクト層には JPA アノテーションや SQL ステートメントのような、接着剤的な部品を含むこともあるかもしれません。
app/views
アプリケーションのビューのほとんどは、Play によって提供された効率的なテンプレートシステムを使用して生成されます。コントローラは、モデル層からいくつかのデータを取得し、これらのオブジェクトを装飾するためにテンプレートを適用します。このパッケージは HTML、XML、JSON やその他の、動的にモデルの値を表現する特別なディレクティブを持つテンプレートファイルを保持します。
リクエストライフサイクル
Play フレームワークは完全にステートレスであり、リクエスト/レスポンスのみを重視します。すべての HTTP リクエストは同じ処理フローを通ります:
- HTTP リクエストがフレームワークによって受信されます。
- Router コンポーネントは、このリクエストに適合する最も特殊なルーティングを探します。そして、対応するアクションメソッドが起動されます。
- アプリケーションコードが実行されます。
- 複雑なビューを生成する必要がある場合は、テンプレートファイルがレンダリングされます。
- アクションメソッドの結果 (HTTP レスポンスコードと内容) は HTTP レスポンスとして出力されます。
HTTP リクエストの処理フローを下図にまとめます:
標準的なアプリケーションレイアウト
Play アプリケーションのレイアウトは、できるだけ物事を簡単に保つために標準化されています。
app ディレクトリ
このディレクトリはすべての実行可能な部品: Java ソースコードとビューテンプレートを含みます。
.classファイルはどこ?
コンパイルされた Java クラスを探さないでください。フレームワークは実行時に Java ソースコードをコンパイルして、 tmp
ディレクトリ配下にバイトコードキャッシュとしてコンパイルされたクラスを保持するだけです。Play アプリケーションにおける主な実行可能な成果物は、コンパイルされたクラスではなく、 .java ソースファイルです。
app ディレクトリには、MVC アーキテクチャパターンのそれぞれの層にあたる 3 つの標準的なパッケージがあります。もちろん、例えば utils のような独自のパッケージを追加することも可能です。
加えて、view パッケージの内容は複数のサブパッケージに整理されます:
tags
ディレクトリは、例えば再利用できるテンプレート部品のようなアプリケーションタグを管理します。- コントローラごとにひとつの
view
ディレクトリが割り当てられます。慣例により、コントローラに関連するテンプレートはそれぞれのサブパッケージ内に保持されます。
public ディレクトリ
public
ディレクトリに保存されたリソースは、静的な資産であり、Web サーバによって直接配信されます。
このディレクトリは 3 つの標準的なサブディレクトリ: 画像、CSS スタイルシート、および JavaScript ファイル用のディレクトリに分けられます。すべての Play アプリケーションにおいて一貫性を保つために、静的な資産はこのように管理されるべきです。
デフォルトでは /public
ディレクトリは /public
という URL にマッピングされますが、これは容易に変更可能であり、静的な資産のために複数のディレクトリを使用することもできます。
conf ディレクトリ
conf
ディレクトリはアプリケーションのためのすべての構成ファイルを含んでいます。
2 つの必要な構成ファイルがあります:
application.conf
は、アプリケーションのための主な構成ファイルです。標準的な 設定パラメータ を含んでいます。routes
は、ルーティングを定義するファイルです。
アプリケーションに特化した設定オプションをいくつか追加する必要がある場合、 application.conf
にさらにオプションを追加することは良い考えです。このファイル内の設定オプションは Play.configuration.get("propertyName")
によってプラグラムに読み込まれます。新しいアプリケーションを作成したとき play new
コマンドは $PLAY_HOME/resources/application-skel/conf
ディレクトリから、作業を始めるためにいくつかオプションをコメントアウトしたデフォルトの設定ファイルをコピーします。
ライブラリが特別な設定ファイルを必要とする場合、この conf
ディレクトリ配下に置いてみてください: このディレクトリは Java クラスパスに含まれます 。
@include
を付けたオプション設定値として application.conf
にファイル名を指定することで、Play の設定に更に設定ファイルを追加することができます。
実験的な機能であり、適切に動作しません。特に、プレースホルダー、および、フレームワーク ID は適切に扱われません。
例えば、 conf/mime-types.conf に追加の MIME タイプを定義する場合
# Web fonts
mimetype.eot = application/vnd.ms-fontobject
mimetype.otf = application/octet-stream
mimetype.ttf = application/octet-stream
mimetype.woff = application/x-font-woff
application.conf
に以下の行を追加することで、これらを取り込むことができます:
@include.mime = mime-types.conf
lib ディレクトリ
このディレクトリはアプリケーションに必要なすべての標準的な Java ライブラリを含みます。これらのライブラリは、自動的に Java クラスパスに追加されます。
開発ライフサイクル
Play を使って作業している間、コンパイル、パッケージング、そしてデプロイのいずれのフェーズも存在しません。一方で、Play には 2 つの異なった環境が用意されています: 開発フェーズ中の DEV モードと、アプリケーションがデプロイされるときの PROD モードです。
DEV/PROD モードについて
アプリケーションは DEV か PROD いずれかのモードで実行できます。 application.mode 設定 プロパティを使ってこのモードを切り換えます。DEV モードで動作している場合、Play はファイルの変更をチェックし、必要な場合は動的にリロードします。
PROD モードは本番稼動向けに完全に最適化されます: Java ソースとテンプレートは、一度だけコンパイルされ、複数の用途のためにキャッシュされます。
Java ソースコードは、実行時にコンパイルされ、ロードされます。アプリケーションが動作している間に Java ソースファイルが変更された場合、ソースコードは再コンパイルされて JVM 上に動的にリロードされます。
コンパイルエラーが発生した場合、問題が正確にブラウザに表示されます (DEV モードの場合のみ) 。
テンプレートも動的に再コンパイルされ、リロードされます。
Java デバッガへの接続
アプリケーションを DEV モードで実行している場合、Java デバッガをポート 8000 に接続することができます。
例えば、NetBeans デバッガはこのように使用します:
クラス拡張
Play プラグイン (すなわち play.PlayPlugin
のサブクラス) は、機能を追加するために、実行時にアプリケーションのクラスファイルに手を入れる ‘enhancer’ を含むかもしれません。ここでは、いくつかの Play の魔法がどのようにして動作しているかを示します。
組み込みの play.CorePlugin
は、アプリケーションのクラスに動的にコードを追加するために play.classloading.enhancers
パッケージの enhancer を使用します:
ContinuationEnhancer
- コントローラクラスに継続サポートを追加するControllersEnhancer
- コントローラのアクションメソッドをスレッドセーフにする。メソッド呼び出しに HTTP リダイレクトを追加するLocalvariablesNamesEnhancer
- コントローラ内のローカル変数名を追跡するMailerEnhancer
-play.mvc.Mailer
サブクラスを設定するPropertiesEnhancer
- フィールドに基づいたプロパティによってアプリケーションのすべてのクラスを妥当な JavaBean にするSigEnhancer
- 自動リロードを行うために、すべてのクラスの署名となる一意なハッシュを計算する
これに加えて、 play.db.jpa.JPAPlugin
は JPA クエリ用のメソッド規約に従って play.db.jpa.JPABase
を拡張します。通常、この拡張は play.db.jpa.Model
のサブクラスであるアプリケーションのモデルクラスに適用されます。質問にある JPA クエリは play.db.jpa.GenericModel
に定義されているものです。
独自の enhancer を追加するには、プラグインの enhance(ApplicationClass)
メソッドで play.classloading.enhancers.Enhancer
のサブクラスを使用します。
考察を続けます
ここまでは、Play アプリケーションがどういったものであるかを見てきたので、 HTTP ルーティング がどのように動作するかを見ていきましょう。Router は送り込まれた HTTP リクエストのアクションへの対応付けを担当します。