JSF/Facelets

Cet article décrit comment intégrer les tags du framework Shale Validator avec Facelets. Il s'agit notamment d'indiquer à Facelets comment interpréter les tags <s:commonsValidator>, <s:validatorVar> et <s:validatorScript>. Par exemple:

 
  <s:commonsValidator type="minlength" arg="#{bundle['login.login']}" server="true" client="true" minlength="4"/>
  <s:commonsValidator type="mask" arg="#{bundle['login.login']}" server="true" client="true">
    <s:validatorVar name="mask" value="^[a-zA-Z0-9]*$"/>
  </s:commonsValidator>
  <s:validatorScript functionName="validateForm"/>
  

Handler pour CommonsValidator

Un handler spécifique facelets doit être redéfini afin de pouvoir prendre en compte les variables de commons validator renseignées avec le tag <s:validatorVar>. L'exemple ci-dessous permet de traiter uniquement le cas de la variable "mask", mais la classe handler peut être facilement étendue afin de prendre en compte d'autres variables. A noter que ce handler n'hérite pas de ValidatorHandler, car précisément, la méthode apply() (méthode finale) de ValidatorHandler ne propage pas le traitement aux handlers fils. Le code ci-dessous est donc une copie de la classe ValidatorHandler qui permet de propager le traitement au handler du tag <s:validatorVar>.

 package fr.icodem.facelets.shale;
 
 public class CommonsValidatorHandler extends MetaTagHandler {
 
   // ************ validatorVar tag ************
   // set mask variable on commons validator
   public static class MaskMetadata extends Metadata {
     public void applyMetadata(FaceletContext ctx, Object instance) {
       ValueExpression var = ctx.getVariableMapper().resolveVariable("mask");
       if (var != null) {
         String expression = var.getExpressionString();
         CommonsValidator v = (CommonsValidator)instance;
         v.setMask(expression);
       }
     }
   }
 
   private final TagAttribute binding;
  
   private String validatorId = "org.apache.shale.CommonsValidator";
 
   public CommonsValidatorHandler(TagConfig config) {
     super(config);
     this.binding = this.getAttribute("binding");
   }
 
   public final void apply(FaceletContext ctx, UIComponent parent)
          throws IOException, FacesException, FaceletException, ELException {
 
     if (parent == null || !(parent instanceof EditableValueHolder)) {
          throw new TagException(this.tag,
                   "Parent not an instance of EditableValueHolder: " + parent);
     }
       
     // ************ validatorVar tag ************
     // get validator vars
     if (nextHandler != null) nextHandler.apply(ctx, parent);
 
     // only process if it's been created
     if (parent.getParent() == null) {
       // cast to a ValueHolder
       EditableValueHolder evh = (EditableValueHolder) parent;
       ValueExpression ve = null;
       Validator v = null;
       if (this.binding != null) {
         ve = this.binding.getValueExpression(ctx, Validator.class);
         v = (Validator) ve.getValue(ctx);
       }
       if (v == null) {
         v = this.createValidator(ctx);
         if (ve != null) {
           ve.setValue(ctx, v);
         }
       }
       if (v == null) {
         throw new TagException(this.tag, "No Validator was created");
       }
       this.setAttributes(ctx, v);
       evh.addValidator(v);
     }
   }
 
   protected Validator createValidator(FaceletContext ctx) {
     if (this.validatorId == null) {
       throw new TagException(
                   this.tag,
                   "Default behavior invoked of requiring a validator-id " + 
                   "passed in the constructor, must override ValidateHandler(ValidatorConfig)");
       }
       return ctx.getFacesContext().getApplication().createValidator(
               this.validatorId);
   }
 
   // ************ commons validator tag ************
   // create specific rule set
   @SuppressWarnings("unchecked")
   protected MetaRuleset createMetaRuleset(Class type) {
     MetaRuleset  metaRuleset = super.createMetaRuleset(type)
                                             .ignore("binding")
                                             .alias("minlength", "minLength")
                                             .alias("maxlength", "maxLength")
                                             .add(new MaskMetadata());
   	
     return metaRuleset;
   }
 }

Handler pour ValidatorVar

Ce handler permet de placer dans le context de Facelets les variables renseignées avec le tag <s:validatorVar>.

 public class ValidatorVarHandler extends TagHandler {
 
   // possible attributes
   private final TagAttribute name;
   private final TagAttribute value;
 
   public ValidatorVarHandler(TagConfig config) {
     super(config);
     this.name = getRequiredAttribute("name");
     this.value = getRequiredAttribute("value");
   }
 
   @Override
   public void apply(FaceletContext ctx, UIComponent parent)
              throws IOException, FacesException, ELException {
     String nameStr = this.name.getValue(ctx);	
     ValueExpression veObj = this.value.getValueExpression(ctx, Object.class);
     ctx.getVariableMapper().setVariable(nameStr, veObj);
   }
 }

Fichier taglib Facelets pour Shale

Les handlers définis précédemment sont utilisés dans le fichier shale.taglib.xml :

 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE facelet-taglib PUBLIC
   "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
   "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
 
 <facelet-taglib>
   <namespace>http://shale.apache.org/core</namespace>
     <tag>
       <tag-name>commonsValidator</tag-name>
       <handler-class>org.librairie.web.CommonsValidatorHandler</handler-class>
   </tag>
   <tag>
     <tag-name>validatorScript</tag-name>
     <component>
       <component-type>org.apache.shale.ValidatorScript</component-type>
     </component>
   </tag>
   <tag>
     <tag-name>validatorVar</tag-name>
     <handler-class>org.librairie.web.ValidatorVarHandler</handler-class>
   </tag>
 </facelet-taglib>