JSF is beginning to dominate the Java Web application market because of its status as a Java Web standard. As more developers are being mandated to architect applications using JSF as the foundation, they are discovering something that is clearly stated in the core specification: JSF was not designed to be a complete Web application framework. Rather, it provides a sturdy, event-driven API and UI component library on which to build a more complete application framework.
In my search for an extension to complement JSF's component-driven architecture, I recorded short stints with both Shale and Struts 2. I ruled out Struts 2 because it treats JSF as merely a stepchild to a much broader design. Shale seems to come closer, being fundamentally based on JSF, but I have some reservations about it. In contrast, JBoss Seam is a comprehensive application framework that builds on the foundation of JSF without compromising any of its core goals.
This three-part series introduces the Seam application framework, demonstrates its strengths, and hopefully will convince you that it is the perfect companion to JSF for developing Java enterprise applications. Refer to the Resources section if you would like to download Seam before you begin reading the series.
After reading just one page of an article about JBoss Seam (see Resources), I knew that Seam was the project for which I had been searching. The developers of Seam, most notably Gavin King, have logged enough painstaking, real-world development hours to know that a Web application framework must attack tough issues from the very start, which include contextual state management, RESTful and user-friendly URLs, Ajax remoting, proper exception handling, and convention over configuration. Blissfully for Java developers, Seam delivers on all of these requirements and more. If you are using JSF and haven't heard of Seam, I highly recommend that you check out the Seam reference documentation (see Resources). The manual provided with Seam is one of its best assets!
Despite its apparent suitability as a complement to JSF, Seam has been met with some degree of indifference among heavy competition. In a market already flooded with Web application frameworks -- including Shale and Struts 2 -- newcomers are treated as yearlings, and Seam has yet to fully establish itself among the majority. Another reason Seam's adoption has been slow is that certain myths about the framework have kept Java developers from recognizing its immediate benefits.
The myth that I would like to shatter is that Seam is useful only when used in conjunction with EJB3, or that you need an EJB3 container to develop applications with Seam. In fact, the Seam documentation clearly refutes this misconception: "Seam does not require that components be EJBs and can even be used without an EJB 3.0 compliant container." Claiming that you can only use Seam if you also use EJB3 is analogous to implying that you can only use Spring if you also use Hibernate. While both pairings have a strong chemistry, they are not dependent on one another.
As I will shortly explain, Seam extends the default JSF life cycle with valuable hooks and component-management processes. You can also use it in complete isolation from EJB3. However, keep in mind that like EJB3, Seam does rely on JDK 5 annotation metadata for component declaration, so using it requires that you also use a Java 5-compliant JVM. Figure 1 shows the application stack for a Seam POJO implementation:
Figure 1. A Seam POJO application stack
You can actually leverage much of Seam's power without even a reference to an EJB3 jar or descriptor file. When using Seam with POJOs, the framework retains complete control of component instantiation and does not require any special configuration. Seam handles most of the Java 5 annotation processing rather than relying on any mechanisms in EJB3. The bounded set of annotations that do depend on an EJB3 container are geared specifically for that environment. In some cases, integrating Seam into a current IT investment without the EJB3 coupling will prove more cost-effective. How you use Seam really is just a matter of preference.
Given the vast pool of Java frameworks and the limited number of hours in each day, it's obvious that Seam doesn't stand a chance if it is difficult to integrate. Fortunately, adding Seam to your project is trivial. Because the JSF life cycle remains the central piece of a Seam application, there is no retraining period to endure. Just add four additional jar files, register both a servlet listener and a JSF phase listener, and finally, toss in an empty java properties file. Once that setup is complete, you can shift your native JSF application to Seam one managed bean at a time.
The first thing you need to do to start using Seam is to add the required jar files to your project. If you are not using Hibernate or have not upgraded to the latest version, that will count as an extra step in the setup. You will need to include the jars from the Hibernate 3.2 distribution, as well as its numerous dependencies. Seam also uses Hibernate annotations for data validation, so you must include that extension jar in addition to the main Hibernate jar. The libraries required from the Seam distribution are jboss-seam.jar and jboss-seam-ui.jar, as well two supporting libraries: Javassist (a load-time reflective system for Java) and the Java Persistence API. The project tree in Figure 2 illustrates the cumulative set of jars in a Seam project. Most of the additional libraries shown in the figure support the MyFaces implementation of JSF.
Figure 2. Libraries in a Seam project
The next step is to install the servlet listener class in the web.xml file, as shown in Listing 1. This listener initializes Seam when the application is deployed.
Listing 1. Seam servlet listener configuration
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
|
Next, you add the JSF phase listener to the faces-config.xml file, as shown in Listing 2. This listener integrates Seam into the standard JSF life cycle. (See Figure 3 for an overview of the enhancements Seam weaves into this life cycle.)
Listing 2. Seam phase listener configuration
<lifecycle>
<phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
</lifecycle>
|
Finally, you place an empty seam.properties file in the root of the classpath so that Seam is instructed to load, as shown in Listing 3. The empty file is used as a JVM classloader optimization to give Seam a narrower region of the classpath in which to search for components, drastically reducing load time.
Listing 3. Seam properties file
# The mere presence of this file triggers Seam to load
# It can also be used to tune parameters on configurable Seam components
|
Of course, many features of Seam are not available with this minimal setup. These instructions are merely intended to demonstrate that Seam has a very small footprint for entry-level use. For instance, Seam includes a servlet filter that extends the scope of its features beyond the JSF life cycle. Uses of this servlet filter include integration with non-JSF requests, propagating conversations over redirects, and managing file uploads. See Resources for the Seam reference documentation, which discusses configuration files that control additional functionality -- most notably the EJB3 integration.
Developing a managed bean with Seam is almost shockingly easy compared to
the typical JSF configuration process. To expose your bean to the JSF
life cycle, all you need to do is place a single annotation, @Name, above the class definition. Seam takes care of
controlling the visibility and life cycle of the component thereafter. Best of
all, you do not need to define this bean in the faces-config.xml file.
The @Name annotation, along with @DataModel, @DataModelSelection, @In, @Out, and @Factory are depicted in Listing 4. These annotations enable a bidirectional flow of variables
between the view template and Seam components.
In Seam parlance, this action is called bijection, short for bidirectional injection. When property data is outjected, it becomes directly visible to the view by name. Data is injected into a component either on postback or when the component is initialized. The latter is an implementation of the well-known inversion of control (IOC) pattern and can be used to tie in delegate objects. The major difference between classic IOC and Seam's bijection is that bijection enables components in a long-term scope to have references to those in a short-term scope. The connection is possible because Seam resolves dependencies each time a component is invoked, rather than once when the container is started. Bijection is a cornerstone of stateful component development.
Obviously the POJO bean in Listing 4 barely scratches the surface of how Seam operates. I'll explore additional ways to implement Seam as the series continues.
Listing 4. A typical Seam POJO bean
@Name("addressManager")
public class AddressManagerBean {
@DataModel
private List<Address> addresses;
@DataModelSelection
@Out( required = false )
private Address selectedAddress;
@Factory( value = "addresses" )
public void loadAddress() {
// logic to load addresses into this.addresses
}
public String showDetail() {
// no work needs to be done to prepare the selected address
return "/address.jspx";
}
public String list() {
return "/addresses.jspx";
}
} |
To leverage your investment in service-layer objects managed by an
existing Spring container, you need to inject any Spring beans that handle related
business logic into your Seam component. You first need to ensure
that you have the Spring-JSF integration configured, which is handled by a
custom variable resolver included with the Spring framework (see Resources). With that bridge in place,
integrating Spring with Seam is just a matter of using the @In Java 5 annotation in combination with a value binding
expression to indicate which properties of the Seam component should receive an
injection of a Spring bean, as shown in Listing 5. (Future versions of Seam
will include a custom namespace for Spring that will absorb the need for the
value binding expression.)
Listing 5. Injecting a Spring bean
@Name("addressManager")
public class AddressManagerBean {
@In("#{addressService}")
private AddressService addressService;
}
|
This example setup supports the use of stateless service and data access (DAO) layers that are configured using a lightweight container, in this case Spring. Because EJB3 is not required, the target of the deployment can be any basic servlet container.
Now that you've had a first look at a Seam-JSF implementation, I'll delve a little deeper into the challenges I have encountered using JSF and how Seam alleviates them.
To fully appreciate what Seam brings to JSF, you need to understand how JSF differs from other popular approaches to Web-based programming. JSF is a Web framework that implements the classic Model-View-Controller (MVC) architecture. The difference is that it employs an exceptionally rich implementation of the pattern. The MVC implementation in JSF more closely approximates the style of a traditional GUI application than the Model 2, or "push-MVC" approach used in frameworks such as Struts, WebWork, and Spring MVC. These later frameworks are classified as action-based, whereas JSF is a member of a new family of frameworks based on a component model.
The distinction becomes easier to grasp if you think of action-based frameworks as using a "push" model, whereas component frameworks utilize a "pull" model. Instead of taking an active role in the request for a page up front (as it would in an action-based framework), the controller in a component framework takes a back seat in the request life cycle and invokes data-providing methods from within the view. Additionally, elements on the page, known as components, are bound to events that can trigger method invocations on server-side objects when activated, which results in either a redisplay of the same view or a transition to another page. Hence, component frameworks are also classified as event-driven. A component framework abstracts away the underlying request-response protocol that is used to communicate events.
The event-driven approach is beneficial because it reduces the amount of work that must be done up front, in a single method, to prepare for the rendering of the view. In a component framework, invocations are a direct result of either UI events or resolved value-binding expressions.
Once an application reaches even a moderate level of maturity, it generally requires a lot of unrelated activity on any given page. Stuffing the management of all of this information into a single action, or even a chain of actions, quickly becomes a maintenance nightmare. As a result, developers often find their code departing from the object-oriented model and diving instead into a procedural programming style. Component frameworks, by contrast, isolate the work and more naturally enforce the roles and responsibilities of objects.
Enough about the basics of JSF and component frameworks. The fact of the matter is -- as many Java developers have recently discovered -- moving to JSF is not all smooth sailing. Adopting the component model brings with it a whole new set of problems, beginning with the reality that you often must attempt to force your application into the action-based Web world. There are times when JSF simply needs to behave like an action-based framework, but that's not a viable option in native JSF, at least not without resorting to using phase listeners that execute for every request.
JSF's other major shortcomings include a heavy reliance on the HTTP session (especially when propagating data across a sequence of pages), cursory exception handling, lack of bookmarking support, and XML-hell configuration. Seam rectifies many of these problems by naturally integrating with JSF while at the same time weaving in new functionality that the JSF specification committee either renounced or simply overlooked. Seam's framework encourages very compact, readable, and reusable code, void of all the "glue" logic that routinely leaks in to manage the aforementioned problems. Figure 3 covers most of Seam's extension points in the JSF life cycle that help to simplify your application's code:
Figure 3. Seam life cycle enhancements
Let's consider some of these enhancements as they apply to the common challenges of JSF development.
Seam demonstrates a very practical use of Java 5 annotations. Seam's
deployment scanner examines all archives containing a seam.properties file
and creates a Seam component for any class marked with a @Name annotation. Many XML configurations were devised
because the Java language lacked a common syntax for adding metadata at the
code level. When annotations were added in the Java 5 specification, a
better solution had arrived. Because most backing beans are developed for use
within a specific application, there is no reason to "abstract" the
configuration of these beans into any file other than the class itself. As
an added benefit, you're left with one less file to juggle. Seam offers an
entire catalog of annotations that help to integrate the beans into the JSF
life cycle. Listing 4 shows several of them in use.
One familiar crutch that you must do without in a component framework is processing each request up front, as you do in action-based frameworks. Use cases affected by this trade-off are RESTful URLs, bookmarking support, security through URL patterns, and page-flow validation, to mention a few. Hands down, this deficiency is one of the primary sources of confusion for developers learning to use JSF. Some JSF vendors work around this by offering an onPageLoad functionality (see Resources) with their developer tools, but it is not part of the core specification.
Consider what commonly happens when a user requests an item detail screen directly, perhaps from a bookmark. Because the JSF controller works in a passive manner, once the page begins rendering you cannot reroute the user to the start of logical flow, even when it becomes apparent that the target data is absent. Instead, you have no choice but to display a page with blank values and other potential rendering glitches.
At first, you may instinctively think to implement a "prerender" method on the page's primary backing bean. However, in a component framework, the association between backing bean and page is not necessarily one-to-one. Each page can rely on a mixture of backing beans, and each of those beans can also be used across several different pages. Instead, there must be some way to associate a single view ID (such as /user/detail.jspx) with one or more methods that you want to have invoked when the corresponding view template is selected for rendering. You could use a phase-listener approach, but that would still require custom logic to determine whether or not the functionality should be executed for the current view and phase. Not only does this solution lead to a lot of redundant logic, but you end up hardcoding the view IDs -- easily the most irresolute component of the application -- into your compiled Java code.
Seam's page actions give you a way to intercept rendering glitches before they happen. Page actions are specified using method bindings that are executed when entering a page, just prior to the Render Response phase. You can configure any number of method bindings for a given view ID in the /WEB-INF/pages.xml configuration file. (Alternatively, you can split up the definitions on a per-page basis by placing them in a file adjacent to the view template, cloning its name but replacing the file extension with *.page.xml.) In the case of page actions, the XML is desirable since view IDs are volatile to change. Just as JSF maps post data onto model objects through value bindings during the Apply Request Values phase, Seam can map arbitrary request parameters onto model objects through value bindings prior to the execution of the page action. The configuration of these request parameter injections are nested within the page action XML declaration. If a page action method invocation returns a non-null string value, Seam treats it as a navigation event. Hence, without migrating to a full-blown action-based framework, it is still possible to emulate the most distinctive feature of one. Seam includes an ample set of built-in page actions that are commonly used across applications. The set includes an action to verify that a conversation is established; actions that can start, nest, and end conversations; an action to handle bubbled exceptions; and an action that ensures proper credentials.
Page actions are the key to enabling bookmarking support for JSF. Seam's
creators leveraged this feature by allowing the magic request parameter
actionMethod to trigger a method invocation upon entering a page. Even
better, you don't need to do any extra work to create links for bookmarking.
Seam provides two component tags, s:link and s:button, to handle the details for you. These two tags
correspond to their native JSF counterparts, h:commandLink and h:commandButton, respectively. The difference is that
links assembled by the Seam component tags issue requests using an HTTP GET operation, rather than the HTTP POST form submission model indicative of JSF. Thus,
links created by Seam are "friendlier" to bookmarking and considered to
be far more convenient for developers.
You may also notice that when you use page actions, the URL in the location bar corresponds to the page being shown rather than always being one page behind. (The latter situation occurs because JSF configures forms to post back to the same URL that generated them. The location bar does not get updated to reflect the new view after an action because JSF advances to it through a server-side redirect.) If you really want to demonstrate the flexibility of page actions, you can use them to create RESTful URLs (for example, /faces/product/show/10). To do so, you map the page action method to the view ID "/product/show/*", where the /faces prefix is the JSF servlet-mapping portion. The page action method then mines the request URL to determine the type of data and the data identifier, loads that data, and then navigates to the appropriate template. This example clearly demonstrates that the one-to-one mapping between a JSF request URL and view template is not imperative.
One of the biggest frustrations with JSF is that it provides no definitive moment during which to prepare data for the view, apart from within a user-triggered action or action-listener method. Placing the logic inside an action method does not guarantee that it will be executed prior to rendering because a page view is not always preceded by a user-triggered event.
For example, consider what happens when the URL to a JSF application is initially requested. If you are required to display a collection of data retrieved from the service layer on this page, there is just no good opportunity in the JSF life cycle to fetch the data. You might assume that you can stick the logic inside the getter method of the backing bean that maps to the value binding expression in the view. However, each time JSF resolves that expression, it triggers an additional invocation, which could in turn hit the service layer. With just a few components on the page, it is possible that the getter method will be called upwards of a half-dozen times. Clearly this is not optimal in terms of performance! Even if you maintain state by using a private property on the managed bean, you still have to add extra plumbing each time you are faced with this use case. One solution, as you've learned, is to use Seam's page actions. But this task is so common that Seam offers an even easier solution.
Seam introduces the concept of a factory data
provider, which is designated by the @Factory
Java 5 annotation. While there are a couple of ways to configure the factory,
the end result is that the data is prepared exactly once, when first requested.
Seam ensures that subsequent requests for the same data will return the
previously created result set rather than triggering an additional invocation
of the lookup method. Combined with conversations, the factory data provider
becomes a very powerful feature for implementing a short-term cache of data
that could otherwise be expensive to retrieve. Given that JSF does not care to
reduce the number of times it resolves a value binding expression, Seam's
factory feature often comes in handy.
One of the common points of confusion about JSF is its state management
facility. The JSF specification explains how pages are "restored" after
receiving an action, during which time events are queued and selections
registered. Examining the words used in the specification reveals
that while the component tree is restored on a postback, the backing bean data
used by those components is not restored. The components merely store value
bindings (EL expressions using the syntax #{value}) as string literals,
which only resolve to the underlying data at run time. This means that if a
value is stored in a short-term scope, such as page or request scope, it will
be absent by the time the JSF life cycle arrives at the Restore View
phase.
The most noticeable downside of not storing value binding data in the
component tree is the ghost event effect (see Resources), which is caused by transient parent components in the UIData family. If model data referenced by a value
binding expression is no longer available or has changed prior to the
component tree being restored, it can result in portions of the tree being
dropped. If an event had been triggered from a component within one of these
dropped branches, then it will not be discovered and its omission will be
remarkably silent (except for the sound of queue developers screaming, "Why
isn't my action being called?!").
While the lost events may seem like an exceptional condition, it raises no red flags in the JSF life cycle. Because these components rely on the underlying data to be stable to be properly restored, it is hard for JSF to know that something is missing.
Unfortunately, the JSF specification naively leads developers down a path
of placing most backing beans in session scope -- you could even call it
"convenient" scope. Server administrators then have to deal with the fallout
in the form of "out of memory" errors, server affinity in clustered
environments, and serialization exceptions on server restarts. The MyFaces
Tomahawk project does offer a solution to ghost events in the form of the
t:saveState tag. The MyFaces tag allows you to store data (including entire backing beans) as part of the component tree rather than
just the value bindings. This solution is rather crude, however, closely
resembling the use of hidden form fields to pass along values between requests.
It also creates a tight coupling between the view and the controller. The
creators of Seam recognized that the three built-in contexts (request, session,
and application) in the Java Servlet specification do not constitute a
sufficient set of scopes for data-driven Web applications. With Seam, they
introduced the conversation scope, which is a stateful scope bounded by start
and end points in the page flow.
"Seam emphasizes the use of stateful components." This statement, from the Seam reference documentation, embodies the core vision of Seam. The mindset surrounding Web applications has long been that they are stateless -- a philosophy that can be partially attributed to the stateless nature of the HTTP protocol. Most frameworks cater to this preference by offering one-shot-processing before concluding with the rendering of a page. This approach causes considerable impedance because any significant application demands long-running conversations to satisfy certain use cases. Examples of applications that require a stateful context include a store checkout process, product customization, multipage form wizards, and many other applications based on linear interactions. While some of these cases can certainly get away with using URL parameters (aka RESTful URLs) and hidden fields to migrate the data from page to page, doing so quickly becomes cumbersome for the developer. At this point, it also has to be considered outdated. Because most Web frameworks are still operating under the stateless model, you often find yourself stepping outside of the framework to "hack" custom solutions.
JSF attempts to introduce a stateful context by depending heavily on the HTTP session. In fact, JSF components behave much better -- one could even argue they behave as expected -- when working with session-scoped backing beans. Without careful design, overuse of the HTTP session can cause severe memory leaks, performance bottlenecks, and security problems. Additionally, using the HTTP session can cause very strange behavior in a multitab browser environment and break the user's sacred Back button. The important point here, though, is that JSF only meets you halfway: it is a stateful UI and handles all the details of saving and restoring the component tree, but it provides no assistance in saving and restoring your data. Under this agreement, JSF brings the stateful UI and you bring the stateful data. Unfortunately, the burden is placed on you to ensure that they coincide.
Prior to Seam, the only convenient way to have stateful data was to rely on the HTTP session. Seam rectifies this and completes JSF's state management picture by establishing an entirely new conversation scope. With Seam's addition to the JSF life cycle, the conversation context is tied to a single browser window (or tab), identified by a token that is submitted with each request. The conversation scope migrates data between pages using an isolated segment of the HTTP session. Keep in mind that Seam's use of the HTTP session for conversation persistence is completely transparent. Seam does not carelessly dump components into the HTTP session, leaving them there indefinitely. Instead, the life cycle of that segment of session data is carefully managed by Seam and it is automatically cleaned up when the conversation terminates. Seam cleverly uses bijection to allow data to flow in and out of each page of a "Web conversation" in a new, declarative manner. Seam's conversation scope simultaneously overcomes the limits of the HTTP session and helps to wean developers away from its use.
Seam's creator has said that "JSF is surprisingly limited when it comes to
exception handling," and there is certainly no arguing with him on this point.
The JSF specification completely disregards exception management, placing its
responsibility entirely on the servlet container. The problem with allowing
the servlet container to handle exceptions is that it severely limits what can
be displayed on the resulting error page and makes transactional rollbacks all
but impossible. Because the error page is displayed after a request-dispatcher
forward, the FacesContext is no longer in scope and
it is therefore too late to do any business logic. Your last-ditch hope is to
reach into the Servlet API and grab the javax.servlet.error.* request
attributes to search the information for some indication of what went wrong.
Once again, Seam comes to the rescue by offering elegant and declarative
exception handling. Exception management is designated either through
annotations or in a configuration file. The annotations @HttpError, @Redirect, and
@ApplicationException can be placed on top of
exception classes to indicate an action that should be taken in the event
that they are thrown. For those exception classes that are not accessible
for modification, the XML configuration option can be used. The exception
manager in Seam is responsible for sending HTTP status codes, performing
redirects, forcing page rendering, terminating conversations, and customizing
user messages when an exception is raised. Because JSF cannot change the
course of action after beginning to render the response, some inherent
limitations dictate when these exceptions can be handled. Appropriate use
of other Seam features, such as page actions, can ensure that most, if not
all, exceptional situations can be addressed prior to rendering the
response.
Because the release of the final JSF specification nearly coincided with
the explosion of Ajax, the JSF framework offers very little assistance in the
area of asynchronous JavaScript and partial page rendering. For some time, it
even appeared that the two styles of programming were at odds with each other.
Eventually, solutions began to roll out that suggested using JSF PhaseListeners or component Renderers to handle partial page updates. Even then, it
was readily apparent that JSF made adopting Ajax more difficult than it had
to be. Some projects, such as ICEfaces, went so far as to completely replace the JSF life cycle with one better designed for page-to-server communication (known as direct-to-DOM rendering).
Seam offers a unique approach to JavaScript remoting (a technology often
grouped under the Ajax umbrella) that loosely parallels that of the Direct
Web Remoting (DWR) library. Seam fuses the client and server together by
allowing JavaScript to directly invoke methods on server components. Seam
remoting is more powerful than DWR because it has access to the rich
contextual component model as opposed to merely an isolated endpoint. This
interaction builds on the event-driven design of JSF, allowing it to more
closely follow the Swing paradigm. The best part is that this functionality
is provided with almost no added development effort. A simple annotation,
@WebRemote on a component's method, makes it
accessible to JavaScript. Once the state of the server component has been
modified, partial rendering can be then handled by the Ajax4JSF component library. In short: The Seam
remoting library enables JSF to achieve the interactive design that its
creators had envisioned all along.
Based on what you've learned so far in the Seamless JSF series, it would not seem far-fetched to argue that developing in JSF without using Seam is preposterous. For further proof, look no further than the ballot results for JSR 299, Web Beans (see Resources). It is clear that at some point in the near future, Seam will be an official spec, and the Java EE stack will finally offer "a significantly simplified programming model for Web-based applications." This is good news for JSF developers and for Seam. But even without the claim of being a Java standard, Seam is a worthy complement to JSF.
Seam requires very little setup to begin plugging the gaps in JSF -- and for that small effort, it resolves some of the most troubling conundrums of JSF development. Benefits trump effort -- and the ones discussed here are only the beginning of what there is to like about Seam.
| Description | Name | Size | Download method |
|---|---|---|---|
| Barebones Seam project1 | j-seam1.zip | 13KB | HTTP |
Information about download methods
Note
- This project skeleton uses the Maven 2 build infrastructure. All dependencies will be fetched on demand when the build is executed.
Learn
- "Web 2.0 application made easy with Rational Application Developer V7" (Yury Kats, developerWorks, December 2006): Learn how to use Ajax and JSF together in Rational Application Developer V7.
- "JSF for nonbelievers: Clearing the FUD about JSF" (Richard Hightower,
developerWorks, February 2005): A four-part series that explores issues
in JSF programming while advocating for its strengths. Also a good introduction to the JSF life cycle.
- "Facelets fits JSF like a glove" (Richard Hightower, developerWorks, February 2006): Introduces Facelets -- also now the preferred view handler for Seam applications.
- "The Next Generation Web Framework" (Michael Juntao Yuan, Red Hat Application Stack, September 2006): A positive, forward-thinking review of Seam.
- "Seam: The Next Step in the Evolution of Web Applications" (Norman Richards, Java Developers Journal, February 2006): Explains how Seam helps to wean developers away from the HTTP session.
-
The MyFaces Wiki FAQ: Discusses the so-called ghost event that can occur in events
triggered from UIData components.
- "Creating onPageLoad functionality for JavaServer Faces using Facelets" (Alyssar, JSFCentral, March 2007): An alternative approach to request processing in JSF applications.
-
developerWorks Java technology zone: Hundreds of articles about every aspect of Java programming.
Get products and technologies
-
Rational Application Developer: Download a free trial version.
-
Download JBoss
Seam: Get the complete distribution, including the bundled example applications.
-
Download Maven 2: The build infrastructure used in the source code sample for this article.
Discuss
-
JSR 299, Web Beans: Join the effort to standardize JSF and EJB3 integration.
-
developerWorks blogs: Get involved in the developerWorks
community.

Dan Allen is currently a senior Java engineer at CodeRyte, Inc. He is also a passionate open source advocate and gets a bit manic whenever he catches sight of a penguin. After graduating from Cornell University with a degree in Materials Science and Engineering, Dan became captivated by the world of Linux and open source software. He has been slaving over Web applications ever since, with the last several years focused exclusively on Java-related technologies, including Spring, Hibernate, Maven 2, and the abundant JSF stack. You can keep up with Dan's development experiences by subscribing to his blog at http://www.mojavelinux.com.





