Chapter 9. Seam-managed persistence and transactions

This chapter covers

  • Handling the persistence context properly
  • Bootstrapping Java persistence in Seam
  • Applying a multifaceted transaction strategy
  • Implementing an application transaction

Most web frameworks remain agnostic of persistence rather than recognize it as vital to the overall state of the application. Stateless architectures, especially, have depleted the persistence manager of its true value—to monitor a set of managed entities and transparently migrate changes made to them to the database. Seam seeks to restore Java persistence (i.e., ORM) to its full potential by recognizing it as a core part of the application. In addition to adeptly managing the persistence context, Seam ensures that a transaction is always active, commits the transaction when appropriate, and broadcasts transaction synchronization events to improve transparency of persistence operations. In the previous chapter, you learned the fundamentals of Java persistence and how persistence is used both inside and out of a Java EE container. In this chapter, you’ll discover how Seam’s involvement with transactions and persistence helps make these services truly manageable.

The conversation is also revisited in this chapter, which combines with persistence to form the core of Seam’s state-management architecture. Seam hosts the persistence manager in the conversion context, giving it refuge from the confines of a stateless design. The true benefit of this union is realized at the end of the chapter when you learn about an application transaction, a special type of transaction that allows modifications made to managed entities to be queued across requests until the end of the use case, at which time the changes are committed to the database within a database transaction.

This chapter also prepares you to use the Seam Application Framework, covered in the next chapter, which enables rapid development of create, read, update, delete (CRUD)-based applications and embodies the design goal of properly handling the persistence context, a theme that continues through this chapter. Let’s pick up with this theme where the previous chapter left off.

9.1. Getting persistence context management right

To realize the true value of Java persistence, the persistence manager—a general term for a JPA EntityManager or Hibernate Session—must be scoped properly. In chapter 8, you learned that if you treat the persistence manager as a stateful component, it can do a lot for you; if you don’t, it can lead to a lot of pain. The transaction-scoped persistence context inhibits the capabilities of Java persistence and is generally discouraged in Seam.

The challenge of using an extended persistence context is deciding how long to extend it without overdoing it. If it’s not held open long enough, your entities become detached prematurely. If it’s held open for too long, it can result in an overzealous cache and memory leaks. As it turns out, the persistence manager was intended to serve a use case, making the conversation context the ideal host for an extended persistence context. In this section, I explain how a conversation-scoped persistence manager gets to the heart of the problems that many developers encounter using ORM. I then show you two ways to bind the persistence manager to a conversation in a Seam application.

9.1.1. Respecting the persistence manager

It’s true that using Java persistence in a web application can be a challenge. Unfortunately, some developers have made it harder than it has to be. I want to educate you about the shortcomings of the so-called “patterns” that have been developed to solve Hibernate lazy-loading exceptions. The purpose in raising this issue is to emphasize that this exception is really a symptom of incorrect usage, which these shortsighted fixes fail to address.

The Open Session in View remedy

Recognizing that Hibernate wasn’t going to allow lazy loading in the view unless the Session remained open, developers created the Open Session in View pattern,[1] which controls the Session from the outer rim of the application using a servlet filter. It works by preventing the data layer from closing the Session and instead the filter closes it at the end of the request. (There is a parallel implementation for JPA that also applies here.)

1http://www.hibernate.org/43.html

The problem with this fix is that a filter is too far removed from the application to know what it’s doing. It blindly tries to determine whether it should open one Session or whether several are needed. Complications also arise because now the Session has two masters, the application framework and the filter, which may not always be in agreement.

The filter may make a mess of things, but at least it allows lazy loading in the view, right? Sure, but the benefits end there. By waiting until the end of the request to flush and close the persistence context, the application doesn’t know if the database writes succeeded or failed until after the view is rendered, a problem addressed in section 9.4.1. Once the page is rendered, all of the entity instances stored in stateful scopes become detached. Thus, the lazy-loading problems are merely deferred until postback, where you no longer benefit from the persistence cache or automatic dirty checking of entities. In addition, having detached entities around during a postback can introduce the NonUniqueObjectException. A far better solution is to respect the persistence manager by scoping it to the conversation.

The Open Session in Conversation solution

As you learned in chapter 7, conversations last for at least the entire request, including redirects. By associating the persistence manager with the conversation, you get the Open Session in View pattern for free. But now, you aren’t allowing a filter to make arbitrary decisions about how the persistence manager should be managed. If the conversation is long-running, then the persistence manager stretches to match it, termed the Open Session in Conversation pattern. As a result, entities aren’t detached prematurely, which means you can avoid merging and instead benefit from automatic dirty checking. In fact, to propagate an entity instance between requests, you only have to keep track of the entity’s identifier since the same instance can be retrieved again out of the persistence context.

Placing the persistence manager directly into the conversation introduces the problem that no one tends to it. Who will close it? How will it be enlisted in transactions? I present two options for tying the persistence manager to a conversation in a way that it is still managed.

9.1.2. Managing an extended persistence context

Seam has two strategies for managing an extended persistence context, contrasted in figure 9.1. In chapter 8, you learned that a container-managed persistence manager can latch onto a stateful session bean (SFSB) for the duration of its lifetime. By scoping the SFSB to the conversation, Seam can indirectly manage the extended persistence context. Alternatively, Seam can take full control of the extended persistence context by creating its own persistence manager and storing it directly in the conversation. The benefit of the Seam-managed persistence manager is that it can be injected into any Seam component.

Figure 9.1. Contrasts the independence of a Seam-managed persistence context with the coupling of the container-managed persistence managers to their stateful session bean components.

Picking up from the previous chapter, I reiterate the inherent limitations of using an SFSB to host the extended persistence context and segue into Seam’s more flexible solution.

Scoping the persistence context indirectly

When an SFSB becomes a Seam component, Seam doesn’t control how a container-managed persistence manager is bound to the SFSB. Thus, Seam can only tune the lifetime of the extended persistence context by managing the lifetime of the SFSB. (Keep in mind that this has no effect on a transaction-scope persistence context on the SFSB.) However, there are several problems with this solution:

I’m not saying that you can’t make the conversation-scoped SFSB work. It may sufficiently suit your needs. But if any one of these issues gets in your way, it calls for a more flexible solution. Seam can assume the task of managing the persistence manager, a feature known in Seam as a Seam-managed persistence context. Seam can even go a step further by managing Java persistence end to end.

Letting Seam manage the persistence context

A Seam-managed persistence context is a Hibernate or JPA extended persistence manager operating in isolation of Java EE. It’s application managed, which means that Seam is responsible for instantiating it. After that, you use it just as you would a container-managed persistence context in a Java EE component, except that it’s injected using @In rather than @PersistenceContext. To give Seam control of creating the persistence manager, you have to feed it a persistence unit, which you’ll learn to do in section 9.3.

The Seam-managed persistence context is scoped to the conversation, which means you tune its lifetime using the conversation propagation controls you learned about in chapter 7. What sets the Seam-managed persistence context apart from its container-managed counterpart is that it’s stored directly in the conversation, making it a first-class citizen of the application, rather than being bound to the lifetime of a single component. Consider that if an SFSB hosting an extended persistence context is removed, the persistence context goes along with it. In contrast, a Seam-managed persistence context remains available as long as the conversation is active, regardless of which components come and go. The best part is that you can share the persistence context between Java EE and non–Java EE components alike without having to worry about complex (and tricky) propagation rules. Although the extended persistence context in EJB 3 is a good start, Seam is better at handling this task.

Another nice feature of the Seam persistence infrastructure is that the support for JPA and native Hibernate is parallel. The classes and configurations differ, of course, but the overall architecture is the same, making it easy to switch between the two APIs across different projects. This parallel support extends into the Seam Application Framework, covered in the next chapter, which wraps the persistence manager and provides additional built-in functionality to support persistence tasks.

Regardless of who controls the persistence manager, the conversation is the key to giving the persistence manager the respect it deserves. It’s really a perfect marriage. Seam’s persistence strategy goes beyond just scoping the persistence manager. When used in a Seam application, your persistence manager gets some upgrades. If you’re using native Hibernate or Hibernate as the JPA provider, you get yet another set of enhancements.

9.2. Enhancing the capabilities of the persistence manager

Seam proxies the persistence manager when it’s injected into a Seam component and decorates it with extra functionality (i.e., the Decorator pattern). This section presents these upgrades, starting with standard enhancements and then those specific to Hibernate.

9.2.1. Seam’s standard enhancements

Given that Seam and Hibernate are both JBoss-supported frameworks, it should come as no surprise that Hibernate gets special treatment in Seam. If you’re already using Hibernate, this is good news. But Seam also offers some standard enhancements that are available to any persistence provider:

  • EL notation in persistence queries
  • Entity converter that allows entities to be used in UI select menus
  • Managed entity identity across session passivation

Only the first two items will be covered in detail. The last item is a low-level feature and it’s not necessary to concern yourself with the details. Let’s start with the crowd favorite: the EL.

EL in the QL

As you have come to expect by now, Seam lets you use the EL all over a Seam application. With persistence, the EL is back again. Seam supports the use of EL value expressions within a JPQL or HQL query just as it does in JSF messages and log messages. This holds true regardless of which persistence provider or API you’re using.

The value expressions provide an alternative to supplying positional or named parameters in your queries and are evaluated when the query is executed. Let’s say that in the registration process, you want to check to make sure that a username isn’t taken:

  assert entityManager.createQuery(
      "select m from Member m where m.username = #{newGolfer.username}")
      .list() == 0;

Using the EL in a query provides a number of benefits. First, it serves as shorthand for creating a named query parameter and assigning it a value. Also, since the value of the expression is assigned using a query parameter (i.e., setParameter()), it’s properly escaped, protecting the query from SQL injection. And any value that can be resolved via the EL can be used as a parameter. That includes contextual variables as well as factory and manager components. You see this combination used in the restriction clauses of the Query component, covered in chapter 10. Finally, the inline EL syntax moves all parameters into a string, making it possible to define the query in a string constant or externalize it to a configuration file, where it can be assigned using component configuration.

Pick me out an entity

I bet that at one point or another, you’ve needed to present a list of entities in a form field and let the user select one or more of them. This is one of those tasks JSF doesn’t support out of the box (or most frameworks for that matter). It’s your job to convert the instances into a string representation and then reinterpret the selections when the form is submitted. Well, guess what? Seam offers to take care of it for you! The only catch is that you must be using a Seam-managed persistence context and, ideally, a long-running conversation.

Let’s assume that you need to assign a member a list of roles and you’ve prepared a factory named availableRoles that returns a list of Role entity instances. (You cannot use a Set with a UISelectMany component, only a parameterized List or an array.) You can assign roles to a member as follows, nesting the <s:convertEntity> UI component tag to let Seam know to handle the conversion:

  <h:selectManyListbox size="10" value="#{member.roles}">
    <s:selectItems var="r" value="#{availableRoles}" label="#{r.name}"/>
    <s:convertEntity/>
  </h:selectManyListbox>

That’s all there is to it! When the view is rendered, the id of each entity (as defined by its @Id property) is used in the value of a select option. On postback, the entity instance is restored by passing the id to the persistence manager. For the selection to be valid, its object identity must be equivalent to an instance in the collection. The best way to guarantee this condition is to use a conversation-scoped collection and a long-running conversation.

The component that handles the conversion for <s:convertEntity> is named org.jboss.seam.ui.EntityConverter. This component looks for a JPA persistence manager according to a standard naming convention, described at the end of section 9.3.2. It’s possible to override the JPA persistence manager that the converter uses, or configure the converter to use a Hibernate persistence manager. However, the configuration changed between Seam 2.0 and 2.1. Let’s start with Seam 2.0.

In Seam 2.0, you can establish the persistence manager that the converter uses by setting its entityManager property (for JPA) or session property (for Hibernate). Here’s an example of an override when using JPA:

  <component name="org.jboss.seam.ui.EntityConverter">
    <property name="entityManager">#{em}</property>
  </component>

If you only want to override the persistence manager for a single conversion, you first define a new component for the converter class in the component descriptor:

  <component name="customEntityConverter"
    class="org.jboss.seam.ui.converter.EntityConverter">
    <property name="entityManager">#{em}</property>
  </component>

The name of this component is a valid JSF converter id, which you then supply to a JSF converter tag that takes the place of <s:convertEntity> within the select component:

  <f:converter converterId="customEntityConverter"/>

In Seam 2.1, a layer of indirection was introduced. Instead of the entity converter using a persistence manager directly, it uses an entity loader component. In addition, two configuration elements in the component namespace http://jboss.com/products/seam/ui, prefixed as ui, were introduced to simplify the configuration. The entity loader elements are <ui:jpa-entity-loader> and <ui:hibernate-entity-loader> for JPA and Hibernate, respectively. Here’s the same global override for JPA in Seam 2.1:

  <ui:jpa-entity-loader entityManager="#{em}"/>

To define a custom entity converter, you must also define a custom entity loader:

  <ui:jpa-entity-loader name="customEntityLoader" entityManager="#{em}"/>
  <ui:entity-converter name="customEntityConverter"
    entity-loader="#{customEntityLoader}"/>

If all of this configuration is stressing you out, just remember that you can be configuration free if you stick to the defaults. These overrides are just there if you need them.

No thanks, Hibernate

Before moving on to the Hibernate extensions that Seam exposes, I want to discuss Seam’s JPA extension manager and how it affects using alternate JPA providers. Seam uses a built-in component named persistenceProvider to transparently tap into vendor-specific JPA extensions, such as Hibernate’s manual flushing, allowing Seam to leverage the strengths of the persistence provider while respecting your choice to use JPA. As its JavaDoc states, “The methods on this class are the TODO list for the next revision of the JPA specification.”

The only trouble with this component is that in Seam 2.0, it has a strong affinity for Hibernate. If the Hibernate JARs are present on the classpath, Seam automatically assumes that Hibernate is the JPA provider. To reverse this assumption and prevent Seam from trying to use Hibernate extensions, add the following configuration to the component descriptor:

  <component name="org.jboss.seam.persistence.persistenceProvider"
    class="org.jboss.seam.persistence.PersistenceProvider"/>

Seam 2.1 switched to using runtime detection of the JPA provider by consulting the persistence manager, thus making this override unnecessary. Let’s check out what extensions are used if it is Hibernate.

9.2.2. Letting Hibernate shine through

As I mentioned in chapter 8, Hibernate has several nice extensions that Seam can elegantly expose to your application even if you’re using JPA. Here are the most notable extensions:

  • Postquery filters
  • Hibernate Search
  • Manual flushing of the persistence context

This section focuses on the first two features, as well as how to elegantly expose the Hibernate Session. An entire section, section 9.4, is dedicated to the last feature and how it relates to application transactions.

Filtering the query results

Although it’s perhaps not the first feature you’ll use in Hibernate, if the need arises, it’s nice to know that Hibernate supports filtering of the query results for a given Session. This feature is useful for regional filtering and redacting sensitive data. Best of all, you can apply it without touching Java code. Instead, you define filters using XML in the component descriptor. This feature is only available if you’re using a Seam-managed persistence context. Consult the Hibernate reference documentation for details on how to define filters.

But why filter when you can search? That’s what Hibernate Search is all about.

Calling on Hibernate Search

For more sophisticated searching, and to take load off the database, you can use Hibernate Search, a Hibernate extension that can perform Lucene-based full text search queries against the domain model. When the Hibernate Search libraries are present on the classpath (consisting of hibernate-search.jar, hibernate-commons-annotations.jar, and lucene-core.jar), Seam proxies the persistence manager, wrapping it with Hibernate Search capabilities. If you’re using Hibernate, the Session is wrapped in a FullTextSession; if you’re using JPA, the EntityManager is wrapped in a FullTextEntityManager. Hibernate Search is available even when you’re using a Java EE container-managed EntityManager (i.e., @PersistenceContext).

To use Hibernate Search, you either downcast to the full-text variant when you need its features or, if you’re using a Seam-managed persistence context, just inject it directly using the appropriate property type. Here, we search for golf courses using a Lucene query:

  @Name("courseSearch")
  public class CourseSearchAction {
      @In private FullTextEntityManager entityManager;
      @Out private List<Course> searchResults;

      public void search(String searchString) {
          org.apache.lucene.query.Query luceneQuery =
              new MultiFieldQueryParser(new String[] {"name", "description"},
              new StandardAnalyzer()).parse(searchString);
          javax.persistence.Query query = entityManager
              .createFullTextQuery(luceneQuery, Course.class);
          searchResults = (List<Course>) query.getResultList();
      }
  }

Of course, to query entities with Hibernate Search, you need to apply the Hibernate Search annotations to your entity classes and add the indexer settings to the persistence unit descriptor. A minimal configuration consists of an index storage provider and index location, shown here for JPA (/META-INF/persistence.xml):

  <properties>
     ...
     <property name="hibernate.search.default.directory_provider"
         value="org.hibernate.search.store.FSDirectoryProvider"/>
     <property name="hibernate.search.default.indexBase"
         value="/home/twoputt/indexes/open18-index"/>
  </properties>

There’s no way to do Hibernate Search justice in this small amount of space. Besides, Seam simply handles the task of wrapping the full-text search persistence manager around the native one. From there, it’s out of Seam’s hands. I encourage you to grab a copy of Hibernate Search in Action (Manning, 2008) to learn how to use this extremely powerful feature of Hibernate.

While Seam’s role as liaison between JPA and the underlying Hibernate API is a desirable abstraction and usually fishes what you need out of Hibernate, there may be times when you have to work directly with the Hibernate Session. Fortunately, Seam offers a neat trick.

Getting down to Hibernate

When you’re using JPA, you can always get down to the provider interface by calling the getDelegate() method on the EntityManager instance. But you have to perform a cast that makes an assumption about the underlying JPA provider:

  Session session = (Session) entityManager.getDelegate();

You can define a factory in Seam to hide the cast:

  <factory name="hibernateSession" value="#{entityManager.delegate}"
    auto-create="true"/>

You then use the @In annotation to inject the value of this factory into your component:

  @In private Session hibernateSession;

One reason you might need the Hibernate Session is to check if there are modified entities in the persistence context:

  boolean dirty = hibernateSession.isDirty();

Hopefully these upgrades motivate you to use the Seam-managed persistence components. In the next section, you’ll learn to set up a persistence unit and persistence manager in Seam. I present the JPA configuration followed by Hibernate configuration. If you’re only interested in one of the frameworks, you can skip over its complement.

9.3. Setting up a persistence unit in Seam

In the previous chapter, you learned how to prepare a persistence unit descriptor for JPA (META-INF/persistence.xml) and one for Hibernate (hibernate.cfg.xml), which you’ll use in this section to load JPA and Hibernate, respectively. While the Java EE container can find the JPA persistence unit descriptor on its own, Seam requires some direction in locating a persistence unit. Seam’s persistence management is capable of bootstrapping the persistence unit, but it’s not required. You can also configure Seam to use the persistence unit runtime managed by the Java EE container, which only applies to JPA, or, as you’ll learn in chapter 15 (online), Seam can retrieve a persistence unit runtime that’s managed by the Spring container.

I start by introducing you to Seam’s built-in components that load and manage either a JPA or Hibernate persistence unit, then move on to configuring them.

9.3.1. Seam’s persistence manager factories

Seam provides manager components for bootstrapping JPA and Hibernate persistence units. I refer to these components, which wrap the runtime configuration object of the persistence unit, as Seam-managed persistence units. Table 9.1 shows the mapping between each Seam-managed persistence unit and the persistence manager factory it manages.

Table 9.1. The Seam-managed persistence units

Persistence framework

Seam component org.jboss.seam.persistence.*

Persistence configuration it manages

JPA EntityManagerFactory javax.persistence.EntityManagerFactor
Hibernate HibernateSessionFactory org.hibernate.SessionFactory

The Manager design pattern allows Seam to tie the life cycle of the underlying persistence manager factory to that of an application-scoped Seam component. Each of the two components listed in table 9.1 has a @Create method, which starts the persistence manager factory, and a @Destroy method, which closes it. The components initialize on application startup as directed by the @Startup annotation.

Since the Seam-managed persistence units are manager components, they resolve to the value they manage, which is the persistence manager factory. Thus, when a Seam-managed persistence unit is injected into a property of a Seam component, the property’s type must be that of the persistence manager factory. Assuming the name of the JPA persistence unit component is entityManagerFactory, it’s injected as follows:

  @In private EntityManagerFactory entityManagerFactory;

For Hibernate, if the component is named sessionFactory, the injection looks like this:

  @In private SessionFactory sessionFactory;

The Seam-managed persistence unit components are actually just component templates, meaning that neither has a @Name annotation. To actualize them as Seam components, you must declare them in the component descriptor. Only then will the persistence manager factory be loaded.

As with all of the built-in Seam components, Seam provides a component namespace to ease the XML configuration burden. Seam’s persistence components fall under http://jboss.com/products/seam/persistence, aliased as persistence throughout this section. With the namespace declaration in place, let’s see how this component is configured in the case of JPA and Hibernate.

Bootstrapping a JPA EntityManagerFactory

The component definition for the Seam-managed persistence unit must include both a name and a reference to a persistence unit. Let’s assume you have a JPA persistence unit named open18 defined in META-INF/persistence.xml as follows:

  <persistence-unit name="open18" transaction-type="JTA">
    ...
  </persistence-unit>

For that, you declare the following declaration in the component descriptor:

  <persistence:entity-manager-factory name="entityManagerFactory"
    persistence-unit-name="open18"/>

If the persistence-unit-name attribute is excluded from the component definition, the name of the component is used as the persistence unit name, which in this case would be entityManagerFactory.

That’s pretty much all there is to it! Internally, Seam uses the persistence unit name to create an EntityManagerFactory as follows:

  EntityManagerFactory entityManagerFactory =
      Persistence.createEntityManagerFactory("open18");

To have Seam defer loading of the persistence unit until it’s needed, perhaps for a quicker deployment turnaround, you can disable the startup behavior of this component:

  <persistence:entity-manager-factory name="entityManagerFactory"
    persistence-unit-name="open18" startup="false"/>

JPA can accept vendor-specific properties for a persistence unit. Typically these properties are defined inside the <properties> element in the persistence unit descriptor. In Seam, you have the option of defining these properties on the manager component itself:

  <persistence:entity-manager-factory name="entityManagerFactory"
    persistence-unit-name="open18">
    <persistence:persistence-unit-properties>
      <key>hibernate.show_sql</key><value>true</value>
    </persistence:persistence-unit-properties>
  </persistence:entity-manager-factory>

Supplying these properties using Seam’s component configuration feature gives you the flexibility to tune them for a specific environment by using a replacement token or value expression as the property’s value. See Chapter 5 for more details.

The component that loads the Hibernate configuration is a touch more sophisticated.

Bootstrapping a Hibernate SessionFactory

Hibernate is configured in much the same way as JPA, only instead of providing a persistence unit name, you indicate the location where the Hibernate configuration resides on the classpath. If the configuration file is named according to Hibernate’s convention, you don’t even need to specify the file’s location. Hibernate automatically looks for hibernate.cfg.xml (as well as hibernate.properties) at the root of the classpath when it loads, unless told otherwise. In this default case, the component definition is specified as follows:

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

Internally, Seam loads the Hibernate SessionFactory as follows:

  SessionFactory sessionFactory =
      new AnnotationConfiguration().configure().buildSessionFactory();

If the name of the configuration file doesn’t follow the Hibernate convention, perhaps because you’re loading a second Hibernate persistence unit, you must specify the location of the Hibernate configuration file:

  <persistence:hibernate-session-factory name="teetimeSessionFactory"
    cfg-resource-name="hibernate-teetime.cfg.xml"/>

In this case, the load performed internally changes to

  SessionFactory sessionFactory =
      new AnnotationConfiguration().configure(cfgResourceName)
      .buildSessionFactory();

With Hibernate, you have the option of configuring the persistence unit entirely in the component descriptor, specifying the Hibernate configuration properties[3] using component configuration properties:

3 For a full list of properties available to Hibernate, please refer to the Hibernate reference documentation.

  <persistence:hibernate-session-factory name="sessionFactory">
    <persistence:cfg-properties>
      <key>hibernate.connection.driver_class</key>
      <value>org.h2.Driver</property>
      <key>hibernate.connection.username</key>
      <value>open18</value>
      <key>hibernate.connection.password</key>
      <value>tiger</value>
      <key>hibernate.connection.url</key>
      <value>jdbc:h2:/home/twoputt/databases/open18-db/h2</value>
    </persistence:cfg-properties>
  </persistence:hibernate-session-factory>

You have to decide you want whether to define the Hibernate configuration properties in the Hibernate persistence unit descriptor or the Seam component descriptor. If the cfg-resource-name attribute is present, the <cfg-properties> element is ignored.

The Hibernate persistence unit component offers a rich set of configuration properties for supplying the location of mapping artifacts. The properties are defined using the <mapping-classes>, <mapping-files>, <mapping-jars>, <mapping-packages>, and <mapping-resources> elements. Consult the Hibernate documentation for information on using these settings.

Seam’s components are just one option you have for loading a persistence unit. In section 9.3.3, you’ll learn how to work with a persistence manager factory stored in JNDI, a less Seam-centric approach. We’ll forge ahead for now using the Seam-managed persistence unit as the source from which a Seam-managed persistence context is created.

9.3.2. Seam-managed persistence contexts

Having just registered a persistence manager factory, you could use it to create your own application-managed persistence manager. But why manage this resource yourself when Seam can take the burden off your shoulders? Once again, Seam uses a manager component to handle this task. However, in this case the persistence manager is allocated when the Seam-managed persistence context is retrieved from the Seam container rather than being initialized at application startup like the persistence manager factory.

When the Seam-managed persistence context is created, it’s stored in the active conversation context—regardless of whether the conversation is temporary or long-running. The life cycle of the underlying persistence manager is then bound to the lifetime of the conversation. When the conversation ends, Seam calls the close() method on the persistence manager to close the persistence context. Table 9.2 shows the persistence manager that Seam creates for each persistence framework.

Table 9.2. The Seam-managed persistence contexts

Persistence framework

Seam component org.jboss.seam.persistence.*

Persistence manager it creates

JPA ManagedPersistenceContext javax.persistence.EntityManager
Hibernate ManagedHibernateSession org.hibernate.Session

Once the Seam-managed persistence context is defined (which will be covered shortly), you can inject it into the property of another Seam component using the @In annotation. The target property’s type is expected to be that of the persistent manager. Assuming the name of the JPA component is entityManager, it’s injected as follows:

  @In private EntityManager entityManager;

Remember that this injection can occur at any layer in your application, not just on a JSF action bean component as you see in many of the examples in this book.

For Hibernate, where application-managed persistence contexts are your only option, the injection is performed as follows, assuming the component is named hibernateSession:

  @In private Session hibernateSession;

If a JTA transaction is active when the Seam-managed persistence context is injected, the persistence manager is enlisted in that transaction. In addition, if you’re using Hibernate, either as a provider for JPA or natively, and Hibernate filters are defined on the component, they’re applied to the persistence manager at this time.

Like the Seam-managed persistence units, the Seam-managed persistence contexts are component templates. To make them available to the application, they must be activated using the component descriptor. Let’s see how they’re defined.

Defining a managed persistence context

When you declare the Seam-managed persistence context, you must supply a name and a reference to a persistence manager factory. If you’ve configured a Seam-managed persistence unit named entityManagerFactory that loads the JPA persistence unit, you inject a reference to it as a value expression into the Seam-managed persistence context:

  <persistence:managed-persistence-context name="entityManager"
    entity-manager-factory="#{entityManagerFactory}" auto-create="true"/>

Likewise, if you’ve configured a Seam-managed persistence unit named session-Factory to load the Hibernate persistence unit, you inject the corresponding value expression:

  <persistence:managed-hibernate-session name="hibernateSession"
    hibernate-session-factory="#{sessionFactory}" auto-create="true"/>

In the previous two declarations, the auto-create attribute is set to true. By default, the Seam-managed persistence context components are defined with the autocreate feature disabled. By enabling this feature, you can inject these components using an @In annotation without having to supply the create attribute.

 

Tip

If you assign the name entityManager to the JPA persistence manager and session (or hibernateSession as of Seam 2.1) to the Hibernate persistence manager, you can save yourself a couple of keystrokes. Seam uses these names in several of its modules to look up the Seam-managed persistence context, unless an override is specified.

 

So far you’ve established Seam-managed persistence contexts for both JPA and Hibernate, letting Seam handle the entire process. Although there are times when this is the most convenient approach, Seam won’t always be in command. Fortunately, Seam is able to look to JNDI and use a persistence unit waiting there, loaded and ready.

9.3.3. Sharing the persistence manager factory through JNDI

Seam’s JPA persistence manager component is capable of obtaining a reference to a JPA persistence unit loaded by the Java EE container, if made available through JNDI. Seam can also retrieve a Hibernate SessionFactory stored in JNDI for use in its Hibernate persistence manager component. We explore how to make these resources available in JNDI and how to get Seam to use them, starting with the native Java EE integration.

Persistence unit references

There’s no use loading a JPA persistence unit if one’s already available, which is the case in a standard Java EE environment. However, the Java EE container doesn’t expose the EntityManagerFactory by default, which means it’s not published to JNDI. This isn’t necessary for using the @PersistenceContext annotation on a Java EE component. But now, you need to allow Seam to obtain the persistence manager factory from the Java EE container. That requires the extra step of declaring it as a resource reference.

The persistence unit reference can be defined in either the web.xml descriptor using the <persistence-unit-ref> element or in a @PersistenceUnit annotation on a Java EE component. I cover only the XML-based configuration here. The reference associates a JNDI name in the java:comp/env namespace with the persistence unit name, as follows:

  <persistence-unit-ref>
    <persistence-unit-ref-name>open18/emf</persistence-unit-ref-name>
    <persistence-unit-name>open18</persistence-unit-name>
  </persistence-unit-ref>

In order for this reference to be usable, the persistence unit descriptor and entities must be on the classpath of a WAR or packaged as a persistence archive[4] (PAR) and placed in the lib directory of an EAR. When a PAR is in the lib directory of an EAR, its persistence units are visible to the WAR and the EJB JAR. If the persistence unit is packaged inside an EJB JAR, it’s private and therefore not visible to the web context or Seam (JBoss AS is an exception).

4 The persistence archive is detailed in this blog entry: http://in.relation.to/Bloggers/PartitionYourApplication

A reference to the EntityManagerFactory for this persistence unit is obtained by looking up the qualified JNDI name java:comp/env/open18/emf in the Initial-Context. Of course, you don’t have to perform this lookup yourself since Seam can accept a JNDI name in the configuration of the persistence manager, replacing the entity-manager-factory attribute:

  <persistence:managed-persistence-context name="entityManager"
    persistence-unit-jndi-name="java:comp/env/open18/emf"
    auto-create="true"/>

This whole setup assumes you’re working in a Java EE 5–compliant environment, and JBoss AS 4.2 is not. Until JBoss AS 5.0 is rolled out, the means of binding to JNDI and the JNDI naming convention are different.

Dealing with JNDI in JBoss AS

JBoss AS 4.2 doesn’t implement the entire Java EE 5 specification, coming up short in the area of persistence archives. It doesn’t support the use of persistence unit references, as described earlier. Your only option is to instruct Hibernate to bind the EntityManagerFactory to JNDI at runtime by adding a special JNDI Hibernate property to the persistence unit configuration:

  <persistence-unit name="open18" transaction-type="JTA">
    ...
    <properties>
      <property
        name="jboss.entity.manager.factory.jndi.name" value="open18/emf"/>
    </properties>
  </persistence-unit>

This trick only works, however, if Hibernate is the persistence provider. It also depends on Hibernate being able to write to JNDI at runtime, which isn’t supported in all environments (see the accompanying sidebar). Also note that this JNDI name isn’t placed in the java:comp/env namespace[5] but rather in the global JNDI namespace, so the reference to the EntityManagerFactory is obtained by looking up the JNDI name verbatim:

5 On most Java EE application servers, the java:comp/env namespace can’t be modified at runtime.

  <persistence:managed-persistence-context name="entityManager"
    persistence-unit-jndi-name= "open18/emf" auto-create="true"/>

Unfortunately, the situation with JBoss AS is even grimmer. JBoss AS 4.2 only loads persistence units if they’re packaged as an EJB JAR inside an EAR and declared as an EJB module in the EAR’s application.xml descriptor. If your configuration is different, you need to have Seam bootstrap the persistence unit before it can be bound to JNDI. The same goes if you deploy your application to a servlet container such as Tomcat or Jetty. A Hibernate SessionFactory is bound to JNDI using the same runtime technique.

 

Writing to the JNDI registry is not so easy

JNDI namespaces, and the rules regarding which namespaces can be modified at runtime, vary widely across application servers. For instance, JBoss AS supports the namespace java:/, which isn’t available on any other server. GlassFish doesn’t permit the application to modify the java:comp/env namespace. Tomcat disables writing to the JNDI registry at runtime entirely. Keep in mind that writing to the JNDI registry is only necessary if the application server doesn’t support persistence unit references or if you want to bind a Hibernate SessionFactory to JNDI.

 

Getting the Hibernate Session into JNDI

Hibernate at least has an excuse for JNDI tricks since it doesn’t answer to a standard. The way that Hibernate is configured to bind to JNDI is so subtle that it’s often overlooked. You simply add the name attribute to the <session-factory> node in the Hibernate configuration, and that value is used as the global JNDI name to which to bind:

  <hibernate-configuration>
    <session-factory name="open18/SessionFactory">...</session-factory>
  </hibernate-configuration>

Since the mechanism of binding to JNDI is the same as when Hibernate is used as the JPA provider, the lookup follows the same rules. Namely, the JNDI name is passed verbatim to the Seam-managed persistence context component for Hibernate:

  <persistence:managed-hibernate-session name="hibernateSession"
    session-factory-jndi-name="open18/SessionFactory" auto-create="true"/>

Because a Hibernate configuration isn’t going to be picked up by the Java EE container, you must use Seam (or an alternative) to load the persistence unit. In that regard, JNDI really doesn’t provide much benefit in this scenario.

The downside of relying on a persistence unit in JNDI is that you don’t know whether it’s available until the first time you attempt to retrieve it. This presents an opportunity for you to be proactive and validate the configuration when the application starts.

9.3.4. Validating the persistence context at startup

To remedy the uncertainty of relying on a JNDI lookup, you can register an application-scoped @Startup component, shown in listing 9.1, to perform a sanity check by verifying that a managed persistence context can be successfully created.

Listing 9.1. Verifies the persistence configuration at startup

The reference to the Seam-managed persistence context is supplied as a value expression:

  <component name="persistenceContextValidator">
    <property name="entityManager">#{entityManager}</property>
  </component>

A conversation context is active during container initialization, allowing the conversation-scoped EntityManager to be created at that time.

That gives you a handful of options for setting up Java persistence in Seam. Seam does just as much to aid with transactions, which is the topic of the next section.

9.4. Seam’s transaction support

Seam’s transaction support makes your persistence operations robust and the transaction APIs more accessible. Three services comprise Seam’s transaction support (all optional):

  • Global transactions
  • Transaction abstraction layer
  • Application transactions

Seam recognizes that transactions are not only useful at the business layer, but also around the entire request, making them truly global. As part of providing this service, but also to make transaction APIs more accessible, Seam introduces a transaction abstraction layer built around the JTA interface. Seam’s transaction API makes switching between different transaction platforms a matter of configuration. Finally, Seam works with the Seam-managed persistence context and Hibernate to facilitate application transactions. This section shows how these services support you in creating robust database-oriented applications.

9.4.1. Global transactions

The JSF life cycle grants Seam granular control over a request through the use of a phase listener. Seam takes advantage of this visibility to manage the persistence context, manipulate transaction boundaries, catch exceptions, and issue transaction rollbacks. During the Seam life cycle, Seam applies two key aspects of its global transaction strategy:

  • Wraps each request in two (or three) distinct transactions
  • Disables flushing of the persistence context during view rendering

To safeguard persistence operations, regardless of when they occur, Seam uses two global transactions per request (three, if page actions are triggered). The initial transaction begins either before the Restore View phase or before the Apply Request Values phase, depending on whether JTA or resource-local transactions are being used, respectively. Another distinct transaction wraps page actions, if they are used. These initial transactions allow transactional operations performed through the Invoke Application phase (i.e., event listeners, action listeners, page actions, and the action method) to complete their work before advancing to rendering. That way, a rendering exception doesn’t cause business logic that completed successfully to be rolled back after the fact. If the business logic does fail, it can be handled using a transaction rollback and subsequent navigation to an error view.

The final transaction ensures that database reads occurring in the Render Response phase—as a result of lazy loading and other on-demand fetch operations—remain isolated to protect against interim database changes as defined by the transaction isolation level. Seam also disables flushing of Seam-managed persistence contexts during the Render Response phase if Hibernate is the persistence provider, effectively making the transaction read-only. This measure ensures that the view can’t inadvertently cause the database to be modified. Figure 9.2 illustrates these transaction boundaries by shading each distinct life-cycle region.

Figure 9.2. The boundaries of the transactions are wrapped around the phases of the Seam life cycle by Seam’s transaction management. The RESOURCE_LOCAL transaction is delayed until the start of a conversation.

The transaction manager that Seam uses to originate the global transaction is determined by the transaction component, which you’ll learn to configure in the next section. Use of Seam’s global transactions is optional. You are free to use transactions at the boundaries of your service layer methods (or wherever you have them defined). To disable Seam’s global transactions, you set the following configuration in the component descriptor:

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

As a word of warning, taking away Seam-managed transactions leaves the view rendering without a transaction. Let’s consider the consequences of this choice.

Lazy loading in isolation

Do you need a transaction to use lazy loading? No. Lazy loading is made possible by extending the persistence context for as long as you need to cross the boundary of an uninitialized collection or proxy (the lazy-fetching strategy). But even with a conversation-scoped persistence manager, you still face the problem that without explicit transaction boundaries defined, lazy-load operations execute in autocommit mode, opening and closing a transaction for every query. Not only is this expensive, it also lacks isolation guarantees. Each lazy-load operation could execute more than one query, and you may hit more than one lazy association in a given view. Some queries may take a long time to run. Regardless of how many external transaction commits occur in the interim, you want your reads to return data as if all the queries executed in an instant. Thus, it’s a good idea to use an explicit transaction, even when the operations are read-only. And the global transaction guarantees that they are.

Transactions are another area of turf that is highly contested. The Java EE container offers JTA, the standard transaction manager in Java EE, the persistence frameworks provide resource-local transactions, and Spring has its own platform for transaction management. Which solution should you use? Seam reduces this decision to a mere configuration detail.

9.4.2. Seam’s transaction abstraction layer

Seam normalizes all of the transaction implementations just mentioned under its own abstraction layer. But here’s the kicker: Seam molds this abstraction out of the standard Java EE transaction API by extending JTA’s UserTransaction interface. Calls to this interface are delegated to the underlying transaction manager. That means you can take advantage of Seam’s transaction management without committing to yet another transaction platform. Seam also weaves in a number of convenience methods that ease the task of managing the transaction from the application code. When control of transactions is out of Seam’s hands—which is the case with container-managed transactions on EJB components—Seam still participates by performing a narrower set of operations and listening for transaction synchronization events raised by the EJB container.

 

Note

Container-managed transactions can’t be controlled by the application, so begin(), commit(), and rollback() are disallowed. setRollback-Only() is permitted.

 

Table 9.3 shows the transaction managers that are supported by Seam’s abstraction layer. The namespace alias tx used by the XML elements in this table resolves to http://jboss.com/products/seam/transaction. Your job is to connect Seam to a transaction manager so that it can create transactions as needed.

Table 9.3. Transaction managers supported by Seam’s abstraction layer

Seam transaction manager org.jboss.seam.transaction.*

How installed

Native transaction manage

UTtransaction Default in non-EJB environment Application-managed JTA UserTransaction
EntityTransaction <tx:entity-transaction> JPA EntityTransaction
HibernateTransaction <tx:hibernate-transaction> Hibernate Transaction
CMTTransaction Default in EJB environment Container-managed JTA UserTransaction available via the EJBContext object
NoTransaction <tx:no-transaction> or when JTA is not available Used when no transaction managers are available

Seam’s transaction managers are mutually exclusive. Seam uses application-managed JTA, retrieved from the JNDI registry, in non–EJB environments. If you’d rather have Seam use resource-local transactions, perhaps because JTA isn’t available, you configure the one that corresponds with the persistence API you’re using. To use the resource-local transaction manager with JPA, define the following component configuration:

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

You activate the resource-local transaction manager from Hibernate as follows:

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

The persistence manager only needs to be specified if its name doesn’t adhere to Seam’s standard naming conventions for the respective Seam-managed persistence context.

If your components rely on container-managed transactions, available in an EJB environment, Seam works alongside the UserTransaction on the EJBContext to capture transaction synchronization events. Since Seam isn’t in control of container-managed transactions, it’s necessary to register Seam to be notified of the transaction boundaries:

  <tx:ejb-transaction/>

This configuration activates a stateful session bean that implements the SessionSynchronization interface to capture transaction events from the EJB container. This SFSB is packaged in jboss-seam.jar, which must be bundled in the EAR. From this SFSB, Seam passes on the following two events to other Seam components using its own internal event mechanism, the same events Seam raises for Seam-managed transactions:

  • org.jboss.seam.beforeTransactionCompletion
  • org.jboss.seam.afterTransactionCompletion (raised on commit or rollback)

The second event passes a boolean parameter to the observer indicating whether the transaction was successful (i.e., commit or rollback). As a word of warning, mixing Seam’s global transactions with CMTs is complex since the transactions themselves are not shared.

If you disable the Seam transaction manager (i.e., <tx:no-transaction>), you must also disable Seam’s global transactions. Otherwise, Seam throws an exception when it attempts to look up a transaction.

 

Using distributed transactions in a Seam application

One of the main reasons for using JTA transactions is to take advantage of distributed transactions. Despite Seam wrapping global transactions around each request, only the JTA implementation can support distributed transactions. In that case, you can work with multiple persistence managers and get two-phase commits as long as the underlying data source is configured as an XA resource. Chapter 14 (online) demonstrates how to set up XA data sources in the sample application.

 

When using EJB components, you have the option of declaring transaction boundaries using the standard Java EE mechanism, using either @TransactionAttribute annotations or the ejb-jar.xml descriptor. Seam brings this declarative approach to JavaBean components by providing the @Transactional annotation. The next section focuses on using Seam-managed transactions on non-EJB components.

9.4.3. Controlling Seam-managed transactions

Transactions controlled in the business logic are referred to as bean-managed transactions (BMTs). While BMTs offer more granular control, their use mixes up transaction management with business logic. As with persistence, Seam volunteers to play the role of the “bean” in this equation by taking on management of the transactions, delivering the same value proposition as container-managed transactions (CMTs). The key benefit of this approach is that JavaBean and EJB components can share the same strategy. If necessary, you can still use the Seam transaction API (i.e., the Transactional component) to get more fine-grained control of the transaction.

Seam provides the @Transactional annotation to control the propagation of a Seam-managed transaction around a method call. The @Transactional annotation, summarized in table 9.4, is a synonym for the Java EE @TransactionAttribute annotation. Seam’s annotation supports a set of propagation types that mirror those in the Java EE API. Seam wraps a built-in method interceptor around components that contain the @Transactional annotation, which interprets this annotation and drives the transaction accordingly. Note, however, that the @Transactional annotation is irrelevant during a JSF request when using Seam global transactions.

Table 9.4. The @Transactional annotation

Name:

Transactional

Purpose:

Specifies the transaction propagation that should be used for a method call

Target:

TYPE (class), METHOD

Attribute

Type

Function

value TransactionPropagationType Indicates how the transaction should be handled around the method call. Default: REQUIRED.

The @Transactional annotation can be applied at the class or method level. When it’s applied at the class level, it’s inherited by all methods unless the method overrides this setting with its own @Transactional annotation. The propagation values that are permitted are summarized in table 9.5. Note that Seam doesn’t support suspending or nesting transactions.

Table 9.5. The transaction propagation types supported by the @Transactional annotation

Propagation type

Purpose

REQUIRED Indicates that a transaction is required to execute the method. If a transaction isn’t active, Seam will begin a new transaction. This is the default type.
SUPPORTS Indicates that the method is permitted to execute in the presence of an active transaction, but it won’t begin a transaction if one isn’t active.
MANDATORY Indicates that an active transaction is required to execute the method. A runtime exception is thrown if a transaction isn’t already in progress.
NEVER Indicates that a transaction shouldn’t be active when this method is called. A runtime exception will be thrown if a transaction is active.

Consider that you want to apply a transaction to all of the public methods of a Seam component. For that, you define the @Transactional annotation at the class level:

  @Name("courseAction")
  @Transactional
  public class CourseAction {
      @In private EntityManager entityManger;
      public void addCourse(Course course) {
          entityManager.persist(course);
      }
  }

Now assume you want to delegate work to a method on another component. To ensure that the helper method only executes in the presence of an existing transaction, you declare the propagation type to be mandatory, declared here using a method-level annotation override:

   @Name("courseAuditManager")
   @Transactional
   public class CourseAuditManager {
       @In private EntityManager entityManager;
       @Transactional(TransactionPropagationType.MANDATORY)
       public void storeAuditInfo(Course course) {
           entityManager.persist(new CourseAudit(course));
       }
  }

At the end of any method call that begins a transaction, the transaction is committed. When using Seam global transactions, though, a transaction will already be active, so the transaction commits at the boundaries of the phases illustrated in figure 9.1 instead. But what happens when the method call is disrupted by an exception? That where rollbacks come in.

Rolling back when things go wrong

Seam mimics the rollback behavior employed by the EJB container for transactional method calls. In fact, when using Seam session bean components, Seam steps in and issues the rollback even before the exception gets to the EJB container in certain cases. The rules for rollback are as follows:

  • Roll back if a system exception is thrown. A system exception is a RuntimeException not annotated with @ApplicationException.
  • Roll back if an application exception with rollback enabled is thrown. An application exception is defined by the @ApplicationException annotation, which indicates whether a rollback should be issued when the exception is thrown.
  • Don’t roll back if an application exception with rollback disabled or a checked exception is thrown.

Seam can process the @ApplicationException from the Java EE API and its synonym in Seam, which is summarized in section 3.6.3 of Chapter 3. If the exception bubbles out of the application logic, Seam’s exception-handling facility picks it up and issues a rollback on the transaction if it’s still active. The rollback characteristics on the exception just give you control over when the rollback happens and allow you to handle it more gracefully. Whenever a transaction fails, Seam also adds a JSF warning message to the response from the message key org.jboss.seam.TransactionFailed.

The transactional methods exhibited thus far use atomic database transactions. We’re now going to look at another type of transaction, the application transaction, which is more of a design pattern than a service.

9.4.4. Application transactions

The application transaction (also called an atomic conversation, optimistic transaction, or long-running application transaction) is the pinnacle of Seam’s Java persistence support. It requires coordination from several different aspects of Seam, but it is without a doubt the key to ensuring data consistency in a web-based application.

The goal of an application transaction

A persistence context is flushed by calling the flush() method on the persistence manager. When that happens, modifications made to managed entities (dirty entities) are propagated to the database using a series of Data Modification Language (DML) statements (i.e., INSERT, UPDATE, and DELETE), a strategy referred to as write-behind. When operating within the scope of a database transaction, it doesn’t matter when the DML statements are executed since they’re part of the same transaction and can be rolled back if something causes the transaction to fail (i.e., they are atomic).

However, an extended persistence context can span many requests and therefore many database transactions. Flushes that occur in different transactions aren’t part of the same atomic unit of work. Therefore, it’s not possible to ask the database to roll back to the state it was in when the conversation began. One workaround is to use compensating transactions (i.e., “undo”), but they are laborious and error prone, and don’t address the fact that these interim commits allow data (which is only partially complete from the standpoint of the use case) to enter the database, thus effectively breaking the conversation. Sending modifications to the database prematurely is analogous to charging your credit card as you add items to an online shopping cart. What’s worse is that other parts of the system see these incomplete records as committed, the very situation isolated transactions are intended to prevent.

What you want to be able to do is group all DML statements in a use case together so they can be applied or rolled back uniformly as an atomic unit of work. I can assure you that I’m not proposing the use of a long-term database lock. Holding a database lock during user “think” time would introduce a tremendous bottleneck into the system. The trick is to use an application transaction, which leverages the persistence context as a database intermediary.

You already know that a conversation-scoped persistence context can queue changes throughout a use case, which you can think of as instructions for creating DML statements. In an application transaction, flushing the persistence context is deferred until the final step of the use case and executed within a database transaction. Since the DML statements for the entire use case are applied together, the conversation (i.e., use case) is atomic. An application transaction relies on optimistic locking, presented in the previous chapter, to guarantee that the statements only execute if the database records that map to the managed entities in the persistence context haven’t been modified externally since the use case began.

Let’s consider how an application transaction is implemented according to the JPA specification and the alternate solution that Hibernate provides. The difference is the product of a heated debate. The extension in Hibernate that facilitates an application transaction (manual flushing) was forced out of the specification because several decision makers didn’t understand it. Hopefully, this section will make you one of the enlightened ones.

A wrinkle in the specification

The flushing behavior of the persistence context is controlled using the flush mode setting on the persistence manager. The JPA specification only defines two flush modes, AUTO and COMMIT. In AUTO flush mode, a flush occurs when the persistence manager deems it necessary. The COMMIT flush mode instructs the persistence manager to hold off flushing until the transaction commits.

The specification states that if you want to perform an application transaction, you should set the flush mode to COMMIT and work outside of explicit transactions until you’re ready to perform the flush. At the end of the use case, you call a transactional method, which results in the changes being flushed to the database when the transaction commits.

Following this proposed approach means completely avoiding the use of transactions in the interim, which is a very bad design. You are once again tiptoeing through your own application (reminiscent of the lazy-initialization exception). You’re also operating in autocommit mode, which as you learned earlier doesn’t provide isolation for a sequence of database operations. Finally, it completely rules out the use of Seam’s global transaction strategy, which uses at least two transactions per request. For these reasons, Hibernate adds the MANUAL flush mode as an extension to the JPA specification.

Hibernate’s manual flush mode

Hibernate’s MANUAL flush mode ensures that the persistence context is only flushed when a call is made to the flush() method on the persistence manager API (bean-managed flushing). This mode gives you the flexibility to take your persistence context in and out of transactions as you please without risking a premature flush.

 

Warning

If the entity identifier is generated during an insertion (i.e., auto-increment column), then even with manual flushing, a flush occurs after a call to persist(). This is necessary since each managed entity in the persistence context must be assigned an identifier. To avoid the flush, you need to set the id-generation strategy to sequence (not identity).

 

Application transactions using Hibernate’s MANUAL flush mode extension are controlled at the boundaries of the conversation. Fortunately, Seam can manage the flush mode extension transparently. By setting the flushMode attribute on the @Begin annotation to MANUAL (or the flush-mode attribute on the <begin-conversation> page descriptor tag), Seam switches the persistence manager to manual flushing when the conversation begins:

  @Begin(flushMode = FlushModeType.MANUAL)
  public void beginApplicationTransaction () { ... }

As of Seam 2.1, you can set the default flush mode globally in the component descriptor:

  <core:manager default-flush-mode="MANUAL" .../>

If you want to use application transactions in your application (and don’t want to use the workaround of avoiding transactional methods), you must be using a Seam-managed persistence context and the native Hibernate API or Hibernate as the JPA provider. MANUAL flush mode isn’t supported by any other JPA 1.0 provider. Let’s take a look at a complete example that uses an application transaction.

An application transaction in practice

Two compelling use cases for an application transaction are a wizard-based form and an editor preview screen. In both cases, the user has the opportunity to verify the data is correct before it’s committed. We’ll put the first use case into practice.

Building on the golf course wizard example from Chapter 7, the CourseWizard-Action component, shown in listing 9.2, supports adding a new course as well as updating an existing one, initiated by the action listener methods addCourse() and editCourse(), respectively. Notice that these methods switch to a MANUAL flush mode while initiating a long-running conversation. This opens a Seam-style application transaction. Interim method calls don’t flush changes to the Course entity to the database. Instead, all changes are deferred and sent in an atomic commit when the save() method is called. (Note, however, that the persist() method forces a flush if the entity’s identifier is generated on insert.)

Listing 9.2. A component that supports an application transaction

What’s important is that you aren’t forced to sidestep transactional methods to implement an application transaction. The MANUAL flush mode instructs the persistence context not to take action until it hears your command, ensuring that the conversation isn’t broken by a premature flush. In the interim, you’re free to use transactions to get proper read isolation or for any other purpose.

Application transactions demonstrate the resourcefulness of the persistence context when treated as a first-class citizen of a use case and not relegated to the handyman of a transaction. For more in-depth coverage of application transactions, consult Chapter 11 of Java Persistence with Hibernate (Manning, 2007).

9.5. Summary

This chapter introduced Seam’s managed persistence and transactions as an alternative to the container-managed counterparts in Java EE. I hope you were able to conclude that using Java persistence in Seam is quite compelling. You saw how the persistence context is often mishandled and that by hosting the persistence manager in the conversation, Seam makes these problems melt away, letting you realize the true value of Java persistence. In fact, Seam makes it hard not to get persistence right.

In addition to scoping the persistence manager properly, you discovered that Seam gives it some nice upgrades. We examined the general enhancements and ones specific to Hibernate. To give Seam control of the persistence context, you have to feed it a persistence unit at runtime. You learned how to configure Seam to bootstrap a JPA or Hibernate persistence unit itself or grab one already loaded from JNDI. You also saw how to define a Seam-managed persistence context for either persistence API.

I then unveiled Seam’s transaction support. You saw that global transactions extend the guarantees that transactions provide across the whole request, that Seam’s transaction abstraction layer makes the transaction APIs far more accessible, and that application transactions are the key to ensuring data consistency in a stateful application—enhanced by Hibernate’s MANUAL flush mode extension.

You’re ready to use Seam’s Application Framework to rapidly throw together CRUD applications and gain some experience using Seam-managed persistence contexts and transactions at the same time.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.114.19