SeamFramework.orgCommunity Documentation

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

29.1. Seam の基本設定
29.1.1. Seam と JSF、 サーブレットコンテナとの統合
29.1.2. Using facelets
29.1.3. Seam リソースサーブレット
29.1.4. Seamサーブレットフィルタ
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. カスタムのリソースをデプロイする

Configuration is a very boring topic and an extremely tedious pastime. Unfortunately, several lines of XML are required to integrate Seam into your JSF implementation and servlet container. There's no need to be too put off by the following sections; you'll never need to type any of this stuff yourself, since you can just copy and paste from the example applications!

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

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

We need to apply the SeamInterceptor to our Seam components. The simplest way to do this across an entire application is to add the following interceptor configuration in 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 needs to know where to go to find session beans in JNDI. One way to do this is specify the @JndiName annotation on every session bean Seam component. However, this is quite tedious. A better approach is to specify a pattern that Seam can use to calculate the JNDI name from the EJB name. Unfortunately, there is no standard mapping to global JNDI defined in the EJB3 specification, so this mapping is vendor-specific. We usually specify this option in components.xml.

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


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

Where myEarName is the name of the EAR in which the bean is deployed.

Outside the context of an EAR (when using the JBoss Embeddable EJB3 container), the following pattern is the one to use:


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

You'll have to experiment to find the right setting for other application servers. Note that some servers (such as GlassFish) require you to specify JNDI names for all EJB components explicitly (and tediously). In this case, you can pick your own pattern ;-)

In an EJB3 environment, we recommend the use of a special built-in component for transaction management, that is fully aware of container transactions, and can correctly process transaction success events registered with the Events component. If you don't add this line to your components.xml file, Seam won't know when container-managed transactions end:


<transaction:ejb-transaction/>

Seam ではデフォルトの JPA プロバイダとして 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 分の一しか説明していません。 退屈な設定の説明ばかりであきてしまった場合は残りのセクションは飛ばしてあとでもう一度読み直して頂いても構いません。

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
    >
  • If you are using JDK 6, you must set the Java option sun.lang.ClassLoader.allowArraySyntax to true in Tomcat's startup script (either catalina.bat or catalina.sh):

    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 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 でそれぞれ変更することができます。 このファイルの次のエントリで、 すべてのウェブアプリケーションのデフォルトセッションタイムアウトを制御します。


<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() が Seam のブートストラップの早い時点で呼ばれるので、多くの場合に不便かもしれません。 ただし、 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);
      }
   }

}