Monday, April 18, 2011

Seam Module Spotlight: Seam Faces

This is a blog entry I wrote for in.relation.to. I'm including it here to keep a personal record of the post.



In this entry for the Seam Module Spotlight series, we will take a close look at the “view configuration” feature of Seam Faces.

Seam Faces aims to provide JSF developers with a truly worthy framework for web development by ironing out some of JSF’s pain points, integrating tightly with CDI, and offering out of the box integration with the other Seam Modules and third party libraries. Part of achieving this goal involves providing a means to centrally configure each of these seemingly disparate concerns, without having to create any JSF Phase listeners, nor maintain a bunch XML files.

Adhering to the CDI core tenet of type safety, Seam Faces offers a type-safe mechanism to configure the behaviour of your JSF views. So far these configurable behaviors include:
  1. Restricting view access by integrating with Seam Security
  2. Configuring URL rewriting by integrating with PrettyFaces (or any other pluggable URL rewriting framework)
  3. Configuring Transactions via Seam Persistence
  4. And a personal favorite: setting “?faces-redirect=true” when navigating to a view.
Note: the above integrations are optional, you must include the relevant jars in the application for their respective configurations to have any effect

Lets take a closer look at the View configuration from the Seam Faces example “faces-viewconfig”:

@ViewConfig
public interface Pages {

  static enum Pages1 {

      @ViewPattern("/admin.xhtml")
      @Admin
      ADMIN,

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

      @ViewPattern("/*")
      @FacesRedirect
      @AccessDeniedView("/list.xhtml")
      @LoginView("/login.xhtml")
      ALL;

  }
}
At first glance, the structure of the above configuration might appear odd. The @ViewConfig annotation is on the interface, and the interface is nothing more than a container for a static enum. This arrangement is unfortunately required by the current CDI specification for the view configuration annotations to be scanned, and will hopefully be corrected in future iterations of the CDI spec.

The properties of the enum are annotated with a @ViewPattern annotation, specifying to which views the adjacent annotations apply. ViewPatterns support wildcards, and matches are made to a particular view weighted by the specificity of the match; therefore, if two annotations paired with different @ViewPatterns conflict for a given view, the annotation paired with the more specific @ViewPattern takes precedence.

Seam Security via the @ViewConfig
Now let’s look at the Seam Security annotations @Admin and @Owner. These annotations are user-provided, meaning they were built solely for this example, and are qualified with the Seam Security qualifier: @SecurityBindingType. When a view is requested that matches a pattern in the @ViewConfig annotated with such an annotation, Seam Faces invokes Seam Security to determine if access should be granted. Authorization is evaluated with the following class:

public class SecurityRules {
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());
}
}

public @Secures @Admin boolean adminChecker(Identity identity) {
if (identity.getUser() == null) {
return false;
} else {
return "admin".equals(identity.getUser().getId());
}
}
}

In this way, views annotated with the @Owner annotation are secured by the @Secures method annotated with the same @Owner annotation. Coupled with parameter injection, this is truly a declarative syntax for securing view access.

Furthermore, the @Admin annotation is defined with an additional qualifier:
@RestrictAtPhase(PhaseIdType.RESTORE_VIEW)
This annotation causes the security restriction to be applied at the “Restore View” phase, rather than the default phases: “Invoke Application” and “Render Response”. These default phases were chosen in order for application data to be present and allow access restrictions to be contextual. The default phases also mean that the security restrictions are evaluated twice per lifecycle, as the view often changes at the end of the “Invoke Application” phase.

URL rewriting via the @ViewConfig
The view config also let’s us configure URL rewriting for a view using the @UrlMapping annotation. In the above @ViewConfig, the URL /item.jsf?item =1 would get mapped into /item/1/, courtesy of PrettyFaces and the annotation: @UrlMapping(“/item/#{id}”). In this mapping, “#{id}” tells the rewriting-engine to treat the last portion of the URL as the value of the the query-parameter named “id”. By integrating the configuration of rewriting URLs alongside the rest of the view configuration, Seam Faces attempts to make this powerful technology more accessible, and a core part of JSF application development.

Setting faces-redirect=true
A seemingly simple annotation, @FacesRedirect is a surprisingly useful one. When this annotation is present with a @ViewPattern, any navigation to a matching view is intercepted, and the faces-redirect attribute is activated. In the provided example the @FacesRedirect annotation is applied once to the pattern “/*”, which applies the configuration to all views. One could optionally override this catch all setting on a more specific pattern, or on an individual view, with the annotation @FacesRedirect(false). This annotation has a special place close to my heart - no more “?faces-redirect=true” peppered throughout any more applications!

Seam Persistence via the @ViewConfig
Last, but not least, there is the SeamManagedTransaction annotation that can be applied in the @ViewConfig. This allows transactional behaviour to be defined on a per view basis. Exploring the possibilities here will be the subject matter for a subsequent post.

The future for the @ViewConfig component of Seam Faces is bright, with many more capabilities to be added. In addition, the @ViewConfig presented here is merely a front-end to an internal store of the view configuration data. This opens up the possibility of providing alternate means of populating the view config data store, writing extensions to perform custom operations on view config data for your individual application, and more. One solution being explored is to introduce child tags to the f:metadata tag, which will allow view related concerns to be defined from within the view itself. Additionally, configuration sources like xml and database persistence could be incorporated to provide developers with more options.

Seam Faces provides a centralised, type safe way of configuring the behaviour of your JSF views. Try the ViewConfig out and be sure to send in your feedback. This is still early days for the feature, and all feedback is very much appreciated!

Sunday, April 3, 2011

RichFaces Plugin for Seam Forge

If you haven't yet heard about it, Seam Forge is a fantastic new tool from JBoss for rapid application development of standards based applications. Forge allows a developer to quickly set up the scaffolding for an application, and quickly get to the matter of solving domain problems.

What makes Forge particularly interesting, from my perspective, is the way it was built with plugins in mind as a defining way in which the platform is meant to be extended. To take this new tool for a spin, I created a Forge plugin for RichFaces - the killer component kit for JSF 2.

For instructions on installing Forge, refer to the Forge Documentation. The following guide assumes you have Forge installed and functional.

** The instructions in this blog are for the 0.1.0 version of the RichFaces plugin for Seam Forge. See the project's README.txt for update usage instructions. **


First, lets install the RichFaces plugin for forge (installing from git!):
$ forge git-plugin git://github.com/bleathem/richfaces-forge-plugin.git

Forge makes it easy to create a new project:
$ new-project --named richfacesApp --topLevelPackage ca.bleathem.richfaces.test --projectFolder richfacesApp

Next, make the project a Java EE wep app, by installing the "servlet facet":
$ project install-facet forge.spec.servlet

Now, we can run the "richfaces" command, with no arguments to see the options available:
$ richfaces
Use the install commands to install:
  install-base: maven dependencies, and web.xml configuration
  install-example-facelet: a sample RichFaces enabled facelet file with backing bean
  install: both base and example-facelet

Running "richfaces install" duplicates the behaviour of the existing RichFaces maven archetype. If you have an existing project, and you just want to use forge to add the RichFaces dependencies and setup the web.xml, run "richfaces isntall-base". For our vanilla application, we'll run the full install, and see a simple facelet page with an input component "ajaxified" with RichFaces.

$ richfaces install
***SUCCESS*** RichFaces BOM dependency has been installed.
***SUCCESS*** org.richfaces.ui:richfaces-components-ui:4.0.0.Final dependency has been installed.
***SUCCESS*** org.richfaces.core:richfaces-core-impl:4.0.0.Final dependency has been installed.
***SUCCESS*** javax.servlet:servlet-api dependency has been installed.
***SUCCESS*** javax.servlet.jsp:jsp-api dependency has been installed.
***SUCCESS*** javax.servlet:jstl dependency has been installed.
***SUCCESS*** net.sf.ehcache:ehcache dependency has been installed.
***SUCCESS*** javax.faces.PROJECT_STAGE context-param has been installed.
***SUCCESS*** javax.faces.SKIP_COMMENTS context-param has been installed.
***SUCCESS*** Faces Servlet mapping has been installed.
Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/WEB-INF/web.xml
Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/templates/template.xhtml
***SUCCESS*** template.xhtml file has been installed.
Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/index.xhtml
***SUCCESS*** index.xhtml file has been installed.
Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/java/ca/bleathem/richfaces/test/RichBean.java
***SUCCESS*** RichBean class has been installed.

This new RichFaces enabled maven project is ready to be opened up in your favorite IDE (I used Netbeans) and run in your preferred run-time container (I used Glassfish 3.1).

This is early days for this plugin. I achieved my initial goal of being functionally equivalent to the maven archetype, but there is plenty of room for improvement. Some of my ideas are:

  • Make the sample facelet page more attractive, and showcase more of RichFaces capabilities
  • Test and support the generated application in more containers - including Servlet 2.5
  • Scan and convert vanilla facelet tags (or tags from other frameworks) converting them to RichFaces components. I'm thinking specifically dataTables, but I'm sure this would work well for other components.

Fork away, lets show the power of Seam Forge with the RichFaces plugin!