SeamFramework.org Community Documentation

- 前のページ
- 次のページ

## 第30章 Seam の設定と Seam アプリケーションのパッケージング

話題にするにはあまりにつまらないし道楽にするには単調すぎる作業が設定だと言えます。 残念ながら XML の数行が JSF 実装およびサーブレットコンテナへの Seam の統合に必要となります。 ただし、 次のセクションにあるようなものを独自に入力する必要はなく seam-gen を使ってアプリケーションを起動するかサンプルのアプリケーションからコピーして貼り付けるだけの作業になりますので、 それほど心配することもありません。

## 30.1. Seam の基本設定

最初に JSF と Seam を併用する場合に常に必要となる基本の設定について見ていくことにします。

### 30.1.1. Seam と JSF、 サーブレットコンテナとの統合

当然 faces サーブレットが必要になります。

    <servlet>

        <servlet-name

    >Faces Servlet</servlet-name>

        <servlet-class

    >javax.faces.webapp.FacesServlet</servlet-class>

        <load-on-startup

    >1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name

    >Faces Servlet</servlet-name>

        <url-pattern

    >*.seam</url-pattern>

    </servlet-mapping

    >

(適宜 URL パターンを調整することができます。)

また、 Seam には `web.xml`ファイルに次の記述も必要になります。

    <listener>

        <listener-class

    >org.jboss.seam.servlet.SeamListener</listener-class>

    </listener

    >

このリスナーは Seam のブートストラップおよびセッションとアプリケーションコンテキストの破棄を行います。

JSF 実装の中には Seam の対話伝播と動作するサーバー側状態保存の実装が破損しているものがあります。 フォームサブミット中の対話伝播に関する問題が見られる場合はクライアント側状態保存に切り替えて見てください。 `web.xml` に次が必要となります。

    <context-param>

        <param-name

    >javax.faces.STATE_SAVING_METHOD</param-name>

        <param-value

    >client</param-value>

    </context-param

    >

ビュー状態値の変異性に関する JSF 仕様には不明瞭な部分があります。 Seam は JSF ビュー状態を使用してその PAGE スコープを支えるため、 特定の場合に問題となる可能性があります。 JSF-RI でサーバー側状態保存を使用し PAGE スコープの Bean に任意のページの特定ビューに対するその正確な値を維持させたい場合には次のコンテキストパラメータを指定する必要があります。 そうしなければ、 ユーザー−が「戻る」ボタンを使用したときに PAGE スコープのコンポーネントは最新の値を持つことになります。 つまり「戻る」ページの値から変えていればその値が使われます。 ( 仕様に関する問題 を参照)。 要求ごとに JSFビューのシリアライズが発生し性能に影響するため、 この設定はデフォルトでは有効にされません。

    <context-param>

        <param-name

    >com.sun.faces.serializeServerState</param-name>

        <param-value

    >true</param-value>

    </context-param

    >

### 30.1.2. facelet を使用する

私たちの意見を聞き入れていただいて、JSPの替わりに faceletを使っていただけるとしたら、`faces-config.xml`に以下の行を追加してください。

    <application>

        <view-handler

    >com.sun.facelets.FaceletViewHandler</view-handler>

    </application

    >

そして、 `web.xml`に下の記述も必要です。

    <context-param>

        <param-name

    >javax.faces.DEFAULT_SUFFIX</param-name>

        <param-value

    >.xhtml</param-value>

    </context-param

    >

JBoss AS で facelets を使用している場合は facelets のログ機能が破損しているのに気づかれるでしょう (ログメッセージがサーバーのログに届きません)。 Seam はこれを修正するための橋渡しを提供しています。 これを使用するには `lib/interop/jboss-seam-jul.jar` を `$JBOSS_HOME/server/default/deploy/jboss-web.deployer/jsf-libs/` にコピーしてから使用するアプリケーションの `WEB-INF/lib` に `jboss-seam-ui.jar` を含めます。 Facelets のログカテゴリは Facelets Developer Documentation に記載されています。

### 30.1.3. Seam リソースサーブレット

Seam リソースサーブレットは Seam Remoting 、キャプチャ (セキュリティの章を参照) や JSF の UI コントロールで使用されるリソースを提供します。 Seam リソースサーブレットの設定には `web.xml` に以下の記述が必要です。

    <servlet>

      <servlet-name

    >Seam Resource Servlet</servlet-name>

      <servlet-class

    >org.jboss.seam.servlet.SeamResourceServlet</servlet-class>

    </servlet>

    <servlet-mapping>

      <servlet-name

    >Seam Resource Servlet</servlet-name>

      <url-pattern

    >/seam/resource/*</url-pattern>

    </servlet-mapping

    >

### 30.1.4. Seamサーブレットフィルタ

Seam は基本的な操作の場合はサーブレットフィルタを必要としません。 ただし、 フィルタの使用に依存する機能がいくつかあります。 Seam ではわかりやすいように他の組み込み Seam コンポーネントを設定する場合と同じようにしてサーブレットフィルタを追加したり設定することができます。 この機能を利用するにはまず `web.xml` にマスターフィルタをインストールする必要があります。

    <filter>

        <filter-name

    >Seam Filter</filter-name>

        <filter-class

    >org.jboss.seam.servlet.SeamFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name

    >Seam Filter</filter-name>

        <url-pattern

    >/*</url-pattern>

    </filter-mapping

    >

Seam マスターフィルタは `web.xml` で指定される 一番目のフィルタでなければなりません。 これによりマスターフィルタが一番最初に実行されるようになります。

Seam フィルタはいくつかの共通の属性を持ちます。 これらに加えて以降で説明するパラメータを `components.xml` に設定することができます。

- `url-pattern` — フィルタされる要求を指定するのに使用します。 デフォルトは全要求です。 `url-pattern` はワイルドカードサフィックスを許可する Tomcat スタイルのパターンになります。

- `regex-url-pattern` — フィルタされる要求を指定するのに使用します。 デフォルトは全要求です。 `regex-url-pattern` は要求パスにマッチする正規表現になります。

- `disabled` — 組み込みのフィルタの無効化に使用します。

パターンは要求の URI パスに対してマッチングが行われる点 (`HttpServletRequest.getURIPath()` を参照)、 およびサーブレットコンテキスト名はマッチングが行われる前に削除される点に注意してください。

マスターフィルタを組み込むことにより、以下の組み込みフィルタを使用できるようになります。

#### 30.1.4.1. 例外処理

このフィルタは `pages.xml` で例外マッピングの機能を提供します (ほぼすべてのアプリケーションでこの機能が必要とされます)。 また、 捕捉されなかった例外が発生した場合にコミットされていないトランザクションのロールバックも行います。 (Java EE 仕様によるとこれは Web コンテナによって自動的に行われるはずですが、 すべてのアプリケーションサーバーでこの動作をあてにできるわけではないことが判明しています。 また、 Tomcat のようなプレーンなサーブレットエンジンには必要ありません。)

デフォルトで、すべての要求に対して例外処理フィルタが適用されますが、下のように、 `components.xml`に`<web:exception-filter>`を記述して、 これを変更することもできます。

    <components xmlns="http://jboss.com/products/seam/components"

                xmlns:web="http://jboss.com/products/seam/web">

        <web:exception-filter url-pattern="*.seam"/>

    </components

    >

#### 30.1.4.2. リダイレクトによる対話の伝搬

このフィルタはSeamがブラウザのリダイレクトにより対話コンテキストを伝搬する事を可能にします。 ブラウザリダイレクトをインタセプトし、 Seam の対話 ID をパラメータに追加することにより、実現しています。

リダイレクトフィルタも、デフォルトですべての要求を対象としますが、 `components.xml`の記述を以下のようにして変更することが可能です。

    <web:redirect-filter url-pattern="*.seam"/>

#### 30.1.4.3. URL のリライト

このフィルタにより Seam は `pages.xml` ファイルの設定をベースとしたビューの URL 書き換えを適用することができるようになります。 このフィルタはデフォルトではアクティブにはなっていませんが、 `components.xml` に設定を追加することでアクティブにすることができます。

    <web:rewrite-filter view-mapping="*.seam"/>

`view-mapping` パラメータは `web.xml` ファイルにある Faces サーブレット用に定義されたサーブレットマッピングに合致しなければなりません。 省略するとリライトフィルタはパターンが `*.seam` であるとみなします。

#### 30.1.4.4. マルチパートフォームの送信

この機能は Seam のファイルアップロード JSF コントロールを使用するときに必要となります。 マルチパートフォームの要求を検出すると、 RFC-2388 (multipart/form-data 仕様) に従い処理を行います。 デフォルトの設定をオーバーライドするためには `components.xml`に以下の設定を追加します。

    <web:multipart-filter create-temp-files="true"

                          max-request-size="1000000"

                          url-pattern="*.seam"/>

- `create-temp-files` — `true` にセットするとアップロードされたファイルがメモリに維持される代わりにテンポラリファイルに書き込まれます。 大容量ファイルのアップロードが予期される場合は考慮すべき重要な点となるかもしれません。 デフォルト設定は `false` です。

- `max-request-size` — ファイルのアップロード要求サイズがこの値を越えると (要求内の `Content-Length` ヘッダーを読み取り判定される) その要求は中断されます。 デフォルト設定は 0 です (サイズ制限なし)。

#### 30.1.4.5. キャラクタエンコーディング

送信されたフォームデータのキャラクターエンコーディングをセットします。

デフォルトではこのフィルタはインストールされていませんので、`components.xml` に以下の記述が必要です。

    <web:character-encoding-filter encoding="UTF-16"

                                   override-client="true"

                                   url-pattern="*.seam"/>

- `encoding` — 使用するエンコーディングです。

- `override-client` — `true` にセットすると要求エンコーディングはその要求がすでにエンコーディングを指定しているか否かにかかわらず `encoding` で指定されているものにセットされます。 `false` にセットすると要求エンコーディングは要求がまだエンコーディングを指定していない場合にのみセットされます。 デフォルト設定は `false` です。

#### 30.1.4.6. RichFaces

RichFaces をプロジェクトに使用すると Seam は RichFaces Ajax フィルタをインストールしてその他すべての組み込みフィルタより先にこのフィルタがインストールされるようにします。 `web.xml` に手作業で RichFaces Ajax をインストールする必要はありません。

RichFaces Ajax フィルタは RichFaces jar 群がプロジェクトにある場合にのみインストールされます。

デフォルトの設定を上書きするには次のエントリを `components.xml` に追加します。 オプションは RichFaces Developer Guide に記載されているものと同じです。

    <web:ajax4jsf-filter force-parser="true"

                         enable-cache="true"

                         log4j-init-file="custom-log4j.xml"

                         url-pattern="*.seam"/>

- `force-parser` — JSF の全ページが Richfaces の XML 構文チェッカーにより強制的に検証されるようにします。 `false` なら AJAX の応答のみが検証され整形式の XML に変換されます。 `force-parser` を `false` に設定するとパフォーマンスは向上しますが AJAX 更新でおかしな結果が見えてしまう可能性があります。

- `enable-cache` — フレームワーク生成のリソースのキャッシュ化を有効にします (javascript、 CSS、 イメージなど)。 カスタムの javascript や CSS を開発している場合は true に設定するとブラウザにリソースをキャッシュさせないようにします。

- `log4j-init-file` — アプリケーションごとのログ記録のセットアップに使用されます。 log4j.xml 設定ファイルへのパスをウェブアプリケーションコンテキストからの相対パスで与えてください。

#### 30.1.4.7. アイデンティティロギング

このフィルタは認証されたユーザー名を log4j マップ診断コンテキストに追加するため、 パターンに %X{username} を追加することで必要に応じてユーザー名をフォーマット化されたログ出力に含めることができます。

デフォルトではロギングフィルタは全要求を処理しますが、 以下の例で示すように `<web:logging-filter>` のエントリを `components.xml` に追加してこの動作を調整することができます。

    <components xmlns="http://jboss.com/products/seam/components"

                xmlns:web="http://jboss.com/products/seam/web">

        <web:logging-filter url-pattern="*.seam"/>

    </components

    >

#### 30.1.4.8. カスタムなサーブレットのコンテキスト管理

JSF サーブレット以外のサーブレットに直接送信される要求は、JSFのライフサイクルでは処理されません。 そこで、Seamは Seamのコンポーネントにアクセスする必要の有る その他のサーブレットに対してサーブレットフィルタを提供しています。

このフィルタを適用することにより、カスタムなサーブレットが Seamコンテキストと相互に作用することを可能にします。 個々の要求の最初にSeamコンテキストをセットアップし、要求の終了畤にこれを破棄します。このフィルタは JSFの `FacesServlet` には決して適用されないようにしてください。 Seam はJSFの要求のコンテキスト管理には phase listenerを使用します。

デフォルトではこのフィルタはインストールされていませんので、`components.xml` に以下の記述が必要です。

    <web:context-filter url-pattern="/media/*"/>

コンテキストフィルタは`conversationId`という名前で要求パラメータ中に対話 ID を探そうとします。必ず、要求パラメータに対話 IDを含めるようにしてください。

また、新たな対話 IDをクライアント側に確実に伝える必要があります。 Seamは組み込みコンポーネント `conversation`のプロパティとして対話 IDを公開しています。

#### 30.1.4.9. カスタムのフィルタを追加する

Seam はカスタムのフィルタをインストールすることができ、 チェーン内にフィルタを配置する 場所 を指定できます (サーブレットの仕様はフィルタを `web.xml` に指定したときの明確な順序を提供しません)。 `@Filter` アノテーションを Seam コンポーネント (`javax.servlet.Filter` を実装しなければなりません) に追加するだけです。

    @Startup

    @Scope(APPLICATION)

    @Name("org.jboss.seam.web.multipartFilter")

    @BypassInterceptors

    @Filter(within="org.jboss.seam.web.ajax4jsfFilter")

    public class MultipartFilter extends AbstractFilter {

`@Startup` アノテーションを追加すると Seam 起動時にコンポーネントが使用可能となります。 バイジェクションはここでは使用できません (`@BypassInterceptors`)。 フィルタは RichFaces フィルタよりチェーンの下方になります (`@Filter(within="org.jboss.seam.web.ajax4jsfFilter")`)。

### 30.1.5. EJB コンテナと Seam の統合

Seam アプリケーションでは EJB コンポーネントは EJB コンテナと Seam の両方で管理されるためある種の二重性を持ちます。 実際に Seam は EJB コンポーネントの参照を解決し、 ステートフルセッション Bean コンポーネントのライフタイムを管理、 またインタセプタを通じて各メソッド呼び出しにも参加します。 まず、 Seam のインタセプタチェーンの設定から見てみることにします。

`SeamInterceptor` を Seam コンポーネントに適用する必要があります。 このインタセプタはバイジェクション、 対話境界設定、 ビジネスプロセスのシグナルなどの問題を処理する組み込みのサーバー側インタセプタ一式に委譲します。 アプリケーション全体に渡りこれを最も容易に行う方法は次のインタセプタ設定を `ejb-jar.xml` に追加する方法です。

    <interceptors>

        <interceptor>

            <interceptor-class

    >org.jboss.seam.ejb.SeamInterceptor</interceptor-class>

        </interceptor>

    </interceptors>

    <assembly-descriptor>

        <interceptor-binding>

            <ejb-name

    >*</ejb-name>

            <interceptor-class

    >org.jboss.seam.ejb.SeamInterceptor</interceptor-class>

        </interceptor-binding>

    </assembly-descriptor>

Seam は、セッション Bean が JNDI でどこにあるかを知る必要があります。 このための方法の 1 つは、 それぞれの Session Bean コンポーネントに、`@JndiName` を指定することです。 しかし、 これではつまらな過ぎます。 もっと良い方法は、 EJB 名から JNDI 名を判断するために、 Seam が使用するパターンを指定することです。 あいにく、EJB3 標準に定義されたグローバル JNDI をマッピングする標準は存在しないため、 このマッピングはベンダー固有になります (また、 使用している命名規則により異なる場合があります)。 通常、`components.xml`にこのオプションを指定します。

JBossアプリケーションサーバーでは、次のパターンが正しいです。

    <core:init jndi-name="earName/#{ejbName}/local" />

この場合、 `earName` は Bean がデプロイされる EAR の名前となり、 Seam は `#{ejbName}` を EJB の名前に置き換えるため最終部分はインタフェースの種類を表します (ローカルまたはリモート)。

EAR のコンテキストの外側では (JBoss 組み込み可能 EJB3 コンテナを使用するとき)、 EAR がないため最初の部分はドロップされ次のようなパターンになります。

    <core:init jndi-name="#{ejbName}/local" />

この時点ではどのように JNDI 名を解決するのかまた EJB コンポーネントをどのように検索させるのかよくわからないので、 もう少し詳しく見ていきます。 まず、 EJB コンポーネントを JNDI に入れる方法について説明します。

JBoss では XML にあまり注意が払われないため、 JBoss AS の設計時に 前述したようにパターンを使用して EJB コンポーネントにグローバルな JNDI 名が自動的に割り当てられることを決定しました (EAR の name/EJB name/interface タイプ)。 EJB 名は次の一覧のいずれかとなる値が空白にならない最初の値になります。

- ejb-jar.xml 内の `<ejb-name>` 要素の値

- @Stateless または @Stateful アノテーション内の `name` 属性の値

- Bean クラスのシンプルな名前

例を見てみます。 次の EJB Bean と定義済みインタフェースがあると仮定します。

    package com.example.myapp;

    import javax.ejb.Local;

    @Local

    public class Authenticator

    {

        boolean authenticate();

    }

    package com.example.myapp;

    import javax.ejb.Stateless;

    @Stateless

    @Name("authenticator")

    public class AuthenticatorBean implements Authenticator

    {

        public boolean authenticate() { ... }

    }

EJB Bean クラスが myapp という名前の EAR にデプロイされると仮定して、 グローバルな JNDI 名 myapp/AuthenticatorBean/local が JBoss AS 上のそれに割り当てられます。 学んできたように、 この EJB コンポーネントを `authenticator` という名前で Seam コンポーネントとして参照することができるため、 Seam は JNDI 内で JNDI パターンに準じてコンポーネントの検索処理を行うようになります (または `@JndiName` アノテーション)。

ではアプリケーションサーバーの他の部分はどうでしょうか。 ほとんどのベンダーが決まって固執する Java EE 仕様によると、 EJB 参照に JNDI 名が割り当てられるよう EJB に EJB 参照を宣言する必要があります。 これには何らかの XML が必要となります。 また、 Seam JNDI パターンを活用できるよう JNDI 命名規約を確立するかどうかもその人次第となります。 JBoss 規約が便利である場合があります。

JBoss ではないアプリケーションサーバーで Seam を使用する場合、 EJB 参照を定義しなければならない箇所が 2 箇所あります。 JSF で Seam EJB コンポーネントを検索する (JSF ビュー内または JSF アクションリスナーとして)、 または Seam JavaBean コンポーネントを検索する場合は web.xml で EJB 参照を宣言しなければなりません。 以下に例としてコンポーネントの EJB 参照を示します。

    <ejb-local-ref>

        <ejb-ref-name

    >myapp/AuthenticatorBean/local</ejb-ref-name>

        <ejb-ref-type

    >Session</ejb-ref-type>

        <local

    >org.example.vehicles.action.Authenticator</local>

    </ejb-local-ref>

この参照は Seam アプリケーション内のコンポーネント使用例をカバーします。 ただし、 Seam EJB コンポーネントを `@In` を使って別の Seam EJB コンポーネントにインジェクトできるようにしたい場合、 この EJB 参照を別の場所で定義する必要があります。 この場合、 ejb-jar.xml で定義しなければなりません。 これは若干複雑になります。

EJB メソッドコールのコンテキスト内で、 保護された JNDI コンテキストを処理する必要があります。 Seam が `@In` を使って定義されたインジェクションポイントに応じるため別の Seam EJB コンポーネントの検索を試行する場合、 コンポーネントが見つかっても見つからなくても EJB 参照が JNDI に存在するかどうかに依存します。 厳密に言うと、 好きなように JNDI 名を解決することはできないということです。 参照を明示的に定義する必要があります。 幸運なことに開発者にとってこれがいかに深刻となるか JBoss は認識していたため、 JBoss のバージョンはすべて自動的に EJB を登録するので Web コンテナおよび EJB コンテナの両方に対して JNDI 内で常に使用可能となります。 このため、 JBoss を使用している場合、 次の数段落を省略することができます。 ただし、 GlassFish をデプロイしている場合は注意が必要となります。

EJB 仕様に忠実に従うアプリケーションサーバーの場合、 EJB 参照は常に明示的に定義しなければなりません。 ただし、 単一のリソース参照が Web 環境から EJB の全ユーザーをカバーするような Web コンテキストとは異なり、 EJB 参照を JEB コンテナ内でグローバルには宣言できません。 代わりに、 特定の EJB コンポーネントに対してひとつずつ JNDI 参照を指定する必要があります。

RegisterAction という名前の EJB があると仮定します (この名前は前述の 3 ステップで解決されます)。 EJB には次のような Seam インジェクションがあります。

    @In(create = true)

    Authenticator authenticator;

このインジェクションが動作するようにするには、 次のようにリンクが ejb-jar.xml ファイルで確立されなければなりません。

    <ejb-jar>

        <enterprise-beans>

            <session>

                <ejb-name

    >RegisterAction</ejb-name>

                <ejb-local-ref>

                    <ejb-ref-name

    >myapp/AuthenticatorAction/local</ejb-ref-name>

                    <ejb-ref-type

    >Session</ejb-ref-type>

                    <local

    >com.example.myapp.Authenticator</local>

                </ejb-local-ref>

            </session>

        </enterprise-beans>

        ...

    </ejb-jar>

`<ejb-local-ref>` のコンテンツは web.xml で定義したものとまったく同一であることに注意してください。 ここでは RegisterAction Bean で使用できるような EJB コンテキストに参照をを入れようとしています。 `@In` を使って Seam EJB コンポーネントから別の Seam EJB コンポーネントにインジェクションをする場合はこれらの参照のいずれかひとつを追加する必要があります。 (このセットアップ例については jee5/booking のサンプルをご覧ください)。

では `@EJB` はどうでしょうか。 1 EJB を `@EJB` を使って別の EJB にインジェクトすることが可能なのは事実です。 ただし、 これを行うと Seam EJB コンポーネントのインスタンスではなく実際の EJB 参照をインジェクトすることになります。 この場合、 いくつかの Seam 機能は動作しますが、 動作しない機能もあります。 Seam のインタセプタが EJB コンポーネントへのメソッド呼び出しで起動されるためです。 しかし、 これは Seam のサーバー側インタセプタのチェーンしか起動しません。 つまり、 Seam の状態管理および Seam のクライアント側インタセプタのチェーンを失うことになります。 クライアント側のインタセプタはセキュリティや並列処理などの問題を処理します。 また、 SFSB をインジェクトする場合、 SFSB がアクティブなセッションまたは対話に必ずバインドされるかは状況により保証できません。 したがって `@In` 使った Seam EJB コンポーネントのインジェクトが必ず必要になるはずです。

これにより JNDI 名の定義方法や使用用途が決定されます。 GlassFish などのアプリケーションサーバーでは、 明示的にすべての EJB コンポーネントに JNDI 名を指定しなければならないことになり、 時には 2 度繰り返して指定する必要があることもあります。 また、 JBoss AS と同じ命名規則に従っている場合、 Seam の JNDI パターンを変更する必要がある場合があります。 たとえば、 GlassFish ではグローバルな JNDI 名には自動的に java:comp/env が付けられるため、 次のように JNDI パターンを定義する必要があります。

    <core:init jndi-name="java:comp/env/earName/#{ejbName}/local" />

最後にトランザクションについて説明します。 EJB3 環境ではトランザクション管理に特殊な組み込みコンポーネントを使用することをお勧めします。 コンテナのトランザクションを完全に認識し、 `Events` コンポーネントに登録されるトランザクションの成功イベントを正しく処理することができます。 この行を `components.xml` ファイルに追加しないと Seam はコンテナ管理トランザクションがいつ終了するのかを認識しません。

    <transaction:ejb-transaction/>

### 30.1.6. 忘れないようにしてください。

最後にもう一つ理解しておくことがあります。 Seamコンポーネントがデプロイされるどのようなアーカイブにも、 `seam.properties`、`META-INF/seam.properties` あるいは `META-INF/components.xml`を作成しておく必要があります (空のファイルであってもかまいません)。 Seamは起動時に Seamコンポーネントを探すために、すべてのアーカイブで`seam.properties`をスキャンします。

Seamコンポーネントがある場合には、webアーカイブ (WAR) の`WEB-INF/classes`ディレクトリに `seam.properties`ファイルを作成する必要があります。

すべての Seam サンプルに空白の `seam.properties` ファイルがあるのはこのためです。 このファイルを削除してしまうだけですべてが動作しなくなります。

なぜ設計者は空白のファイルがソフトウェアの動作に影響するよう設計したのだろうと不思議に思うかもしれません。 これは JVM の制限を回避する方法なのです。 このメカニズムを使用しなかったとしたら、 他のフレームワーク同様に `components.xml` に明示的にすべてのコンポーネントを記載せざるをえなくなります。 空白ファイルの方がいいでしょう?

## 30.2. 代替の JPA プロバイダを使用する

Seam ではデフォルトの JPA プロバイダとして Hibernate がパッケージ化され、設定されています。 別の JPA プロバイダを使用する必要がある場合は `seam` に指示しなければなりません。

## これは暫定の方策です。

JPA プロバイダの設定は将来的にはより簡単になり、 カスタムの永続プロバイダ実装を追加しない限り設定変更を必要としなくなります。

Seam への別の JPA プロバイダ情報の指示は 2 種類いずれかの方法で行うことができます。

アプリケーションの `components.xml` を更新します。 これにより汎用 `PersistenceProvider` は hibernate バージョンより優先となります。 次をこのファイルに追加するだけです。

    <component name="org.jboss.seam.persistence.persistenceProvider"

               class="org.jboss.seam.persistence.PersistenceProvider"

               scope="stateless">

    </component

    >

JPA プロバイダの非標準の機能を利用したい場合は `PersistenceProvider` の独自の実装を書く必要があります。 `HibernatePersistenceProvider` を起点として使用します (コミュニティに貢献するのも忘れないでくださいね)。 つぎに前述した通り `seam` にそれを使うよう指示する必要があります。

    <component name="org.jboss.seam.persistence.persistenceProvider"

               class="org.your.package.YourPersistenceProvider">

    </component

    >

あとは正しいプロバイダクラスおよび使用するプロバイダが必要とするプロパティで `persistence.xml` を更新するだけです。 新しいプロバイダの jar ファイル群をアプリケーションでパッケージ化する必要があればそれも忘れないようにしてください。

## 30.3. Java EE 5 で Seam を設定

Java EE 5 環境で実行している場合は Seam を使いはじめるのに必要な設定はこれだけです。

### 30.3.1. パッケージング

EAR にこれらすべてをパッケージ化したらアーカイブの構造は以下のようになります。

    my-application.ear/
        jboss-seam.jar
        lib/
            jboss-el.jar
        META-INF/
            MANIFEST.MF
            application.xml
        my-application.war/
            META-INF/
                MANIFEST.MF
            WEB-INF/
                web.xml
                components.xml
                faces-config.xml
                lib/
                    jsf-facelets.jar
                    jboss-seam-ui.jar
            login.jsp
            register.jsp
            ...
        my-application.jar/
            META-INF/
                MANIFEST.MF
                persistence.xml
            seam.properties
            org/
                jboss/
                    myapplication/
                        User.class
                        Login.class
                        LoginBean.class
                        Register.class
                        RegisterBean.class
                        ...

`jboss-seam.jar` を ejb モジュールとして `META-INF/application.xml` で宣言しなければなりません。 `jboss-el.jar` は EAR の lib ディレクトリに配置されるはずです (EAR クラスパスに配置します)。

jBPM または Drools を使用したい場合は EAR の lib ディレクトリに必要な jar 群を含ませなければなりません。

facelets を使用する場合 (推奨) は WARの`WEB-INF/lib`ディレクトリに `jsf-facelets.jar`を含める必要があります。

Seam のタグライブラリを使用する場合には (ほとんどの Seam アプリケーションで使用されます)、 WAR ファイルの `WEB-INF/lib` ディレクトリに `jboss-seam-ui.jar` を含める必要があります。 PDFや email のタグライブラリを使用する場合には、 `WEB-INF/lib` に `jboss-seam-pdf.jar` または `jboss-seam-mail.jar` を含める必要があります。

Seam デバッグページを使用する (facelets を使用している場合のみ利用可能) 場合には WARの `WEB-INF/lib`ディレクトリに`jboss-seam-debug.jar`を含めます。

サンプルアプリケーションには EJB 3.0をサポートする Java EEコンテナにデプロイ可能ないくつかの Seam アプリケーションがふくまれています。

設定に関するトピックはこれですべてですと言いたいところなんですが、 実はまた3 分の一しか説明していません。 退屈な設定の説明ばかりであきてしまった場合は残りのセクションは飛ばしてあとでもう一度読み直して頂いても構いません。

## 30.4. J2EEでの Seam の設定

Seam は EJB 3.0 の使用にまだ思い切りがつかない方にも便利です。 このような場合には EJB 3.0 永続性ではなく Hibernate3 か JPA を使用し、 セッション Bean の代わりにプレーン JavaBean を使用するとよいでしょう。 セッション Bean のいくつかの優れた機能は使用できませんが、 一旦決心がついたら EJB 3.0 への移行が非常に簡単になりますし、 それまでの間は Seam 固有の宣言的な状態管理アーキテクチャを利用することができます。

Seam JavaBean コンポーネントはセッション Bean のような宣言的トランザクション境界設定は提供しません。 手作業で JTA `UserTransaction` を使用するか、 宣言的に Seam の `@Transactional` アノテーションを使って管理することが できます。 ただし JavaBean と Hibernate を使用する場合、ほとんどのアプリケーションは Seam 管理のトランザクションを使用します。

Seam ディストリビューションには、EJB3 の代わりに Hibernate や JavaBean を使用した 予約サンプルアプリケーションが含まれています。 このサンプルアプリケーションはどんなJ2EEアプリケーションサーバーでも すぐにデプロイ可能です。

### 30.4.1. Seam での Hibernateのブートストラップ

Seam は組み込みコンポーネントがインストールされていれば、 `hibernate.cfg.xml` ファイルから Hibernate の `SessionFactory` をブートストラップします。

    <persistence:hibernate-session-factory name="hibernateSessionFactory"/>

この時、インジェクションを使って、Seamの管理する Hibernateの`Session`を利用するのであれば、 managed sessionを設定する必要があります。

    <persistence:managed-hibernate-session name="hibernateSession"

                                session-factory="#{hibernateSessionFactory}"/>

### 30.4.2. Seam での JPAのブートストラップ

Seam はもし組み込みコンポーネントがインストールされていれば、`persistence.xml` から`EntityManagerFactory` JPAをブートストラップします。

    <persistence:entity-manager-factory name="entityManagerFactory"/>

インジェクションで Seam 管理のJPA `EntityManager` を使用可能にしたい場合は 管理永続コンテキスト を設定する必要があります。

    <persistence:managed-persistence-context name="entityManager"

                                entity-manager-factory="#{entityManagerFactory}"/>

### 30.4.3. パッケージング

アプリケーションは WARとしてパッケージすることができ、その構成は以下の様になります。

    my-application.war/
        META-INF/
            MANIFEST.MF
        WEB-INF/
            web.xml
            components.xml
            faces-config.xml
            lib/
                jboss-seam.jar
                jboss-seam-ui.jar
                jboss-el.jar
                jsf-facelets.jar
                hibernate3.jar
                hibernate-annotations.jar
                hibernate-validator.jar
                ...
                my-application.jar/
                    META-INF/
                       MANIFEST.MF
                    seam.properties
                    hibernate.cfg.xml
                    org/
                        jboss/
                            myapplication/
                                User.class
                                Login.class
                                Register.class
                                ...
        login.jsp
        register.jsp
        ...

Hibernate を Tomcat や TestNG のような EE 以外の環境にデプロイしたい場合はもう少し作業が必要となります。

## 30.5. JBoss Embedded なしの Java SE で Seam を設定する

Seam を完全に EE 環境の外側で使用することが可能です。 この場合、 使用できる JTA がないので Seam にどのようにトランザクションを管理するのかを指示する必要があります。 JPA を使用している場合は Seam に JPA リソースローカルのトランザクション、 `EntityTransaction` などを使用するよう指示することができます。

    <transaction:entity-transaction entity-manager="#{entityManager}"/>

Hibernate を使用している場合は Seam に次のように Hibernate トランザクション API を使用するよう指示することができます。

    <transaction:hibernate-transaction session="#{session}"/>

当然、 データソースも定義する必要があります。

よりよい代替としては JBoss Embedded を使用して EE の API にアクセスします。

## 30.6. JBoss Embedded を使用し Java SE で Seam を設定する

JBoss Embedded により Java EE 5 アプリケーションサーバーのコンテキストの外側で EJB 3 のコンポーネントを実行することができるようになります。 これには限られませんが、 特にテストに便利です。

Seam 予約サンプルアプリケーションには TestNG 統合テストスィートが含まれ、 `SeamTest` を通じて JBoss Embedded で実行します。

この予約サンプルアプリケーションは Tomcat にもデプロイ可能です。

### 30.6.1. Embedded JBoss をインストールする

Embedded JBoss を正しく動作させるには Seam アプリケーション用の Tomcat にインストールしなければなりません。 Embedded JBoss は JDK 5 または JDK 6 で実行します (JDK 6 の使い方については 項42.1. 「JDK の依存性」 を参照)。 Embedded JBoss は ここ でダウンロードできます。 Embedded JBoss の Tomcat 6 へのインストール手順は非常にシンプルです。 まず、 Embedded JBoss JAR 群と設定ファイル群を Tomcat にコピーします。

- `jndi.properties` ファイルを除き、 Embedded JBoss の `bootstrap` ディレクトリと `lib` ディレクトリの配下にある全ファイルとディレクトリを Tomcat の `lib` ディレクトリにコピーします。

- Tomcat の `lib` ディレクトリから `annotations-api.jar` ファイルを削除します。

次に、 Embedded JBoss 固有の機能を追加するため 2 つの設定ファイルを更新する必要があります。

- Embedded JBoss リスナー `EmbeddedJBossBootstrapListener` を `conf/server.xml` に追加します。 このファイル内の他のすべてのリスナーの後ろに現れなければなりません。

      <Server port="8005" shutdown="SHUTDOWN">

        <!-- Comment these entries out to disable JMX MBeans support used for the

             administration web application -->

        <Listener className="org.apache.catalina.core.AprLifecycleListener" />

        <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />

        <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

        <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener" />

        <!-- Add this listener -->

        <Listener className="org.jboss.embedded.tomcat.EmbeddedJBossBootstrapListener" />

- WAR ファイルのスキャンは `WebinfScanner` リスナーを `conf/context.xml` に追加することで有効になるはずです。

      <Context>

          <!-- Default set of monitored resources -->

          <WatchedResource

      >WEB-INF/web.xml</WatchedResource>

          <!-- Uncomment this to disable session persistence across Tomcat restarts -->

          <!--

          <Manager pathname="" />

          -->

        <!-- Add this listener -->

        <Listener className="org.jboss.embedded.tomcat.WebinfScanner" />

      </Context

      >

- Sun JDK 6 を使用している場合は Catalina の起動スクリプト (Windows なら catalina.bat、 Unix なら catalina.sh) で使用される JAVA_OPTS 環境変数内の Java オプション`sun.lang.ClassLoader.allowArraySyntax` を `true` にセットする必要があります。

  使用しているオペレーティングシステムに応じたスクリプトをテキストエディタで開きます。 JAVA_OPTS 環境変数を定義する場所、 ファイルの先頭にあるコメントのすぐ下に新しい行を追加します。 Windows なら次の構文を使用します。

      set JAVA_OPTS=%JAVA_OPTS% -Dsun.lang.ClassLoader.allowArraySyntax=true

  Unix の場合は次の構文を使用してください。

      JAVA_OPTS="$JAVA_OPTS -Dsun.lang.ClassLoader.allowArraySyntax=true"

設定オプションの詳細については Embedded JBoss Tomcat 統合 wiki エントリ を参照してください。

### 30.6.2. パッケージング

Tomcat のような サーブレットエンジンへの WAR ベースのデプロイメントのアーカイブの構造は、以下のようになります。

    my-application.war/
        META-INF/
            MANIFEST.MF
        WEB-INF/
            web.xml
            components.xml
            faces-config.xml
            lib/
                jboss-seam.jar
                jboss-seam-ui.jar
                jboss-el.jar
                jsf-facelets.jar
                jsf-api.jar
                jsf-impl.jar
                ...
                my-application.jar/
                    META-INF/
                        MANIFEST.MF
                        persistence.xml
                    seam.properties
                    org/
                        jboss/
                            myapplication/
                                User.class
                                Login.class
                                LoginBean.class
                                Register.class
                                RegisterBean.class
                                ...
        login.jsp
        register.jsp
        ...

ほとんどの Seam サンプルアプリケーションは、`ant deploy.tomcat` を実行することによって、 Tomcat にデプロイすることも可能です。

## 30.7. SeamでのjBPM設定

Seam の jBPM 統合はデフォルトではインストールされないため組み込みコンポーネントをインストールすることにより jBPM を有効にする必要があります。 また、 使用するプロセスとページフローの定義を `components.xml` で明示的に記載する必要があります。

    <bpm:jbpm>

        <bpm:pageflow-definitions>

            <value

    >createDocument.jpdl.xml</value>

            <value

    >editDocument.jpdl.xml</value>

            <value

    >approveDocument.jpdl.xml</value>

        </bpm:pageflow-definitions>

        <bpm:process-definitions>

            <value

    >documentLifecycle.jpdl.xml</value>

        </bpm:process-definitions>

    </bpm:jbpm

    >

ページフローのみの指定であれば、これ以上の設定は不要です。ビジネスプロセス定義を利用する場合、 jBPM 設定および jBPM 用の Hibernate 設定も用意する必要があります。Seam DVD Store demoは Seam で機能する `jbpm.cfg.xml`と`hibernate.cfg.xml`を含めた サンプルです。

    <jbpm-configuration>

      <jbpm-context>

        <service name="persistence">

           <factory>

              <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">

                 <field name="isTransactionEnabled"

    ><false/></field>

              </bean>

           </factory>

        </service>

        <service name="tx" factory="org.jbpm.tx.TxServiceFactory" />

        <service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />

        <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />

        <service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />

        <service name="authentication"

                 factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />

      </jbpm-context>

    </jbpm-configuration

    >

ここでのもっとも重要なことは、jBPMトランザクション制御は無効になっているということです。 Seam、あるいはEJB3がJTAトランザクションを制御するべきです。

### 30.7.1. パッケージング

jBPM 設定やプロセスおよびページフローの定義ファイルに対する明確なパッケージング形式がいまだありません。 Seam サンプルでは単純にこうしたファイルはすべて EAR のルートにパッケージすることにしました。 将来的には何らかの標準的なパッケージング形式を設計することになると思います。 EAR は次のようになります。

    my-application.ear/
        jboss-seam.jar
        lib/
           jboss-el.jar
           jbpm-3.1.jar
        META-INF/
            MANIFEST.MF
            application.xml
        my-application.war/
            META-INF/
                MANIFEST.MF
            WEB-INF/
                web.xml
                components.xml
                faces-config.xml
                lib/
                    jsf-facelets.jar
                    jboss-seam-ui.jar
            login.jsp
            register.jsp
            ...
        my-application.jar/
            META-INF/
                MANIFEST.MF
                persistence.xml
            seam.properties
            org/
                jboss/
                    myapplication/
                        User.class
                        Login.class
                        LoginBean.class
                        Register.class
                        RegisterBean.class
                        ...
        jbpm.cfg.xml
        hibernate.cfg.xml
        createDocument.jpdl.xml
        editDocument.jpdl.xml
        approveDocument.jpdl.xml
        documentLifecycle.jpdl.xml

## 30.8. JBoss ASでの SFSBとセッションタイムアウトの設定

ステートフルセッション Bean のタイムアウトは HTTP セッションのタイムアウトより高く設定することが非常に重要となります。 これをしないと SFSB がユーザーの HTTP セッションが終了する前にタイムアウトする可能性があります。 JBoss Application Server はセッション Bean タイムアウトがデフォルトでは 30 分になり、 server/default/conf/standardjboss.xml (default は各自の設定セット名に置き換えてください) で設定されています。

デフォルトの SFSB タイムアウトは `LRUStatefulContextCachePolicy` キャッシュ設定内の `max-bean-life` の値を変更して調整することができます。

    <container-cache-conf>

        <cache-policy

    >org.jboss.ejb.plugins.LRUStatefulContextCachePolicy</cache-policy>

        <cache-policy-conf>

            <min-capacity

    >50</min-capacity>

            <max-capacity

    >1000000</max-capacity>

            <remover-period

    >1800</remover-period>

            <!-- SFSB timeout in seconds; 1800 seconds == 30 minutes -->

            <max-bean-life

    >1800</max-bean-life

    >

            <overager-period

    >300</overager-period>

            <max-bean-age

    >600</max-bean-age>

            <resizer-period

    >400</resizer-period>

            <max-cache-miss-period

    >60</max-cache-miss-period>

            <min-cache-miss-period

    >1</min-cache-miss-period>

            <cache-load-factor

    >0.75</cache-load-factor>

        </cache-policy-conf>

    </container-cache-conf

    >

デフォルトの HTTP セッションタイムアウトは、 JBoss 4.0.x なら `server/default/deploy/jbossweb-tomcat55.sar/conf/web.xml` で、 JBoss 4.2.x なら `server/default/deploy/jboss-web.deployer/conf/web.xml` でそれぞれ変更することができます。 このファイルの次のエントリですべての Web アプリケーションのデフォルトセッションタイムアウトを制御します。

    <session-config>

        <!-- HTTP Session timeout, in minutes -->

        <session-timeout

    >30</session-timeout>

    </session-config

    >

使用するアプリケーション用にこの値を上書きするにはこのエントリをそのアプリケーションの `web.xml` に含めるだけです。

## 30.9. Portlet で Seam を実行する

Seam アプリケーションを porlet で実行させたい場合は Seam および RichFaces 用の拡張を持ち portlet 内で JSF をサポートする JSR-301 の実装 JBoss Portlet Bridge を見てみてください。 詳細は http://labs.jboss.com/portletbridge を参照してください。

## 30.10. カスタムのリソースをデプロイする

Seam はリソースの起動時に `/seam.properties`、 `/META-INF/components.xml`、 または `/META-INF/seam.properties` を含むすべての jar をスキャンします。 たとえば、 `@Name` アノテーションが付与されたクラスはすべて Seam コンポーネントとして Seam に登録されます。

また、 Seam にカスタムのリソースを処理させたい場合があります。 一般的な使用例としては特定のアノテーションを処理することで、 Seam はこれに対する固有のサポートを提供します。 まず Seam に `/META-INF/seam-deployment.properties` で処理するアノテーションを指示します。

    # A colon-separated list of annotation types to handle
    org.jboss.seam.deployment.annotationTypes=com.acme.Foo:com.acme.Bar

するとアプリケーション起動時に `@Foo` アノテーションが付くすべてのクラスを捕らえることができます。

    @Name("fooStartup")
    @Scope(APPLICATION)
    @Startup
    public class FooStartup {

       @In("#{deploymentStrategy.annotatedClasses['com.acme.Foo']}")
       private Set<Class<Object
    >
    > fooClasses;

       @In("#{hotDeploymentStrategy.annotatedClasses['com.acme.Foo']}")
       private Set<Class<Object
    >
    > hotFooClasses;

       @Create
       public void create() {
          for (Class clazz: fooClasses) {
             handleClass(clazz);
          }
          for (Class clazz: hotFooClasses) {
             handleClass(clazz);
          }
       }

       public void handleClass(Class clazz) {
           // ...
       }

    }

また、 あらゆる リソースを処理することができます。 たとえば、 `.foo.xml` 拡張子が付くファイルすべてを処理する場合、 カスタムのデプロイメントハンドラを記述する必要があります。

    public class FooDeploymentHandler implements DeploymentHandler {
        private static DeploymentMetadata FOO_METADATA = new DeploymentMetadata()
        {

            public String getFileNameSuffix() {
                return ".foo.xml";
            }
        };

       public String getName() {
          return "fooDeploymentHandler";
       }

        public DeploymentMetadata getMetadata() {
            return FOO_METADATA;
        }
    }

ここではサフィックス `.foo.xml` が付くすべてのファイルの一覧を作成しているだけです。

つぎに `/META-INF/seam-deployment.properties` でデプロイメントハンドラを Seam に登録する必要があります。 コンマで区切った一覧を使うと複数のデプロイメントハンドラを登録することができます。

    # For standard deployment
    org.jboss.seam.deployment.deploymentHandlers=com.acme.FooDeploymentHandler
    # For hot deployment
    org.jboss.seam.deployment.hotDeploymentHandlers=com.acme.FooDeploymentHandler

Seam は内部的にデプロイメントハンドラを使ってコンポーネントや名前空間をインストールします。 `APPLICATION` スコープのコンポーネントの起動中にデプロイメントハンドラに簡単にアクセスすることができます。

    @Name("fooStartup")
    @Scope(APPLICATION)
    @Startup
    public class FooStartup {

       @In("#{deploymentStrategy.deploymentHandlers['fooDeploymentHandler']}")
       private FooDeploymentHandler myDeploymentHandler;

       @In("#{hotDeploymentStrategy.deploymentHandlers['fooDeploymentHandler']}")
       private FooDeploymentHandler myHotDeploymentHandler;

       @Create
       public void create() {
          for (FileDescriptor fd: myDeploymentHandler.getResources()) {
               handleFooXml(fd);
          }

          for (FileDescriptor f: myHotDeploymentHandler.getResources()) {
               handleFooXml(fd);
          }
       }

       public void handleFooXml(FileDescriptor fd) {
           // ...
       }
    }

- 前のページ第29章 Hibernate Search
- 上に戻る
- ホーム
- 次のページ第31章 Seam アノテーション