2009 update: you should be looking at jboss-el if you'd like to get an esay integration of parameters handling in your application.

The usual way to use EL expression in JSF could seem a little too
restrictive for some of us who are used to scripting languages.

For instance, if you'd like to display a bean property, you will write a
getter on it:

public class MyBean {

String myProperty;

public String getMyProperty() {
return myProperty;
}

}


Then you'll be able to write the following value expression in a template:

<h:outputText value="#{myBean.myProperty}" />

Now imagine that your bean has to perform a more complex task to retrieve the property, like calling a service, and pass parameters to it. Even if there is always the possibility to pass the parameter using a "f:parameter" tag, the bean API will look kind of awkward. The more natural way to do so is to write a method with this parameter, and find a way to call it from the template.

For instance, we could have:

public String getMyProperty(String param) {
// execute any function to get the result
return function(param);
}
<h:outputText value="#{myBean.getMyProperty('foo')}" />

Sadly, there is no way to do that using "pure" JSF implementations.

That's where facelets can be very handy. In a very nice blog post, Andrew Robinson explains how to pass method bindings to children components using the facelet user tag system. I will explain how the Nuxeo Platform uses the same tricks to invoke method expressions with parameters as regular value expressions.

First let's define the famous MethodValueExpression class, that will behave
as a regular value expression but will invoke a method expression when
trying to resolve the value:

public class MethodValueExpression extends ValueExpression implements
Externalizable {

public MethodValueExpression(MethodExpression methodExpression,
Class[] paramTypesClasses) {
this.methodExpression = methodExpression;
this.paramTypesClasses = paramTypesClasses;
}

...

@Override
public Object getValue(ELContext context) {
// invoke method instead of resolving value
Object res;
try {
return methodExpression.invoke(context, paramTypesClasses);
}
catch(Throwable t) {
return null;
}
}

}


Nuxeo benefits from an extension to the EL provided by Seam: it makes it possible to use parameters on any method expression without having to configure parameter types. That's why parameter types classes are never actually set in the Nuxeo code.

When this is done, we can use facelets meta rules to use this class instead
of the generic one. This is done via a component handler:

public class GenericHtmlComponentHandler extends HtmlComponentHandler {

...

protected MetaRuleset createMetaRuleset(Class type) {
MetaRuleset m = super.createMetaRuleset(type);
if (ValueHolder.class.isAssignableFrom(type)) {
m.addRule(GenericValueHolderRule.Instance);
}
return m;
}

}


This configuration tells to use the GenericValueHolderRule class when
setting a component attributes. This rule does not do much but use our MethodValueExpression when appropriate, e.g. when brackets are detected.

We can configure tags to use this handler in a facelet taglib:

<tag>
<tag-name>outputText</tag-name>
<component>
<component-type>javax.faces.HtmlOutputText</component-type>
<renderer-type>javax.faces.Text</renderer-type>
<handler-class>org.nuxeo.ecm.platform.ui.web.tag.handler.GenericHtmlComponentHandler</handler-class>
</component>
</tag>

Note that there is no need to use another term than "value" as shown in this
code (using "genericValue") as the last rule added to the MetaRuleSet will
apply first and override the default behaviour.

The nxh taglib, using the namespace "http://nuxeo.org/nxweb/html" redefines all basic jsf html tags to use this handler.

We could add any number of attributes to be dealt in the same way than
"value": for instance, being able to write <nxh:outputText
rendered="#{myBean.getProperty('foo')}" /> can be handy too.

Now it can a little painful to define a new taglib with this handler when
reusing custom tag libraries. The Nuxeo tag library defines a new tag
"nxu:methodResult", that will make the result of the given expression
available in the variable map:

<nxu:methodResult name="prop" value="#{myBean.getMyProperty('foo'}">
<h:outputText value="foo" rendered="#{prop == 'bar'}" />
</nxu:methodResult>

The variable named "prop" is available inside the methodResult tag, as a row
variable in a "h:dataTable" tag.

This behaviour is achieved using a specific tag handler that will use the
MethodValueExpression presented above:

public class MethodResultTagHandler extends MetaTagHandler {

private final TagAttribute name;

private final TagAttribute value;

public MethodResultTagHandler(TagConfig config) {
super(config);
name = getRequiredAttribute("name");
value = getRequiredAttribute("value");
}

public void apply(FaceletContext ctx, UIComponent parent)
throws IOException {
String nameStr = name.getValue(ctx);
// parameter types evaluation not needed using Seam
MethodExpression meth = value.getMethodExpression(ctx, Object.class,
new Class[0]);
ValueExpression ve = new MethodValueExpression(meth, paramTypesClasses);
ctx.getVariableMapper().setVariable(nameStr, ve);
this.nextHandler.apply(ctx, parent);
}

}


This tag handler is linked to the MethodResult tag in a taglib file:

<tag>
<tag-name>methodResult</tag-name>
<handler-class>org.nuxeo.ecm.platform.ui.web.tag.handler.MethodResultTagHandler</handler-class>
</tag>

Nice, huh?

Hey, Nuxeo is hiring! Why don't you check our cool jobs offers in Paris and Boston?