SeamFramework.orgCommunity Documentation

Seam Faces Module

Reference Guide


To use the Seam Faces module, you need to put the API and implementation JARs on the classpath of your web application. Most of the features of Seam Faces are enabled automatically when it's added to the classpath. Some extra configuration, covered below, is required if you are not using a Servlet 3-compliant container.

If you are using Maven as your build tool, you can add the following single dependency to your pom.xml file to include Seam Faces:


<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces</artifactId>
   <version>${seam.faces.version}</version>
</dependency>
        

Tip

Substitute the expression ${seam.faces.version} with the most recent or appropriate version of Seam Faces. Alternatively, you can create a Maven user-defined property to satisfy this substitution so you can centrally manage the version.

Alternatively, you can use the API at compile time and only include the implementation at runtime. This protects you from inadvertently depending on an implementation class.


<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-api</artifactId>
   <version>${seam.faces.version}</version>
   <scope>compile</scope>
</dependency>

<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-impl</artifactId>
   <version>${seam.faces.version}</version>
   <scope>runtime</scope>
</dependency>
        

In a Servlet 3.0 or Java EE 6 environment, your configuration is now complete!

JSF 2.0 introduced the concept of the Flash object and the @ViewScope; however, JSF 2.0 did not provide annotations accessing the Flash, and CDI does not support the non-standard ViewScope by default. The Seam Faces module does both, in addition to adding a new @RenderScoped context. Beans stored in the Render Scope will survive until the next page is rendered. For the most part, beans stored in the ViewScope will survive as long as a user remains on the same page, and data in the JSF 2 Flash will survive as long as the flash survives).

Beans placed in the @RenderScoped context are effectively scoped to, and live through but not after, "the next Render Response phase".

You should think about using the Render scope if you want to store information that will be relevant to the user even after an action sends them to another view. For instance, when a user submits a form, you may want to invoke JSF navigation and redirect the user to another page in the site; if you needed to store a message to be displayed when the next page is rendered -but no longer- you would store that message in the RenderContext. Fortunately, Seam provides RenderScoped messages by default, via the Seam Messages API.

To place a bean in the Render scope, use the @org.jboss.seam.faces.context.RenderScoped annotation. This means that your bean will be stored in the org.jboss.seam.context.RenderContext object until the next page is rendered, at which point the RenderScope will be cleared.

@RenderScoped

public class Bean {
    // ...
}

@RenderScoped beans are destroyed when the next JSF RENDER_RESPONSE phase ends, however, if a user has multiple browser windows open for the same user-session, multiple RenderContexts will be created, one for each incoming request. Seam Faces keeps track of which RenderContext belongs to each request, and will restore/destroy them appropriately. If there is more than one active RenderContext at the time when you issue a redirect, you will see a URL parameter ?fid=... appended to the end of the outbound URL, this is to ensure the correct context is restored when the request is received by the server, and will not be present if only one context is active.

Caution

If you want to use the Render Scope with custom navigation in your application, be sure to call ExternalContext.encodeRedirectURL(String url, Map<String, List<String>> queryParams) on any URL before using it to issue a redirect. This will ensure that the RenderContext ID is properly appended to the URL, enabling the RenderContext to be restored on the subsequent request. This is only necessary if issuing a Servlet Redirect; for the cases where Faces non-redirecting navigation is used, no URL parameter is necessary, and the context will be destroyed at the end of the current request.

In addition to ???, Seam Faces provides an additional producer which returns the supported locale of the UIViewRoot or ViewHandler. This Locale has the @Faces qualifier to help distinguish it from other produced locales.

Seam Faces also provides easy access to the configured list of locales for the application both via injection and via EL. Using EL thould would be #{supportedLocales} and #{defaultFacesLocale}. Via injection one would use

@Inject @Faces

List<Locale> supportedLocales;
  

or

@Inject @Faces @DefaultLocale

Locale defaultLocale;
  

While JSF already has the concept of adding FacesMessage objects to the FacesContext in order for those messages to be displayed to the user when the view is rendered, Seam Faces takes this concept one step farther with the Messages API provided by the Seam International module. Messages are template-based, and can be added directly via the code, or templates can be loaded from resource bundles using a BundleKey.

Consistent with the CDI programming model, the Messages API is provided via bean injection. To add a new message to be displayed to the user, inject org.jboss.seam.international.status.Messages and call one of the Message factory methods. As mentioned earlier, factory methods accept either a plain-text template, or a BundleKey, specifying the name of the resource bundle to use, and the name of the key to use as a message template.

@Named

public class Example
{
   @Inject
   Messages messages;
   public String action()
   {
      messages.info("This is an {0} message, and will be displayed to {1}.", "INFO", "the user");
      return null;
   }
}

Adds the message: "This is an INFO message, and will be displayed to the user."

Notice how {0}, {1} ... {N} are replaced with the given parameters, and may be used more than once in a given template. In the case where a BundleKey is used to look up a message template, default text may be provided in case the resource cannot be loaded; default text uses the same parameters supplied for the bundle template. If no default text is supplied, a String representation of the BundleKey and its parameters will be displayed instead.

public String action()

{
   messages.warn(new BundleKey("org.jboss.seam.faces.exampleBundle", "messageKey"), "unique");
   return null;
}

classpath:/org/jboss/seam/faces/exampleBundle.properties

messageKey=This {0} parameter is not so {0}, see?

Adds the message: "This unique parameter is not so unique, see?"

While Seam Faces does not provide layout components or other UI-design related features, it does provide functional components designed to make developing JSF applications easier, more functional, more scalable, and more practical.

For layout and design components, take a look at RichFaces, a UI component library specifically tailored for easy, rich web-interfaces.

On many occasions you might find yourself needing to compare the values of multiple input fields on a given page submit: confirming a password; re-enter password; address lookups; and so on. Performing cross-field form validation is simple - just place the <s:validateForm> component in the form you wish to validate, then attach your custom Validator.


<h:form id="locationForm">
   <h:inputText id="city" value="#{bean.city}" />
   <h:inputText id="state" value="#{bean.state}" />
   <h:inputText id="zip" value="#{bean.zip}" />
   <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
                  
   <s:validateForm validatorId="locationValidator" />
</h:form>

The corresponding Validator for the example above would look something like this:

@FacesValidator("locationValidator")

public class LocationValidator implements Validator
{
   @Inject
   Directory directory;
   @Inject
   @InputField
   private Object city;
   @Inject
   @InputField
   private Object state;
   @Inject
   @InputField
   private ZipCode zip;
   @Override
   public void validate(final FacesContext context, final UIComponent comp, final Object values)
         throws ValidatorException
   {
      if(!directory.exists(city, state, zip))
      {
         throw new ValidatorException(
            new FacesMessage("Sorry, that location is not in our database. Please try again."));
      }
   }
}

Notice that the IDs of the inputText components match the IDs of your Validator @InputFields; each @Inject @InputField member will be injected with the value of the form input field who's ID matches the name of the variable.

In other words - the name of the @InputField annotated member variable will automatically be matched to the ID of the input component, unless overridden by using a field ID alias (see below.)


<h:form id="locationForm">
   <h:inputText id="cityId" value="#{bean.city}" />
   <h:inputText id="stateId" value="#{bean.state}" />
   <h:inputText id="zip" value="#{bean.zip}" />
   <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
                  
   <s:validateForm fields="city=cityId state=stateId" validatorId="locationValidator" />
</h:form>

Notice that "zip" will still be referenced normally; you need only specify aliases for fields that differ in name from the Validator @InputFields.

An alternate way of accessing those fields on the validator by injecting an InputElement. It works similarly to @InputField, but stores the clientId and a JSF UIComponent, along with the field value.

@FacesValidator("fooValidator")

public class FooValidator implements Validator {
    @Inject
    private InputElement<String> firstNameElement;
    @Inject
    private InputElement<String> lastNameElement;
    
    @Inject
    private InputElement<Date> startDateElement;
    @Inject
    private InputElement<Date> endDateElement;
    ...
    
    }

Use get methods to access those information

public void validate(final FacesContext ctx, final UIComponent form, final Object value) throws ValidatorException {

        Date startDate = startDateElement.getValue();
        
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        
        if (startDate.before(calendar.getTime())) {
            String message = messageBuilder.get().key(new DefaultBundleKey("booking_checkInNotFutureDate"))
                    .targets(  startDateElement.getClientId()  ).build().getText();
            throw new ValidatorException(new FacesMessage(message));
        } 
        ...
    }

The view action component (UIViewAction) is an ActionSource2 UIComponent that specifies an application-specific command (or action), using an EL method expression, to be invoked during one of the JSF lifecycle phases proceeding Render Response (i.e., view rendering).

View actions provide a lightweight front-controller for JSF, allowing the application to accommodate scenarios such as registration confirmation links, security and sanity checking a request (e.g., ensuring the resource can be loaded). They also allow JSF to work alongside action-oriented frameworks, and existing applications that use them.

JSF employs an event-oriented architecture. Listeners are invoked in response to user-interface events, such as the user clicking on a button or changing the value of a form input. Unfortunately, the most important event on the web, a URL request (initiated by the user clicking on a link, entering a URL into the browser's location bar or selecting a bookmark), has long been overlooked in JSF. Historically, listeners have exclusively been activated on postback, which has led to the common complaint that in JSF, "everything is a POST."

We want to change that perception.

Processing a URL request event is commonly referred to as bookmarkable or GET support. Some GET support was added to JSF 2.0 with the introduction of view parameters and the pre-render view event. View parameters are used to bind query string parameters to model properties. The pre-render view event gives the developer a window to invoke a listener immediately prior to the view being rendered.

That's a start.

Seam brings the GET support full circle by introducing the view action component. A view action is the compliment of a UICommand for an initial (non-faces) request. Like its cohort, it gets executed by default during the Invoke Application phase (now used on both faces and non-faces requests). A view action can optionally be invoked on postback as well.

View actions (UIViewAction) are closely tied to view parameters (UIViewParameter). Most of the time, the view parameter is used to populate the model with data that is consumed by the method being invoked by a UIViewAction component, much like form inputs populate the model with data to support the method being invoked by a UICommand component.

Let's consider a typical scenario in web applications. You want to display the contents of a blog entry that matches the identifier specified in the URL. We'll assume the URL is:

http://localhost:8080/blog/entry.jsf?id=10

We'll use a view parameter to capture the identifier of the entry from the query string and a view action to fetch the entry from the database.


<f:metadata>
   <f:viewParam name="id" value="#{blogManager.entryId}"/>  
   <s:viewAction action="#{blogManager.loadEntry}"/>  
</f:metadata>

What do we do if the blog entry can't be found? View actions support declarative navigation just like UICommand components. So you can write a navigation rule that will be consulted before the page is rendered. If the rule matches, navigation occurs just as though this were a postback.


<navigation-rule>
      <from-view-id>/entry.xhtml</from-view-id>
      <navigation-case>
         <from-action>#{blogManager.loadEntry}</from-action>
         <if>#{empty entry}</if>
         <to-view-id>/home.xhtml</to-view-id>
         <redirect/>
      </navigation-case>
   </navigation-rule>

After each view action is invoked, the navigation handler looks for a navigation case that matches the action's EL method signature and outcome. If a navigation case is matched, or the response is marked complete by the action, subsequent view actions are short-circuited. The lifecycle then advances appropriately.

By default, a view action is not executed on postback, since the primary intention of a view action is to support a non-faces request. If your application (or use case) is decidedly stateless, you may need the view action to execute on any type of request. You can enable the view action on postback using the onPostback attribute:


<s:viewAction action="#{blogManager.loadEntry}" onPostback="true"/>

You may only want the view action to be invoked under certain conditions. For instance, you may only need it to be invoked if the conversation is transient. For that, you can use the if attribute, which accepts an EL value expression:


<s:viewAction action="#{blogEditor.loadEntry}" if="#{conversation.transient}"/>

There are two ways to control the phase in which the view action is invoked. You can set the immediate attribute to true, which moves the invocation to the Apply Request Values phase instead of the default, the Invoke Application phase.


<s:viewAction action="#{sessionManager.validateSession}" immediate="true"/>

You can also just specify the phase directly, using the name of the phase constant in the PhaseId class (the case does not matter).


<s:viewAction action="#{sessionManager.validateSession}" phase="APPLY_REQUEST_VALUES"/>

If the phase is set, it takes precedence over the immediate flag.

UIInputContainer is a supplemental component for a JSF 2.0 composite component encapsulating one or more input components (EditableValueHolder), their corresponding message components (UIMessage) and a label (HtmlOutputLabel).

This component takes care of wiring the label to the first input and the messages to each input in sequence. It also assigns two implicit attribute values, "required" and "invalid" to indicate that a required input field is present and whether there are any validation errors, respectively. To determine if a input field is required, both the required attribute is consulted and whether the property has Bean Validation constraints.

Finally, if the "label" attribute is not provided on the composite component, the label value will be derived from the id of the composite component, for convenience.

There's a composite componente that ships with seam-faces under the url:

http://java.sun.com/jsf/composite/components/seamfaces.


xmlns:sc="http://java.sun.com/jsf/composite/components/seamfaces"
    <sc:inputContainer label="name" id="name">
        <h:inputText id="input" value="#{person.name}"/>
    </sc:inputContainer>

If you want to define your own composite component, follow this definition example (minus layout):


<cc:interface componentType="org.jboss.seam.faces.InputContainer"/>
 <cc:implementation>
   <h:outputLabel id="label" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">
     <h:outputText styleClass="required" rendered="#{cc.attrs.required}" value="*"/>
   </h:outputLabel>
   <h:panelGroup>
     <cc:insertChildren/>
   </h:panelGroup>
   <h:message id="message" errorClass="invalid message" rendered="#{cc.attrs.invalid}"/>
 </cc:implementation>

One of the goals of the Seam Faces Module is to make support for CDI a more ubiquitous experience, by allowing injection of JSF Lifecycle Artifacts into managed beans, and also by providing support for @Inject where it would not normally be available. This section describes the additional CDI integration for faces artifact injection

Frequently when performing complex validation, it is necessary to access data stored in a database or in other contextual objects within the application itself. JSF does not, by default, provide support for @Inject in Converters and Validators, but Seam Faces makes this available. In addition to injection, it is sometimes convenient to be able to scope a validator just as we would scope a managed bean; this feature is also added by Seam Faces.

Notice how the Validator below is actually @RequestScoped, in addition to using injection to obtain an instance of the UserService with which to perform an email database lookup.

@RequestScoped

@FacesValidator("emailAvailabilityValidator")
public class EmailAvailabilityValidator implements Validator
{
   @Inject
   UserService us;
   @Override
   public void validate(final FacesContext context, final UIComponent component, final Object value)
            throws ValidatorException
   {
      String field = value.toString();
      try
      {
         us.getUserByEmail(field);
         FacesMessage msg = new FacesMessage("That email address is unavailable");
         throw new ValidatorException(msg);
      }
      catch (NoSuchObjectException e)
      {
      }
   }
}

An example Converter using @Inject

@SessionScoped

@FacesConverter("authorConverter")
public class UserConverter implements Converter
{
   @Inject
   private UserService service;
 
   @PostConstruct
   public void setup()
   {
      System.out.println("UserConverter started up");
   }
 
   @PreDestroy
   public void shutdown()
   {
      System.out.println("UserConverter shutting down");
   }
 
   @Override
   public Object getAsObject(final FacesContext arg0, final UIComponent arg1, final String userName)
   {
      // ...
      return service.getUserByName(userName);
   }
 
   @Override
   public String getAsString(final FacesContext context, final UIComponent comp, final Object user)
   {
      // ...
      return ((User)user).getUsername();
   }
}

This is the list of inject-able artifacts provided through Seam Faces. These objects would normally require static method-calls in order to obtain handles, but Seam Faces attempts to break that coupling by providing @Inject'able artifacts. This means it will be possible to more easily provide mocked objects during unit and integration testing, and also simplify bean code in the application itself.

Artifact ClassExample
javax.faces.context.FacesContext
public class Bean {
   @Inject FacesContext context;
}
javax.faces.context.ExternalContext
public class Bean {
   @Inject ExternalContext context;
}
javax.faces.application.NavigationHandler
public class Bean {
   @Inject NavigationHandler handler;
}
javax.faces.context.Flash
public class Bean {
   @Inject Flash flash;
}

When the seam-faces module is installed in a web application, JSF events will automatically be propagated via the CDI event-bridge, enabling managed beans to easily observe all Faces events.

There are two categories of events: JSF phase events, and JSF system events. Phase events are triggered as JSF processes each lifecycle phase, while system events are raised at more specific, fine-grained events during request processing.

A JSF phase listener is a class that implements javax.faces.event.PhaseListener and is registered in the web application's faces-config.xml file. By implementing the methods of the interfaces, the user can observe events fired before or after any of the six lifecycle phases of a JSF request: restore view, apply request values, process validations, update model values, invoke application or render view.

What Seam provides is propagation of these Phase events to the CDI event bus; therefore, you can observe events using normal CDI @Observes methods. Bringing the events to CDI beans removes the need to register phase listener classes via XML, and gives the added benefit of injection, alternatives, interceptors and access to all other features of CDI.

Creating an observer method in CDI is simple; just provide a method in a managed bean that is annotated with @Observes. Each observer method must accept at least one method parameter: the event object; the type of this object determines the type of event being observed. Additional parameters may also be specified, and their values will be automatically injected by the container as per the CDI specification.

In this case, the event object passed along from the phase listener is a javax.faces.event.PhaseEvent. The following example observes all Phase events.



public void observeAll(@Observes PhaseEvent e)
{
    // Do something with the event object
} 

Events can be further filtered by adding Qualifiers. The name of the method itself is not significant. (See the CDI Reference Guide for more information on events and observing.)

Since the example above simply processes all events, however, it might be appropriate to filter out some events that we aren't interested in. As stated earlier, there are six phases in the JSF lifecycle, and an event is fired before and after each, for a total of 12 events. The @Before and @After "temporal" qualifiers can be used to observe events occurring only before or only after a Phase event. For example:



public void observeBefore(@Observes @Before PhaseEvent e)
{
    // Do something with the "before" event object
}
public void observeAfter(@Observes @After PhaseEvent e)
{
    // Do something with the "after" event object
} 

If we are interested in both the "before" and "after" event of a particular phase, we can limit them by adding a "lifecycle" qualifier that corresponds to the phase:



public void observeRenderResponse(@Observes @RenderResponse PhaseEvent e)
{
    // Do something with the "render response" event object
} 

By combining a temporal and lifecycle qualifier, we can achieve the most specific qualification:



public void observeBeforeRenderResponse(@Observes @Before @RenderResponse PhaseEvent e)
{
    // Do something with the "before render response" event object
} 

This is the full list of temporal and lifecycle qualifiers

QualifierTypeDescription
@BeforetemporalQualifies events before lifecycle phases
@AftertemporalQualifies events after lifecycle phases
@RestoreViewlifecycleQualifies events from the "restore view" phase
@ApplyRequestValueslifecycleQualifies events from the "apply request values" phase
@ProcessValidationslifecycleQualifies events from the "process validations" phase
@UpdateModelValueslifecycleQualifies events from the "update model values" phase
@InvokeApplicationlifecycleQualifies events from the "invoke application" phase
@RenderResponselifecycleQualifies events from the "render response" phase

The event object is always a javax.faces.event.PhaseEvent and according to the general CDI principle, filtering is tightened by adding qualifiers and loosened by omitting them.

Similar to JSF Phase Events, System Events take place when specific events occur within the JSF life-cycle. Seam Faces provides a bridge for all JSF System Events, and propagates these events to CDI.

Since all JSF system event objects are distinct, no qualifiers are needed to observe them. The following events may be observed:

Event objectContextDescription
SystemEventallAll events
ComponentSystemEventcomponentAll component events
PostAddToViewEventcomponentAfter a component was added to the view
PostConstructViewMapEventcomponentAfter a view map was created
PostRestoreStateEventcomponentAfter a component has its state restored
PostValidateEventcomponentAfter a component has been validated
PreDestroyViewMapEventcomponentBefore a view map has been restored
PreRemoveFromViewEventcomponentBefore a component has been removed from the view
PreRenderComponentEventcomponentAfter a component has been rendered
PreRenderViewEventcomponentBefore a view has been rendered
PreValidateEventcomponentBefore a component has been validated
ExceptionQueuedEventsystemWhen an exception has been queued
PostConstructApplicationEventsystemAfter the application has been constructed
PostConstructCustomScopeEventsystemAfter a custom scope has been constructed
PreDestroyApplicationEventsystemBefore the application is destroyed
PreDestroyCustomScopeEventsystemBefore a custom scope is destroyed

The Seam Faces module provides integration with the JSF project stage system. Beside the injection of the current project stage into beans, Seam Faces also allows to enable specific beans only for certain project stages.

Seam Faces provides a set of annotations that can be used to activate beans only in specific project stages. The following table shows the JSF project stages and the corresponding Seam Faces annotations.

Project StageProjectStage EnumSeam Faces Anntotation
ProductionProjectStage.Production@Production
DevelopmentProjectStage.Development@Development
UnitTestProjectStage.UnitTest@UnitTest
SystemTestProjectStage.SystemTest@SystemTest

To restrict a bean to a project stage just place the correspoding annotation on the class.

The following example shows a bean that logs the beginning and end of each JSF lifecycle phase. As the bean is annotated with @Development, it will only be activated if the application runs in the Development project stage.



@Development
public class PhaseEventLogBean {
    public void before(@Observes @Before PhaseEvent event) {
        log.debug("Before: " + event.getPhaseId());
    }
    
    public void after(@Observes @After PhaseEvent event) {
        log.debug("After: " + event.getPhaseId());
    }
}
        

Seam Faces will automatically detect the project stage that is used for the application. If you want Seam Faces to use a different project stage, you can use one of the following two ways.

The first possibility to change the project stage for Seam Faces is to set the system property org.jboss.seam.faces.PROJECT_STAGE. This option is the most easiest to use but is also very unflexible because the project stage be set for all applications running in a container.

-Dorg.jboss.seam.faces.PROJECT_STAGE=Development

If you need more control over the project stage that is used you can implement the Seam Faces SPI org.jboss.seam.faces.projectstage.ProjectStageDetector. Just implement this interface and add the fully-qualified classname of the class to the file META-INF/services/org.jboss.seam.faces.projectstage.ProjectStageDetector. See the following class for an example:



public class MyProjectStageDetector implements ProjectStageDetector {
    @Override
    public int getPrecedence() {
        return 10;
    }
    @Override
    public ProjectStage getProjectStage() {
    
        if (System.getProperty("user.name").startsWith("dev-")) {
            return ProjectStage.Development;
        }
        
        return ProjectStage.Production;
        
    }
}        
        

Seam Faces aims to provide JSF web developers with a truly worthy framework for web development by ironing out some of the JSF pain points, integrating tightly with CDI, and offering out of the box integration with the other Seam Modules. The view configuration presented here provides a central means of configuring seemingly disparate concerns.

Adhering to the CDI core tenet of type safety, Seam Faces offers a type-safe way to configure the behaviour of your JSF views. So far these configurable behaviors include:

  • Configuring view access by integrating with Seam Security

  • Configuring URL rewriting by integrating with Pretty Faces (or any other pluggable URL rewriting framework)

  • A personal favorite of the Seam Faces lead: setting faces-direct=true when navigating to a view.

The Seam Faces example application faces-viewconfig, demonstrates all the view configuration techniques discussed in this chapter.

Faces pages are configured by placing annotations on the properties of an Java enum. The annotation @ViewConfig is placed on a Java interface, which contains a static enum. It is the properties of this static enum that hold the individual annotations used to configure the view.



@ViewConfig
public interface Pages {
    static enum Pages1 {
        @ViewPattern("/admin.xhtml")
        @Admin
        ADMIN,
        
        @UrlMapping(pattern="/item/#{item}/")
        @ViewPattern("/item.xhtml")
        @Owner
        ITEM,
        
        @FacesRedirect
        @ViewPattern("/*")
        @AccessDeniedView("/denied.xhtml")
        @LoginView("/login.xhtml")
        ALL;
        
    }
}
        

The interface containing the enum is required due to a limitation in version 1.0 of the CDI specification. If the @ViewConfig is placed directly on the enum, the CDI specification does not require the annotations to be scanned.

Each property of the enum is annotated with at least the @ViewPattern annotation. This view pattern is used to match against the JSF view ids, to determine which annotations apply to a given view id. The view patterns themselves support the * wild character. A view is matched against all view parameters that apply to determine the relevant annotations. If conflicting annotations are found, the annotation paired with the most specific matching view pattern takes precedence.

Securing view access is achieved through integration with Seam Security, which must be explicitly bundled with your web application. Refer to the Seam Security documentation for details on how to setup authentication. What we'll cover here is the authorisation to JSF views.

Seam Faces delegates URL Rewriting to Pretty Faces. The Rewriting mechanism however is pluggable, and an alternate URL Rewriting engine could easily be used instead. What makes SeamFaces unique in it's approach to URL rewriting, is that the rewrite configuration is done via the @ViewConfig mechanism, so all view configuration is done consistently.

To configure UrlRewriting, use the @UrlRewrite Seam Faces annotation:



        ...
        @UrlMapping(pattern="/item/#{item}/")
        @ViewPattern("/item.xhtml")
        ITEM;
        ...
        

The above listing would rewrite the url /item.jsf/item=2 into /item/2/. See the Pretty Faces documentation for further details on configuring URL rewriting.

Seam Faces makes use of Solder Exception Handling, coupled with JSF2 exception handlers to provide a robust and complete means of handling exceptions that occur in a JSF application. For more information about using Solder Exception Handling, please see ???.

All exceptions that occur during the JSF life cycle should be caught by Seam Faces and passed along to Solder Exception Handling. There may be a few cases where this doesn't happen, fortunately, a Solder servlet filter acts as a catch all for exceptions and will pass along the uncaught exception.

Warning

Something that must be considered when handling an exception within the JSF life cycle is the phase in which the exception occurred. Most exceptions can be handled easily and a FacesMessage can be added and displayed to the user, or the user can be redirected to an error page. However, if the exception occurred in the RENDER_RESPONSE phase this is not the case. No redirection, or messages, or other output to the response can be used if the request is in this part of the life cycle. Please inject the FacesContext and determine the life cycle phase of the request before proceeding with exception handling.