カンバセーションスコープ

カンバセーション (会話) スコープはJBoss Seamが初めて提唱したスコープで、複数のリクエストにまたがって持続するスコープだ。

セッションスコープとの違いは、セッションスコープよりも持続時間が短く、1セッションユーザが複数作成する可能性があることだ。

たとえば「登録画面→入力確認画面→完了画面」のように、複数のリクエストから成る論理的に一つの処理を行う間、状態を保持するために使用する。その応用範囲は大きく、HTTPリダイレクトをまたがって状態を保持したり、Ajaxリクエストを何度も受け付ける場合などに威力を発揮する。

会話スコープを使用するには、Conversationクラスのbegin()とend()を明示的に呼び出す必要がある。

リスト11 RegisterUser.java

@Component
public class RegisterUser {
  @In Conversation conversation;

  public void init() {
    conversation.begin();
    ...
  }

  public void complete() {
    ...
    conversation.end();
  }
}

カスタムスコープの作成

また、カスタマイズされたスコープを作成することも可能だ。現在のスレッドに限定したスコープ、メソッドの開始から終了までという短いスコープ、またはビジネスプロセス全体にわたって生存するスコープなど、さまざまな可能性が考えられる。

スコープの作成方法は、アノテーションとコンテキストを作成し、コンテナに登録する、という作業から成る。

「コンテキストとは何か」を言葉で表すのは難しいが、「現在実行中のコードに関連付けられているスコープ」とほぼ同義だと言える。HTTPリクエストによって実行されたメソッドのコンテキストからは、リクエストやセッション、アプリケーションと言ったスコープにアクセスできるということだ。

アノテーションの作成方法は非常に簡単で、@ScopeTypeを付与したアノテーションを作成するだけだ。

リスト12

    @ScopeType
    @Target({TYPE, METHOD})
    @Retention(RUNTIME)
    public @interface ThreadScoped {
    }

コンテキストは、javax.webbeans.Contextインタフェースを実装したクラスを作成する。同インタフェースには、オブジェクトを取得するためのget()とオブジェクトを削除するためのremove()メソッドが定義されている。

リスト13

    public class ThreadContext implements Context{
      public  T get(Component component, boolean create) {
        // スレッドローカルなMapなどからオブジェクトを取得
        T componentInstance = ...
        if (componentInstance == null && create) {
          componentInstance = component.create();
          // スレッドローカルなMapなどにオブジェクトを保存
          ...
        }
        return componentInstance;
      }
      public  void remove(Component component) {
        // スレッドローカルなMapなどからオブジェクトを削除
        ...
      }
    }

あとは、コンテナに対してスコープを登録する。コンテナはjavax.webbeans.Containerインタフェースによって表現されており、リスト14のようなメソッドを持つ。

リスト14

    public interface Container {
      public void addContext(Class scopeType, Context context);
      ...
    }

プログラムの任意の箇所で、addContext()メソッドを呼び出せば、コンテキストを登録できる。

リスト15

    // 第一引数はアノテーションのクラス、第二引数はコンテキスト
    container.addContext(ThreadScoped.class, new ThreadContext());

以降、アノテーションを付与したコンポーネントはそのスコープに関連付けられる。

リスト16

    <strong>@ThreadScoped</strong>
    @Component
    public class CurrentTransaction {
      ...
    }