Easy Page Actions with Facelets

By , 28 August 2007

Easy Page Actions with Facelets

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 Facelets

There are two advantages to using TagHandlers to implement page actions:

  1. They are only executed once during the tree build, so don't interfere with the rest of the lifecycle or cause EL to be evaluated multiple times (like some components).
  2. There is no need to map the view id since the TagHandler is placed directly in the template for the view.

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.

References

[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

About Roger Keays

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.

Comment posted by: , 5 years ago

The method you bind to can just have no parameters and a void return type, e.g:

public void mergeUser() {
   user = em.merge(user);
}
Comment posted by: cp, 5 years ago

cool. tnx 

Comment posted by: Tim Büthe, 5 years ago

Hi,

can I somehow make this work with JSF 1.1? The method getELContext is new in 1.2, so I get an error in this line:

invoke(ctx.getFacesContext().getELContext(), null);

regards,

Tim

Comment posted by: Shane Genschaw, 5 years ago

Tim, change it "invoke(ctx, null);" instead.  (FaceletsContext extends ELContext).

-Shane

Add a comment

Please visit http://www.NinthAvenue.com.au/blog/easy-page-actions-with-facelets to add your comments.

Join The Mailing List

Subscribe to our mailing list for the latest news and announcements.

Follow Ninth Avenue

Get Results With Women

Website Updates