SeamFramework.orgCommunity Documentation
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.
To secure a view, we start by
writing an annotation qualified with a @SecurityBindingType
qualifier:
@SecurityBindingType
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface Owner {
}
This @SecurityBindingType
qualified annotation is placed on an enum property in the
@ViewConfig
annotated interface
, adjacent to the @ViewPattern
to which the security restriction applies. View patterns with wildcards are supported for security
based annotations.
Methods that enforce the Security restriction are annotated with the @Secures
annotation, as well as the same @SecurityBindingType
qualified annotation used on the
@ViewConfig enum
property.
public @Secures @Owner boolean ownerChecker(Identity identity, @Current Item item) {
if (item == null || identity.getUser() == null) {
return false;
} else {
return item.getOwner().equals(identity.getUser().getId());
}
}
When a JSF view is visited, matching @ViewPattern
patterns are found, and their
associated @SecurityBindingType
qualified annotations are looked up. The
corresponding method is invoked, and access is either granted or denied. If access is denied, and the
user is not yet logged in, the user will be redirected to a view specified in a
@LoginView
annotation for that view. However if access is denied, and the user is
logged in, navigation will be redirected to a view specified in the @AccessDeined
annotation.
Refer to the Seam Security documentation for further details on writing @Secures
methods for restricting view access, including support for parameter injection.
By default, Security restrictions are enforced before the Invoke Application
phase,
and before the Render Response
phase. Restrictions are enforced twice per lifecycle,
as the view id normally changes at the end of the Invoke Application
phase. However,
use cases exist requiring enforcement of a Security restriction at a different phase. For instance it is
desirable to enforce a role-based restriction as early in the lifecycle as possible, to prevent any
unnecessary computations from occurring. This is achieved using the @RestrictAtView
annotation.
By qualifying a @SecurityBindingType
qualified annotation with the
@RestrictAtView
qualifier, one is able to specify at which phase that individual
Security restriction should be applied. Additionally, the @RestrictAtView
annotation
can be applied directly to a @ViewConfig enum
property, to determine the restriction
phase of all associated @SecurityBindingType
qualified annotations.
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.
A @ViewPattern
annotated with @FacesRedirect
will cause all
navigations to views that match that pattern to have their faces-redirect property set to true. This
alleviates the requirement to append ?faces-redirect=true
to all implicit navigation
rules, and neither does it have to be specified in the navigation rules defined in the faces-config.xml.