[jboss-cvs] jboss-seam/doc/reference/en/modules ...

Gavin King gavin.king at jboss.com
Sun Jan 28 00:49:56 EST 2007


  User: gavin   
  Date: 07/01/28 00:49:56

  Modified:    doc/reference/en/modules    configuration.xml
                        conversations.xml
  Added:       doc/reference/en/modules    persistence.xml
  Log:
  split out persistence chapter
  updated configuration chapter
  
  Revision  Changes    Path
  1.33      +186 -313  jboss-seam/doc/reference/en/modules/configuration.xml
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: configuration.xml
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/doc/reference/en/modules/configuration.xml,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -b -r1.32 -r1.33
  --- configuration.xml	5 Dec 2006 20:28:27 -0000	1.32
  +++ configuration.xml	28 Jan 2007 05:49:56 -0000	1.33
  @@ -49,7 +49,7 @@
           
           <para>
               If you are using Sun's JSF 1.2 reference implementation, you should
  -            add this to <literal>faces-config.xml</literal>:
  +            also add this to <literal>faces-config.xml</literal>:
           </para>
           
           <programlisting><![CDATA[<application>
  @@ -98,10 +98,8 @@
               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 must specify a pattern using the configuration
  -            property named <literal>org.jboss.seam.core.init.jndiPattern</literal>.
  -            We may specify this using <literal>components.xml</literal>,
  -            <literal>web.xml</literal> or even <literal>seam.properties</literal>.
  +            vendor-specific. We usually specify this option in 
  +            <literal>components.xml</literal>.
           </para>
           
           <para>
  @@ -111,36 +109,24 @@
           <programlisting><![CDATA[<core:init jndi-name="myEarName/#{ejbName}/local" />]]></programlisting>
   
           <para>
  -            Or:
  -        </para>
  -
  -        <programlisting><![CDATA[<context-param>
  -    <param-name>org.jboss.seam.core.init.jndiPattern</param-name>
  -    <param-value>myEarName/#{ejbName}/local</param-value>
  -</context-param>]]></programlisting>
  -
  -        <para>
               Where <literal>myEarName</literal> is the name of the EAR in which
               the bean is deployed. 
           </para>
           
           <para>
  -            Outside the context of an EAR (when using
  -            the JBoss Embeddable EJB3 container), the following pattern is
  -            the one to use:
  +            Outside the context of an EAR (when using the JBoss Embeddable EJB3 container), 
  +            the following pattern is the one to use:
           </para>
           
           <programlisting><![CDATA[<core:init jndi-name="#{ejbName}/local" />]]></programlisting>
   
           <para>
  -            Or:
  +            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 ;-) 
           </para>
   
  -        <programlisting><![CDATA[<context-param>
  -    <param-name>org.jboss.seam.core.init.jndiPattern</param-name>
  -    <param-value>#{ejbName}/local</param-value>
  -</context-param>]]></programlisting>
  -
           </sect2>
           
           <sect2>
  @@ -152,7 +138,7 @@
               you need to register a servlet filter:
           </para>
   
  -<programlisting><![CDATA[<filter>
  +            <programlisting><![CDATA[<filter>
       <filter-name>Seam Redirect Filter</filter-name>
       <filter-class>org.jboss.seam.servlet.SeamRedirectFilter</filter-class>
   </filter>
  @@ -192,6 +178,33 @@
   
           </sect2>
   
  +        <sect2>
  +            <title>Don't forget!</title>
  +            
  +            <para>
  +                There is one final item you need to know about. You must place a <literal>seam.properties</literal>, 
  +                <literal>META-INF/seam.properties</literal> or <literal>META-INF/components.xml</literal>
  +                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
  +                <literal>seam.properties</literal> files for seam components.
  +            </para>
  +            
  +            <para>
  +                That's why all the Seam examples have an empty <literal>seam.properties</literal>
  +                file. You can't just delete this file and expect everything to still work! 
  +            </para>
  +            
  +            <para>
  +                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&mdash;if we didn't use this mechanism,
  +                our next best option would be to force you to list every component explicitly
  +                in <literal>components.xml</literal>, just like some other competing 
  +                frameworks do! I think you'll like our way better.
  +            </para>
  +            
  +        </sect2>
  +
       </sect1>
       
       <sect1>
  @@ -208,14 +221,7 @@
           
           <para>
               If you're running in a Java EE 5 environment, this is all the configuration
  -            required to start using Seam! But there is one final item you need to know about. 
  -            You must place a <literal>seam.properties</literal>, 
  -            <literal>META-INF/seam.properties</literal> or <literal>META-INF/components.xml</literal>
  -            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
  -            <literal>seam.properties</literal> files for seam components. If that doesn't
  -            work for you, you can also add components by installing them explicitly via
  -            <literal>components.xml</literal>. (We don't recommend this alternative approach.)
  +            required to start using Seam! 
           </para>
           
           <sect2>
  @@ -281,7 +287,9 @@
           <para>
               If you want to use the Seam tag library (most Seam applications do), you must include
               <literal>jboss-seam-ui.jar</literal> in the <literal>WEB-INF/lib</literal> directory
  -            of the WAR.
  +                of the WAR. If you want to use the PDF or email tag libraries, you need to put 
  +                <literal>jboss-seam-pdf.jar</literal> or <literal>jboss-seam-mail.jar</literal>
  +                in <literal>WEB-INF/lib</literal>.
           </para>
           
           <para>
  @@ -307,7 +315,8 @@
       </sect1>
       
       <sect1>
  -        <title>Configuring Seam with the JBoss Embeddable EJB3 container</title>
  +        <title>Configuring Seam in Java SE, with the JBoss Embeddable EJB3 container</title>
  +        
           <para>
               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. 
  @@ -480,129 +489,11 @@
       </sect1>
       
       <sect1>
  -        <title>Seam managed transactions</title>
  -        <para>
  -            EJB session beans feature declarative transaction management. The EJB container is able
  -            to start a transaction transparently when the bean is invoked, and end it when the
  -            invocation ends. If we write a session bean method that acts as a JSF action listener, 
  -            we can do all the work associated with that action in one transaction, and be sure that
  -            it is committed or rolled back when we finish processing the action. This is a great feature, 
  -            and all that is needed by many Seam applications.
  -        </para>
  -        
  -        <para>
  -            There is just one problem with this approach. ORM solutions like Hibernate and EJB 3.0
  -            persistence support lazy fetching of entity associations inside a transaction context, 
  -            but throw <literal>LazyInitializationException</literal>s if you try to access an unfetched
  -            association outside the context of a transaction. This is a problem if your view page
  -            tries to access data that was not fetched during the transaction. Hibernate users developed 
  -            the <emphasis>open session in view</emphasis> pattern to work around this problem. This
  -            pattern is usually implemented as a transaction which spans the entire request. There are
  -            several problems with this idea, the most serious being that we can't be sure that a
  -            transaction has been successful until we commit it, but by the time we commit the transaction,
  -            we have already rendered the view. Furthermore, this is at best a partial solution to the
  -            problem, because we can still meet the dreaded <literal>LazyInitializationException</literal>
  -            if we try to re-use the entity object in the next request.
  -        </para>
  -        
  -        <para>
  -            Seam <emphasis>completely solves</emphasis> the problem of unwanted
  -            <literal>LazyInitializationException</literal>s, while working around the biggest problem
  -            in the <emphasis>open session in view</emphasis> pattern. The solution comes in two parts:
  -        </para>
  +        <title>Configuring Seam in J2EE</title>
           
  -        <itemizedlist>
  -            <listitem>
  -                <para>
  -                    use an extended persistence context that is scoped to the conversation, 
  -                    instead of to the request
  -                </para>
  -            </listitem>
  -            <listitem>
  -                <para>
  -                    use two transactions per request; the first spans the beginning of the update model
  -                    values phase until the end of the invoke application phase; the second spans the
  -                    render response phase
  -                </para>
  -            </listitem>
  -        </itemizedlist>
  -        
  -        <sect2>
  -            <title>Enabling Seam-managed transactions</title>
  -        
  -        <para>
  -            To make use of <emphasis>Seam managed transactions</emphasis>, you need to use 
  -            <literal>SeamExtendedManagedPersistencePhaseListener</literal> in place of
  -            <literal>SeamPhaseListener</literal>.
  -        </para>
  -        
  -        <programlisting><![CDATA[<lifecycle>
  -     <phase-listener>
  -        org.jboss.seam.jsf.SeamExtendedManagedPersistencePhaseListener
  -    </phase-listener>
  -</lifecycle>]]></programlisting>
  -
  -        <para>
  -            It's also a good idea to add a servlet filter to rollback uncommitted transactions 
  -            when uncaught exceptions occur.
  -        </para>
  -        
  -<programlisting><![CDATA[<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>*.jsf</url-pattern>
  -</filter-mapping>]]></programlisting>
  -
  -        </sect2>
  -        
  -        <sect2>
  -            <title>Using a Seam-managed persistence context</title>
  -
  -        <para>
  -            You'll need to use a <emphasis>managed persistence context</emphasis> (for EJB3) or
  -            <emphasis>managed session</emphasis> (for Hibernate) in your components. We'll see how to 
  -            use a managed session later. Configuring a managed persistence context is easy. In
  -            <literal>components.xml</literal>, we can write:
  -        </para>
  -
  -        <programlisting><![CDATA[<core:managed-persistence-context name="bookingDatabase" auto-create="true"
  -    persistence-unit-jndi-name="java:/EntityManagerFactories/bookingData"/>]]></programlisting>
  -
  -        <para>
  -            This configuration creates a conversation-scoped Seam component named 
  -            <literal>bookingDatabase</literal> that manages the lifecycle of <literal>EntityManager</literal> 
  -            instances for the persistence unit (<literal>EntityManagerFactory</literal> instance) 
  -            with JNDI name <literal>java:/EntityManagerFactories/bookingData</literal>.
  -        </para>
  -        
  -        <para>
  -            Of course, you need to make sure that you have bound the <literal>EntityManagerFactory</literal> 
  -            into JNDI. In JBoss, you can do this by adding the following property setting to 
  -            <literal>persistence.xml</literal>.
  -        </para>
  -        
  -        <programlisting><![CDATA[<property name="jboss.entity.manager.factory.jndi.name" 
  -          value="java:/EntityManagerFactories/bookingData"/>]]></programlisting>
  -        
  -        <para>
  -            Now we can have our <literal>EntityManager</literal> injected using:
  -        </para>
  -
  -        <programlisting><![CDATA[@In EntityManager bookingDatabase;]]></programlisting>
  -        
  -        </sect2>
  -                
  -    </sect1>
  -    
  -    <sect1>
  -        <title>Configuring Seam with Hibernate in Java EE</title>
           <para>
               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 instead of EJB 3.0 persistence, and plain JavaBeans
  +            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
  @@ -623,14 +514,15 @@
               beans do. You <emphasis>could</emphasis> manage your transactions manually using the
               JTA <literal>UserTransaction</literal> (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 above to
  -            enable <literal>SeamExtendedManagedPersistencePhaseListener</literal>.
  +            transactions when using Hibernate with JavaBeans. Follow the instructions in the
  +            persistence chapter to install <literal>TransactionalSeamPhaseListener</literal>.
           </para>
           
           <para>
               The Seam distribution includes a version of the booking example application that 
  -            uses Hibernate and JavaBeans instead of EJB3. This example application is ready to 
  -            deploy into any J2EE application server.
  +            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.
           </para>
           
           <sect2>
  @@ -638,57 +530,34 @@
           
           <para>
               Seam will bootstrap a Hibernate <literal>SessionFactory</literal> from your
  -            <literal>hibernate.cfg.xml</literal> file if you install the built-in component
  -            named <literal>org.jboss.seam.core.hibernate</literal>. 
  +                <literal>hibernate.cfg.xml</literal> file if you install a built-in component: 
           </para>
           
  -        </sect2>
  -        
  -        <sect2>
  -            <title>Using a Seam-managed Hibernate Session</title>
  -        
  -        <para>
  -            We will also need to configure a <emphasis>managed session</emphasis> if we want a Seam 
  -            managed Hibernate <literal>Session</literal> to be available via injection. 
  -        </para>
  +            <programlisting><![CDATA[<core:hibernate-session-factory name="hibernateSessionFactory"/>]]></programlisting>
           
           <para>
  -            To configure our Seam component, as usual, we use <literal>components.xml</literal>:
  +                You will also need to configure a <emphasis>managed session</emphasis> if you want 
  +                a Seam managed Hibernate <literal>Session</literal> to be available via injection. 
           </para>
           
  -        <programlisting><![CDATA[<core:managed-hibernate-session name="hibernateSessionFactory"/>
  +        </sect2>
   
  -<core:managed-hibernate-session name="bookingDatabase" auto-create="true"
  -    session-factory-jndi-name="java:/bookingSessionFactory"/>]]></programlisting>
  +        <sect2>
  +            <title>Boostrapping JPA in Seam</title>
   
           <para>
  -            Where <literal>java:/bookingSessionFactory</literal> is the name of the session factory 
  -            specified in <literal>hibernate.cfg.xml</literal>. 
  +                Seam will bootstrap a JPA <literal>EntityManagerFactory</literal> from your
  +                <literal>persistence.xml</literal> file if you install this built-in component: 
           </para>
           
  -        <programlisting><![CDATA[<session-factory name="java:/bookingSessionFactory">
  -		<property name="transaction.flush_before_completion">true</property>
  -		<property name="connection.release_mode">after_statement</property>
  -		<property name="transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
  -		<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
  -		<property name="connection.datasource">java:/bookingDatasource</property>
  -    ...
  -</session-factory>]]></programlisting>
  -
  -        <para>
  -            Note that Seam does not flush the session, so you should always enable
  -            <literal>hibernate.transaction.flush_before_completion</literal> to 
  -            ensure that the session is automatically flushed before the JTA transaction
  -            commits.
  -        </para>
  +            <programlisting><![CDATA[<core:entity-manager-factory name="entityManagerFactory"/>]]></programlisting>
           
           <para>
  -            We can now have a managed Hibernate <literal>Session</literal> injected into our
  -            JavaBean components using the following code:
  +                You will also need to configure a <emphasis>managed persistencece context</emphasis> 
  +                if you want a Seam managed JPA <literal>EntityManager</literal> to be available via 
  +                injection. 
           </para>
           
  -        <programlisting><![CDATA[@In Session bookingDatabase;]]></programlisting>
  -
           </sect2>
           
           <sect2>
  @@ -712,6 +581,7 @@
               el-ri.jar
               jsf-facelets.jar
               hibernate3.jar
  +            hibernate-annotations.jar
               ...
               my-application.jar/
                   META-INF/
  @@ -739,15 +609,15 @@
       </sect1>
       
       <sect1>
  -        <title>Configuring Seam with Hibernate in Java SE</title>
  +        <title>Configuring Seam in Java SE, with the JBoss Microcontainer</title>
           <para>
  -            The Seam support for Hibernate 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. 
  +            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. 
           </para>
           
           <para>
  -            You can even deploy the Hibernate version of the booking example in Tomcat.
  +            You can even deploy the Hibernate and JPA versions of the booking example in Tomcat.
           </para>
           
           <mediaobject>
  @@ -791,7 +661,7 @@
               JTA, your JCA datasource and Hibernate into the microcontainer:
           </para>
           
  -<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
  +            <programlisting><![CDATA[<?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"
  @@ -823,10 +693,10 @@
         </constructor>
      </bean>
      
  -   <bean name="bookingDatabaseFactory" class="org.jboss.seam.microcontainer.HibernateFactory"/>
  -   <bean name="bookingDatabase" class="java.lang.Object">
  +   <bean name="bookingSessionFactoryFactory" class="org.jboss.seam.microcontainer.HibernateFactory"/>
  +   <bean name="bookingSessionFactory" class="java.lang.Object">
         <constructor factoryMethod="getSessionFactory">
  -         <factory bean="bookingDatabaseFactory"/>
  +         <factory bean="bookingSessionFactoryFactory"/>
         </constructor>
         <depends>bookingDatasource</depends>
      </bean>
  @@ -940,6 +810,7 @@
           
           <sect2>
               <title>Packaging</title>
  +            
               <para>
                   There is not yet any well-defined packaging format for jBPM configuration
                   and process/pageflow definition files. In the Seam examples we've decided
  @@ -1013,10 +884,12 @@
           <para>
               In addition, you'll need to use a portlet-specific phase listener
               instead of <literal>SeamPhaseListener</literal> or 
  -            <literal>SeamExtendedManagedPersistencePhaseListener</literal>.
  +            <literal>TransactionalSeamPhaseListener</literal>.
               The <literal>SeamPortletPhaseListener</literal> and
  -            <literal>SeamExtendedManagedPersistencePortletPhaseListener</literal>
  -            are adapted to the portlet lifecycle.
  +            <literal>TransactionalSeamPortletPhaseListener</literal>
  +            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.
           </para>
           
       </sect1>
  
  
  
  1.23      +0 -67     jboss-seam/doc/reference/en/modules/conversations.xml
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: conversations.xml
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/doc/reference/en/modules/conversations.xml,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -b -r1.22 -r1.23
  --- conversations.xml	17 Jan 2007 03:14:29 -0000	1.22
  +++ conversations.xml	28 Jan 2007 05:49:56 -0000	1.23
  @@ -814,73 +814,6 @@
       </section>
       
       <section>
  -        <title>Seam-managed persistence contexts and atomic conversations</title>
  -        <para>
  -            Seam provides built-in components for EJB 3.0 and Hibernate persistence context 
  -            management that support the use of persistence contexts scoped to the conversation.
  -            This useful feature allows you to program optimistic transactions that span multiple
  -            requests to the server without the need to use the merge() operation or to re-load 
  -            data at the beginning of each request, and without the need to wrestle with the 
  -            dreaded <literal>LazyInitializationException</literal> or 
  -            <literal>NonUniqueObjectException</literal>. Please see the configuration chapter 
  -            for information about configuring Seam-managed persistence contexts and 
  -            Seam-managed transactions.
  -        </para>
  -        <para>
  -            As with any optimistic transaction management, transaction isolation and consistency
  -            can be achieved via use of optimistic locking. Fortunately, both Hibernate and EJB 
  -            3.0 make it very easy to use optimistic locking, by providing the 
  -            <literal>@Version</literal> annotation.
  -        </para>
  -        <para>
  -            By default, the persistence context is flushed (synchronized with the database)
  -            at the end of each transaction. This is sometimes the desired behavior. But very 
  -            often, we would prefer that all changes are held in memory and only written to
  -            the database when the conversation ends successfully. This allows for truly
  -            atomic conversations. As the result of a truly stupid and shortsighted decision
  -            by certain non-JBoss, non-Sun and non-Sybase members of the EJB 3.0 expert group, 
  -            there is currently no simple, usable and portable way to implement atomic 
  -            conversations using EJB 3.0 persistence. However, Hibernate provides this feature
  -            as a vendor extension to the <literal>FlushModeType</literal>s defined by the 
  -            specification, and it is our expectation that other vendors will soon provide
  -            a similar extension.
  -        </para>
  -        <para>
  -            Seam lets you specify <literal>FlushModeType.MANUAL</literal> when beginning a
  -            conversation. Currently, this works only when Hibernate is the underlying 
  -            persistence provider, but we plan to support other equivalent vendor extensions.
  -        </para>
  -        
  -        <programlisting><![CDATA[@In EntityManager em; //a Seam-managed persistence context
  -
  - at Begin(flushMode=MANUAL)
  -public void beginClaimWizard() {
  -    claim = em.find(Claim.class, claimId);
  -}]]></programlisting>
  -
  -        <para>
  -            Now, the <literal>claim</literal> object remains managed by the persistence context
  -            for the rest ot the conversation. We can make changes to the claim:
  -        </para>
  -        
  -        <programlisting><![CDATA[public void addPartyToClaim() {
  -    Party party = ....;
  -    claim.addParty(party);
  -}]]></programlisting>
  -
  -        <para>
  -            But these changes will not be flushed to the database until we explicitly force
  -            the flush to occur:
  -        </para>
  -        
  -        <programlisting><![CDATA[@End
  -public void commitClaim() {
  -    em.flush();
  -}]]></programlisting>
  -
  -    </section>
  -    
  -    <section>
           <title>Seam and Servlets</title>
           
           <para>
  
  
  
  1.1      date: 2007/01/28 05:49:56;  author: gavin;  state: Exp;jboss-seam/doc/reference/en/modules/persistence.xml
  
  Index: persistence.xml
  ===================================================================
  <chapter id="persistence">
      <title>Seam and Object/Relational Mapping</title>
      
      <para>
          Seam provides extensive support for the two most popular persistence
          architectures for Java: Hibernate3, and the Java Persistence API
          introduced with EJB 3.0. Seam's unique state-management architecture
          allows the most sophisticated ORM integration of any web application 
          framework.
      </para>
      
      <section>
          <title>Introduction</title>
      
      <para>
          Seam grew out of the frustration of the Hibernate team with the 
          statelessness typical of the previous generation of Java application 
          architectures. The state management architecture of Seam was originally
          designed to solve problems relating to persistence&mdash;in particular
          problems associated with <emphasis>optimistic transaction processing</emphasis>.
          Scalable online applications always use optimistic transactions. An atomic 
          (database/JTA) level transaction should not span a user interaction unless
          the application is designed to support only a very small number of concurrent
          clients. But almost all interesting work involves first displaying data
          to a user, and then, slightly later, updating the same data. So Hibernate was
          designed to support the idea of a persistence context which spanned an
          optimistic transaction. 
      </para>
      
      <para>
          Unfortunately, the so-called "stateless" architectures that preceded Seam and 
          EJB 3.0 had no construct for representing an optimistic transaction. So, instead,
          these architectures provided persistence contexts scoped to the atomic
          transaction. Of course, this resulted in many problems for users, and is the
          cause of the number one user complaint about Hibernate: the dreaded 
          <literal>LazyInitializationException</literal>. What we need is a construct
          for representing an optimistic transaction in the application tier.
      </para>
      
      <para>
          EJB 3.0 recognizes this problem, and introduces the idea of a stateful
          component (a stateful session bean) with an <emphasis>extended persistence 
          context</emphasis> scoped to the lifetime of the component. This is a
          partial solution to the problem (and is a useful construct in and of 
          itself) however there are two problems:
      </para>
      
      <itemizedlist>
          <listitem>
              <para>
                  The lifecycle of the stateful session bean must be managed manually
                  via code in the web tier (it turns out that this is a subtle problem
                  and much more difficult in practice than it sounds).
              </para>
          </listitem>
          <listitem>
              <para>
                  Propagation of the persistence context between stateful components
                  in the same optimistic transaction is possible, but tricky.
              </para>
          </listitem>
      </itemizedlist>
      
      <para>
          Seam solves the first problem by providing conversations, and stateful
          session bean components scoped to the conversation. (Most conversations 
          actually represent optimistic transactions in the data layer.) This is
          sufficient for many simple applications (such as the Seam booking
          demo) where persistence context propagation is not needed. For more
          complex applications, with many loosly-interacting components in each
          conversation, propagation of the persistence context across components
          becomes an important issue. So Seam extends the persistence context
          management model of EJB 3.0, to provide conversation-scoped extended
          persistence contexts.
      </para>
      
      </section>
      
      <section>
          <title>Seam managed transactions</title>
          <para>
              EJB session beans feature declarative transaction management. The EJB container is able
              to start a transaction transparently when the bean is invoked, and end it when the
              invocation ends. If we write a session bean method that acts as a JSF action listener, 
              we can do all the work associated with that action in one transaction, and be sure that
              it is committed or rolled back when we finish processing the action. This is a great feature, 
              and all that is needed by many Seam applications.
          </para>
          
          <para>
              There is just one problem with this approach. ORM solutions like Hibernate and EJB 3.0
              persistence support lazy fetching of entity associations inside a transaction context, 
              but throw <literal>LazyInitializationException</literal>s if you try to access an unfetched
              association outside the context of a transaction. This is a problem if your view page
              tries to access data that was not fetched during the transaction. Hibernate users developed 
              the <emphasis>open session in view</emphasis> pattern to work around this problem. This
              pattern is usually implemented as a transaction which spans the entire request. There are
              several problems with this idea, the most serious being that we can't be sure that a
              transaction has been successful until we commit it, but by the time we commit the transaction,
              we have already rendered the view. Furthermore, this is at best a partial solution to the
              problem, because we can still meet the dreaded <literal>LazyInitializationException</literal>
              if we try to re-use the entity object in the next request.
          </para>
          
          <para>
              Seam <emphasis>completely solves</emphasis> the problem of unwanted
              <literal>LazyInitializationException</literal>s, while working around the biggest problem
              in the <emphasis>open session in view</emphasis> pattern. The solution comes in two parts:
          </para>
          
          <itemizedlist>
              <listitem>
                  <para>
                      use an extended persistence context that is scoped to the conversation, 
                      instead of to the request
                  </para>
              </listitem>
              <listitem>
                  <para>
                      use two transactions per request; the first spans the beginning of the update model
                      values phase until the end of the invoke application phase; the second spans the
                      render response phase
                  </para>
              </listitem>
          </itemizedlist>
          
          <section>
              <title>Enabling Seam-managed transactions</title>
          
              <para>
                  To make use of <emphasis>Seam managed transactions</emphasis>, you need to use 
                  <literal>TransactionalSeamPhaseListener</literal> in place of
                  <literal>SeamPhaseListener</literal>.
              </para>
          
              <programlisting><![CDATA[<lifecycle>
       <phase-listener>
          org.jboss.seam.jsf.TransactionalSeamPhaseListener
      </phase-listener>
  </lifecycle>]]></programlisting>
  
              <para>
                  It's also a good idea to add a servlet filter to rollback 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.)
              </para>
          
              <programlisting><![CDATA[<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>*.jsf</url-pattern>
  </filter-mapping>]]></programlisting>
              
              <para>
                  Seam transaction management is useful even if you're using EJB 3.0 
                  container-managed persistence contexts. But it is especially useful
                  if you use Seam outside a Java EE 5 environment, or in any other
                  case where you would use a Seam-managed persistence context.
              </para>
              
          </section>
          
      </section>
      
      <section>
          <title>Seam-managed persistence contexts</title>
  
          <para>
              If you're using Seam outside of a Java EE 5 environment, you can't rely upon the
              container to manage the persistence context lifecycle for you. Even if you are
              in an EE 5 environment, you might have a complex application with many loosly
              coupled components that collaborate together in the scope of a single conversation,
              and in this case you might find that propagation of the persistence context between
              component is tricky and error-prone.
          </para>
          
          <para>
              In either case, you'll need to use a <emphasis>managed persistence context</emphasis> 
              (for JPA) or a <emphasis>managed session</emphasis> (for Hibernate) in your components.
              A Seam-managed persistence context is just a built-in Seam component that manages an
              instance of <literal>EntityManager</literal> or <literal>Session</literal> in the
              conversation context. You can inject it with <literal>@In</literal>.
          </para>
          
          <section>
          <title>Using a Seam-managed persistence context with JPA</title>
          
          <para>
              Configuring a managed persistence context is easy. In <literal>components.xml</literal>, 
              we can write:
          </para>
  
          <programlisting><![CDATA[<core:managed-persistence-context name="bookingDatabase" 
                             auto-create="true"
              persistence-unit-jndi-name="java:/EntityManagerFactories/bookingData"/>]]></programlisting>
  
          <para>
              This configuration creates a conversation-scoped Seam component named 
              <literal>bookingDatabase</literal> that manages the lifecycle of <literal>EntityManager</literal> 
              instances for the persistence unit (<literal>EntityManagerFactory</literal> instance) 
              with JNDI name <literal>java:/EntityManagerFactories/bookingData</literal>.
          </para>
          
          <para>
              Of course, you need to make sure that you have bound the <literal>EntityManagerFactory</literal> 
              into JNDI. In JBoss, you can do this by adding the following property setting to 
              <literal>persistence.xml</literal>.
          </para>
          
          <programlisting><![CDATA[<property name="jboss.entity.manager.factory.jndi.name" 
            value="java:/EntityManagerFactories/bookingData"/>]]></programlisting>
          
          <para>
              Now we can have our <literal>EntityManager</literal> injected using:
          </para>
  
          <programlisting><![CDATA[@In EntityManager bookingDatabase;]]></programlisting>
                  
      </section>
  
      <section>
          <title>Using a Seam-managed Hibernate session</title>
                  
          <para>
              Seam-managed Hibernate sessions are similar. In <literal>components.xml</literal>:
          </para>
          
          <programlisting><![CDATA[<core:hibernate-session-factory name="hibernateSessionFactory"/>
  
  <core:managed-hibernate-session name="bookingDatabase" 
                           auto-create="true"
             session-factory-jndi-name="java:/bookingSessionFactory"/>]]></programlisting>
  
          <para>
              Where <literal>java:/bookingSessionFactory</literal> is the name of the session factory 
              specified in <literal>hibernate.cfg.xml</literal>. 
          </para>
          
          <programlisting><![CDATA[<session-factory name="java:/bookingSessionFactory">
      <property name="transaction.flush_before_completion">true</property>
      <property name="connection.release_mode">after_statement</property>
      <property name="transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
      <property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
      <property name="connection.datasource">java:/bookingDatasource</property>
      ...
  </session-factory>]]></programlisting>
  
          <para>
              Note that Seam does not flush the session, so you should always enable
              <literal>hibernate.transaction.flush_before_completion</literal> to 
              ensure that the session is automatically flushed before the JTA transaction
              commits.
          </para>
          
          <para>
              We can now have a managed Hibernate <literal>Session</literal> injected into our
              JavaBean components using the following code:
          </para>
          
          <programlisting><![CDATA[@In Session bookingDatabase;]]></programlisting>
  
      </section>
              
      <section>
          <title>Seam-managed persistence contexts and atomic conversations</title>
          <para>
              Persistence contexts scoped to the conversation allows you to program optimistic 
              transactions that span multiple requests to the server without the need to use the 
              <literal>merge()</literal> operation , without the need to re-load 
              data at the beginning of each request, and without the need to wrestle with the 
              <literal>LazyInitializationException</literal> or 
              <literal>NonUniqueObjectException</literal>.
          </para>
          
          <para>
              As with any optimistic transaction management, transaction isolation and consistency
              can be achieved via use of optimistic locking. Fortunately, both Hibernate and EJB 
              3.0 make it very easy to use optimistic locking, by providing the 
              <literal>@Version</literal> annotation.
          </para>
          
          <para>
              By default, the persistence context is flushed (synchronized with the database)
              at the end of each transaction. This is sometimes the desired behavior. But very 
              often, we would prefer that all changes are held in memory and only written to
              the database when the conversation ends successfully. This allows for truly
              atomic conversations. As the result of a truly stupid and shortsighted decision
              by certain non-JBoss, non-Sun and non-Sybase members of the EJB 3.0 expert group, 
              there is currently no simple, usable and portable way to implement atomic 
              conversations using EJB 3.0 persistence. However, Hibernate provides this feature
              as a vendor extension to the <literal>FlushModeType</literal>s defined by the 
              specification, and it is our expectation that other vendors will soon provide
              a similar extension.
          </para>
          
          <para>
              Seam lets you specify <literal>FlushModeType.MANUAL</literal> when beginning a
              conversation. Currently, this works only when Hibernate is the underlying 
              persistence provider, but we plan to support other equivalent vendor extensions.
          </para>
          
          <programlisting><![CDATA[@In EntityManager em; //a Seam-managed persistence context
  
  @Begin(flushMode=MANUAL)
  public void beginClaimWizard() {
      claim = em.find(Claim.class, claimId);
  }]]></programlisting>
  
          <para>
              Now, the <literal>claim</literal> object remains managed by the persistence context
              for the rest ot the conversation. We can make changes to the claim:
          </para>
          
          <programlisting><![CDATA[public void addPartyToClaim() {
      Party party = ....;
      claim.addParty(party);
  }]]></programlisting>
  
          <para>
              But these changes will not be flushed to the database until we explicitly force
              the flush to occur:
          </para>
          
          <programlisting><![CDATA[@End
  public void commitClaim() {
      em.flush();
  }]]></programlisting>
  
      </section>
  
      </section>
      
      <section>
          <title>Using the JPA "delegate"</title>
          
          <para>
              The <literal>EntityManager</literal> interface let's you access a vendor-specific
              API via the <literal>getDelegate()</literal> method. Naturally, the most interesting
              vendor is Hibernate, and the most powerful delegate interface is
              <literal>org.hibernate.Session</literal>. You'd be nuts to use anything else. Trust
              me, I'm not biased at all.
          </para>
          
          <para>
              But regardless of whether you're using Hibernate (genius!) or something else
              (masochist, or just not very bright), you'll almost certainly want to use the
              delegate in your Seam components from time to time. One approach would be the
              following:
          </para>
          
          <programlisting><![CDATA[@In EntityManager entityManager;
  
  @Create
  public void init() {
      ( (Session) entityManager.getDelegate() ).enableFilter("currentVersions");
  }]]></programlisting>
  
          <para>
               But typecasts are unquestionably the ugliest syntax in the Java language, so most
               people avoid them whenever possible. Here's a different way to get at the 
               delegate. First, add the following line to <literal>components.xml</literal>:
          </para>
          
          <programlisting><![CDATA[<factory name="session" 
          scope="STATELESS" 
          auto-create="true" 
          value="#{entityManager.delegate}"/>]]></programlisting>
          
          <para>
              Now we can inject the session directly:
          </para>
          
          <programlisting><![CDATA[@In Session session;
  
  @Create
  public void init() {
      session.enableFilter("currentVersions");
  }]]></programlisting>
  
      </section>
      
  </chapter>
  
  
  



More information about the jboss-cvs-commits mailing list