09/04/2007
How to invoke method expressions with parameters in JSF?

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 Nuxeo 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?

Nuxeo Tag Library documentation: http://maven.nuxeo.org/nuxeo-platform-parent/nuxeo-platform-ui-web/tlddoc/.

Complete code mentioned above is available here:

Posted by Anahide Tchertchian @ 09/04/2007 04:13 PM. - Categories: nuxeo5 -  0 comments
09/30/2005
RDF relations in CPS
A new Zope product, CPSRelation, has been designed to handle RDF relations within  the CPS framework: it gives access to any kind of content RDF indexation and serialization, as well as querying features.

CPSRelation offers RDF features installing a tool, portal_relations, that is able to manage several kinds of graphs. Another tool, portal_serializer, has been designed to provide object serializations via pluggable TALES expressions.

We've been using IOBTree graphs to handle relations between documents, using their docid in the repository as unique identifiers. Now we can also handle RDF relations, provided by the rdflib Python library and the Redland framework.

We have tested Redland graphs to index and serialize CPS content, and query relations created in the graph. The mechanism is rather simple:
  • add a Redland graph with an appropriate supported backend in the portal_relations tool.
  • define a serializer for each kind of content to get the triples to add to the graph, or define triples manually.
  • use the portal_relations API to add/delete relations and query the graph created.
  • use the portal_serializer API to serialize as RDF/XML files the graph, or results of a query.

The product's SVN repository is here: http://svn.nuxeo.org/trac/pub/browser/CPSRelation/trunk/
And can be downloaded using
svn co http://svn.nuxeo.org/pub/CPSRelation/trunk CPSRelation

Additional information:
Posted by Anahide Tchertchian @ 09/30/2005 09:38 PM. - Categories: cps, rdf, semantic_web -  0 comments
06/16/2005
CPSWorkflow Documentation
Woke up this morning, can't believe what I saw: CPSWorkflow documentation was out !

You can find it at the following URL:
http://www.cps-project.org/sections/documentation/developers/cpsworkflow/switchLanguage/en
A Zope product comes with this documentation, as it is constructed as a tutorial.

I hope the document construction makes it easy to understand how CPS workflows work, and how powerful they can be.
The sample workflow is quite simple because I did not want to present a complicated example.

Hope you'll enjoy, any kind of feedback is very welcome.
Posted by Anahide Tchertchian @ 06/16/2005 12:24 PM. - Categories: cps -  0 comments
Last modified: 05/10/2005 04:17 AM

Nuxeo Bloggers: Log in!
Nuxeo - Indesko - Nuxeo 5 Project
All content is copyrighted by their author.
CPSSkins is Copyright © 2003-2006 by Jean-Marc Orliaguet. | CPS is Copyright © 2002-2006 by Nuxeo SAS.