4.4. 切替¶
ここでは、アクセスコンテキストの切替機能の詳細と実装方法について説明します。
項目
4.4.1. 概要¶
切替処理は、アクセスコンテキストの情報を変更する場合に実行されます。切替の処理イメージについては、「 切替 」を参照してください。切替処理を実行すると、アクセスコンテキストの依存関係を考慮して、全てのアクセスコンテキストに対して切替処理が実行されます。これにより、アクセスコンテキストの変更があった場合に、依存するアクセスコンテキストの情報も変更することが可能です。切替が不要なアクセスコンテキストは、切替処理は実行されません。切替機能は、ライフサイクル内でアクセスコンテキストの状態を変更する目的で利用されます。そのため、ライフサイクルが開始していない状態では利用できませんので、注意してください。切替処理の実行は、ライフサイクルの開始処理と同様に、コンテキストビルダを利用して行います。注意
依存関係があるアクセスコンテキストの場合、依存先と同じ切替(コンテキストスイッチ、コンテキストスタック)をサポートする必要があります。 サポートしていない場合、依存先のアクセスコンテキストの再生成により変更された内容を反映することができません。 この影響により、アクセスコンテキストの情報に不整合が発生する場合があります。注意
切替処理は、デフォルトコンテキストビルダで行ってください。 これは、どのようなリソースIDが拡張されても切替が行えるようにするためです。 加えて、デフォルトコンテキストビルダは、実行環境毎に定義してください。デフォルトコンテキストビルダについては、「 デフォルトコンテキストビルダ 」を参照してください。
4.4.2. コンテキストスイッチ¶
4.4.2.1. コンテキストスイッチの処理フロー¶
コンテキストスイッチの処理は、以下の順に実行されます。
- 切替処理の呼び出し( Lifecycle#switchTo() )
- アクセスコンテキスト一覧取得
- アクセスコンテキストごとに以下の処理を実行
- コンテキストビルダの選出
- コンテキストビルダのスイッチ処理実行
- コンテキストストアへの格納
4.4.2.2. コンテキストスイッチ用コンテキストビルダの実装¶
コンテキストスイッチ用コンテキストビルダは、ライフサイクル開始時と同様に、ContextBuilder インタフェースを実装することで作成できます。jp.co.intra_mart.foundation.context.core.ContextBuilderただし、そのままではアクセスコンテキストを再作成することになり、スイッチ前の情報を参照することができません。以下のインタフェースを追加して、 build() メソッドの代わりにswitchFrom() メソッドを実装することでスイッチ前の情報を参照することが可能です。jp.co.intra_mart.foundation.context.core.ContextSwitchSupport実装例
public class SampleContextSwitchBuilder implements ContextBuilder, ContextSwitchSupport { @Override public boolean enableSwitch(Resource resource) { // コンテキストスイッチを利用するため、true を返却する。 return true; } @Override public Context switchFrom(Context source, Resource resource) { // 切り替え前のアクセスコンテキストを参照して、新しいアクセスコンテキストを生成する。 final SampleContext prevContext = SampleContext.class.cast(source); final SampleContext newContext = new SampleContext(); newContext.setFoo(prevContext.getFoo()); return newContext; } @Override public Context build(Resource resource) { // このメソッドは利用しない。 return null; } }注意
キャッシュをサポートするアクセスコンテキストは、Web実行環境で利用するコンテキストスイッチ処理を作成する場合、必ずキャッシュをサポートする必要があります。セッションにキャッシュを保持しつつ、コンテキストスイッチ処理でキャッシュの更新を行わなかった場合、次回アクセス時はセッションの情報を利用するため、コンテキストスイッチが行われない状態となります。また、依存するアクセスコンテキストだけがキャッシュの更新を行った場合、依存関係にあるはずのアクセスコンテキストの内容が整合性のとれないものとなります。例えば、AccountContext のロケール切り替えのスイッチ処理をキャッシュをサポートせずに作成した場合、AccountContext は、次回アクセス時にロケールが元に戻りますが、 UserContext はロケールが変更された状態がキャッシュされるため、ユーザ名が変更されたロケールで表示されます。キャッシュをサポートするためには、「 キャッシュ実装 」に沿って実装してください。
4.4.2.3. キャッシュサポート¶
Web実行環境用の切替処理では、キャッシュの対応が必要です。キャッシュ処理の詳細については、「 キャッシュ 」を参照してください。
4.4.2.4. アクセスコンテキスト設定¶
コンテキストスイッチを利用するためには、作成したコンテキストビルダを設定ファイルに定義する必要があります。コンテキストビルダの設定については、「 コンテキストビルダの設定 」を参照してください。コンテキストビルダのリソースIDは、以下を考慮して定義してください。
4.4.3. コンテキストスタック¶
4.4.3.1. コンテキストスタックの処理フロー¶
コンテキストスタックの処理は、以下の順に実行されます。
- 切替処理の呼び出し( Lifecycle#stack() )
- 現在のアクセスコンテキストの保存
- アクセスコンテキスト一覧取得
- アクセスコンテキストごとに以下の処理を実行
- コンテキストビルダの選出
- コンテキストビルダのスタック処理実行
- コンテキストストアへの格納
- (任意の処理実行)
- コンテキストストアの破棄とスタック前のコンテキストストアの復元( Lifecycle#pop() )
4.4.3.2. コンテキストスタック用コンテキストビルダの実装¶
コンテキストスタック用コンテキストビルダは、ライフサイクル開始時と同様に、ContextBuilder インタフェースを実装することで作成できます。jp.co.intra_mart.foundation.context.core.ContextBuilderただし、そのままではアクセスコンテキストを再作成することになり、スタック前の情報を参照することができません。以下のインタフェースを追加して、 build() メソッドの代わりにpush() メソッドを実装することでスタック前の情報を参照することが可能です。jp.co.intra_mart.foundation.context.core.ContextStackSupport実装例
public class SampleContextStackBuilder implements ContextBuilder, ContextStackSupport { @Override public boolean enableStack(final Resource resource) { // コンテキストスタックを利用するため、true を返却する。 return true; } @Override public Context push(final Context source, final Resource resource) { // 切り替え前のアクセスコンテキストを参照して、新しいアクセスコンテキストを生成する。 final SampleContext prevContext = SampleContext.class.cast(source); final SampleContext newContext = new SampleContext(); newContext.setFoo(prevContext.getFoo()); return newContext; } @Override public Context pop(final Context source) { // スタックから取得したアクセスコンテキストをそのまま返却する。 return source; } @Override public Context build(final Resource resource) { // このメソッドは利用しない。 return null; } }
4.4.3.3. キャッシュサポート¶
コンテキストスタックは、一時的な処理のためキャッシュに対する処理は行いません。そのため、コンテキストスタック用のコンテキストビルダでは、キャッシュ対応は必要ありません。
4.4.3.4. アクセスコンテキスト設定¶
コンテキストスタックを利用するためには、作成したコンテキストビルダを設定ファイルに定義する必要があります。コンテキストビルダの設定については、「 コンテキストビルダの設定 」を参照してください。コンテキストビルダのリソースIDは、以下を考慮して定義してください。
4.4.4. 実行方法(JavaEE開発モデル)¶
コンテキスト切替処理を実行するためには、 Lifecycle API を利用します。Lifecycle API の詳細は、「 Lifecycle クラスの APIドキュメント 」を参照してください。Lifecycle は、インタフェースです。実装クラスを取得するためには、 LifecycleFactory クラスを利用します。jp.co.intra_mart.foundation.context.core.LifecycleFactory実行方法
final Lifecycle lifecycle = LifecycleFactory.getLifecycle();
4.4.4.1. コンテキストスイッチ¶
コンテキストスイッチを実行するためには、以下のメソッドを実行します。
- Lifecycle#switchTo(Resource)
4.4.4.2. コンテキストスタック¶
コンテキストスタックを実行するためには、以下のメソッドを実行します。
- 処理の開始時: Lifecycle#stack(Resource)
- 処理の完了時: Lifecycle#pop()
実行方法
final Resource resource = new Resource("sample.resource.id"); final Lifecycle lifecycle = LifecycleFactory.getLifecycle(); try { // スタックして処理を実行する。 lifecycle.stack(resource); // スタック中のアクセスコンテキストを参照。 final SampleContext currentContext = Contexts.get(SampleContext.class); } finally { // 処理の終了後、 pop() を実行すること。 lifecycle.pop(); }スタック中の処理の範囲が特定できる場合、クロージャ対応のメソッドを実行することで、 pop() の呼び出しを省略することが可能です。
Lifecycle#stack(Resource, LifecycleStackProcedure)
LifecycleStackProcedure は、スタック中の処理を定義したクロージャクラスのインタフェースです。実行方法
// スタックして処理を実行する。 final Resource resource = new Resource("sample.resource.id"); LifecycleFactory.getLifecycle().stack(resource, new LifecycleStackProcedure<Boolean, Exception>() { @Override public Boolean process() throws Exception { // スタック中のアクセスコンテキストを参照。 final SampleContext currentContext = Contexts.get(SampleContext.class); return true; } }); // 処理の完了後は pop() 実行済み。注意
- クロージャ対応のメソッドを利用できるのは、 2014 Spring(Granada) 以降です。
- クロージャ対応のメソッドを利用しない場合、処理の完了時には必ず pop() を実行する必要があります。
4.4.5. 実行方法(スクリプト開発モデル)¶
コンテキスト切替処理を実行するためには、 Lifecycle API を利用します。Lifecycle API の詳細は、「 Lifecycle オブジェクトの APIドキュメント 」を参照してください。
4.4.5.1. コンテキストスイッチ¶
コンテキストスイッチを実行するためには、以下の関数を実行します。
- Lifecycle#switchTo(String, Object)
4.4.5.2. コンテキストスタック¶
コンテキストスタックを実行するためには、 Lifecycle API を利用します。コンテキストスタックを実行するためには、以下の関数を実行します。
- 処理の開始時: Lifecycle#stack(String, Object)
- 処理の完了時: Lifecycle#pop()
注意
処理の完了時には必ず pop() を実行する必要があります。