SeamFramework.orgCommunity Documentation

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

29.1. Seam の基本設定
29.1.1. Seam と JSF、servlet コンテナとの統合
29.1.2. facelet を使用する
29.1.3. Seam リソース Servlet
29.1.4. Seam servlet フィルター
29.1.5. EJB コンテナと Seam の統合
29.1.6. 忘れないようにしてください。
29.2. 代替の JPA プロバイダを使用する
29.3. Java EE 5 で Seam を設定
29.3.1. パッケージング
29.4. J2EEでの Seam の設定
29.4.1. Seam での Hibernateのブートストラップ
29.4.2. Seam での JPAのブートストラップ
29.4.3. パッケージング
29.5. JBoss Embedded なしの Java SE で Seam を設定する
29.6. JBoss Embedded なしの Java SE で Seam を設定する
29.6.1. Embedded JBoss をインストールする
29.6.2. パッケージング
29.7. SeamでのjBPM設定
29.7.1. パッケージング
29.8. JBoss ASでの SFSBとセッションタイムアウトの設定
29.9. Portlet で Seam を実行する
29.10. カスタムのリソースをデプロイする

設定とは非常につまらないトピックであり極めて退屈な作業でもあります。 残念ながら XML の数行が JSF 実装およびサーブレットコンテナへの Seam の統合に必要となります。 ただし、 次のセクションにあるようなものを独自に入力する必要はなくサンプルのアプリケーションからコピーして貼り付けるだけの作業になりますので、 それほど心配することもありません。

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

当然 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
>

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 で指定される 1 番目のフィルタでなければなりません。 これによりマスターフィルタが一番最初に実行されるようになります。

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

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

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

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"/>

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="myEarName/#{ejbName}/local" />

ここで、myEarNameは、Bean がデプロイされた EAR の名前です。

EAR のコンテキストの外側では (JBoss 組み込み可能 EJB3 コンテナを使用するとき)、 次のパターンは使い方の 1 つです。


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

他のアプリケーションサーバーに対して正しい設定を見つけるため実験を行う必要があります。 サーバーのなかにはすべての EJB コンポーネントにいちいち明示的に JNDI 名を指定する必要があるものもあるので注意してください。 この場合は独自のパターンを選択できます。

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


<transaction:ejb-transaction/>

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

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 ファイル群をアプリケーションでパッケージ化する必要があればそれも忘れないようにしてください。

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

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/libjboss-seam-pdf.jar または jboss-seam-mail.jar を含める必要があります。

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

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

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

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アプリケーションサーバでも すぐにデプロイ可能です。

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 へのアクセスを取得すします。

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

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

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

Embedded JBoss を正しく動作させるには Seam アプリケーション用の Tomcat にインストールしなければなりません。 Embedded JBoss は JDK 5 または JDK 6 で実行します (JDK 6 の使い方については 項40.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 リスナー EmbeddedJBossBootstrapListenerconf/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
    >
  • JDK 6 を使用している場合は Tomcat の起動スクリプト (catalina.bat か catalina.sh のどちらか) にある Java オプションの sun.lang.ClassLoader.allowArraySyntaxtrue にセットする必要があります。

    set JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" -Dsun.lang.ClassLoader.allowArraySyntax=true

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

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.xmlhibernate.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トランザクションを制御するべきです。

ステートフルセッション Bean のタイムアウトは HTTP セッションのタイムアウトより高くセットすることが非常に重要となります。 これをしないと SFSB がユーザーの HTTP セッションが終了する前にタイムアウトする可能性があります。 JBoss Application Servre はセッション 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 でそれぞれ変更することができます。 このファイルの次のエントリで、 すべてのウェブアプリケーションのデフォルトセッションタイムアウトを制御します。


<session-config>
    <!-- HTTP Session timeout, in minutes -->
    <session-timeout
>30</session-timeout>
</session-config
>

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

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

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);
      }
   }

}

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

public class FooDeploymentHandler implements DeploymentHandler {
        
   private Set<InputStream
> files = new HashSet<InputStream
>();
        
   public String getName() {
      return "fooDeploymentHandler";
   }
   
   public Set<InputStream
> getFiles() {
      return files;
   }
   
   public void handle(String name, ClassLoader classLoader) {
      if (name.endsWith(".foo.xml")) {
         files.add(classLoader.getResourceAsStream(name));
      }
   }
}

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

つぎにデプロイメントハンドラを Seam に登録する必要があります。 /META-INF/seam-deployment.properties で行います。

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

コンマで区切った一覧を使うと複数のデプロイメントハンドラを登録することができます。

Seam は内部的にデプロイメントハンドラを使ってコンポーネントや名前空間をインストールするため、 その前に handle() を呼び出すと多くの場合に便利です。 ただし、 APPLICATION スコープのコンポーネントの起動中にデプロイメントハンドラに簡単にアクセスすることができます。

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

   @In("#{deploymentStrategy['fooDeploymentHandler']}")
   private MyDeploymentHandler myDeploymentHandler;
   
   @In("#{hotDeploymentStrategy['fooDeploymentHandler']}")
   private MyDeploymentHandler myHotDeploymentHandler;

   @Create
   public void create() {
      for (InputStream is : myDeploymentHandler.getFiles()) {
         handleFooXml(is);
      }
      for (InputStream is : myHotDeploymentHandler.getFiles()) {
         handleFooXml(is);
      }
   }

}