Add stateful behavior to your Spring beans An excerpt from Seam in ActionBy Dan AllenPublished by Manning PublicationsISBN: 1933988401 If you’re using multiple development frameworks in a single application, you’ll want them to complement each other. For instance, it’s hard to add stateful behavior to Spring beans — but not when you put JBoss Seam to the task.Too many developers think of a development framework choice as some kind of irrevocable decision. If you choose a framework for its strengths, this thinking goes, you’re stuck with its weaknesses, too. But in many cases, you can use multiple frameworks in the same applications to allow their strengths to complement each other.In the first article in this series (“Spring into Seam, Part 1: Build a Seam-Spring hybrid component“), you saw some of the details of how two popular Java development frameworks — Spring and JBoss Seam — can work together. You learned how to build a Spring-Seam hybrid component that serves as a citizen of both frameworks. In this article, you’ll see how these components can bring the strengths of one framework to the other. Specifically, you’ll see how Seam can add stateful behavior to Spring beans — something that is still a challenge to accomplish with Spring alone. Spring, meet stateIf there’s one thing you noticed in the first article in this series, it’s that creating Spring-Seam hybrid components meant typing <seam:component> an awful lot. That’s kind of a downer; after all, the goal of Seam is to reduce typing, and this tag is just adding to the pile of XML mess in Spring. Fortunately, there is an easier way to achieve the same end that leverages another highly anticipated feature of Spring 2.0: custom scopes. Custom scopes expand the choices for where instances of Spring beans can be stored.While Spring added the mechanism to support custom scopes, the built-in implementations are stuck in the past, only covering the scopes in the Servlet API (request, session, and application), plus a stateless scope named prototype. These scopes are ill-suited for modern business applications. To bring Spring up with the times, Seam registers a custom scope handler that allows Spring beans to be stored in Seam contexts. Uses include the (temporary) conversation scope for implementing the redirect-after-post pattern (sometimes called a flash); the (long-running) conversation scope for single-user page flows; and the business process scope to support interactions from multiple users over an extended period of time. At last, Spring beans can be stateful without having to resort to the crutch of the HTTP session!As it turns out, specifying a Seam scope on a Spring bean has the same effect as applying a nested <seam:component> tag to the bean definition in that it results in a Spring-Seam hybrid component. A two-for-one deal! To take advantage of this feature, you first need to register the Seam scope handler in any one of the Spring configuration files (but not more than once) using the tag in Listing 1. That configuration file must also declare the Seam namespace on the root element, which was explained in the first article in this series. Listing 1. Registering a Seam scope handler in Spring<seam:configure-scopes/> To assign a Seam scope to a Spring bean, thus creating a Spring-Seam hybrid component, you simply set the scope attribute on a Spring <bean> definition — or any custom namespace element in the Spring configuration that supports the scope attribute — to one of the Seam scopes. The name of the scope is not case-sensitive.To distinguish Seam scopes from scopes provided by other frameworks, the scope name is prefixed with a namespace, which, by default, is seam. Putting that together, you create a conversation-scoped component by using the value seam.CONVERSATION in the scope attribute. You can customize the namespace prefix that is used by supplying an override to the prefix attribute of the <seam:configure-scopes> declaration, as shown in Listing 2.Listing 2. Overriding the default scope namespace<seam:configure-scopes prefix="org.jboss.seam.ScopeType"/> In this case, the value of the scope attribute would become org.jboss.seam.ScopeType.CONVERSATION, which happens to be the fully qualified name of the enum constant for the conversation scope. In the first part of this series, you were introduced to a golf tournament tracker application, which is used to manage a database of golf tournaments that is made available to partners through a Web service. The read and write operations for the Tournament entity are handled by the tournamentManager bean, a classic singleton Spring bean. It’s not very interesting in our pursuit of state. However, one of the beauties of tying Spring and Seam together is that stateless Spring beans, such as tournamentManager, can be infused with state through the use of other stateful beans. To see how this is done, let’s start by creating a search criteria bean that is stored in Seam’s conversation scope. The definition of this bean is shown in Listing 3. For now, we’re sticking with the default namespace prefix for the scope name.Listing 3. Definition of a stateful Spring bean<bean id="tournamentSearchCriteria" class="org.open18.partner.business.TournamentSearchCriteria" scope="seam.CONVERSATION"/> When working within the context of a long-running conversation in Seam, the tournamentSearchCriteria bean is instantiated once, the first time it is used, and remains available for the duration of the conversation. Keeping this bean in scope is important so that the search criteria entered by the user is not lost between requests. There are several ways to start a long-running conversation in Seam. Since tournamentManager is already a Seam-Spring hybrid component, the easiest way might be to add Seam’s @Begin(join = true) annotation to the search method.When declaring Spring-Seam hybrids using the scope attribute, you do lose some flexibility over the configuration of the component. While setting the scope is in, what is out is the ability to set the auto-create flag, provide an explicit class, supply a custom context variable name, and disable Seam interceptors. Fortunately, there are other ways to configure some of these settings, which you’ll see in a moment. But remember that the idea here is to use the <bean> tag without any additional interference, aside from the value of the scope attribute. This approach is just a shorthand for the more formal <seam:component> declaration, which gives you the extra power if you need it, including the ability to specify the Seam scope. The auto-create flag is set to false by default for components configured using the scope attribute. However, this setting can be controlled globally using the default-auto-create attribute on the <seam:configure-scopes> tag, as shown in Listing 4. For the duration of the article, I will assume the use of this setting so that Spring initializes the bean for Seam when it is requested.Listing 4. Setting the auto-create flag globally<seam:configure-scopes default-auto-create="true"/> Listing 5 illustrates the only way to disable intercept for components configured using the scope attribute: by adding Seam’s @BypassInterceptors annotation on the class.Listing 5. Disabling interceptors on a Spring-Seam hybrid component@BypassInterceptors public class TournamentManagerImpl implements TournamentManager { ... } Now that you have your Seam-scope Spring bean defined, you are going to want to start using it in other beans. Finding the right balance with injectionSeam-scoped Spring beans can be injected into other Spring beans using the familiar <ref bean="beanId"> (or equivalent) syntax. In this case, Spring is transparently reaching into the Seam container to grab the instance of the bean out of a Seam scope. The transparency is achieved through the custom scoping mechanism, which is Spring’s version of a variable resolver. This scenario is the opposite of what you learned about in the first article, where Seam was transparently pulling beans from the Spring container. The difference is just a matter of which container the instance is stored in, as dictated by the scope defined on the Spring bean definition. Otherwise, a Spring-Seam hybrid can mask itself as a native component in either container. That means you can also inject any Seam component (including another Spring-Seam hybrid component) into a property of a Spring-Seam hybrid component using the @In annotation.That brings us to an important point about injection that I would like to draw your attention to. While a Spring-Seam hybrid can leverage the injection mechanism from either container, you can quickly get into trouble if you don’t understand how and when the injections are applied in each case. For instance, let’s assume you are injecting the search criteria into the tournamentManager bean. You might decide to use a bean reference when initializing the property in the bean definition, as in Listing 6.Listing 6. Injecting a Seam-scoped bean using a bean reference<bean id="tournamentManager" class="org.open18.partner.business.impl.TournamentManagerImpl" scope="seam.APPLICATION"> <property name="tournamentSearchCriteria" ref="tournamentSearchCriteria"/> </bean> You could also accomplish the injection by using the @In annotation, as in Listing 7. Listing 7. Injecting a Seam-scoped bean using injectionpublic class TournamentManagerImpl implements TournamentManager { @In private TournamentSearchCriteria tournamentSearchCriteria; ... } The manner in which these injections are applied by the two containers is very different. And neither one is appropriate for injecting stateful components into an application-scoped singleton! Spring injects dependencies once at creation time, whereas Seam performs injection dynamically, before every method invocation. This difference in design philosophy can fall heavily on your shoulders as a developer, leading to a paradox known as scope impedance. If you declare your injections carelessly, it can cause serious problems. In the next section, you’ll learn how to work around this potential pitfall.Injection and scope impedanceScope impedance is the situation where a bean outlives its intended lifetime as a result of attaching itself to a longer-lived component. Having the Seam scopes at hand when authoring your Spring configuration, you may be tempted to define a bean in a narrow scope and inject it into a Spring singleton, which is scoped to the lifetime of the container (the application context), using <ref bean="beanId">. Without any other provisions, this leads to scope impedance. Let’s explore this problem.For the purpose of this next example scenario, we will assume the use of two beans. The wider-scoped bean is an application-scoped singleton, such as a service layer object (e.g., tournamentManager). The narrow-scoped bean is stored in the request scope (e.g., selectedTournament). The request-scoped bean is a dependency of the singleton. When the singleton is instantiated, the request-scoped bean, populated by the incoming request, is injected into one of the singleton’s properties. However, once the request ends, the singleton will still hold a reference to the request-scoped bean. Now the request-scope bean has outlived its designed lifetime. Not only that, it is being shared amongst all users of the application because it is attached directly to an application-scoped singleton! So why isn’t Seam managing the request-scoped component so that it is cleaned up after the request ends as it normally would be? The reason this happens is because the requested-scope bean instance is assigned directly to a property of the singleton. When the request scope ends, Seam merely removes bean instances from the request context. The property values of the singleton objects are not affected. Since the singleton is maintaining a reference to the request-scoped bean instance, the object is never garbage collected. On the next request, the singleton retains its reference to the stale instance. As a result, the singleton may make inappropriate decisions based on the state of the stale instance, which is especially problematic if the next request does not come from the same user! This situation not only causes unexpected behavior, but can also compromise security.If you know how bijection works, you may decide to make the switch to using the @In annotation on the properties of the class rather than using a <ref> element in the bean definition (if you don’t mind using Seam annotations in your Spring beans). The @In annotation injects dependencies before every method call and clears them when the call is complete. That definitely gets you out of the scope impedance predicament. However, injecting stateful components using bijection is only safe for synchronized components.Seam serializes access to session and conversation-scoped components automatically, and request-scoped components are naturally thread-safe, since they only service the incoming request thread. However, Seam does not serialize access to application-scoped components, because that would cause an incredible bottleneck in the application. Thus, using @In on application-scoped Spring-Seam hybrid components (or regular Seam components, for that matter) is only appropriate for injecting other application-scoped components. Otherwise, you are going to once again be allowing multiple requests to access the same injected references simultaneously. I may have scared you by mentioning the potential to create a security hole, especially since it can be such an easy trap to fall into. Fortunately, Seam offers an elegant safety net to help you avoid both scope impedance and thread-safety problems. Instead of injecting a bean instance directly using a <ref> element, you inject a proxy using the <seam:instance> tag, as in Listing 8.Listing 8. Injecting a component proxy<bean id="tournamentManager" class="org.open18.partner.business.impl.TournamentManagerImpl" scope="seam.APPLICATION"> <property name="tournament"> <seam:instance name="selectedTournament" proxy="true"/> </property> <property name="tournamentSearchCriteria"> <seam:instance name="tournamentSearchCriteria" proxy="true"/> </property> <property name="currentUser"> <seam:instance name="currentUser" proxy="true" scope="SESSION"/> </property> </bean> Seam’s versus Spring’s If you are familiar with Seam 2.0 custom scopes, you may recognize that the <seam:instance> tag serves the same purpose as the <aop:scoped-proxy> tag. The <aop:scoped-proxy> was also developed to counteract scope impedance for Spring’s native scopes. However, this built-in Spring tag is not compatible with Spring-Seam hybrid components. When a hybrid component is being injected, you must use <seam:instance> in place of <aop:scoped-proxy> to elicit this behavior. Each time the proxy is referenced, it consults the Seam container to ensure it has the proper component instance, and not a stale one from a previous request or from another simultaneous request. Even though the properties on the wider-scoped components still remain unaffected when narrower scopes end, the narrow-scoped instance can now be garbage collected, because the wider-scoped component does not hold a direct reference to it. The proxy acts as a weak reference, which is perfect for avoiding scope impedance. In this way, you are effectively infusing state into stateless objects.Remember, if you don’t want to worry at all about this proxy business, you can simply use bijection annotations, as long as the target bean is also a stateful component. The scope impedance arises when using Spring’s static dependency injection to wire components in different scopes. Thread safety is violated when you inject stateful components into singletons without using a proxy. Now that we are on the topic of the <seam:instance> tag, you will be interested to know that it can also be used to inject native Seam components into Spring beans. Let’s look at how Spring can benefit from already existing Seam components.Donating Seam components to the Spring containerAll we have done so far is take, take, take. It’s time to start giving back to Spring. After all, if Spring components are useful to Seam, then the opposite is likely true as well. The <seam:instance> tag works for any Seam component, not just Spring-Seam hybrids. But here is the real kicker. The <seam:instance> tag can also be used to inject the result of an expression language (EL) value expression into the property of a Spring bean! That makes the possibilities of what Seam can contribute to Spring beans virtually limitless.You can think of the <seam:instance> tag as an alternative to the @In annotation from bijection, particularly when the proxy attribute is set to true. The name attribute can either be a context variable name or a value expression. The scope attribute narrows the search for the context variable to a single scope. If the scope attribute is excluded, then a hierarchical context search will be performed. (Note that in this case, the scope is being interpreted by Seam to perform a lookup, so we don’t use the scope prefix discussed earlier). If the create attribute is specified, and its value is true, a new instance of the component will be created if one does not exist. If this value is not used, or if it is false, a new instance will not be allocated if a value hasn’t already been assigned to the context variable. Recall that value expressions imply that the create flag is true, regardless. The proxy attribute is the key to preventing scope impedance, but do keep in mind that it adds an extra bit of overhead. Setting up a <seam:instance> declaration for a component may not seem so bad if you have to do it once, but having to retype the declaration each time you want to inject a given Seam component can be a drag, not to mention error-prone and non-transparent. That is why the <seam:instance> tag was designed to double as an alias tag. When used as a top-level element, the id attribute of <seam:instance> can be used to create an mediator bean. To the Spring container, this bean is just like any other Spring bean. Under the covers, the <seam:instance> element results in the creation of a SeamFactoryBean, which works just like any other Spring factory bean in that the underlying target object is resolved when the factory bean is injected. In this case, what is injected is a Seam component proxy. Listing 9 gives examples of how all of the references used in this article can be converted into aliases and injected into the application-scoped tournamentManager singleton bean without fearing scope impedance or thread-safety problems.Listing 9. Defining and using aliases for component proxies<bean id="tournamentSearchCriteriaTarget" class="org.open18.partner.business.TournamentSearchCriteria" scope="seam.CONVERSATION"/> <seam:instance id="tournamentSearchCriteria" name="tournamentSearchCriteriaTarget" proxy="true"/> <seam:instance id="currentUser" name="#{currentUser}" proxy="true"/> <seam:instance id="selectedTournament" name="selectedTournament" proxy="true"/> <bean id="tournamentManager" class="org.open18.partner.business.impl.TournamentManagerImpl" scope="seam.APPLICATION"> <property name="tournamentSearchCriteria" ref="tournamentSearchCriteria"/> <property name="selectedTournament" ref="selectedTournament"/> <property name="currentUser" ref="currentUser"/> </bean> By setting up an alias, you are free to inject the component into the properties of other Spring beans using the <ref> tag, which is blissfully unaware that it is actually injecting a Seam component, possibly even one that is proxied. This usage pattern, in my opinion, is the best way to prevent errors and steer clear of scope impedance. I would even recommend creating a separate Spring configuration file to hold these alias definitions. Doing so will make it easy to perform functional tests on the Spring POJOs in the absence of the Spring container, since the main file will not have <seam:instance> references scattered all over the place. You can easily swap implementations of the referenced beans. It’s sort of like a POXD (plain old XML document).Stateful singletonsAs an alternative to injecting a component proxy into the property of a Spring singleton, you can look up the Seam component from the Seam container and assign the result to a local variable. To avoid direct interaction with the Seam container, you add a static lookup method to the component class that reaches into the Seam container and grabs the component instance by name. Listing 10 shows the declaration of the static lookup method and an example of its use in the tournamentManager bean. Listing 10. Looking up a Seam component using a stateful singletonpublic class TournamentSearchCriteria { ... public static TournamentSearchCriteria instance() { return (TournamentSearchCriteria) Component.getInstance("tournamentSearchCriteria"); } } public class TournamentManagerImpl implements TournamentManager { ... public List<Tournament> findTournaments() { TournamentSearchCriteria criteria = TournamentSearchCriteria.instance(); ... } } The technique used here is known as a stateful singleton. Rather than the singleton being instantiated once and shared across the entire application, it is instantiated once and bound to the stateful scope. That means there is one instance in that particular scope, but there may be many instances across the whole application. For instance, if the stateful component is session-scoped, then there can be one instance per user session. The stateful singleton allows you to avoid the multi-threaded issues discussed earlier. In addition, since the result is assigned to a local variable, there is no chance of scope impedance. The only downside is that the static instance method relies on the Seam container being available, which can make testing more challenging. However, you can design the lookup so that it has a fallback in a test environment.Learning to shareAt this point in the series, you should have a good sense of how to inject Seam components into the Spring container and how to avoid scope impedance and thread-safety problems when mixing singletons and stateful components. The Seam component that is most frequently donated in this way is the Seam-managed persistence context. In such a case, Seam offers a tighter integration than what is possible with the <seam:instance> tag. In the third and final part of this series, you’ll see how to allow Spring to benefit from Seam’s automatic persistence context management and how it can dually benefit your development process.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. Open SourceSoftware DevelopmentWeb DevelopmentJava