SeamFramework.org Community Documentation

- Prev
- Next

## Chapter 10. Seam and Object/Relational Mapping

Seam provides extensive support for the two most popular persistence architectures for Java: Hibernate, and the Java Persistence API 2.0 introduced with EJB 3.1. Seam's unique state-management architecture allows the most sophisticated ORM integration of any web application framework.

## 10.1. Introduction

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 — in particular problems associated with optimistic transaction processing. 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.

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 `LazyInitializationException`. What we need is a construct for representing an optimistic transaction in the application tier.

EJB 3.0 recognizes this problem, and introduces the idea of a stateful component (a stateful session bean) with an extended persistence context 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:

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

- Propagation of the persistence context between stateful components in the same optimistic transaction is possible, but tricky.

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 loosely-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.

## 10.2. Seam managed transactions

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 some Seam applications.

However, there is a problem with this approach. A Seam application may not perform all data access for a request from a single method call to a session bean.

- The request might require processing by several loosely-coupled components, each of which is called independently from the web layer. It is common to see several or even many calls per request from the web layer to EJB components in Seam.

- Rendering of the view might require lazy fetching of associations.

The more transactions per request, the more likely we are to encounter atomicity and isolation problems when our application is processing many concurrent requests. Certainly, all write operations should occur in the same transaction!

Hibernate users developed the "open session in view" pattern to work around this problem. In the Hibernate community, "open session in view" was historically even more important because frameworks like Spring use transaction-scoped persistence contexts. So rendering the view would cause `LazyInitializationException`s when unfetched associations were accessed.

This pattern is usually implemented as a single transaction which spans the entire request. There are several problems with this implementation, the most serious being that we can never be sure that a transaction is successful until we commit it — but by the time the "open session in view" transaction is committed, the view is fully rendered, and the rendered response may already have been flushed to the client. How can we notify the user that their transaction was unsuccessful?

Seam solves both the transaction isolation problem and the association fetching problem, while working around the problems with "open session in view". The solution comes in two parts:

- use an extended persistence context that is scoped to the conversation, instead of to the transaction

- use two transactions per request; the first spans the beginning of the restore view phase (some transaction managers begin the transaction later at the beginning of the apply request values phase) until the end of the invoke application phase; the second spans the render response phase

In the next section, we'll tell you how to set up a conversation-scope persistence context. But first we need to tell you how to enable Seam transaction management. Note that you can use conversation-scoped persistence contexts without Seam transaction management, and there are good reasons to use Seam transaction management even when you're not using Seam-managed persistence contexts. However, the two facilities were designed to work together, and work best when used together.

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 environment, or in any other case where you would use a Seam-managed persistence context.

### 10.2.1. Disabling Seam-managed transactions

Seam transaction management is enabled by default for all JSF requests. If you want to disable this feature, you can do it in `components.xml`:

    <core:init transaction-management-enabled="false"/>

    <transaction:no-transaction />

### 10.2.2. Configuring a Seam transaction manager

Seam provides a transaction management abstraction for beginning, committing, rolling back, and synchronizing with a transaction. By default Seam uses a JTA transaction component that integrates with Container Managed and programmatic EJB transactions. If you are working in a Java EE environment, you should install the EJB synchronization component in `components.xml`:

    <transaction:ejb-transaction />

However, if you are working in a non EE 5 container, Seam will try auto detect the transaction synchronization mechanism to use. However, if Seam is unable to detect the correct transaction synchronization to use, you may find you need configure one of the following:

- JPA RESOURCE_LOCAL transactions with the `javax.persistence.EntityTransaction` interface. `EntityTransaction` begins the transaction at the beginning of the apply request values phase.

- Hibernate managed transactions with the `org.hibernate.Transaction` interface. `HibernateTransaction` begins the transaction at the beginning of the apply request values phase.

- Spring managed transactions with the `org.springframework.transaction.PlatformTransactionManager` interface. The Spring `PlatformTransactionManagement` manager may begin the transaction at the beginning of the apply request values phase if the `userConversationContext` attribute is set.

- Explicitly disable Seam managed transactions

Configure JPA RESOURCE_LOCAL transaction management by adding the following to your components.xml where `#{em}` is the name of the `persistence:managed-persistence-context` component. If your managed persistence context is named `entityManager`, you can opt to leave out the `entity-manager` attribute. (see Seam-managed persistence contexts )

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

To configure Hibernate managed transactions declare the following in your components.xml where `#{hibernateSession}` is the name of the project's `persistence:managed-hibernate-session` component. If your managed hibernate session is named `session`, you can opt to leave out the `session` attribute. (see Seam-managed persistence contexts )

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

To explicitly disable Seam managed transactions declare the following in your components.xml:

    <transaction:no-transaction />

For configuring Spring managed transactions see using Spring PlatformTransactionManagement .

### 10.2.3. Transaction synchronization

Transaction synchronization provides callbacks for transaction related events such as `beforeCompletion()` and `afterCompletion()`. By default, Seam uses it's own transaction synchronization component which requires explicit use of the Seam transaction component when committing a transaction to ensure synchronization callbacks are correctly executed. If in a Java EE environment the `<transaction:ejb-transaction/>` component should be declared in `components.xml` to ensure that Seam synchronization callbacks are correctly called if the container commits a transaction outside of Seam's knowledge.

## 10.3. Seam-managed persistence contexts

If you're using Seam outside of a Java EE 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.

In either case, you'll need to use a managed persistence context (for JPA) or a managed session (for Hibernate) in your components. A Seam-managed persistence context is just a built-in Seam component that manages an instance of `EntityManager` or `Session` in the conversation context. You can inject it with `@In`.

Seam-managed persistence contexts are extremely efficient in a clustered environment. Seam is able to perform an optimization that EJB 3.0 specification does not allow containers to use for container-managed extended persistence contexts. Seam supports transparent failover of extended persistence contexts, without the need to replicate any persistence context state between nodes. (We hope to fix this oversight in the next revision of the EJB spec.)

### 10.3.1. Using a Seam-managed persistence context with JPA

Configuring a managed persistence context is easy. In `components.xml`, we can write:

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

                                      auto-create="true"

                       persistence-unit-jndi-name="java:/EntityManagerFactories/bookingData"/>

This configuration creates a conversation-scoped Seam component named `bookingDatabase` that manages the lifecycle of `EntityManager` instances for the persistence unit (`EntityManagerFactory` instance) with JNDI name `java:/EntityManagerFactories/bookingData`.

Of course, you need to make sure that you have bound the `EntityManagerFactory` into JNDI. In JBoss, you can do this by adding the following property setting to `persistence.xml`.

    <property name="jboss.entity.manager.factory.jndi.name"

              value="java:/EntityManagerFactories/bookingData"/>

Now we can have our `EntityManager` injected using:

    @In EntityManager bookingDatabase;

If you are using EJB3 and mark your class or method `@TransactionAttribute(REQUIRES_NEW)` then the transaction and persistence context shouldn't be propagated to method calls on this object. However as the Seam-managed persistence context is propagated to any component within the conversation, it will be propagated to methods marked `REQUIRES_NEW`. Therefore, if you mark a method `REQUIRES_NEW` then you should access the entity manager using @PersistenceContext.

### 10.3.2. Using a Seam-managed Hibernate session

Seam-managed Hibernate sessions are similar. In `components.xml`:

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

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

                                    auto-create="true"

                      session-factory-jndi-name="java:/bookingSessionFactory"/>

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

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

Note that Seam does not flush the session, so you should always enable `hibernate.transaction.flush_before_completion` to ensure that the session is automatically flushed before the JTA transaction commits.

We can now have a managed Hibernate `Session` injected into our JavaBean components using the following code:

    @In Session bookingDatabase;

### 10.3.3. Seam-managed persistence contexts and atomic conversations

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 `merge()` operation , without the need to re-load data at the beginning of each request, and without the need to wrestle with the `LazyInitializationException` or `NonUniqueObjectException`.

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 `@Version` annotation.

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 `FlushModeType`s defined by the specification, and it is our expectation that other vendors will soon provide a similar extension.

Seam lets you specify `FlushModeType.MANUAL` when beginning a conversation. Currently, this works only when Hibernate is the underlying persistence provider, but we plan to support other equivalent vendor extensions.

    @In EntityManager em; //a Seam-managed persistence context

    @Begin(flushMode=MANUAL)

    public void beginClaimWizard() {

        claim = em.find(Claim.class, claimId);

    }

Now, the `claim` object remains managed by the persistence context for the rest ot the conversation. We can make changes to the claim:

    public void addPartyToClaim() {

        Party party = ....;

        claim.addParty(party);

    }

But these changes will not be flushed to the database until we explicitly force the flush to occur:

    @End

    public void commitClaim() {

        em.flush();

    }

Of course, you could set the `flushMode` to `MANUAL` from pages.xml, for example in a navigation rule:

    <begin-conversation flush-mode="MANUAL" />

You can set any Seam Managed Persistence Context to use manual flush mode:

    <components xmlns="http://jboss.org/schema/seam/components"
       xmlns:core="http://jboss.org/schema/seam/core">
       <core:manager conversation-timeout="120000" default-flush-mode="manual" />
    </components>

## Warning

if you use SMPC in your Stateful bean, manual flush mode is ignored as this mode is specific Hibernate extension to JPA specification. Seam can’t control the flush mode of the persistence context on an SFSB - that means no manual flushing on SFSB!

## 10.4. Using the JPA "delegate"

The `EntityManager` interface lets you access a vendor-specific API via the `getDelegate()` method. Naturally, the most interesting vendor is Hibernate, and the most powerful delegate interface is `org.hibernate.Session`. You'd be nuts to use anything else. Trust me, I'm not biased at all. If you must use a different JPA provider see Using Alternate JPA Providers.

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:

    @In EntityManager entityManager;

    @Create

    public void init() {

        ( (Session) entityManager.getDelegate() ).enableFilter("currentVersions");

    }

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 `components.xml`:

    <factory name="session"

             scope="STATELESS"

             auto-create="true"

             value="#{entityManager.delegate}"/>

Now we can inject the session directly:

    @In Session session;

    @Create

    public void init() {

        session.enableFilter("currentVersions");

    }

## 10.5. Using EL in EJB-QL/HQL

Seam proxies the `EntityManager` or `Session` object whenever you use a Seam-managed persistence context or inject a container managed persistence context using `@PersistenceContext`. This lets you use EL expressions in your query strings, safely and efficiently. For example, this:

    User user = em.createQuery("from User where username=#{user.username}")

             .getSingleResult();

is equivalent to:

    User user = em.createQuery("from User where username=:username")

             .setParameter("username", user.getUsername())

             .getSingleResult();

Of course, you should never, ever write it like this:

    User user = em.createQuery("from User where username=" + user.getUsername()) //BAD!

             .getSingleResult();

(It is inefficient and vulnerable to SQL injection attacks.)

## 10.6. Using Hibernate filters

The coolest, and most unique, feature of Hibernate is filters. Filters let you provide a restricted view of the data in the database. You can find out more about filters in the Hibernate documentation. But we thought we'd mention an easy way to incorporate filters into a Seam application, one that works especially well with the Seam Application Framework.

Seam-managed persistence contexts may have a list of filters defined, which will be enabled whenever an `EntityManager` or Hibernate `Session` is first created. (Of course, they may only be used when Hibernate is the underlying persistence provider.)

    <persistence:filter name="regionFilter">

        <persistence:name>region</persistence:name>

        <persistence:parameters>

            <key>regionCode</key>

            <value>#{region.code}</value>

        </persistence:parameters>

    </persistence:filter>

    <persistence:filter name="currentFilter">

        <persistence:name>current</persistence:name>

        <persistence:parameters>

            <key>date</key>

            <value>#{currentDate}</value>

        </persistence:parameters>

    </persistence:filter>

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

        persistence-unit-jndi-name="java:/EntityManagerFactories/personDatabase">

        <persistence:filters>

            <value>#{regionFilter}</value>

            <value>#{currentFilter}</value>

        </persistence:filters>

    </persistence:managed-persistence-context>

- PrevChapter 9. Pageflows and business processes
- Top of page
- Front page
- NextChapter 11. JSF form validation in Seam