站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > JBoss Seam 1.1.6 正式版英文参考手册

Chapter 19. Configuring Seam and packaging Seam applications - JBoss Seam 1.1.6 正式版英文参考手册

Chapter 19. Configuring Seam and packaging Seam applications

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!

19.1. Basic Seam configuration

First, let's look at the basic configuration that is needed whenever we use Seam with JSF.

19.1.1. Integrating Seam with JSF and your servlet container

Seam requires the following entry in your web.xml file:

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

This listener is responsible for bootstrapping Seam, and for destroying session and application contexts.

To integrate with the JSF request lifecycle, we also need a JSF PhaseListener registered in in the faces-config.xml file:

<lifecycle>
    <phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
</lifecycle>

The actual listener class here varies depending upon how you want to manage transaction demarcation (more on this below).

If you are using Sun's JSF 1.2 reference implementation, you should also add this to faces-config.xml:

<application>
    <el-resolver>org.jboss.seam.jsf.SeamELResolver</el-resolver>
</application>

(This line should not strictly speaking be necessary, but it works around a minor bug in the RI.)

Some JSF implementations have a broken implementation of server-side state saving that interferes with Seam's conversation propagation. If you have problems with conversation propagation during form submissions, try switching to client-side state saving. You'll need this in web.xml:

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

19.1.2. Integrating Seam with your EJB container

We need to apply the SeamInterceptor to our Seam components. The simplest way to do this is to add the following interceptor binding to the <assembly-descriptor> in ejb-jar.xml:

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

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.

For JBoss AS, the following pattern is correct:

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

19.1.3. Enabling Seam exception handling

If you want to use Seam's exception mapping functionality in pages.xml (almost all applications will need this), you need to add a servlet filter to web.xml:

<filter>
    <filter-name>Seam Exception Filter</filter-name>
    <filter-class>org.jboss.seam.servlet.SeamExceptionFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Seam Exception Filter</filter-name>
    <url-pattern>*.seam</url-pattern>
</filter-mapping>

This servlet filter also takes care of rolling back uncommitted transactions when uncaught exceptions occur. (According to the Java EE specification, the web container should do this automatically, but we've found that this behavior cannot be relied upon in all application servers. And it is certainly not required of plain servlet engines like Tomcat.)

19.1.4. Enabling conversation propagation with redirects

If you want to use post-then-redirect in JSF, and you want Seam to propagate the conversation context across the browser redirects, you need to register a servlet filter:

<filter>
    <filter-name>Seam Redirect Filter</filter-name>
    <filter-class>org.jboss.seam.servlet.SeamRedirectFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Seam Redirect Filter</filter-name>
    <url-pattern>*.jsf</url-pattern>
</filter-mapping>

This filter intercepts any browser redirects and adds a request parameter that specifies the Seam conversation id.

19.1.5. Using facelets

If you want follow our advice and use facelets instead of JSP, add the following lines to faces-config.xml:

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

And the following lines to web.xml:

<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
</context-param>

19.1.6. Don't forget!

There is one final item you need to know about. You must place a seam.properties, META-INF/seam.properties or META-INF/components.xml file in any archive in which your Seam components are deployed (even an empty properties file will do). At startup, Seam will scan any archives with seam.properties files for seam components.

That's why all the Seam examples have an empty seam.properties file. You can't just delete this file and expect everything to still work!

You might think this is silly and what kind of idiot framework designers would make an empty file affect the behavior of their software?? Well, this is a workaround for a limitation of the JVM—if we didn't use this mechanism, our next best option would be to force you to list every component explicitly in components.xml, just like some other competing frameworks do! I think you'll like our way better.

19.2. Configuring Seam in Java EE 5

If you're running in a Java EE 5 environment, this is all the configuration required to start using Seam!

19.2.1. Packaging

Once you've packaged all this stuff together into an EAR, the archive structure will look something like this:

my-application.ear/
    jboss-seam.jar
    el-api.jar
    el-ri.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
                    ...

You must include jboss-seam.jar, el-api.jar and el-ri.jar in the EAR classpath. Make sure you reference all of these jars from application.xml.

If you want to use jBPM or Drools, you must include the needed jars in the EAR classpath. Make sure you reference all of the jars from application.xml.

If you want to use facelets (our recommendation), you must include jsf-facelets.jar in the WEB-INF/lib directory of the WAR.

If you want to use the Seam tag library (most Seam applications do), you must include jboss-seam-ui.jar in the WEB-INF/lib directory of the WAR. If you want to use the PDF or email tag libraries, you need to put jboss-seam-pdf.jar or jboss-seam-mail.jar in WEB-INF/lib.

If you want to use the Seam debug page (only works for applications using facelets), you must include jboss-seam-debug.jar in the WEB-INF/lib directory of the WAR.

Seam ships with several example applications that are deployable in any Java EE container that supports EJB 3.0.

I really wish that was all there was to say on the topic of configuration but unfortunately we're only about a third of the way there. If you're too overwhelmed by all this tedious configuration stuff, feel free to skip over the rest of this section and come back to it later.

19.3. Configuring Seam in Java SE, with the JBoss Embeddable EJB3 container

The JBoss Embeddable EJB3 container lets you run EJB3 components outside the context of the Java EE 5 application server. This is especially, but not only, useful for testing.

The Seam booking example application includes a TestNG integration test suite that runs on the Embeddable EJB3 container.

The booking example application may even be deployed to Tomcat.

19.3.1. Installing the Embeddable EJB3 container

Seam ships with a build of the Embeddable EJB3 container in the embedded-ejb directory. To use the Embeddable EJB3 container with Seam, add the embedded-ejb/conf directory, and all jars in the lib and embedded-ejb/lib directories to your classpath. Then, add the following line to components.xml:

<core:ejb />

This setting installs the built-in component named org.jboss.seam.core.ejb. This component is responsible for bootstrapping the EJB container when Seam is started, and shutting it down when the web application is undeployed.

19.3.2. Configuring a datasource with the Embeddable EJB3 container

You should refer to the Embeddable EJB3 container documentation for more information about configuring the container. You'll probably at least need to set up your own datasource. Embeddable EJB3 is implemented using the JBoss Microcontainer, so it's very easy to add new services to the minimal set of services provided by default. For example, I can add a new datasource by putting this jboss-beans.xml file in my classpath:

<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="urn:jboss:bean-deployer bean-deployer_1_0.xsd"
            xmlns="urn:jboss:bean-deployer">

   <bean name="bookingDatasourceBootstrap"
        class="org.jboss.resource.adapter.jdbc.local.LocalTxDataSource">
      <property name="driverClass">org.hsqldb.jdbcDriver</property>
      <property name="connectionURL">jdbc:hsqldb:.</property>
      <property name="userName">sa</property>
      <property name="jndiName">java:/bookingDatasource</property>
      <property name="minSize">0</property>
      <property name="maxSize">10</property>
      <property name="blockingTimeout">1000</property>
      <property name="idleTimeout">100000</property>
      <property name="transactionManager">
        <inject bean="TransactionManager"/>
      </property>
      <property name="cachedConnectionManager">
        <inject bean="CachedConnectionManager"/>
      </property>
      <property name="initialContextProperties">
        <inject bean="InitialContextProperties"/>
      </property>
   </bean>

   <bean name="bookingDatasource" class="java.lang.Object">
      <constructor factoryMethod="getDatasource">
         <factory bean="bookingDatasourceBootstrap"/>
      </constructor>
   </bean>

</deployment>

19.3.3. Packaging

The archive structure of a WAR-based deployment on an servlet engine like Tomcat will look something like this:

my-application.war/
    META-INF/
        MANIFEST.MF
    WEB-INF/
        web.xml
        components.xml
        faces-config.xml
        lib/
            jboss-seam.jar
            jboss-seam-ui.jar
            el-api.jar
            el-ri.jar
            jsf-facelets.jar
            myfaces-api.jar
            myfaces-impl.jar
            jboss-ejb3.jar
            jboss-jca.jar
            jboss-j2ee.jar
            ...
            mc-conf.jar/
                ejb3-interceptors-aop.xml
                embedded-jboss-beans.xml
                default.persistence.properties
                jndi.properties
                login-config.xml
                security-beans.xml
                log4j.xml
            my-application.jar/
                META-INF/
                    MANIFEST.MF
                    persistence.xml
                    jboss-beans.xml
                log4j.xml
                seam.properties
                org/
                    jboss/
                        myapplication/
                            User.class
                            Login.class
                            LoginBean.class
                            Register.class
                            RegisterBean.class
                            ...
    login.jsp
    register.jsp
    ...

The mc-conf.jar just contains the standard JBoss Microcontainer configuration files for Embeddable EJB3. You won't usually need to edit these files yourself.

Most of the Seam example applications may be deployed to Tomcat by running ant deploy.tomcat.

19.4. Configuring Seam in J2EE

Seam is useful even if you're not yet ready to take the plunge into EJB 3.0. In this case you would use Hibernate3 or JPA instead of EJB 3.0 persistence, and plain JavaBeans instead of session beans. You'll miss out on some of the nice features of session beans but it will be very easy to migrate to EJB 3.0 when you're ready and, in the meantime, you'll be able to take advantage of Seam's unique declarative state management architecture.

Seam JavaBean components do not provide declarative transaction demarcation like session beans do. You could manage your transactions manually using the JTA UserTransaction (you could even implement your own declarative transaction management in a Seam interceptor). But most applications will use Seam managed transactions when using Hibernate with JavaBeans. Follow the instructions in the persistence chapter to install TransactionalSeamPhaseListener.

The Seam distribution includes a version of the booking example application that uses Hibernate3 and JavaBeans instead of EJB3, and another version that uses JPA and JavaBeans. These example applications are ready to deploy into any J2EE application server.

19.4.1. Boostrapping Hibernate in Seam

Seam will bootstrap a Hibernate SessionFactory from your hibernate.cfg.xml file if you install a built-in component:

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

You will also need to configure a managed session if you want a Seam managed Hibernate Session to be available via injection.

19.4.2. Boostrapping JPA in Seam

Seam will bootstrap a JPA EntityManagerFactory from your persistence.xml file if you install this built-in component:

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

You will also need to configure a managed persistencece context if you want a Seam managed JPA EntityManager to be available via injection.

19.4.3. Packaging

We can package our application as a WAR, in the following structure:

my-application.war/
    META-INF/
        MANIFEST.MF
    WEB-INF/
        web.xml
        components.xml
        faces-config.xml
        lib/
            jboss-seam.jar
            jboss-seam-ui.jar
            el-api.jar
            el-ri.jar
            jsf-facelets.jar
            hibernate3.jar
            hibernate-annotations.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
    ...

If we want to deploy Hibernate in a non-J2EE environment like Tomcat or TestNG, we need to do a little bit more work.

19.5. Configuring Seam in Java SE, with the JBoss Microcontainer

The Seam support for Hibernate and JPA requires JTA and a JCA datasource. If you are running in a non-EE environment like Tomcat or TestNG you can run these services, and Hibernate itself, in the JBoss Microcontainer.

You can even deploy the Hibernate and JPA versions of the booking example in Tomcat.

Seam ships with an example Microcontainer configuration in microcontainer/conf/jboss-beans.xml that provides all the things you need to run Seam with Hibernate in any non-EE environment. Just add the microcontainer/conf directory, and all jars in the lib and microcontainer/lib directories to your classpath. Refer to the documentation for the JBoss Microcontainer for more information.

19.5.1. Using Hibernate and the JBoss Microcontainer

The built-in Seam component named org.jboss.seam.core.microcontainer bootstraps the microcontainer. As before, we probably want to use a Seam managed session.

<core:microcontainer/>

<core:managed-hibernate-session name="bookingDatabase" auto-create="true"
    session-factory-jndi-name="java:/bookingSessionFactory"/>

Where java:/bookingSessionFactory is the name of the Hibernate session factory specified in hibernate.cfg.xml.

You'll need to provide a jboss.beans.xml file that installs JNDI, JTA, your JCA datasource and Hibernate into the microcontainer:

<?xml version="1.0" encoding="UTF-8"?>

<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="urn:jboss:bean-deployer bean-deployer_1_0.xsd"
            xmlns="urn:jboss:bean-deployer">
            
   <bean name="Naming" class="org.jnp.server.SingletonNamingServer"/>

   <bean name="TransactionManagerFactory" class="org.jboss.seam.microcontainer.TransactionManagerFactory"/>
   <bean name="TransactionManager" class="java.lang.Object">
      <constructor factoryMethod="getTransactionManager">
         <factory bean="TransactionManagerFactory"/>
      </constructor>
   </bean>

   <bean name="bookingDatasourceFactory" class="org.jboss.seam.microcontainer.DataSourceFactory">
      <property name="driverClass">org.hsqldb.jdbcDriver</property>
      <property name="connectionUrl">jdbc:hsqldb:.</property>
      <property name="userName">sa</property>
      <property name="jndiName">java:/hibernateDatasource</property>
      <property name="minSize">0</property>
      <property name="maxSize">10</property>
      <property name="blockingTimeout">1000</property>
      <property name="idleTimeout">100000</property>
      <property name="transactionManager"><inject bean="TransactionManager"/></property>
   </bean>
   <bean name="bookingDatasource" class="java.lang.Object">
      <constructor factoryMethod="getDataSource">
         <factory bean="bookingDatasourceFactory"/>
      </constructor>
   </bean>
   
   <bean name="bookingSessionFactoryFactory" class="org.jboss.seam.microcontainer.HibernateFactory"/>
   <bean name="bookingSessionFactory" class="java.lang.Object">
      <constructor factoryMethod="getSessionFactory">
         <factory bean="bookingSessionFactoryFactory"/>
      </constructor>
      <depends>bookingDatasource</depends>
   </bean>

</deployment>

19.5.2. Packaging

The WAR could have the following structure:

my-application.war/
    META-INF/
        MANIFEST.MF
    WEB-INF/
        web.xml
        components.xml
        faces-config.xml
        lib/
            jboss-seam.jar
            jboss-seam-ui.jar
            el-api.jar
            el-ri.jar
            jsf-facelets.jar
            hibernate3.jar
            ...
            jboss-microcontainer.jar
            jboss-jca.jar
            ...
            myfaces-api.jar
            myfaces-impl.jar
            mc-conf.jar/
                jndi.properties
                log4j.xml
            my-application.jar/
                META-INF/
                    MANIFEST.MF
                    jboss-beans.xml
                seam.properties
                hibernate.cfg.xml
                log4j.xml
                org/
                    jboss/
                        myapplication/
                            User.class
                            Login.class
                            Register.class
                            ...
    login.jsp
    register.jsp
    ...

19.6. Configuring jBPM in Seam

Seam's jBPM integration is not installed by default, so you'll need to enable jBPM by installing a built-in component. You'll also need to explicitly list your process and pageflow definitions. In components.xml:

<core:jbpm>
    <core:pageflow-definitions>
        <value>createDocument.jpdl.xml</value>
        <value>editDocument.jpdl.xml</value>
        <value>approveDocument.jpdl.xml</value>
    </core:pageflow-definitions>
    <core:process-definitions>
        <value>documentLifecycle.jpdl.xml</value>
    </core:process-definitions>
</core:jbpm>

No further special configuration is needed if you only have pageflows. If you do have business process definitions, you need to provide a jBPM configuration, and a Hibernate configuration for jBPM. The Seam DVD Store demo includes example jbpm.cfg.xml and hibernate.cfg.xml files that will work with Seam:

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

The most important thing to notice here is that jBPM transaction control is disabled. Seam or EJB3 should control the JTA transactions.

19.6.1. Packaging

There is not yet any well-defined packaging format for jBPM configuration and process/pageflow definition files. In the Seam examples we've decided to simply package all these files into the root of the EAR. In future, we will probably design some other standard packaging format. So the EAR looks something like this:

my-application.ear/
    jboss-seam.jar
    el-api.jar
    el-ri.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

Remember to add jbpm-3.1.jar to the manifest of your EJB-JAR and WAR.

19.7. Configuring Seam in a Portal

To run a Seam application as a portlet, you'll need to provide certain portlet metadata (portlet.xml, etc) in addition to the usual Java EE metadata. See the examples/portal directory for an example of the booking demo preconfigured to run on JBoss Portal.

In addition, you'll need to use a portlet-specific phase listener instead of SeamPhaseListener or TransactionalSeamPhaseListener. The SeamPortletPhaseListener and TransactionalSeamPortletPhaseListener are adapted to the portlet lifecycle. I would like to offer my sincerest apologies for the name of that last class. I really couldn't think of anything better. Sorry.