JSF 2 - Seam's Other Avenue to Standardization
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.
Ajax for JSF now part of JSFAjax is nothing new. So it's about time we start calling it a standard (even if the W3C hasn't gotten around to it), right? Well, the foundation is finally in place. Ajax is now part of JSF!
But weaving Ajax into JSF is about more than just adopting a fad. The stateful UI component tree in JSF is an ideal candidate for communicating partial page updates to the client via Ajax. In JSF, the server maintains a representation of the view at all times. When a user interface event occurs, the server simply processes the relevant sections of the tree and pushes any changes in the tree's structure back to the browser. An Ajax bridge can then stitch the changes, in the form of HTML fragments, into the live view. A match made in Web 2.0 heaven.
Now, regardless of which Ajax feature a third party component library introduces, it should attach to this bridge to ensure compatibility and reduce disparate chatter with the server. RichFaces 4 will be designed around this API, for example. This Ajax bridge can be leveraged either by the components themselves or directly by the page author. For example, the Ajax functionality in RichFaces extends from the standard API. Jim Driscoll demonstrates in his blog how to bridge to the Open Ajax Alliance API.
To reiterate an earlier point, the defacto standards were blended together to form the Ajax support rather than the EG inventing yet another solution. For example, the familiar approach from Ajax4JSF of adding Ajax behavior to existing components evolved into the behaviors framework. The first standard implementation, <f:ajax>, is an adaptation of the <a4j:support> tag.
Validation is back in the right handsJSF has always had a comprehensive validation mechanism. However, when you look at the big picture, it's clear that the UI is the wrong place to define validations. That's because likely you are going to end up validating again in the business layer and perhaps a third time in the data access layer. Thus, the best solution is to centralize the validation constraints and have each layer enforce, rather than define, these constraints. The purpose of JSR-303: Bean Validation is to define a meta-data model and API for JavaBean validation. The meta-data model is declared using Java 5 annotations, with an option to describe them in XML as an alternative.
That leaves it up to JSF to enforce the Bean Validation constraints in the UI. JSF 2 integrates with Bean Validation using a built-in JSF validator. The validator enforces field-level constraints defined on the model properties that are bound to UIInput components. Consistent with the behavior of other JSF validators, this check occurs before the value is applied to the model.
The best part is, if Bean Validation is present, the validation takes place automatically, with no requirement to include special markup in the UI. Not only does the page author not have to worry about validation tags, there is no chance the constraints can get out of sync since they are read from the model. But that doesn't mean that the user will have to wait to see the violations. If Ajax is enabled for an input or a region of the page, the constraints will be enforced in almost real time.
Introducing the validator alone left a gap, though. In the past, JSF would not validate null or empty fields, making it impossible for Bean Validation to enforce these constraints. When Bean Validation is present, JSF defers the decision to validate a field in this state to Bean Validation.
Of course, developers may not always want the constraints to be enforced. Therefore, the integration allows the page author to disable the Bean Validation on a field or page region. Instead of disabling validation outright, the page author can alternatively choose which constraints are enforced by activating select validation groups for those regions.
Future goals of the Bean Validation integration are to offer true client-side validation that enforces the validation constraints defined on the model and to have a facility to accommodate multi-field validation--it's trickier than it appears at first.
When things go wrong, it's not always the user who is to blame. When a runtime exception occurs, it's important that JSF handle it appropriately. As many JSF developers have discovered in the early morning hours, sometimes when an exception occurs, you'd never know it.
Queue exceptions, don't swallow themIn JSF 1.2 and earlier, exceptions were frequently either swallowed or wrapped to the point where it was difficult to make out the root cause of the problem. JSF 2 introduces an ExceptionHandler, which is the central point for handling unexpected exceptions that are thrown during the JSF life cycle. The specification explicitly states that unexpected exceptions must not be swallowed, but rather queued and allowed to bubble up to the ExceptionHandler.
The default ExceptionHandler that must be provided by any JSF 2 implementation unwraps the root exception, rewraps it in a ServletException and throws it. This allows a developer to use the <error-page> directive in the web.xml descriptor to declaratively handle unexpected exceptions. Even before that point, the application has the opportunity to react to an unexpected exception by implementing an listener that observes the ExceptionQueuedEvent that is fired by the new system event infrastructure at the point the exception is trapped.
If the default behavior does not meet the application's requirements, then it's possible to provide a replacement ExceptionHandler. For instance, a substitute exception handler can be installed to handle a specific exception, as described in this article by Ed Burns, or delegate the the default resolver for all other exceptions. Another possibility is that a third-party framework can provide a generic exception handler that provides an alternative means of declaratively capturing and handling exceptions. A future goal for the exception handling intrastructure is to introduce a powerful, declarative configuration syntax for defining exception handling rules.
In addition to circumventing swallowed exceptions, Red Hat lobbied to eliminate many other "pet peeves" that remained in JSF 1.2.
Pet peeve raidThe biggest complaint about JSF is that it has a lot of little annoyances that tend to build up and lead to developer rage. Red Hat swept away as many of these as possible, and has plans on doing another cleaning the next revision of JSF. Here's a couple of the minor fixes that have been addressed so far:
- <f:selectItems> component capable of building a collection of SelectItems from any collection of objects
- Support for a "no selection option" in UISelectOne components
- varStatus attribute on <ui:repeat> (but not yet on all UIData components)
- Allow alteration of naming container separator character
All of the aforementioned improvements, whether big or small, can be traced back to community feedback. Regardless of how elegant the framework appears on paper, it must work in the enterprise and therefore it's the community feedback that will ultimately ensure JSF remains a successful and useful UI framework.
OpennessPutting technical concerns aside, one of the most notable advancements in JSF is the design process itself. Red Hat, Oracle, Sun, Apache and other key independent members of the JSF EG have continued to lobby to open up participation in the specification. Consequently, with each quarter that goes by, the JSR-314 specification takes another step towards openness. The goal is to get the community involved, give them a voice, and break away from the "closed door" practices that have driven the JCP and the Java EE community apart in the past.
Previous iterations of the JSF specification have lead the way by using an open issue tracker. JSR-314 took another step towards openness by introducing an open mailinglist viewable to any registered subscriber. Registration is open to the public. However, the aforementioned EG members are not yet content with the level of openness. Alternatives such as a second, read-write mailinglist open to the community and invitations for non-EG members with unique expertise in JSF to post to the primary EG list are being considered.
Not only does Red Hat want to bring openness to the JSR-314 specification, it strives to make JSR-314 a model for other JSRs to employ an open participation policy. Given how important the Java EE platform is to businesses worldwide, it's crucial that consumers be allowed to participate in how the platform is defined. The general philosophy is, the more experienced eyes reviewing it, the better the result. Since this philosophy mirrors that of Red Hat, it's understandable why Red Hat would lobby for this mode of operation in the JCP.
The JCP recently relaunched the JCP website as a community portal with registration open to the public. There are both open forums for each specification and a wiki that can be utilized by members. The JavaServer Faces EG has created a wiki book for brainstorming purposes. The problem so far is that there is no clear relationship between the open mailinglist and the forums and the wiki remains quite barren. So there is still work to be done, but the steps so far are encouraging.
Going beyond the bullet points
Although JSF 2 has been a long time coming, it has a lot to show for
it's time spent on the drafting table. A significant portion of the new
features in JSF 2 emerged from Seam as part of Red Hat's initiative to
standardize Seam. With the core programming model in Seam evolving into
JSR-299, that left Seam's JSF enhancements to find a home in JSR-314.
Because there are so many new features in JSF 2, covering them all in a single series is unreasonable. Therefore, this series focuses on the "big ticket" items that were contributed by Red Hat and its community. In return, the series will go beyond the bullet points of new features by explaining the motivation behind each feature and give an example of how the feature is used. The next article in this series will begin this deep dive by covering a particularly hot topic, view parameters and bookmarkable links. Stay tuned!