Ymirではリクエストパスに対応するPageクラスのメソッドが呼び出されます。対応するPageクラスが存在しない場合、メソッド呼び出しは行なわれません。このクラスが存在する場合、以下のような処理が行なわれます。
- このクラスのインスタンスをS2Containerから取り出す(なおインスタンスはrequestスコープです)。
- type="file"以外のリクエストパラメータ(URIパラメータがマージされたもの)をPageインスタンスにinjectする。
- type="file"であるリクエストパラメータをPageインスタンスにinjectする。
- @Inアノテーションが付与されているsetterメソッドがあれば、アノテーションに従ったオブジェクトスコープからオブジェクトを取り出してそのsetterメソッドを使ってセットする。
- Pageクラスに書かれている制約アノテーションに従って制約(リクエストパラメータの正当性やアクセス権限)のチェックを行なう。
- Pageインスタンスについてアクションを実行する。具体的には、マッチしたパスマッピングから構築したアクション名と同じ名前のメソッドを呼び出す。アクション名と同じ名前のメソッドが存在しない場合は_default()メソッドを呼び出す。_default()メソッドも存在しない場合はPermissionDeniedExceptionをスローする。
- メソッドの返り値からResponseオブジェクトを構築する。構築したResponseのtypeがPASSTHROUGHでかつマッチしたパスマッピングから構築したデフォルトの返り値がnullでない場合は、Responseオブジェクトをデフォルトの返り値から構築したResponseオブジェクトで置き換える。
- ResponseのtypeがPASSTHROUGHまたはFORWARDの場合、Pageインスタンスの_render()メソッドを呼び出す。(このメソッドの中で、テンプレートのレンダリングに必要なオブジェクトやプロパティの準備を行なうようにして下さい。)
- @Outアノテーションが付与されているgetterメソッドがあれば、アノテーションに従ったオブジェクトスコープにgetterメソッドの返り値を格納する。
なお、制約チェックで失敗した場合はアクションメソッドの呼び出しの代わりに、_validationFailedメソッドまたは_permissionDeniedメソッドが呼び出されます。
具体的には、リクエストパラメータの正当性チェックに失敗した場合は_validationFailed(Notes)メソッド、なければ_validationFailed()メソッドが呼び出され、アクセス権限チェックに失敗した場合は_permissionDenied(PermissionDeniedException)メソッド、なければ_permissionDenied()メソッドが呼び出されます。
どちらの場合もメソッド呼び出しの後_render()メソッドの呼び出しが行なわれます。
なお、_validationFailedメソッドが存在しない場合は単にメソッド呼び出しがスキップされますが、_permissionDeniedメソッドが存在しない場合はPermissionDeniedExceptionがスローされます。PermissionDeniedExceptionがスローされた場合は_render()メソッドの呼び出しは行なわれません。
例
標準のマッピングでは、例えばリクエストパスが/path.htmlある場合、アプリケーションのルートパッケージ名をcom.example.appとしてcom.example.app.web.PathPageクラスがPageクラスとなります。
今HTTPメソッドがPOSTであるようなリクエストが/path.htmlに対してなされた場合の処理の流れは以下のようになります。
制約チェックでエラーにならないケース
- PathPageインスタンスの取り出し
- リクエストパラメータやスコープ内オブジェクトのinject
- PathPage#_post()、なければPathPage#_default()の呼び出し
- PathPage#_render()の呼び出し
リクエストパラメータの正当性チェックでエラーになるケース
- PathPageインスタンスの取り出し
- リクエストパラメータやスコープ内オブジェクトのinject
- PathPage#_validationFailed(Notes)、なければPathPage#_validationFailed()の呼び出し
- PathPage#_render()の呼び出し
アクセス権限チェックでエラーになるケース
- PathPageインスタンスの取り出し
- リクエストパラメータやスコープ内オブジェクトのinject
- PathPage#_permissionDenied(PermissionDeniedException)、なければPathPage#_permissionDenied()の呼び出し、なければPermissionDeniedExceptionをスロー
- PathPage#_render()の呼び出し
リクエストパラメータのインジェクト
リクエストパラメータはユーザが自由に外部から指定することができるため、アプリケーション設計者の意図しないGetter/Setterメソッドを使って外部からPageオブジェクトに値がセットされてしまう危険性があります。
Ymirではこの危険を回避するために、リクエストパラメータのインジェクトに使用できるGetter/Setterメソッドには明示的に@RequestParameterアノテーションを付与することになっています。このアノテーションが付与されていないGetter/Setterはリクエストパラメータのインジェクトには用いられません。
アノテーションのついていないGetter/Setterについてもリクエストパラメータのインジェクトを許可したい場合は、app.propertiesに書かれている以下の行を削除して下さい:
core.requestParameter.strictInjection=true
なおこの行をアプリケーションの開発途中に変えると脆弱性が混入する危険性がありますので十分注意して下さい!
フェーズ毎のカスタムメソッド呼び出し
Pageコンポーネントに関する処理フェーズ毎に特定のメソッドを呼ぶようにすることができます。
ある処理フェーズの時点で呼び出したいメソッドにはorg.seasar.ymir.annotation.Invokeアノテーションを付与します。アノテーションのプロパティとして、フェーズを表すEnum(org.seasar.ymir.Phase)を指定します。以下に例を示します:
@Invoke(Phase.PAGECOMPONENT_CREATED)
public void initialize() {
...
}
フェーズには以下のものがあります。
| フェーズ名 | 説明 |
|---|---|
| PAGECOMPONENT_CREATED | Pageコンポーネントの生成直後(1.の直後) |
| SCOPEOBJECT_INJECTING | スコープオブジェクトのインジェクション処理の前(5.の直前) |
| ACTION_INVOKING | アクションの実行前(6.の直前) |
| ACTION_INVOKED | アクションの実行後(8.の直後) |
| SCOPEOBJECT_OUTJECTING | スコープオブジェクトのアウトジェクション処理の前(10.の直前) |
| SCOPEOBJECT_OUTJECTED | スコープオブジェクトのアウトジェクション処理の後(10.の直後) |
Invokeアノテーションをつけるメソッドは、引数がないメソッドである必要があります。またメソッドが返り値を持つ場合、返り値は無視されます。