2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Coverage Report - org.apache.shale.validator.faces.ValidatorScript
 
Classes in this File Line Coverage Branch Coverage Complexity
ValidatorScript
100%
209/209
N/A
4.056
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to you under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.shale.validator.faces;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Iterator;
 23  
 import java.util.LinkedHashMap;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 import javax.faces.component.EditableValueHolder;
 28  
 import javax.faces.component.UIComponent;
 29  
 import javax.faces.component.UIComponentBase;
 30  
 import javax.faces.component.UIForm;
 31  
 import javax.faces.component.UINamingContainer;
 32  
 import javax.faces.context.FacesContext;
 33  
 import javax.faces.context.ResponseWriter;
 34  
 import javax.faces.el.ValueBinding;
 35  
 import org.apache.commons.validator.ValidatorAction;
 36  
 import org.apache.commons.validator.Var;
 37  
 import org.apache.shale.util.Tags;
 38  
 import org.apache.shale.validator.CommonsValidator;
 39  
 
 40  
 /**
 41  
  * <p>A JSF component that encodes JavaScript for
 42  
  *    all client-side validations specified in the same
 43  
  *    JSP page (with <code>s:commonsValidator</code>.
 44  
  *
 45  
  * $Id: ValidatorScript.java 464373 2006-10-16 04:21:54Z rahul $
 46  
  */
 47  13
 public class ValidatorScript extends UIComponentBase {
 48  
 
 49  
 
 50  
     // -------------------------------------------------------- Private Variables
 51  
 
 52  
 
 53  
     /**
 54  
      * <p>The value of the <code>functionName</code> property.</p>
 55  
      */
 56  
     private String functionName;
 57  
 
 58  
 
 59  
     /**
 60  
      * <p>A map of validators, representing all of the Commons Validators
 61  
      *    attached to components in the current component hierarchy.
 62  
      *    The keys of the map are validator type names. The values are
 63  
      *    maps from IDs to CommonsValidator objects.</p>
 64  
      */
 65  13
     private Map validators = new LinkedHashMap();
 66  
 
 67  
 
 68  
     /**
 69  
      * <p>Holds vars loaded with EL that are evaluated at render time.
 70  
      * The key into the map is the component's client id.</p>
 71  
      */
 72  13
     private Map validatorVars = new LinkedHashMap();
 73  
 
 74  
 
 75  
     /**
 76  
      * <p>The component renders itself; therefore, this
 77  
      *    method returns null.</p>
 78  
      *
 79  
      * @return <code>null</code> component handles renderering
 80  
      */
 81  
     public String getRendererType() {
 82  26
         return null;
 83  
     }
 84  
 
 85  
 
 86  
     /**
 87  
      * <p>Returns the component's family. In this case,
 88  
      *    the component is not associated with a family,
 89  
      *    so this method returns null.</p>
 90  
      *
 91  
      * @return component's family
 92  
      */
 93  
     public String getFamily() {
 94  
         return null;
 95  
     }
 96  
 
 97  
 
 98  
     /**
 99  
      * <p>Return the value of the <code>functionName</code> property.</p>
 100  
      *
 101  
      * @return callback function from the form's onsubmit.
 102  
      */
 103  
     public String getFunctionName() {
 104  
 
 105  13
         if (this.functionName != null) {
 106  13
             return functionName;
 107  
         }
 108  
         ValueBinding _vb = getValueBinding("functionName");
 109  
         if (_vb != null) {
 110  
             return (String) _vb.getValue(getFacesContext());
 111  
         } else {
 112  
             return null;
 113  
         }
 114  
 
 115  
     }
 116  
 
 117  
 
 118  
     /**
 119  
      * <p>Set the value of the <code>functionName</code> property.</p>
 120  
      *
 121  
      * @param functionName The new function name
 122  
      */
 123  
     public void setFunctionName(String functionName) {
 124  13
         this.functionName = functionName;
 125  13
     }
 126  
 
 127  
 
 128  
     /**
 129  
      * <p>Restore the state of this component.</p>
 130  
      *
 131  
      * @param context FacesContext for the current request
 132  
      * @param state State to be restored
 133  
      */
 134  
     public void restoreState(FacesContext context, Object state) {
 135  
 
 136  
         Object values[] = (Object[]) state;
 137  
         super.restoreState(context, values[0]);
 138  
         this.functionName = (String) values[1];
 139  
 
 140  
     }
 141  
 
 142  
 
 143  
     /**
 144  
      * <p>Save the state of this component.</p>
 145  
      *
 146  
      * @param context FacesContext for the current request
 147  
      * @return component's state
 148  
      */
 149  
     public Object saveState(FacesContext context) {
 150  
 
 151  
         Object values[] = new Object[2];
 152  
         values[0] = super.saveState(context);
 153  
         values[1] = this.functionName;
 154  
         return values;
 155  
 
 156  
     }
 157  
 
 158  
 
 159  
     /**
 160  
      * <p>Restructures the validator hierarchy grouping by
 161  
      * form name, type and id.</p>
 162  
      *
 163  
      * @return validators grouped by form, type and clientId
 164  
      */
 165  
     private Map getValidatorsGroupByFormName() {
 166  
 
 167  13
         Map formValidators = new LinkedHashMap();
 168  
 
 169  13
         Iterator vi = validators.entrySet().iterator();
 170  28
         while (vi.hasNext()) {
 171  
 
 172  15
             Map.Entry typeEntry = (Map.Entry) vi.next();
 173  15
             Map typeMap = (Map) typeEntry.getValue();
 174  
 
 175  15
             String type = (String) typeEntry.getKey();
 176  
 
 177  15
             Iterator ti = typeMap.entrySet().iterator();
 178  45
             while (ti.hasNext()) {
 179  
 
 180  30
                 Map.Entry idEntry = (Map.Entry) ti.next();
 181  30
                 String id = (String) idEntry.getKey();
 182  30
                 CommonsValidator v = (CommonsValidator) idEntry.getValue();
 183  30
                 String formName = v.getFormName();
 184  
 
 185  30
                 Map formTypeMap = (Map) formValidators.get(formName);
 186  30
                 if (formTypeMap == null) {
 187  26
                     formTypeMap = new LinkedHashMap();
 188  26
                     formValidators.put(formName, formTypeMap);
 189  
                 }
 190  
 
 191  30
                 Map formTypeIdMap = (Map) formTypeMap.get(type);
 192  30
                 if (formTypeIdMap == null) {
 193  30
                     formTypeIdMap = new LinkedHashMap();
 194  30
                     formTypeMap.put(type, formTypeIdMap);
 195  
                 }
 196  
 
 197  30
                 formTypeIdMap.put(id, v);
 198  30
             }
 199  
 
 200  15
         }
 201  
 
 202  13
         return formValidators;
 203  
 
 204  
     }
 205  
 
 206  
 
 207  
     /**
 208  
      * <p>Registers a validator according to type and id.</p>
 209  
      *
 210  
      * @param type The type of the validator
 211  
      * @param id The validator's identifier
 212  
      * @param v The Commons validator associated with the id and type
 213  
      */
 214  
     private void addValidator(String type, String id, CommonsValidator v) {
 215  
         // look for validators organized by type
 216  30
         Map map = (Map) validators.get(type);
 217  30
         if (map == null) {
 218  15
             map = new LinkedHashMap();
 219  15
             validators.put(type, map);
 220  
         }
 221  30
         if (id != null) {
 222  30
              map.put(id, v);
 223  
         }
 224  30
    }
 225  
 
 226  
 
 227  
     /**
 228  
      * <p>Recursively finds all Commons validators for the all of the
 229  
      *    components in a component hierarchy and adds them to a map.</p>
 230  
      * <p>If a validator's type is required, this method sets the
 231  
      *    associated component's required property to true. This is
 232  
      *    necessary because JSF does not validate empty fields unless
 233  
      *    a component's required property is true.</p>
 234  
      *
 235  
      * @param c The component at the root of the component tree
 236  
      * @param context The FacesContext for this request
 237  
      */
 238  
    private void findCommonsValidators(UIComponent c, FacesContext context) {
 239  79
       if (c instanceof EditableValueHolder && c.isRendered()) {
 240  26
          EditableValueHolder h = (EditableValueHolder) c;
 241  26
          javax.faces.validator.Validator[] vs = h.getValidators();
 242  52
          for (int i = 0; i < vs.length; i++) {
 243  26
             if (vs[i] instanceof CommonsValidator) {
 244  26
                CommonsValidator v = (CommonsValidator) vs[i];
 245  26
                v.setFormName(findForm(context, c));
 246  26
                if (Boolean.TRUE.equals(v.getClient())) {
 247  
 
 248  
                    //look for the clientId set
 249  26
                    Map clientIds = (Map) c.getAttributes().get(ValidatorInputRenderer.VALIDATOR_CLIENTIDS_ATTR);
 250  26
                    if (clientIds != null) {
 251  
 
 252  
                       validatorVars.putAll(clientIds);
 253  
                       Iterator ci = clientIds.entrySet().iterator();
 254  
                       while (ci.hasNext()) {
 255  
                          Map.Entry e = (Map.Entry) ci.next();
 256  
 
 257  
                          String id = (String) e.getKey();
 258  
                          addValidator(v.getType(), id, v);
 259  
 
 260  
                          ValidatorAction action = v.getValidatorAction();
 261  
                          List list = action.getDependencyList();
 262  
                          Iterator iter = list.iterator();
 263  
                          while (iter.hasNext()) {
 264  
                              String type = (String) iter.next();
 265  
                              addValidator(type, id, v);
 266  
                          }
 267  
 
 268  
                       }
 269  
 
 270  
                    } else {
 271  
                        //otherwise just try using the client id
 272  26
                        String id = c.getClientId(context);
 273  26
                        addValidator(v.getType(), id, v);
 274  
 
 275  26
                        ValidatorAction action = v.getValidatorAction();
 276  26
                        List list = action.getDependencyList();
 277  26
                        Iterator iter = list.iterator();
 278  30
                        while (iter.hasNext()) {
 279  4
                            String type = (String) iter.next();
 280  4
                            addValidator(type, id, v);
 281  4
                        }
 282  
                    }
 283  
 
 284  
                }
 285  26
                if (Boolean.TRUE.equals(v.getServer())) {
 286  
                   // Fields with empty values are not validated, so
 287  
                   // we force the issue here by setting the component's
 288  
                   // required attribute to true.
 289  
 
 290  26
                   if ("required".equals(v.getType())) {
 291  2
                      h.setRequired(true);
 292  
                   }
 293  
                }
 294  
             }
 295  
          }
 296  
       }
 297  
 
 298  79
       Iterator childrenIterator = c.getFacetsAndChildren();
 299  145
       while (childrenIterator.hasNext()) {
 300  66
          UIComponent child = (UIComponent) childrenIterator.next();
 301  66
          findCommonsValidators(child, context);
 302  66
       }
 303  79
       childrenIterator = null;
 304  79
    }
 305  
 
 306  
 
 307  
     /**
 308  
      * <p>Write the start of the script for client-side validation.</p>
 309  
      *
 310  
      * @param writer A response writer
 311  
      *
 312  
      * @exception IOException if an input/output error occurs
 313  
      */
 314  
    private void writeScriptStart(ResponseWriter writer) throws IOException {
 315  13
       writer.startElement("script", this);
 316  13
       writer.writeAttribute("type", "text/javascript", null);
 317  13
       writer.writeAttribute("language", "Javascript1.1", null);
 318  13
       writer.write("\n");
 319  13
     }
 320  
 
 321  
 
 322  
     /**
 323  
      * <p>Write the end of the script for client-side validation.</p>
 324  
      *
 325  
      * @param writer A response writer
 326  
      *
 327  
      * @exception IOException if an input/output error occurs
 328  
      */
 329  
    private void writeScriptEnd(ResponseWriter writer) throws IOException {
 330  13
       writer.write("\n");
 331  13
       writer.endElement("script");
 332  13
    }
 333  
 
 334  
 
 335  
     /**
 336  
      * <p>Returns the name of the JavaScript function, specified in
 337  
      *    the JSP page (presumably), that validates this JSP page's form.</p>
 338  
      *
 339  
      * @param writer A response writer
 340  
      * @param context The FacesContext for this request
 341  
      *
 342  
      * @exception IOException if an input/output error occurs
 343  
      */
 344  
    private void writeValidationFunctions(ResponseWriter writer,
 345  
       FacesContext context) throws IOException {
 346  
 
 347  13
       StringBuffer buff = new StringBuffer();
 348  13
       buff.append("var bCancel = false;\n")
 349  
           .append("function ")
 350  
           .append(getAttributes().get("functionName").toString()).append("(form) {\n")
 351  
           .append("\tvar bValid = true;\n")
 352  
           .append("\tvar sFormName = jcv_retrieveFormName(form);\n");
 353  
 
 354  13
       Map formValidators = getValidatorsGroupByFormName();
 355  13
       Iterator formIter = formValidators.entrySet().iterator();
 356  39
       while (formIter.hasNext()) {
 357  26
           Map.Entry typeEntry = (Map.Entry) formIter.next();
 358  26
           String formName = (String) typeEntry.getKey();
 359  26
           Map formTypeValidators = (Map) typeEntry.getValue();
 360  
 
 361  
           // for each validator type, write callback
 362  
 
 363  26
           buff.append("\tif ((bValid && !bCancel && (\"")
 364  
               .append(formName)
 365  
               .append("\" == sFormName))) {\n")
 366  
               .append("\t\tbValid = (");
 367  
 
 368  
 
 369  26
           Iterator iter = getTypesOrderedByDependencies(formTypeValidators.keySet()).iterator();
 370  26
           boolean first = true;
 371  56
           while (iter.hasNext()) {
 372  30
               String type = (String) iter.next();
 373  30
               ValidatorAction a = CommonsValidator.getValidatorAction(type);
 374  
 
 375  30
               buff.append((!first ? " && " : ""))
 376  
                   .append(a.getJsFunctionName())
 377  
                   .append("(form)");
 378  30
               first = false;
 379  
 
 380  30
               writer.write("function ");
 381  30
               StringBuffer callback = new StringBuffer();
 382  
 
 383  
               // most of the type the callback function is based on the form name and
 384  
               // type but for some rules require special names
 385  30
               String fnameMnemonic = CommonsValidator.getJsCallbackMnemonic(type);
 386  
 
 387  30
               callback.append(formName).append('_').append(fnameMnemonic);
 388  30
               writer.write(callback.toString());
 389  30
               writer.write("() { \n");
 390  
               // for each field validated by this type, add configuration object
 391  30
               Map map = (Map) formTypeValidators.get(type);
 392  30
               Iterator iter2 = map.keySet().iterator();
 393  30
               int k = 0;
 394  60
               while (iter2.hasNext()) {
 395  30
                   String id = (String) iter2.next();
 396  30
                   CommonsValidator v = (CommonsValidator) map.get(id);
 397  30
                   writer.write("this[" + k + "] = ");
 398  30
                   k++;
 399  30
                   writeJavaScriptParams(writer, context, id, v);
 400  30
                   writer.write(";\n");
 401  30
               }
 402  30
               writer.write("\t}\n");
 403  30
           }
 404  
 
 405  26
           buff.append(");\n\t\n}");
 406  
 
 407  26
       }
 408  13
       formValidators.clear();
 409  
 
 410  
       // write out the form function
 411  13
       buff.append("\n\treturn bValid;\n")
 412  
           .append("}\n");
 413  
 
 414  13
       writer.write(buff.toString());
 415  
 
 416  
       // resolve dependencies for a complete types list
 417  
 
 418  13
       List types = new ArrayList(validators.keySet());
 419  13
       types.add("includeJavaScriptUtilities");
 420  
 
 421  13
       Iterator iter = types.iterator();
 422  41
       while (iter.hasNext()) {
 423  28
          String type = (String) iter.next();
 424  28
          ValidatorAction a = CommonsValidator.getValidatorAction(type);
 425  28
          writer.write(a.getJavascript());
 426  28
          writer.write("\n");
 427  28
       }
 428  
 
 429  13
       types.clear();
 430  
 
 431  13
    }
 432  
 
 433  
 
 434  
    /**
 435  
     * <p>Backslash-escapes the following characters from the input string:
 436  
     * &quot;, &apos;, \, \r, \n.</p>
 437  
     *
 438  
     * <p>This method escapes characters that will result in an invalid
 439  
     * Javascript statement within the validator Javascript.</p>
 440  
     *
 441  
     * @param str The string to escape.
 442  
     * @return The string <code>s</code> with each instance of a double quote,
 443  
     *         single quote, backslash, carriage-return, or line feed escaped
 444  
     *         with a leading backslash.
 445  
     */
 446  
    private String escapeJavascript(String str) {
 447  54
        if (str == null) {
 448  
            return null;
 449  
        }
 450  
 
 451  54
        int length = str.length();
 452  
 
 453  54
        if (length == 0) {
 454  
            return str;
 455  
        }
 456  
 
 457  
        // guess at how many chars we'll be adding...
 458  54
        StringBuffer out = new StringBuffer(length + 4);
 459  
 
 460  
        // run through the string escaping sensitive chars
 461  362
        for (int i = 0; i < length; i++) {
 462  308
            char c = str.charAt(i);
 463  
 
 464  308
            if ((c == '"') || (c == '\'') || (c == '\\') || (c == '\n')
 465  
                    || (c == '\r')) {
 466  
                out.append('\\');
 467  
            }
 468  
 
 469  308
            out.append(c);
 470  
        }
 471  
 
 472  54
        return out.toString();
 473  
    }
 474  
 
 475  
 
 476  
 
 477  
    /**
 478  
     * <p>Returns an array of validator types organized by dependencies.</p>
 479  
     *
 480  
     * @param typeSet The type set to be processed
 481  
     * @return array of validator types ordered by dependencies
 482  
     */
 483  
    private List getTypesOrderedByDependencies(Set typeSet) {
 484  
 
 485  26
        List tmpList = new ArrayList(typeSet);
 486  
 
 487  30
        ordered: for (int i = 0; i < tmpList.size(); i++) {
 488  30
            boolean swap = false;
 489  64
            for (int j = 0; j < tmpList.size(); j++) {
 490  34
                String type = (String) tmpList.get(j);
 491  34
                ValidatorAction a = CommonsValidator.getValidatorAction(type);
 492  
 
 493  34
                List dependencies  = a.getDependencyList();
 494  34
                if (dependencies != null && dependencies.size() > 0) {
 495  8
                    int max = -1;
 496  16
                    for (int n = 0; n < dependencies.size(); n++) {
 497  8
                        max = Math.max(max, tmpList.indexOf(dependencies.get(n)));
 498  
                    }
 499  8
                    if (max > j) {
 500  4
                        String tmp = (String) tmpList.get(j);
 501  4
                        tmpList.remove(j);
 502  4
                        tmpList.add(max, tmp);
 503  4
                        swap = true;
 504  4
                        j = max;
 505  
                    }
 506  
                }
 507  
 
 508  
            }
 509  30
            if (!swap) {
 510  26
              break ordered;
 511  
            }
 512  
        }
 513  
 
 514  26
        return tmpList;
 515  
 
 516  
    }
 517  
 
 518  
     /**
 519  
      * <p>Writes the JavaScript parameters for the client-side
 520  
      *    validation code.</p>
 521  
      *
 522  
      * @param writer A response writer
 523  
      * @param context The FacesContext for this request
 524  
      * @param id The clientId of the owning component
 525  
      * @param v The Commons validator
 526  
      *
 527  
      * @exception IOException if an input/output error occurs
 528  
      */
 529  
    public void writeJavaScriptParams(ResponseWriter writer,
 530  
       FacesContext context, String id, CommonsValidator v) throws IOException {
 531  
 
 532  30
       Map localVars = null;
 533  
       // look for var's evaluated at render time.  This is for client
 534  
       // side JavaScript validation
 535  30
       if (validatorVars != null && validatorVars.containsKey(id)) {
 536  
           Map typeVars = (Map) validatorVars.get(id);
 537  
           if (typeVars != null && typeVars.containsKey(v.getType())) {
 538  
               localVars = (Map) typeVars.get(v.getType());
 539  
           }
 540  
       }
 541  
 
 542  30
       Tags tagUtils = new Tags();
 543  30
       ValidatorAction validatorAction = v.getValidatorAction();
 544  30
       writer.write("new Array(\"");
 545  30
       writer.write(id);
 546  30
       writer.write("\", \"");
 547  30
       writer.write(v.getErrorMessage(context, validatorAction, localVars));
 548  30
       writer.write("\", new Function(\"x\", \"return {");
 549  
 
 550  30
       Iterator vi = v.getVars().entrySet().iterator();
 551  
 
 552  30
       boolean first = true;
 553  
 
 554  
       // vars captured at render time and are the result of
 555  
       // EL.
 556  30
       Map idVars = (Map) validatorVars.get(id);
 557  
 
 558  84
       next: while (vi.hasNext()) {
 559  54
          Map.Entry e = (Map.Entry) vi.next();
 560  
 
 561  54
          Object value = e.getValue();
 562  
 
 563  
          // look for a render override by clientId/type
 564  54
          if (idVars != null && idVars.containsKey(v.getType())) {
 565  
 
 566  
              Map typeVars = (Map) idVars.get(v.getType());
 567  
              // look for a render override by clientId/type/name
 568  
              if (typeVars != null && typeVars.containsKey(e.getKey())) {
 569  
                 value = typeVars.get(e.getKey());
 570  
              }
 571  
          } else {
 572  54
             if (value != null && value instanceof String
 573  
                 && isValueReference((String) e.getValue())) {
 574  
 
 575  
                 value = tagUtils.eval((String) e.getValue());
 576  
             }
 577  
          }
 578  
 
 579  54
          if (value == null) {
 580  
             continue next;
 581  
          }
 582  54
          String name = (String) e.getKey();
 583  54
          if (!first) {
 584  24
              writer.write(",");
 585  24
          } else {
 586  30
              first = false;
 587  
          }
 588  54
          writer.write(name);
 589  54
          writer.write(":");
 590  
 
 591  54
          String jsType = v.getVarType(name);
 592  
          // Ugh...mask validator doesn't construct RegExp
 593  54
          if (jsType.equals(Var.JSTYPE_REGEXP)) {
 594  2
              writer.write("/");
 595  2
          } else {
 596  52
              writer.write("'");
 597  
          }
 598  
 
 599  54
          writer.write(escapeJavascript(value.toString()));
 600  
 
 601  54
          if (jsType.equals(Var.JSTYPE_REGEXP)) {
 602  2
              writer.write("/");
 603  2
          } else {
 604  52
              writer.write("'");
 605  
          }
 606  54
       }
 607  30
       writer.write("}[x];\"))");
 608  30
    }
 609  
 
 610  
 
 611  
    /**
 612  
     * <p>Traverses up the tree looking for the owning form.
 613  
     * Returns the parent <code>UIForm</code> or empty string
 614  
     * if one is not found.</p>
 615  
     *
 616  
     * @param context FacesContext for the current request
 617  
     * @param component <code>UIForm</code> parent of the component.
 618  
     * @return client id of the parent form component
 619  
     */
 620  
    public String findForm(FacesContext context, UIComponent component) {
 621  
 
 622  26
        UIComponent parent = component.getParent();
 623  26
        if (parent != null) {
 624  26
           if (parent instanceof UIForm) {
 625  26
              return parent.getClientId(context).replace(UINamingContainer.SEPARATOR_CHAR, '_');
 626  
           } else {
 627  
              return findForm(context, parent);
 628  
           }
 629  
        }
 630  
 
 631  
        return "";
 632  
    }
 633  
 
 634  
 
 635  
     /**
 636  
      * <p>Begin encoding for this component. This method
 637  
      *    finds all Commons validators attached to components
 638  
      *    in the current component hierarchy and writes out
 639  
      *    JavaScript code to invoke those validators, in turn.</p>
 640  
      *
 641  
      * @param context The FacesContext for this request
 642  
      *
 643  
      * @exception IOException if an input/output error occurs
 644  
      */
 645  
    public void encodeBegin(FacesContext context) throws IOException {
 646  13
       ResponseWriter writer = context.getResponseWriter();
 647  
 
 648  13
       validators.clear();
 649  13
       findCommonsValidators(context.getViewRoot(), context);
 650  
 
 651  13
       writeScriptStart(writer);
 652  13
       writeValidationFunctions(writer, context);
 653  13
       writeScriptEnd(writer);
 654  13
    }
 655  
 
 656  
 
 657  
     /**
 658  
      * <p>Return true if the specified string contains an EL expression.</p>
 659  
      * 
 660  
      * <p>This is taken almost verbatim from {@link javax.faces.webapp.UIComponentTag}
 661  
      * in order to remove JSP dependencies from the renderers.</p>
 662  
      *
 663  
      * @param value String to be checked for being an expression
 664  
      */
 665  
     private boolean isValueReference(String value) {
 666  
 
 667  54
         if (value == null) {
 668  
             return false;
 669  
         }
 670  
 
 671  54
         int start = value.indexOf("#{");
 672  54
         if (start < 0) {
 673  54
             return false;
 674  
         }
 675  
 
 676  
         int end = value.lastIndexOf('}');
 677  
         return (end >= 0) && (start < end);
 678  
     }
 679  
 
 680  
 
 681  
 }