6.1.5. スレッドコンテキスト変数管理ハンドラ

スレッドコンテキストの各属性値について、リクエスト毎に初期化処理を行うハンドラ。

スレッドコンテキストとは、リクエストIDやユーザIDなど、 同一の処理スレッド内で共有する値をスレッドローカル領域上に保持するための仕組みである。

重要

本ハンドラでは、往路処理のはじめにスレッドコンテキストのクリアを行い、 復路処理ではスレッドコンテキストをクリアしていない。 そのため、ウェブアプリケーションのように、スレッドプールが使われる環境では、 スレッドが再利用されるため、リクエストを受け付けてから本ハンドラの往路処理が始まるまでの間、 一時的にスレッドコンテキストの内容が古い状態となる。 したがって、本ハンドラより手前のハンドラでは、スレッドコンテキストへアクセスしないこと。

ちなみに

スレッドコンテキストの属性値の多くは、本ハンドラによって設定されるが、 本ハンドラ以外のハンドラや業務アクションから任意の変数を設定することも可能である。

本ハンドラでは、以下の処理を行う。

処理の流れは以下のとおり。

../../../../_images/ThreadContextHandler_flow.png

6.1.5.2. モジュール一覧

<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-fw</artifactId>
</dependency>

<!-- 国際化対応により、言語やタイムゾーンを選択できる画面を作る場合のみ  -->
<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-fw-web</artifactId>
</dependency>

6.1.5.3. 制約

なし。

6.1.5.4. リクエスト毎にスレッドコンテキストの初期化を行う

スレッドコンテキストの初期化は、 ThreadContextAttributeインタフェース を実装したクラスを使用して行う。

デフォルトで以下のクラスを提供している。

リクエストID、内部リクエストID
ユーザID
言語
タイムゾーン
実行時ID

これらのクラスは、コンポーネント定義に追加して使用する。

<component class="nablarch.common.handler.threadcontext.ThreadContextHandler">
  <property name="attributes">
    <list>

      <!-- リクエストID -->
      <component class="nablarch.common.handler.threadcontext.RequestIdAttribute" />

      <!-- 内部リクエストID -->
      <component class="nablarch.common.handler.threadcontext.InternalRequestIdAttribute" />

      <!-- ユーザID -->
      <component class="nablarch.common.handler.threadcontext.UserIdAttribute">
        <property name="sessionKey"  value="user.id" />
        <property name="anonymousId" value="guest" />
      </component>

      <!-- 言語 -->
      <component class="nablarch.common.handler.threadcontext.LanguageAttribute">
        <property name="defaultLanguage" value="ja" />
      </component>

      <!-- タイムゾーン -->
      <component class="nablarch.common.handler.threadcontext.TimeZoneAttribute">
        <property name="defaultTimeZone" value="Asia/Tokyo" />
      </component>

      <!-- 実行時ID -->
      <component class="nablarch.common.handler.threadcontext.ExecutionIdAttribute" />
    </list>
  </property>
</component>

6.1.5.5. スレッドコンテキストの属性値を設定/取得する

スレッドコンテキストへのアクセスは、 ThreadContext を使用する。

// リクエストIDの取得
String requestId = ThreadContext.getRequestId();

6.1.5.6. ユーザが言語を選択する画面を作る

国際化対応などで、ユーザが言語を選択できることが求められることがある。 このような場合、以下のクラスのいずれかと LanguageAttributeInHttpUtil を使うことで、ユーザの言語選択を実現できる。

ここでは、クッキーに言語を保持し、リンクにより言語を選択させる画面の実装例を示す。

設定例
<!-- LanguageAttributeInHttpUtilを使用するため、
     コンポーネント名を"languageAttribute"にする。-->
<component name="languageAttribute"
           class="nablarch.common.web.handler.threadcontext.LanguageAttributeInHttpCookie">
  <property name="defaultLanguage" value="ja" />
  <property name="supportedLanguages" value="ja,en" />
</component>
JSPの実装例
<%-- n:submitLinkタグを使用しリンクを出力し、
     n:paramタグを使用しリンク毎に別々の言語を送信する。 --%>
<n:submitLink uri="/action/menu/index" name="switchToEnglish">
  英語
  <n:param paramName="user.language" value="en" />
</n:submitLink>
<n:submitLink uri="/action/menu/index" name="switchToJapanese">
  日本語
  <n:param paramName="user.language" value="ja" />
</n:submitLink>
ハンドラの実装例
// ユーザが選択した言語の保持を行うハンドラ。
// 複数画面でユーザに言語を選択させる場合を想定しハンドラとして実装する。
public class I18nHandler implements HttpRequestHandler {

    public HttpResponse handle(HttpRequest request, ExecutionContext context) {
        String language = getLanguage(request, "user.language");
        if (StringUtil.hasValue(language)) {

            // LanguageAttributeInHttpUtilのkeepLanguageメソッドを呼び出し、
            // クッキーに選択された言語を設定する。
            // スレッドコンテキストにも言語が設定される。
            // 指定された言語がサポート対象の言語でない場合は、
            // クッキーとスレッドコンテキストへの設定を行わない。
            LanguageAttributeInHttpUtil.keepLanguage(request, context, language);
        }
        return context.handleNext(request);
    }

    private String getLanguage(HttpRequest request, String paramName) {
        if (!request.getParamMap().containsKey(paramName)) {
            return null;
        }
        return request.getParam(paramName)[0];
    }
}

6.1.5.7. ユーザがタイムゾーンを選択する画面を作る

国際化対応などで、ユーザがタイムゾーンを選択できることが求められることがある。 このような場合、以下のクラスのいずれかと TimeZoneAttributeInHttpUtil を使うことで、ユーザのタイムゾーン選択を実現できる。

ここでは、クッキーにタイムゾーンを保持し、リンクによりタイムゾーンを選択させる画面の実装例を示す。

設定例
<!-- TimeZoneAttributeInHttpUtilを使用するため、
     コンポーネント名を"timeZoneAttribute"にする。-->
<component name="timeZoneAttribute"
           class="nablarch.common.web.handler.threadcontext.TimeZoneAttributeInHttpCookie">
  <property name="defaultTimeZone" value="Asia/Tokyo" />
  <property name="supportedTimeZones" value="Asia/Tokyo,America/New_York" />
</component>
JSPの実装例
<%-- n:submitLinkタグを使用しリンクを出力し、
     n:paramタグを使用しリンク毎に別々のタイムゾーンを送信する。 --%>
<n:submitLink uri="/action/menu/index" name="switchToNewYork">
  ニューヨーク
  <n:param paramName="user.timeZone" value="America/New_York" />
</n:submitLink>
<n:submitLink uri="/action/menu/index" name="switchToTokyo">
  東京
  <n:param paramName="user.timeZone" value="Asia/Tokyo" />
</n:submitLink>
ハンドラの実装例
// ユーザが選択したタイムゾーンの保持を行うハンドラ。
// 複数画面でユーザにタイムゾーンを選択させる場合を想定しハンドラとして実装する。
public class I18nHandler implements HttpRequestHandler {

    public HttpResponse handle(HttpRequest request, ExecutionContext context) {
        String timeZone = getTimeZone(request, "user.timeZone");
        if (StringUtil.hasValue(timeZone)) {

            // TimeZoneAttributeInHttpUtilのkeepTimeZoneメソッドを呼び出し、
            // クッキーに選択されたタイムゾーンを設定する。
            // スレッドコンテキストにもタイムゾーンが設定される。
            // 指定されたタイムゾーンがサポート対象のタイムゾーンでない場合は、
            // クッキーとスレッドコンテキストへの設定を行わない。
            TimeZoneAttributeInHttpUtil.keepTimeZone(request, context, timeZone);
        }
        return context.handleNext(request);
    }

    private String getTimeZone(HttpRequest request, String paramName) {
        if (!request.getParamMap().containsKey(paramName)) {
            return null;
        }
        return request.getParam(paramName)[0];
    }
}