The ability to handle exceptions is just as important as all the other cool and exciting things that a framework such as Seam can do. Unfortunately, exception handling is often overlooked. This is true of JSF. The faces-config.xml descriptor doesn’t allow exception handlers to be defined. Fortunately, Seam taps into the JSF life cycle to trap and handle exceptions gracefully.
3.6.1 Failing gracefully or with intentional crudeness
Seam handles failures by catching a thrown exception that occurs during the process-ing of the request and offers you a chance to deal with it from within the same execu-tion of the life cycle. By catching the excepexecu-tion as part of its life cycle, Seam can retain page parameters, the temporary or long-running conversation, and any JSF messages that may have been added before the exception occurred. Seam will also ensure that any transactions are rolled back before delegating to the exception han-dler if deemed appropriate.
When dealing with an exception, you can take one of two actions:
■ Redirect
■ Send HTTP error code
In the process of handling an exception, you may also
■ Add a JSF message
■ End a conversation
■ Add parameters to a redirect
There are two ways you can define how an exception is handled. You can either define exception matching rules in the page descriptor that watch and act on exceptions when they are thrown, or you can go straight to the exception class and configure how the exception should be handled when it is raised.
3.6.2 Registering an exception handler
To configure an exception handler, you again leverage the page descriptor. Using the code in listing 3.6, we capture a Seam authorization exception in a graceful manner.
When Seam catches the exception, it first stores the original exception in the conver-sation-scoped variable named org.jboss.seam.caughtException.12 It then looks through the exception hierarchy for an exception handler. If it finds one, it stores the
12Prior to Seam 2.1 the original exception was stored in the variable named org.jboss.seam.exception.
handled exception in the conversation-scoped variable named org.jboss.seam.
handledException. The exception handler can then add a message to the request and issue navigation to an error page. The message is a standard JSF FacesMessage and is thus displayed in the user interface using the <h:messages> component tag.
<exception class="org.jboss.seam.security.AuthorizationException">
<redirect view-id="/error.xhtml">
<message severity="WARN">
Sorry, you do not have access to the requested resource.
This message may explain why:
#{org.jboss.seam.handledException.message}
or
#{org.jboss.seam.caughtException.message}
</message>
</redirect>
</exception>
NOTE If you’re using Facelets, you have to ensure that both Facelets develop-ment mode and Seam debug mode are disabled in order for the excep-tion handler to kick in all cases. Otherwise, you may be presented with a special debug page that displays the exception. The instructions for tog-gling Seam debug mode and Facelets development mode can be found in section section 2.6.1 of chapter 2.
3.6.3 Handling the exception at the source
You can also configure exception handling through annotations by adding either an
@HttpError annotation or a @Redirect annotation to the exception class (but not both). You can supplement either of these with the @ApplicationException annota-tion to control how the active transacannota-tion or long-running conversaannota-tion is handled.
The @Redirect annotation, summarized in table 3.3, allows you to render a pretty error page and kindly inform the user what went wrong.
The @HttpError annotation, on the other hand, is typically used to generate a fatal and ungraceful response to the client. I think of it as screaming at an unwelcome
Listing 3.6 Configuration for capturing authorization exceptions
Table 3.3 The @Redirect annotation Name: Redirect
Purpose: Indicates that an HTTP redirect should be issued when this exception is raised.
Target: TYPE (exception class)
Attribute Type Function
message String (EL) The message used to register an info-level FacesMessage. Default: the exception message.
viewId String (EL) The JSF view ID to redirect to when this exception is thrown.
Default: the current view ID.
Inner exception Outermost exception
guest. When an exception class annotated with @HttpError is thrown, Seam will send the specified HTTP status code to the browser along with the message in the excep-tion. The @HttpError annotation is summarized in table 3.4.
The @ApplicationException annotation, summarized in table 3.5, is used to end a long-running conversation or immediately roll back the active transaction. When an exception class annotated with @ApplicationException is thrown, Seam determines from this annotation how to handle the conversation and the transaction. Note that unhandled exceptions always force a rollback. The @ApplicationException just forces the rollback to happen immediately.
As an example, suppose you’ve implemented an exception specific to your application:
@Redirect(viewId = "/penaltyStrokeWarning.xhtml"
message = "You're ball is out of play. That will cost you one stroke.") public class OutOfBoundsException extends Exception {}
With exceptions handled properly, and the user having received the appropriate slap on the wrist for foul play, the coverage of the Seam life cycle comes to a close. Seam is
Table 3.4 The @HttpError annotation Name: HttpError
Purpose: Indicates that an HTTP error response should be sent when this exception is raised.
Target: TYPE (exception class)
Attribute Type Function
message String (EL) The message used to register an info-level FacesMessage. Default: the exception message.
errorCode int One of the HTTP error code constants in the Java Servlet API.
Default: 500, an internal server error.
Table 3.5 The @ApplicationException annotation Name: ApplicationException
Purpose: Controls how the long-running conversation and transaction are handled when this exception is raised. A synonym to javax.ejb.ApplicationException for use in non-EJB environments.
Target: TYPE (exception class)
Attribute Type Function
rollback boolean If true, this flag indicates that the transaction should roll back immediately. If false, the transaction is rolled back at the end of the request. Default: false.
end boolean If true, this flag indicates the long-running conversation should be ended. If false, the conversation is left untouched.
Default: false.
a tremendous web-oriented framework because it has taken JSF and extended it to give you all the control you need over the pages in your application.
3.7 Summary
In this chapter, you learned how Seam hooks into the Java Servlet and JSF life cycles to provide services for both JSF and non-JSF requests. You witnessed the multifaceted nature of this integration, which leverages a servlet listener to bootstrap Seam and lis-ten for HTTP session events, a JSF phase listener to tap into the JSF life cycle, a servlet to generate and serve supporting resources, and a servlet filter to provide services beyond the reach of the JSF servlet. With this integration in place, focus turned toward Seam’s JSF enhancements.
This chapter dedicated a section to reviewing the JSF life cycle, presenting the stark contrast between an initial request and a postback and identifying which of the six life-cycle JSF phases play a role in each scenario. You discovered that the notification of each phase transition, captured using a JSF phase listener, is how Seam weaves in many of its JSF enhancements, giving rise to the Seam life cycle. The steps of the Seam life cycle were explained.
Most of Seam’s enhancements affect the initial request, in the form of page-oriented controls, which were covered in detail. The controls are configured in Seam’s page descriptor, which you learned acts as a stand-in replacement for naviga-tion rules defined in the JSF configuration file. I encouraged you to move to Seam’s navigation rules to gain more intelligent navigation. You also learned that committing to Seam’s page descriptor gives you the ability to accomplish tasks that JSF has been criticized for lacking in the past, such as a front controller, advanced page navigation, RESTful URLs, and exception handling. In short, by extending JSF, Seam delivers fea-tures of an action-based framework like Struts without ditching the many benefits of a component-based model.
Having gained the big picture of a Seam request, you are now ready to turn to the other essential aspects of Seam: components and contexts. In the next chapter, you’ll learn about Seam components, those classes in a seam-gen project decorated with the
@Name annotation. You’ll discover that Seam components can effectively replace the managed bean facility in JSF. But what makes Seam stand apart is that Seam compo-nents can serve many roles, ranging from presentation to business to persistence. In fact, a single component can serve in all three roles. Read on to discover how Seam’s contextual container is used to support the Seam life cycle and how Seam’s liberal architecture gives Seam components tremendous utility.
130