by Dan Allen

Spring into Seam, Part 3: Persistence for two

how-to
May 20, 200823 mins

Sparks fly (and so does data) when Spring shares Seam's persistence context

 

An excerpt from Seam in Action

By Dan Allen

Published by Manning Publications

ISBN: 1933988401

So far in the Spring into Seam series, you’ve learned how to build Seam-Spring hybrid components and how to add stateful behavior to Spring beans with help from JBoss Seam. In this final article, you’ll learn how to coax Seam and Spring into sharing a single persistence context — the pinnacle feat of Spring-Seam integration.

Spring and JBoss Seam are both powerful and popular frameworks for Java development — and they also complement one another. In previous installments in this series (excerpted from Seam in Action) you’ve seen how to build hybrid components that can participate in both frameworks and learned how Seam can enhance Spring beans by making them stateful. In this third and final article in the series, you’ll see that one of Seam’s best features — its conversation-scoped persistence context — can also solve one of Spring’s greatest weaknesses. This feature is by far the most compelling reason for Spring developers to incorporate Seam into their development toolbox. As is customary, I have saved the best for last.

For everything except extending the persistence context, the template classes in Spring’s object-relational mapping (ORM) module offer a convenient way to manage the Hibernate Session or Java Persistence API (JPA) EntityManager. But where Spring’s ORM support breaks down is in its mishandling of the persistence context. Spring can scope the persistence context anywhere from a single operation (method call) to an entire request. But out of the box, it cannot go any further. Spring Web Flow, an extension module for Spring, does offer a solution to manage an extended persistence context over the course of a flow, but Seam’s persistence context management is arguably more versatile overall.

Let’s look more closely at how Spring shanks the persistence context before diving into the configuration necessary to make the exchange of the Seam-managed persistence context possible. The way the persistence manager (the generic term for a Hibernate Session or JPA EntityManager) is handled turns out to be the biggest challenge in the effort to integrate Spring and Seam. It’s akin to a custody battle over a child in a divorce. Only in this case, learning how to share the child (the persistence manager) is what ends up saving the marriage.

The problem with Spring’s thread-local approach

Spring’s ORM support for JPA and Hibernate improved dramatically in Spring 2.0. The JPA support framework can now assume responsibility for injecting an EntityManager instance into a @PersistenceContext field on a bean in a non-Java EE environment. (The annotation would typically be handled by the Java EE container.) The Hibernate package now leverages the thread-local Hibernate Session as returned by the getCurrentSession() method on the SessionFactory, by implementing the CurrentSessionContext contract rather than by introducing yet another proxy layer. However, Spring still imposes one key limitation as custodian of the persistence managers, which interferes with their function in stateful applications: Spring scopes the persistence context to the atomic transaction rather than to the business use case (e.g., the conversation).

Request-scoped persistence contexts

Let’s start from the viewpoint of the OpenEntityManagerInViewFilter. Why is this filter needed in a Spring application? While persistence unit runtimes (e.g., EntityManagerFactory) are thread-safe, persistence managers (e.g., EntityManager) are not. The former can be stored in the application scope as a singleton. The later must be reserved for a given use case, which has traditionally been a single request. This filter binds the persistence manager to the thread that is processing the request so that the persistence context remains available for all persistence operations in that request. Without this filter, the best Spring can do is ensure that the persistence manager remains available for the lifetime of the transaction. The worst approach you can take with Spring is to allow the persistence manager to run free (not even binding it to a transaction), in which case a new instance is created for each persistence operation!

Since the persistence context is one the most compelling features of ORM, the OpenEntityManagerInViewFilter is at least a step in the right direction towards maximizing the value you are getting from the ORM. With the filter in place, Spring scopes the persistence manager to the thread using the bindResource() method of the TransactionSynchronizationManager, a page from Hibernate’s playbook. (Hibernate can perform this work on its own, although the OpenSessionInViewFilter is still available as an alternative, serving the same role as its JPA counterpart.)

This thread-bound approach gives you the flexibility to lazy-load associations in the view layer from the same persistence manager that retrieved the primary entity instance (meaning that the instances do not become detached at any point during the request). However, the benefit dies with the thread (and, in turn, the request).

Why filters just don’t work

The problem with using the OpenEntityManagerInViewFilter is twofold:

  • Lazy loading occurs non-transactionally.
  • Entity instances are detached before the next request.

While there is a OpenEntityManagerInViewFilter, there is no corresponding OpenTransactionInViewFilter. The absence of a transaction around the view partly has to do with the fact that Spring’s view layer support is independent. The net effect is that Spring lacks the comprehensive request lifecycle management that Seam boasts. Seam uses at least two transactions per request so that lazy loading can happen in a read-only transaction designated solely for the rendering of the view (the JSF Render Response phase). You need two transactions because you want to make sure that the primary action triggered by the request completes successfully before rendering the ensuing view. An OpenTransactionInViewFilter in Spring would not have this granularity (since filters can only work on the outskirts of a request). You could probably spark a heated debate over the importance of the transaction around the view, but suffice to say that Spring just doesn’t support it out of the box.

The second bullet point is the worse of the two, and is the focus of this article. JPA and Hibernate were designed to rely on the persistence context to guarantee the identity of the managed entities. If the persistence context is closed prematurely at the end of the request, entity instances propagated through to the next request are abandoned by their persistence manager, and can only contribute to the new persistence context through the use of (dirty) merge operations. If you are lucky, that is all you have to worry about. However, with detached instances floating around, you run the risk of encountering exceptions that occur as the result of violating the unique entity contract (recall that only a single instance of a entity class with a given identifier is allowed to be associated with a persistence context at any given time). As the application grows in complexity, the chance of running into this problem increases dramatically.

Fortunately, by moving to Seam-managed persistence, we can say goodbye to the problems of using the persistence context in Spring and the haphazard fix provided by the OpenEntityManagerInViewFilter. In making this move, we don’t want to lose out on all the Spring classes that make working with Hibernate and the various JPA vendor implementations so easy. Once again, we want the best of both worlds. Seam’s inversion of control (IOC) support answers this call. The first step is to get Seam’s foot in the door by leveraging Spring’s persistence configuration.

Sharing the duty of persistence management

How you choose to make the Seam-managed persistence context available to Spring depends on where you want to do the majority of the configuration. The end goal, which is to replace Spring’s thread-bound approach with Seam’s conversational one, is all that matters.

Except for differences in naming, the steps for incorporating a Seam-managed EntityManager and a Seam-managed Hibernate Session into Spring are almost identical. The focus of this article is on the JPA variant. I must warn you that the first time you see the full handoff in place, it can appear a bit confusing. But by following the steps in this article, you will have it worked out in no time.

Step 1: EntityManagerFactory configuration

In the first step, I am going to work from the assumption that you covet your persistence configuration in Spring and still want to use it. It’s hard to deny that Spring does a great job of consolidating the persistence configuration, making it just another Spring bean definition. You don’t have to worry about JNDI resources or special configuration files for each component. It’s all there in the Spring configuration file.

If you are using Spring to bootstrap the EntityManagerFactory, then you set up the DataSource and the EntityManagerFactory in the Spring configuration file in the typical way. Since the tournament manager Web-based application introduced in the earlier installments in this series is based on Spring, let’s assume the JPA configuration shown in Listing 1 is already in place. In this case, Spring has primary custody of the persistence unit.

Listing 1. Spring JPA configuration

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 <property name="driverClassName" value="org.h2.Driver"/>
 <property name="url" value="jdbc:h2:file:/home/twoputt/databases/tournament-db/h2"/>
 <property name="username" value="open18"/>
 <property name="password" value="tiger"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="persistenceUnitName" value="tournament"/>
 <property name="dataSource" ref="dataSource"/>
 <property name="jpaDialect">
 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
 </property>
 <property name="jpaVendorAdapter">
 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
 <property name="showSql" value="true"/>
 <property name="generateDdl" value="false"/>
 </bean>
 </property>
</bean>

Since the DataSource and the PersistenceProvider are both defined in the Spring configuration, they can be left out of the persistence unit deployment descriptor (e.g., persistence.xml), which is nothing more than a required placeholder, as you can see in Listing 2.

Listing 2. Minimal JPA persistence unit descriptor

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
 http://java.sun.com/xml/ns/persistence
 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
 version="1.0">
 <persistence-unit name="tournament" transaction-type="RESOURCE_LOCAL"/>
</persistence>

With the configuration for the EntityManagerFactory in place, the handoff begins. Seam needs to get a hold of the Spring-managed EntityManagerFactory and use it to create Seam-managed EntityManager instances, which get bound to Seam’s conversation context. That means that you need to be able to expose the entityManagerFactory Spring bean to the Seam container. The best approach here is to supply Seam with an Expression Language (EL) value expression that gets resolved through the Spring JSF variable resolver or EL integration. Both variants of the Spring JSF integration are set up using the JSF configuration file (i.e., WEB-INF/faces-config.xml). If you are using Spring 2.0 or earlier, you register the integration using the variable resolver configuration shown in Listing 3.

Listing 3. Spring JSF integration using a variable resolver

<faces-config>
 <application>
 <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
 </application>
</faces-config>

If you have made the move to Spring 2.5, you can take advantage of the EL resolver instead, the configuration of which is shown in Listing 4.

Listing 4. Spring JSF integration using an EL resolver

<faces-config>
 <application>
 <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
 </application>
</faces-config>

I recommend using the Spring JSF integration for this part of the handoff because it is an easier route than exposing a Spring factory bean — LocalContainerEntityManagerFactoryBean, in this case — as a Spring-Seam hybrid component. All the wrapping and proxying needed to handle a Spring factory bean is a minefield of potential exceptions. If the variable/EL resolver approach works, take it. Besides, you don’t need the EntityManagerFactory to be a Seam component, since it is only needed for what it produces: EntityManager instances.

With that said, Seam resolves the entityManagerFactory from the Spring container using the value expression #{entityManagerFactory} and supplies it to the <persistence:managed-persistence-context> element in the Seam component descriptor, as shown in Listing 5.

Listing 5. Resolving the EntityManagerFactory from the Spring container

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

If you are working with multiple persistence units (e.g., databases), you will need one of these handoffs for each EntityManagerFactory bean definition (e.g., entityMangerFactory2, entityManagerFactory3).

You have now completed the first phase of the handoff. Seam components can now use the EntityManagerFactory prepared by Spring! If you choose to let Seam have custody of the EntityManagerFactory, then this first step is not required, because Seam will already have access to the EntityManagerFactory in its own container. From this point forward, the required steps to expose the Seam-managed persistence context to Spring are the same regardless of who has custody of the persistence unit.

Now let’s turn around and give Spring access to the Seam-managed persistence context. We certainly don’t want Seam components using one persistence manager and Spring beans using their own instance!

Step 2: Re-gifting the EntityManager

In Seam, you inject the EntityManager directly into a component using the @In annotation (as long as the component is stateful). However, in Spring, you inject its parent, the EntityManagerFactory, in almost all cases. Behind the scenes, Spring creates and manages its own EntityManager instance. This may leave you scratching your head as to how you would possibly be able to inject a Seam-managed persistence context into a Spring bean. Fortunately, the Seam IOC module provides a Spring factory bean just for this purpose.

The SeamManagedEntityManagerFactoryBean takes the place of the Spring entity manager factory bean configured in Step 1, rewrapping the Seam-managed persistence context from the current conversation and offering it up in response to the createEntityManager() call on the EntityManagerFactory interface. The Seam spin-off of the entity manager factory bean, which satisfies the same contract as the native Spring entity manager factory bean, tricks Spring into thinking that it is using a real EntityManagerFactory to create a persistence manager instance, when in fact it is using a wrapper that always returns the conversation-scoped persistence context managed by Seam. This handoff is depicted in Figure 1.

Figure 1. The coordination between the Spring and Seam containers (click to enlarge)

The LocalContainerEntityManagerFactoryBean isn’t out of the picture, as you can see. Seam still uses it to produce an EntityManagerFactory in order to create the conversation-scoped EntityManager. Seam becomes the only consumer of this bean, though. To support auto-wiring of Spring beans that rely on an EntityManagerFactory, or to save yourself from having to change the explicit references to the EntityManagerFactory on those same beans if you are not using auto-wiring, you need to rename the native factory bean to entityManagerFactorySpring and reserve the name entityManagerFactory for the Seam wrapper. In Listing 6, the Spring entity manager factory bean defined earlier has been updated to reflect this change.

Listing 6. Renaming of the Spring EntityManagerFactory bean

<bean id="entityManagerFactorySpring" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="persistenceUnitName" value="tournament"/>
 <property name="dataSource" ref="dataSource"/>
 ...
</bean>

All that is left to do is to configure the SeamManagedEntityManagerFactoryBean. Since this factory bean produces an EntityManagerFactory wrapper that distributes the Seam-managed persistence context, the only property it requires is persistenceContextName, which is the component name assigned to the <persistence:managed-persistence-context> in Seam’s component descriptor. The component name is highlighted in bold in Listing 7. The stanza has also been updated to reflect that change in the name of the Spring factory bean.

Listing 7. The managed persistence context configuration in Seam

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

The name of the Seam-managed persistence context, shown in bold in Listing 8, is assigned to the new entityManagerFactory bean definition that in turn responds with the conversation-scoped persistence manager.

Listing 8. Supplying the Seam-managed persistence context to Seam

<bean id="entityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">
 <property name="persistenceContextName" value="entityManager"/>
</bean>

If you decide not to use the naming convention suggested here, make sure that whenever you inject a bean reference into an EntityManagerFactory property, such as on a JpaTemplate or JpaDaoSupport bean, you are using the bean definition from Listing 8. Aside from that, you are done! You can now use a Seam-managed, conversation-scoped EntityManager in Spring beans, Seam components, or Spring-Seam hybrid components.

What follows in the remainder of this article is a bonus round: you’ll learn how to take advantage of Spring’s emulated resource injections to make your Spring beans appear more like Java EE components by using the @PersistenceContext annotation.

Emulating resource injections

Spring boasts the ability to emulate the behavior of the Java EE container by injecting a persistence manager into a property of a bean annotated with @PersistenceContext. This feature is something that even Seam does not support, since Seam’s position is to step out of the way and allow Java EE annotations to be handled by the Java EE container. Thus, this is a useful feature to leverage from Spring if you’re interested in using this annotation in a standalone environment.

Spring’s LocalContainerEntityManagerFactoryBean loads the persistence unit configuration from the persistence unit descriptor (e.g., META-INF/persistence.xml) whose name is equivalent to the value of the persistenceUnitName property specified on this factory bean (refer to Listings 1 and 2). If a persistence unit name is not provided, the first configuration in the persistence unit descriptor is selected. The injection of the persistence manager into properties of Spring beans annotated with @PersistenceContext is handled by a special bean post-processor, which must be registered in the Spring configuration file, shown in Listing 9.

Listing 9. Registering the Java EE persistence annotation post-processor

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

When Spring encounters a @PersistenceContext annotation on a bean property, it uses the value of the annotation’s unitName attribute to locate an EntityManagerFactory-producing factory bean with a matching persistenceUnitName property value, matching against the bean ID as a fallback. If a unitName attribute is not specified in the annotation, then Spring uses the first EntityManagerFactory-producing factory bean defined in the Spring configuration. An example of using the @PersistenceContext to inject a transaction-scoped EntityManager into a Spring bean is shown in Listing 10. (If there is only a single persistence unit in your application, you can safely leave off the unitName attribute.) Note that you needn’t be worried about thread-safety here, as the EntityManager instance that Spring injects is merely a proxy to the real transaction-scoped EntityManager. (It would pose a thread-safety issue if you set the value of type attribute to EXTENDED.)

Listing 10. Injecting an EntityManager in Spring

public class TournamentServiceImpl implements TournamentService {
  @PersistenceContext(unitName = "tournament")
  private EntityManager entityManager;
}

With some additional configuration, the SeamManagedEntityManagerFactoryBean can be made to step into the middle of this lookup logic to ensure that the EntityManager injected is the conversation-scoped one managed by Seam. The SeamManagedEntityManagerFactoryBean is unique in that it does not define a persistence unit name like its Spring counterpart; this is because it is merely a wrapper around the Seam-managed EntityManager. Therefore, the persistenceUnitName property on this factory bean definition can be assigned an arbitrary value. By default, the value of the persistenceUnitName property is made to be equivalent to the value assigned to its sibling persistenceContextName property. You will likely want to choose a more meaningful value — perhaps, as Listing 11 suggests, using the suffix :seam — so that it is clear that the value of persistenceUnitName is both artificial and managed by Seam.

Listing 11. Defining a synthetic persistence unit name for a Seam persistence context

<bean id="entityManagerFactory" class="org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean">
 <property name="persistenceContextName" value="entityManager"/>
 <property name="persistenceUnitName" value="tournament:seam"/>
</bean>

You can now inject the Seam-managed persistence context into any Spring bean using a @PersistenceContext annotation. This is illustrated in Listing 12.

Listing 12. Injecting the Seam-managed persistence context into a Spring bean

public class TournamentServiceImpl implements TournamentService {
  @PersistenceContext(unitName = "tournament:seam")
  private EntityManager entityManager;
}

However, you have to be careful here! The EntityManager injected in this case is not a proxy, but instead an actual EntityManager instance held in Seam’s conversation scope. Another way to say this is that you are now dealing with an extended persistence context. An extended persistence context is a stateful object. Therefore, you cannot use this annotation to inject an extended persistence context into a stateless, application-scoped singleton! What you would need to do is alter your bean definition for TournamentServiceImpl to make it stateful, perhaps binding it to the Seam conversation scope.

If you want to use the @PersistenceContext without specifying the unitName attribute, and have it select the Seam-managed persistence context, you can set the default persistence unit name on the bean post-processor definition, as in Listing 13.

Listing 13. Setting a default persistence unit name

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
 <property name="defaultPersistenceUnitName" value="tournament:seam"/>
</bean>

The @PersistenceContext can now be used in its most basic form, which you can see in Listing 14.

Listing 14. @PersistenceContext at its simplest

public class TournamentServiceImpl implements TournamentService {
  @PersistenceContext
  private EntityManager entityManager;
}

There you have it! You now have seamless integration of the Seam-managed persistence context between Seam components and Spring beans. What’s better is that Spring doesn’t have to worry about managing the lifecycle of the persistence manager (no OpenEntityManagerInViewFilter). The conversation controls in Seam dictate how long the persistence manager stays open.

Using Seam-managed persistence in Spring makes it possible to work with extended persistence contexts, even though this is discouraged by Spring. The Spring documentation basically tells you to stay away from extended persistence contexts because they are used for stateful components. But you now know that stateful components are easy to create in Spring using Spring-Seam integration! And, thanks to the low-level sharing of the persistence context, both component types end up operating on the active persistence context, relieving the database of unnecessary calls and ensuring object identity throughout the transaction, and beyond.

Keeping transactions in accord

While the persistence context is now being shared between the two frameworks, the transaction managers are not aligned. Given that Seam automatically wraps each request in two-phased transactions, this can result in two isolated transactions going at once, despite only having one transactional resource!

Fortunately, Seam’s transaction layer is very flexible and can adopt itself to Spring’s PlatformTransactionManager, among other options. Anytime Seam begins or commits a transaction, that call is actually delegated to the underlying transaction manager provider. By pointing Seam to Spring’s transaction manager, Seam is able to manipulate the transaction managed by Spring while Spring uses the persistence context managed by Seam. Quite a system!

To configure Seam to use Spring’s PlatformTransactionManager, add the configuration in Listing 15 to the Seam component descriptor (components.xml), where the #{transactionManager} expression must resolve to the appropriate Spring bean via the Spring EL resolver:

Listing 15. Configuring Seam to use Spring’s transaction manager

<spring:spring-transaction platform-transaction-manager="#{transactionManager}"/>

With Spring’s PlatformTransactionManager at the helm, you can effectively have Seam leverage any transaction implementation supported by Spring, including DataSource, resource-local (JPA/Hibernate), or JTA. That’s a double abstraction!

Spring and Seam: Greater than the sum of their parts

This series has set out to demonstrate that Seam and Spring are not mutually exclusive frameworks and that it is possible to take advantage of the strengths of each container. Spring is one of the most valuable libraries in the Java language. A commitment to Seam need not take Spring’s benefits away from you.

The first step to integrating Spring and Seam is to make the two containers one. Once they are starting in tandem, you are able to create Spring-Seam hybrid components that have knowledge of both containers and can thus boast a dual identity. You can then inject Spring beans into Seam components or vice-versa.

Although the two-way interchange of Spring beans and Seam components appears straightforward, you learned about the potential for scope impedance when injecting stateful components into application-scoped singletons, the danger it can cause, and how Seam alleviates the problem by injecting lookup proxies. Even with this safety net, integrating Seam and Spring forces you to think more about the scope of components, something that is new to those who have relied purely on Spring’s stateless behavior. While Spring 2.0 opened the door for custom scopes, Seam delivered the goods by allowing Spring beans to be scoped to Seam’s rich set of contexts.

The toughest integration challenge for any two containers is learning how to share resources. The most common resource shared in database-oriented applications is the persistence manager (the Hibernate Session or JPA EntityManager). Seam offers an entire package of built-in components to enable the sharing of these resources. Once the integration is complete, you are able to take advantage of extended persistence contexts managed by Seam while using the flexible template classes in the Spring arsenal.

The Spring framework is a tremendously useful tool in a Seam developer’s toolbox and vice versa. You may choose to integrate Spring beans in the runtime application or even just for the purpose of testing. Indeed, Spring is a great way to test Java EE components in isolation, because it can emulate the behavior of the container (i.e., @PersistenceContext injection). In a world rife with framework debates, it’s easy to forget that all of this software is available for you to use. You now have the ability to inject collaborator components across framework lines, exercising the combined capabilities of the two containers, and using the best tool for the job. Just watch out for that scope impedance and thread safety!

Dan Allen is an independent software consultant, author, and open source advocate. After graduating from Cornell University with a degree in Materials Science and Engineering in 2000, Dan became captivated by the world of free and open source software, which is how he got his start in software development. He soon discovered the combination of Linux and the Java EE platform to be the ideal blend on which to build his professional career. In his search for a robust Web framework, Dan happened upon JBoss Seam, which was quickly granted this most coveted spot in his development toolbox. Excited about Seam, Dan decided to share his thoughts with the world. He is now the author of Seam in Action, published by Manning Publications, a project which he picked up immediately after completing his three-part series on Seam for IBM developerWorks. Dan is also a committer on the Seam project, an active participant in the Seam community, and a Java blogger. You can keep up with Dan’s development experiences by subscribing to his blog at www.mojavelinux.com.