JSR-314: JavaServer Faces (JSF) 2.0 is the third major revision of the JSF specification. It delivers a strong evolution of the framework driven by de facto standards that emerged from both the JSF community and participating vendor's products. Red Hat played a major role in promoting the JSF enhancements from Seam and RichFaces into JSR-314 and also worked with the Expert Group (EG) to refine additional features that were being incorporated. This series focuses on the features that Red Hat contributed or participated in extensively and provides example scenarios suggesting how these features might be used.
Author's Note: Many thanks to Pete Muir, who played a pivotal role as technical editor of this series.
Read the other parts in this article series:
Part 1 - JSF 2: Seam's Other Avenue to Standardization
Part 2 - JSF 2 GETs Bookmarkable URLs
Part 3 - Fluent Navigation in JSF 2
Part 4 - Ajax and JSF, Joined At Last
Part 5 - Introducing JSF 2 Client Behaviors
You've likely heard that Seam is being standardized through the Java
Community Process (JCP) as JSR-299: Contexts and Dependency Injection
for Java EE (CDI). However, that's not the whole story. The
generalization fails to credit Seam's pioneering enhancements to
JavaServer Faces (JSF). An important part of Seam's passage into
standardization is the collection of Red Hat-sponsored contributions to
JSR-314 that emerged from Seam, and also from Ajax4JSF (now rolled into
RichFaces), which are covered in this series.
The goals Red Hat and Exadel had for enhancing JSF tie nicely with CDI, no surprise given that both contributions originated from Seam. The overarching goal has always been to reduce the amount of glue code needed, or eliminate it altogether if possible. In JSF, you shouldn't need to write a layer of "view Java code". Instead, the declarative view layer should be able to interact directly with your transactional tier. Any obstacle obstructing this realization was identified and removed. Building on the goal to eliminate unnecessary code, Red Hat ensured that JSF could leverage the centralized Bean Validation constraints that reside on the model without any special configuration. And with the view layer and transactional layer working so closely in tandem, it made sense to focus on bringing them in more direct and frequent communication using Ajax. Finally, Red Hat listened to the community's cry for bookmarkability in JSF and delivered on it.
It's important to point out, however, that not all the improvements to JSF originate from Seam and RichFaces. The JSR-314 proposal specifically acknowledges that there are a lot of great ideas which extend from the JSF specification. From the outset, the stated goal of JSR-314 has been to harvest those ideas and align them with the Java EE platform as standards, primarily to ensure compatibility.
JSF gets practicalThe pragmatic approach of standardizing accepted enhancements is what makes JSF 2 successful. Rather than being yet another thought experiment produced in a think tank, the improvements to JSF 2 emerge from a broad pool of proven and accepted frameworks, and were further refined by the same people that coined them. Projects and their contributors include include Seam (Red Hat), ADF Faces (Oracle), Trinidad (Oracle/Apache), Ajax4JSF/RichFaces (Exadel/Red Hat), ICEFaces (ICESoft) and others. That means that instead of you having to learn something entirely new, you'll easily recognize the new features and how they've evolved from their origin. That translates into a gentler migration path.
To cite an quick example, if you have been using the Facelets view language with JSF 1.x, then you'll be happy to know that Facelets is now a standard part of JSF 2, albeit reasonably evolved. You won't have to change more than a couple of characters to take advantage of JSF 2 in this regard. Although not covered in this series, this is just one of many welcomed additions you'll discover in the new JSF specification.
Fortifying JSFBeing a web UI framework, JSF naturally covers a lot of ground, from UI component infrastructure and a standard component set to form processing and navigation. Red Hat focused on solving the major pain points in JSF, which were naturally those areas that were the cause of criticism in the past. Most of these problems are already solved in Seam, but to put things in perspective, there's only so far you can go with the decorations to hide a foundation in disrepair. The problems needed to be fixed at the source.
Let's take a quick look at the features Red Hat contributed to JSF 2 that you'll visit in this series. The features will be covered in this order:
- View parameters and bookmarkable links
- Navigation improvements
- Ajax and component behaviors
- Bean Validation integration
- Exception handling
- "Pet peeve" fixes and a look ahead
We'll start with solution to the most common complaint, that "every request in JSF is a POST."
Not all requests that are interesting happen via POSTIn JSF, a faces request, which happens when a form is submitted using the HTTP POST method, is where all the action happens. The processing of a non-faces request, which occurs when a page is initially requested via HTTP GET, is far less interesting in comparison. Since HTTP GET requests are quite common, especially in web sites that use many hyperlinks between pages, JSF appears deficient. It's deficient because it fails to satisfy the "action-oriented" web scenario. What is needed is a "beefing up" of the non-faces request.
JSF 2 alleviates this problem by introducing view parameters, an evolution of Seam's page parameters. A view parameter is a mapping between a query string parameter and a model value. The collection of view parameters are stored in the view metadata facet, also introduced in JSF 2. The query string values are converted, validated and mapped to properties on the model during the Restore View phase (on both faces and non-faces requests), paralleling the life cycle that processes form input values on faces-requests.
View parameters accommodate "bookmarkable" URLs specifically because they are processed at the start of a non-faces request. They also aid in producing bookmarkable links. That's because view parameters are a two way mapping. Much like form values are displayed in input fields when a form is rendered, view parameters can be written into the query string of output URLs.
Since JSF didn't have a UI component to create a link from one view to another, two new standard UI components were introduced for this purpose in JSF 2, <h:link> and <h:button>. These components render bookmarkable links with view parameter values optionally encoded into the query string. View parameters can also be included in navigation rules that use a redirect, another form of an output URL.
One behavior that is still missing on a non-faces request is an action invocation that follows the model updates from view parameters. However, it's easy enough to emulate this feature using the PreRenderViewEvent that is raised before a view is rendered by the new system event infrastructure in JSF 2.
In JSF, action invocations are typically followed by navigation. Thankfully, navigation has become less of a hassle, and more savvy, in JSF 2.
Hassle free navigation, under one condition
When prototyping a user interaction in JSF that is followed by
navigation to another page, it's always a pain to have to go through
that extra step of mapping an action signature and logical outcome to a
target view ID in the faces-config.xml descriptor. Seam let's you
return the view ID from the action method as a shortcut. JSF 2 formally
defines this shortcut as implicit navigation.
The specification goes a step further by allowing you to drop the file extension from the view ID and have the navigation handler assume that the return value is the root of a view ID in the case no navigation rules can be matched. At last, the extra level of indirection is gone, if you decide you don't need it. You can lean on implicit navigation wherever a logical outcome is used by the framework (e.g., in the action attribute of <h:commandButton>).
Navigation rules aren't all bad, though. As you advance beyond the prototype stage, you'll likely want to rely on the navigation rules to direct the user to different pages based on the outcome of the event. Unfortunately, the JSF navigation rules are already decided in advance based the signature of the action method and the "logical" string outcome of the action (i.e., business) method. That means the navigation system requires that you pollute your business method's conditional logic used to select a string outcome as a return value in order to control navigation. It would be more "logical", and provide a cleaner separation of layers, if the navigation rule could pull state from the model to decide which navigation rule to choose, effectively introducing a declarative condition.
JSF 2 delivers on this design best practice by introducing a conditional expression that controls whether a rule is selected. The conditional expression is defined using value expression syntax. This allows you to decouple your business logic from your navigation system and, thus, further remove the glue code needed if you want to write a cleanly separated system.
As part of improving the navigation handler, the set of navigation rules was exposed through a public API. One way they are used is to support the bookmarkable links introduced above. When a bookmarkable link is rendered, the navigation rules can be evaluated in advance to determine which page to link to. By providing access to the navigation rules, third party libraries have greater insight and control into the navigation system, paving the way for future extensions. A future goal for navigation is define a fluent API for being able to define navigation rules to make navigation rules far less cumbersome to author.
Navigation is so Web 1.0 though, right? If it were possible to use Ajax, all this navigating wouldn't really be necessary. JSF 2 has just what you are looking for.