Spring Web Flow 2: A boon to JSF developers

JSF 2.0 features elevate SWF 2 to more than a page-flow engine

Spring Web Flow 2 supports JavaServer Faces technology through the new Spring Faces module. Spring Faces lets you use JSF as a view technology in Web applications, with the Spring MVC Web framework underneath. Not only does Spring Web Flow 2 address a few thorny JSF programming issues, but it also it gives you advanced features available only in the JSF 2.0 specification. JavaWorld contributor Xinyu Liu presents an overview of Spring Web Flow 2 and details its benefits for JSF developers.

JavaServer Faces, part of the Java EE 5 specification, is a component-oriented and event-driven Web development technology. The JSF developer community has made ample use of its pluggable architecture to enrich the technology by creating and integrating various pieces -- mostly rich UI components, or widgets -- into the JSF backbone. The Spring framework team, meanwhile, has taken an inverse approach. Spring Web Flow 2 makes the JSF UI component model fit into the Spring MVC framework, so that it can benefit from the Spring MVC infrastructure and Web flow navigation. Spring Web Flow 2 aims to make Web development in JSF and Spring MVC easier, with less coding, less coupling, more flexibility, and Ajax techniques that enhance the user experience.

Web page navigation in JSF is specified by default with the <navigation-rule> tag in a faces-config.xml file. In Struts-like fashion, the simple navigation rules map a logical view name to a JavaServer Pages (JSP) page's path. The logical view name is, in general, determined and returned by a JSF backing bean's action method. This approach decouples backing-bean classes from the physical paths to JSP pages, but it still spreads page-navigation logic across Java programs and XML configurations.

Spring Web Flow is fundamentally a workflow engine designed to manage page navigation outside of Java programs. The Spring Web Flow 2 release offers substantial enhancements over its predecessor, however. In particular, the newly introduced Spring Faces module improves Spring's support for JSF. This module allows you to use JSF as a view technology in Web applications on top of Spring MVC. Spring Web Flow 2 addresses some debatable programming issues in JSF, and it supports great features, including some that are available only in the JSF 2.0 (JSR 314) specification, such as:

  • A unified abstract JavaScript library (Spring-JS) for Ajax-enhanced user interfaces and rich validation behavior
  • Facelets integration
  • Support for the JSF Portlet Bridge
  • Both client-side and domain-model validation
  • Theme-controlled look and feel

Spring Web Flow 2 seems tailored exclusively for JSF developers, in that it makes programming with JSF even simpler and smoother than programming with the Spring MVC front end. Read on to learn about Spring Web Flow 2's features and the many compelling reasons to use it for JSF applications.

A workflow engine

Spring Web Flow is a workflow engine designed exclusively for Web page navigation. A Web flow consists of a set of states (view states or action states) and the transitions between the states. Like jPDL in JBoss jBPM, the XML-formatted flow definition language (FDL) in Spring Web Flow is a domain-specific language (DSL) that lets you express Web flows in a declarative or graph-oriented manner (with IDE support). At least theoretically, business people and developers can use the diagrams -- the visual Web flows -- to collaborate on application design. From the perspective of Unified Modeling Language (UML), the visual flows model activity diagrams effectively.

Workflow engines vs. BPM suites

Workflow engines differ from BPM, or business process management suites (see "What's the Difference Between Workflow and BPM?" in Resources). Spring Web Flow is a workflow engine designed exclusively for Web page navigation. JBoss jBPM, for example, is a full-fledged BPM suite that delivers workflow, Web flow (Seam page flow), BPM, and Web services orchestration (through Business Process Execution Language). Seam page flow with jPDL, a special flavor of jBPM, is conceptually and practically very close to Spring Web Flow 2. Both are designed to work with, but are not limited to, JSF technology. The main difference is that Seam is designed primarily to accommodate an EJB 3.0-based back end, while Spring Web Flow 2 aims to work inside the Spring framework. This difference makes it easy to choose between them.

Spring Web Flow aims to separate page-navigation concerns from graphical user interfaces (page templates) and view-independent business logic (Java programs). Flow hierarchy and inheritance make a Web flow defined in FDL reusable in different execution contexts. The concept of flow also introduces new object scopes into the regular Java Web application life cycle.

New scopes

Caching data objects inside a Java Web application is a common practice designed to avoid unnecessary, redundant data fetching from a back-end database and -- more important -- improve application performance. The Servlet specification offers two important object scopes: request and session. You must declare data objects displayed longer than a single request/response life cycle with the session scope, to avoid repeated database queries -- even if the data objects are referenced by only two adjacent requests. Consequently, a substantial volume of data objects stored in the session isn't garbage-collected until the session expires.

Obviously, this is an inefficient memory-management approach. As a workaround, developers using Apache MyFaces can put a custom <saveState value="#{dataObject}"/> tag on a JSP page to make that data object available just for the next request cycle. To some extent, the tag resembles the HTML <input type="hidden" value="data"> postback tag, but it stores Java objects on either the client or the server side depending on the JSF configuration.

Spring Web Flow introduces several new scopes beyond those in the Servlet and JSF specifications. The most interesting ones are view scope and flow scope. Declaring a variable (data object) in view scope is nearly equivalent to using the MyFaces <saveState> tag. Once a data object is loaded through a factory method, it remains available until the associated view state exits, no matter how many times the view (Web page) is refreshed, or a fragment of that page is reloaded (using Ajax). On the other hand, a Web flow by its nature represents a self-contained business process, in which most of the referenced data objects are no longer useful once the flow ends. Declaring variables in flow scope effectively dereferences them and makes them ready for garbage collection when the flow exits. From that perspective, flow scope is a better memory-utilization strategy than session scope, because a user might navigate multiple Web flows during a single Web session. With the help of flow scope, you can accomplish a Hibernate or Java Persistence API (JPA) long session.

Flow-managed persistence

A long session (called a conversation in JBoss Seam), in Hibernate semantics, is a type of persistence strategy. Under this strategy, you create a persistence context (Session in Hibernate, EntityManager in JPA) and reuse it for query purposes across a sequence of user requests, until all the data changes are committed to the database. This scenario is a natural fit with the Web flow concept.

A reminder

When you turn on flow-managed persistence, you should quit using Spring lazy loading filters (OpenSessionInViewFilter, OpenEntityManagerInViewFilter)<wbr>, which open and close a Hibernate Session (or JPA EntityManager) automatically upon receiving a request message and returning the response.

Flow-managed persistence in Spring Web Flow initiates a flow-scoped persistence context when the flow begins, and it flushes all the changes to the database when the flow ends (called deferred commit). You should use this approach in conjunction with an optimistic locking strategy, which you can turn on at the persistence domain-model level in Hibernate or JPA. Seam page flow persistence works essentially the same way. Setting up flow-managed persistence in Spring Web Flow is extremely easy, allowing you to concentrate on handling optimistic locking failure exceptions.

Less coding, zero JSF backing beans

Spring Web Flow's declarative or graph-oriented programming approach makes its underlying API agnostic in Web development. The default action binding in JSF binds a user action (form postback) to a backing bean's action method. In contrast, in Spring Web Flow a user action is bound to an action event, which makes the backing beans play virtually no role in page navigation.

An action event transitions one view state to another in a flow definition. During the transition, an <evaluate> tag processes the data posted back from a Web browser and prepares the data for the next view to render. Depending on the execution context, the same tag can function just as a factory method to load data for a new view to display. With Unified Expression Language (EL) or Object-Graph Navigation Language (OGNL) syntax, you can invoke a Spring bean's method in the <evaluate> tag, and the returned data object (most of the time, persistence domain data) is attached to a specific scope. Note that the POJO (plain old Java object) Spring bean is autowired (injected). Data such as a collection or an array can be configured as wrapped JSF DataModel objects to facilitate the display of HTML tabular data.

This new action-binding approach takes JSF backing beans completely out of the picture. It is consistent with the new Web Beans (JSR 299) concept proposed by the Seam technology developers. In a multilayered architecture, Web-tier Java programming becomes virtually unnecessary. (There are exceptions: you need to write helper classes to support non-POJO JSF data models such as SelectItem, or transient data objects used only for display purposes.)

As a bonus, enforcement of the Factory Method design pattern with the <evaluate> tag eliminates one of the pitfalls of JSF. A common mistake for JSF beginners is to put data-access code inside a backing bean's property getter methods. Under the hood, the JSF runtime invokes the property getter methods many times during a single request/response life cycle. As a result, the database is queried repeatedly during a single operation, which causes unbearably slow performance.

Validation

JSF offers UI component-level validators for validating individual form fields on the server side. Several JavaScript libraries providing client-side validation capabilities are also available. UI component (form field) validation is found to be segregated, superficial, and insufficient for many Web applications for which validation is a core business concern spanning multiple layers. A new perspective on validation -- domain model constraints -- addresses complex validation requirements. A rich domain model in domain-oriented programming captures business data constraints as part of the application's functional requirements and automatically enforces them with the help of certain Web technologies (such as Seam) on form postback. Sometimes, the same domain model is subject to different validation rules when used on different Web screens; this is described as contextual validation.

Spring Web Flow 2 handles all the validation scenarios I just described. It delivers JavaScript client-side validation through the Spring-JS module in conjunction with a set of Spring Faces tags. Contextual validation methods defined inside a rich domain model should be invoked from the <evaluate> tag within a flow definition. Even better, a validator bean named ${model}Validator can be created to pair up with a domain model Spring bean ${model}. Inside the validator bean, contextual validation methods follow the naming convention of $validate{state}, where state is the ID of a view-state (roughly a Web screen) declared in a flow definition. Spring Web Flow automatically detects, registers, and invokes such a validator on form postback.

In a future release, Spring Web Flow is expected to support declarative validation through XML and annotations, similar to Hibernate Validator (JSR 303: Bean Validation). (I'd like to see the Spring Web Flow team leverage the Bean Validation Framework developed as part of the SpringModules project hosted on Java.net; see Resources.)

JavaScript and Ajax

The Spring-JS module is a lightweight abstraction API that can be implemented through any of the popular JavaScript toolkits, such as Dojo or jQuery. From a Web designer's standpoint, the Spring-JS module progressively enhances a Web page so that the page is still functional in a less capable Web browser. The module also offers basic Ajax functions that Spring Faces leverages in the form of custom JSF UICommand components, which are capable of firing Ajax requests (degenerating to regular HTTP requests when JavaScript is disabled). Inside a flow definition, an Ajax event is processed as an in-page action event: it reloads the same page. An extra <render fragments="clientId"/> tag specifies the clientIds of the JSF UI components to be repainted to avoid a full page refresh. In addition to the built-in Ajax functions, Spring Web Flow 2 supports third-party JSF component libraries such as JBoss RichFaces (formerly Ajax4JSF) and Apache MyFaces Trinidad to enhance the user experience with Ajax-enabled widgets and Scalable Vector Graphics (SVG) images.

Portlet support

The JSF API is designed to support access to both the Servlet and Portlet (JSR 168) APIs by exposing an abstract class called ExternalContext. The JSF Portlet Bridge (JSR 301) is an integration library that allows JSF Web applications to run as portlets within a portlet container. Spring Web Flow includes full support for JSR 168 portlets -- in particular, JSF-enabled portlets. As long as you don't touch the underlying Servlet and Portlet APIs in your Java classes, the POJO programming style in Spring and Spring Web Flow effectively makes your JSF applications neutral to the servlet and portlet environments. The adjustments necessary to translate a JSF Web application into a portlet are solely configuration based.

Security integration

Spring Security (formerly Acegi Security) is definitely a good reason to use Spring for Web applications. (My article "From Java EE Security to Acegi" explores Spring Security's comprehensive and powerful features in detail.)

Portlet security

A portal application usually provides gateway protection to the hosted portlets. User identities (principals) are passed from the portal application to the portlets. The standard approach to portlet security is to map roles defined in a portal application to the roles of the hosted portlets. An advanced Spring approach is to have Spring Security take care of the portlet role mapping, which can be decoupled from the portal roles. The Spring approach gives you the full power of Spring Security. See "Securing Portlets with Spring Security" in Resources for more information.

You can employ Spring Security in different application layers with different granularities, including:

  • At form field (UI component) level, through custom JSP (JSF) tags
  • At URL pattern level, through XML configured aspect-oriented programming (AOP) interceptors
  • At source code level, either programmatically or through JSR-250 common annotations

From the standpoint of Spring Web Flow, individual flow, state, and transition can be declared as protected by roles. If you think of security configured in different application layers as laid out vertically, then Web flow security is conceptually horizontal.

In conclusion

Spring Web Flow 2, with its impressive JSF support, is a workflow engine designed specifically for Web page navigation. Its flow definition language enables you to separate the concerns of page navigation from Web user interfaces and view-independent business logic -- which also makes JSF backing beans completely unnecessary. New enhancements related to Ajax, validation, persistence, and security facilitate the development of rich Web applications. As a new Web development approach, the technology helps JSF developers with an enhanced degree of flexibility and productivity. The Spring Web Flow 2 release available for download (see Resources below) is packed with JSF and portlet sample applications that can help you get a jumpstart on the technology.

Dr. Xinyu Liu is a Sun Microsystems certified enterprise architect working in a healthcare corporation and an IT consulting firm.

Learn more about this topic

More

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more