Sunday Sep 01

Key Concepts

Write a JSF 2 custom EL resolver

PDFPrintE-mail
Tuesday, 07 June 2011 10:14
AddThis Social Bookmark Button

JSF Custom EL resolver : PropertyResolver VariableResolver

The following example describe the creation and the configuration of a custom variable resolver or ELResolver using JSF .  The custom resolver we will implement will not implement VariableResolver or PropertyResolver but ELResolver to give you the fexibility to reuse the same implementation for different purpose.

In this example we want to retrieve a collection of JSF  configuration parameters using EL directly in our JSF  page. The keyword used to access the collection will be jsfConfigurations.

Let's define first feature description associated with our variable to resolve :

NameValue
NAME jsfConfigurations
DISPLAY_NAME Jsf configurations
DESCRIPTION JSF  configurations parameters
EXPORT false
HIDDEN false
PREFERRED true
TYPE List.class
RESOLVABLE_DESIGN_TIME Boolean.false

Let's implement ELresover interface. ELResolver enables customization of variable, property and method call resolution behavior for EL expression evaluation.

Implementation of a custom ELResolver

As properties of our EL resolver we will define the feature description for the feature descriptor. If we have multiple FeatureDescriptor we will probably not define those properties as constants. 

Spring java source

public class ConfigurationELResolver extends ELResolver {
    private static final Logger logger = Logger.getLogger(ConfigurationELResolver.class.getName());
    
    private final String NAME = "jsfConfigurations";
    private final String DISPLAYNAME = "Jsf configurations";
    private final String DESCRIPTION = "JSF2 configurations parameters";
    private final boolean EXPERT = false;
    private final boolean HIDDEN = false;
    private final boolean PREFERRED = true;
    private final Class<?> TYPE = List.class;
    private final boolean RESOLVABLE_DESIGN_TIME = Boolean.FALSE;
    .....

Return the correponding value

In the implementation of the getValue() we will return the Configuration items if the property requested correponds to the NAME constants (jsfConfigurations)

Spring java source

 
    @Override
    public Object getValue(ELContext context, Object base, Object property) {
        logger.info("get Value property : "+ property);
        if (NAME.equals(property) && getConfigurationItems() != null){
            logger.info("found configuration request "+ base);
            context.setPropertyResolved(true);
            List<ConfigurationItem> values = getConfigurationItems();
            Collections.sort(values);
            return values;
        }
        return null;
    }

Return the corresponding value type

For a given base and property this method attempts to identify the most general acceptable type for the corresponding property. jsfConfigurations is suppose to return a list of object.

Spring java source

    @Override
    public Class<?> getType(ELContext context, Object base, Object property) {
        if (base != null) return null;
        if (property == null) {
            String message = MessageUtils.getExceptionMessageString
                (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
            throw new PropertyNotFoundException(message);
        }
        if (NAME.equals(property) && getConfigurationItems() != null) {
            context.setPropertyResolved(true);
            return TYPE;
        }
        return null;
    }

EL Resolver base Allowing base to be null for the first part of the expression is the key enabling concept that permits the JSF  1.1 concepts of VariableResolver and PropertyResolver to be combined into the ELResolver. When the base argument is null, an ELResolver functions much like a VariableResolver. Otherwise, it functions as a PropertyResolver.

Implement setValue() method

Attempts to set the value of the given property  object on the given base  object. jsfConfigurations is a read only variable. We return a PropertyNotWritableException if someone try to edit our variable.

JSF custom ELResolver

    @Override
    public void setValue(ELContext context, Object base, Object property,
            Object value) {
        if (base != null) return;
        if (property == null) {
            String message = MessageUtils.getExceptionMessageString
                (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
            throw new PropertyNotFoundException(message);
        }
        if (NAME.equals(property)) {
            throw new PropertyNotWritableException((String) property);
        }
    }

Read only

Our variable is read only

JSF writing el resolver

@Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {
        if (NAME.equals(property)) {
            return true;
        }
        return true;
    }

Feature description

The following method return an iterator returning information about the set of variables or properties that can be resolved.

ELResolver feature

    @Override
    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context,
            Object base) {
        if (base != null) return null;
        ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(14);
        list.add(Util.getFeatureDescriptor(
                    NAME, 
                    DISPLAYNAME,
                    DESCRIPTION,
                    EXPERT, 
                    HIDDEN, 
                    PREFERRED, 
                    TYPE, 
                    RESOLVABLE_DESIGN_TIME)
        );
        return list.iterator();
    }

Common property type

Returns the most general type that this resolver accepts

ELResolver return type

    @Override
    public Class<?> getCommonPropertyType(ELContext context, Object base) {
        if (base != null) return null;
        return String.class;
    }

Return the collection

The last method return the collection needed by the getValue() method. In this example we are using the static attribute defined in our ApplicationBB backing bean.

ELResolver return a collection

    private List<ConfigurationItem> getConfigurationItems(){
        return ApplicationBB.getConfigurationItems();
    }

Configure our EL Resolver in the webapp

Finally declaring the custom resolver in the faces-config is needed in order to put them to the responsibility chain.

The el-resolver element is used to specify the fully qualified class name of a javax.el.ELResolver implementation class that will replace the JSF  implementation’s default expression language resolver implementation. The expression language resolver is called each time an expression
must be resolved. The el-resolver element provides the ability to override the default JSF  expression language resolving by plugging in a custom ELResolver.

EL Resolver configuration in JSF 2 faces_config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
    <application>
        <el-resolver>
            com.ubiteck.jsf.util.ConfigurationELResolver
        </el-resolver>
    </application>
</faces-config>

EL-resolver listener start error  If you are facing a listener start error check if you have correctly defined the class in your EL-resolver. If your logging configuration is not properly defined you we not be able to see the ClassNotFoundException

Display the el expression in a datatable

As a conclusion you are now able to access your newly defined variable and iterate to display it in a data table

javax.el.ELResolver

            <h3><a href="http://java-tutorial.ch/java-server-faces" title="JSF">JSF <img src="http://www.java-tutorial.ch//administrator/components/com_acesef/assets/images/icon-10-external.png"/></a> Configuration</h3>
            <h:dataTable id="jsfConfigurationTable" value="#{jsfConfigurations}" var="config">
                <h:column>
                    <f:facet name="header"><h:outputText style="font-weight: bold;" value="name"/></f:facet>
                    #{config.name}
                </h:column>
                <h:column>
                    <f:facet name="header"><h:outputText style="font-weight: bold;" value="description"/></f:facet>
                    #{config.value}
                </h:column>
                <h:column>
                    <f:facet name="header"><h:outputText style="font-weight: bold;" value="defaultValue"/></f:facet>
                    #{config.defaultValue}
                </h:column>
            </h:dataTable>

The result shoud look like

JSF  Configuration

namedescriptiondefaultValue
com.sun.faces.NUMBER_OF_VIEWS_IN_LOGICAL_VIEW_IN_SESSION 15
com.sun.faces.NUMBER_OF_VIEWS_IN_SESSION 15
com.sun.faces.annotationScanPackages
com.sun.faces.clientStateTimeout
com.sun.faces.clientStateWriteBufferSize 8192
com.sun.faces.compressableMimeTypes
com.sun.faces.defaultResourceMaxAge 604800000
com.sun.faces.disableUnicodeEscaping auto
com.sun.faces.duplicateJARPattern
com.sun.faces.expressionFactory com.sun.el.ExpressionFactoryImpl com.sun.el.ExpressionFactoryImpl
com.sun.faces.faceletCache
com.sun.faces.faceletFactory
com.sun.faces.injectionProvider
com.sun.faces.managedBeanFactoryDecoratorClass
com.sun.faces.numberOfConcerrentFlashUsers 5000
com.sun.faces.numberOfFlashesBetweenFlashReapings 5000
com.sun.faces.numberOfLogicalViews 15
com.sun.faces.numberOfViewsInSession 15
com.sun.faces.resourceBufferSize 2048
com.sun.faces.resourceUpdateCheckPeriod 5
com.sun.faces.responseBufferSize 1024
com.sun.faces.serializationProvider
facelets.BUFFER_SIZE 1024
facelets.DECORATORS
facelets.LIBRARIES
facelets.REFRESH_PERIOD 2
facelets.RESOURCE_RESOLVER
facelets.VIEW_MAPPINGS
javax.faces.CONFIG_FILES
javax.faces.DEFAULT_SUFFIX .xhtml .xhtml .jsp
javax.faces.FACELETS_BUFFER_SIZE 1024
javax.faces.FACELETS_DECORATORS
javax.faces.FACELETS_LIBRARIES /WEB-INF/tags/ubiteck.taglib.xml
javax.faces.FACELETS_REFRESH_PERIOD 2
javax.faces.FACELETS_RESOURCE_RESOLVER
javax.faces.FACELETS_SUFFIX .xhtml
javax.faces.FACELETS_VIEW_MAPPINGS
javax.faces.FULL_STATE_SAVING_VIEW_IDS
javax.faces.LIFECYCLE_ID
javax.faces.PROJECT_STAGE Development Production
javax.faces.RESOURCE_EXCLUDES .class .jsp .jspx .properties .xhtml .groovy
javax.faces.STATE_SAVING_METHOD server
javax.faces.VALIDATE_EMPTY_FIELDS auto

Conclusion

As you have seen, the unified EL provides more features like a pluggable, extensible resolver machinery, and a way to set data and invoke methods from the page.

If you have any remark or questions feel free to put a comment.If you enjoyed this tutorial and want to promote it don't hesitate to click on


Tags: class, public, object, facet, expression, return, resolver, column

Add comment


Security code
Refresh

Java Tutorial on Facebook