Easy Page Actions with FaceletsBy Roger Keays, 28 August 2007, 4:09 PM |
It appears that everybody has come up with their own way to implement page actions in JSF. i.e. execute some code before a page is processed/rendered, like you did in Struts. Well, it turns out that I occasionally need this too (surprisingly infrequently though), so I had a look at how Shale and Seam solve the problem.
Shale uses faces-config.xml to map view ids to managed beans which implement a ViewController interface [1]. Okay, that seems alright, but it means more xml and more classes. Often I just need to put a request-scope attribute in place, so this feels like too much work to me. Seam allows you to map view ids to method expressions via a pages.xml configuration file [2]. This means no extra beans, but does mean more configuration. Can it be done with no xml and no new beans?
Yes! And the tool for the job has probably been in your toolkit all along - Facelets TagHandlers.
Easy Page Actions with FaceletsThere are two advantages to using TagHandlers to implement page actions:
The Java code for the TagHandler is very simple:
/**
* This tag evaluates a method expression, so it can be used to implement
* 'page actions' since it is only executed when the view is built.
*/
public class ActionHandler extends TagHandler {
private final TagAttribute method;
public ActionHandler(TagConfig config) {
super(config);
this.method = this.getRequiredAttribute("method");
}
/** evaluate the method expression */
public void apply(FaceletContext ctx, UIComponent parent) {
method.getMethodExpression(ctx, null, new Class[] {}).
invoke(ctx.getFacesContext().getELContext(), null);
}
}
To use the action, you must map it in your facelets taglib:
...
<tag>
<tag-name>action</tag-name>
<handler-class>furnace.core.tags.ActionHandler</handler-class>
</tag>
and then put it into the template where it is needed, e.g.:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:fc="http://www.ninthavenue.com.au/furnace/core">
<!-- merge the user into the current persistence context -->
<fc:action method="${modules.forums.mergeUser}"/>
<!-- then show their profile -->
<h:outputText value="${user.name}"/>
...
</ui:composition>
You should note though, that the TagHandlers aren't invoked on a postback, so if this is a part of your requirements you could use a PhaseListener, or the Seam or Shale approach.
This code will be available in the next version of the Furnace Webapp Framework.
[1] http://shale.apache.org/shale-view/index.html
[2] http://docs.jboss.org/seam/1.2.1.GA/reference/en/html/events.html#d0e3776
![]() |
Roger is an active member of the JSF 2 Expert Group and is happy to be a contributor to the Java Community. He has been writing software since the age of 8 and his other interests include languages, science, travel and surfing. You can follow Roger on Twitter and Google+. |
| « Centering Multiple Line Content with CSS | Back to Blog | Making the www part optional » |