View Javadoc

    1   /*
    2    * $Id: Field.java 384724 2006-03-10 07:55:23Z niallp $
    3    * $Rev: 384724 $
    4    * $Date: 2006-03-10 07:55:23 +0000 (Fri, 10 Mar 2006) $
    5    *
    6    * ====================================================================
    7    * Copyright 2001-2006 The Apache Software Foundation
    8    *
    9    * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *     http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   */
    21
    22  package org.apache.commons.validator;
    23
    24  import java.io.Serializable;
    25  import java.lang.reflect.InvocationTargetException;
    26  import java.util.ArrayList;
    27  import java.util.Collection;
    28  import java.util.Collections;
    29  import java.util.HashMap;
    30  import java.util.Iterator;
    31  import java.util.List;
    32  import java.util.Map;
    33  import java.util.StringTokenizer;
    34
    35  import org.apache.commons.beanutils.PropertyUtils;
    36  import org.apache.commons.collections.FastHashMap; // DEPRECATED
    37  import org.apache.commons.validator.util.ValidatorUtils;
    38
    39  /***
    40   * This contains the list of pluggable validators to run on a field and any
    41   * message information and variables to perform the validations and generate
    42   * error messages.  Instances of this class are configured with a
    43   * &lt;field&gt; xml element.
    44   * <p>
    45   * The use of FastHashMap is deprecated and will be replaced in a future
    46   * release.
    47   * </p>
    48   * @see org.apache.commons.validator.Form
    49   */
    50  public class Field implements Cloneable, Serializable {
    51
    52      /***
    53       * This is the value that will be used as a key if the <code>Arg</code>
    54       * name field has no value.
    55       */
    56      private static final String DEFAULT_ARG =
    57              "org.apache.commons.validator.Field.DEFAULT";
    58
    59      /***
    60       * This indicates an indexed property is being referenced.
    61       */
    62      public static final String TOKEN_INDEXED = "[]";
    63
    64      /***
    65       * The start of a token.
    66       */
    67      protected static final String TOKEN_START = "${";
    68
    69      /***
    70       * The end of a token.
    71       */
    72      protected static final String TOKEN_END = "}";
    73
    74      /***
    75       * A Vriable token.
    76       */
    77      protected static final String TOKEN_VAR = "var:";
    78
    79      /***
    80       * The Field's property name.
    81       */
    82      protected String property = null;
    83
    84      /***
    85       * The Field's indexed property name.
    86       */
    87      protected String indexedProperty = null;
    88
    89      /***
    90       * The Field's indexed list property name.
    91       */
    92      protected String indexedListProperty = null;
    93
    94      /***
    95       * The Field's unique key.
    96       */
    97      protected String key = null;
    98
    99      /***
    100      * A comma separated list of validator's this field depends on.
    101      */
    102     protected String depends = null;
    103
    104     /***
    105      * The Page Number
    106      */
    107     protected int page = 0;
    108
    109     /***
    110      * The order of the Field in the Form.
    111      */
    112     protected int fieldOrder = 0;
    113
    114     /***
    115      * Internal representation of this.depends String as a List.  This List
    116      * gets updated whenever setDepends() gets called.  This List is
    117      * synchronized so a call to setDepends() (which clears the List) won't
    118      * interfere with a call to isDependency().
    119      */
    120     private List dependencyList = Collections.synchronizedList(new ArrayList());
    121
    122     /***
    123      * @deprecated Subclasses should use getVarMap() instead.
    124      */
    125     protected FastHashMap hVars = new FastHashMap();
    126
    127     /***
    128      * @deprecated Subclasses should use getMsgMap() instead.
    129      */
    130     protected FastHashMap hMsgs = new FastHashMap();
    131
    132     /***
    133      * Holds Maps of arguments.  args[0] returns the Map for the first
    134      * replacement argument.  Start with a 0 length array so that it will
    135      * only grow to the size of the highest argument position.
    136      * @since Validator 1.1
    137      */
    138     protected Map[] args = new Map[0];
    139
    140     /***
    141      * Gets the page value that the Field is associated with for
    142      * validation.
    143      * @return The page number.
    144      */
    145     public int getPage() {
    146         return this.page;
    147     }
    148
    149     /***
    150      * Sets the page value that the Field is associated with for
    151      * validation.
    152      * @param page The page number.
    153      */
    154     public void setPage(int page) {
    155         this.page = page;
    156     }
    157
    158     /***
    159      * Gets the position of the <code>Field</code> in the validation list.
    160      * @return The field position.
    161      */
    162     public int getFieldOrder() {
    163         return this.fieldOrder;
    164     }
    165
    166     /***
    167      * Sets the position of the <code>Field</code> in the validation list.
    168      * @param fieldOrder The field position.
    169      */
    170     public void setFieldOrder(int fieldOrder) {
    171         this.fieldOrder = fieldOrder;
    172     }
    173
    174     /***
    175      * Gets the property name of the field.
    176      * @return The field's property name.
    177      */
    178     public String getProperty() {
    179         return this.property;
    180     }
    181
    182     /***
    183      * Sets the property name of the field.
    184      * @param property The field's property name.
    185      */
    186     public void setProperty(String property) {
    187         this.property = property;
    188     }
    189
    190     /***
    191      * Gets the indexed property name of the field.  This
    192      * is the method name that can take an <code>int</code> as
    193      * a parameter for indexed property value retrieval.
    194      * @return The field's indexed property name.
    195      */
    196     public String getIndexedProperty() {
    197         return this.indexedProperty;
    198     }
    199
    200     /***
    201      * Sets the indexed property name of the field.
    202      * @param indexedProperty The field's indexed property name.
    203      */
    204     public void setIndexedProperty(String indexedProperty) {
    205         this.indexedProperty = indexedProperty;
    206     }
    207
    208     /***
    209      * Gets the indexed property name of the field.  This
    210      * is the method name that will return an array or a
    211      * <code>Collection</code> used to retrieve the
    212      * list and then loop through the list performing the specified
    213      * validations.
    214      * @return The field's indexed List property name.
    215      */
    216     public String getIndexedListProperty() {
    217         return this.indexedListProperty;
    218     }
    219
    220     /***
    221      * Sets the indexed property name of the field.
    222      * @param indexedListProperty The field's indexed List property name.
    223      */
    224     public void setIndexedListProperty(String indexedListProperty) {
    225         this.indexedListProperty = indexedListProperty;
    226     }
    227
    228     /***
    229      * Gets the validation rules for this field as a comma separated list.
    230      * @return A comma separated list of validator names.
    231      */
    232     public String getDepends() {
    233         return this.depends;
    234     }
    235
    236     /***
    237      * Sets the validation rules for this field as a comma separated list.
    238      * @param depends A comma separated list of validator names.
    239      */
    240     public void setDepends(String depends) {
    241         this.depends = depends;
    242
    243         this.dependencyList.clear();
    244
    245         StringTokenizer st = new StringTokenizer(depends, ",");
    246         while (st.hasMoreTokens()) {
    247             String depend = st.nextToken().trim();
    248
    249             if (depend != null && depend.length() > 0) {
    250                 this.dependencyList.add(depend);
    251             }
    252         }
    253     }
    254
    255     /***
    256      * Add a <code>Msg</code> to the <code>Field</code>.
    257      * @param msg A validation message.
    258      */
    259     public void addMsg(Msg msg) {
    260         hMsgs.put(msg.getName(), msg);
    261     }
    262
    263     /***
    264      * Retrieve a message value.
    265      * @param key Validation key.
    266      * @return A validation message for a specified validator.
    267      */
    268     public String getMsg(String key) {
    269         Msg msg = getMessage(key);
    270         return (msg == null) ? null : msg.getKey();
    271     }
    272
    273     /***
    274      * Retrieve a message object.
    275      * @since Validator 1.1.4
    276      * @param key Validation key.
    277      * @return A validation message for a specified validator.
    278      */
    279     public Msg getMessage(String key) {
    280         return (Msg) hMsgs.get(key);
    281     }
    282
    283     /***
    284      * The <code>Field</code>'s messages are returned as an
    285      * unmodifiable <code>Map</code>.
    286      * @since Validator 1.1.4
    287      * @return Map of validation messages for the field.
    288      */
    289     public Map getMessages() {
    290         return Collections.unmodifiableMap(hMsgs);
    291     }
    292
    293     /***
    294      * Add an <code>Arg</code> to the replacement argument list.
    295      * @since Validator 1.1
    296      * @param arg Validation message's argument.
    297      */
    298     public void addArg(Arg arg) {
    299         // TODO this first if check can go away after arg0, etc. are removed from dtd
    300         if (arg == null || arg.getKey() == null || arg.getKey().length() == 0) {
    301             return;
    302         }
    303
    304         determineArgPosition(arg);
    305         ensureArgsCapacity(arg);
    306
    307         Map argMap = this.args[arg.getPosition()];
    308         if (argMap == null) {
    309             argMap = new HashMap();
    310             this.args[arg.getPosition()] = argMap;
    311         }
    312
    313         if (arg.getName() == null) {
    314             argMap.put(DEFAULT_ARG, arg);
    315         } else {
    316             argMap.put(arg.getName(), arg);
    317         }
    318
    319     }
    320
    321     /***
    322      * Calculate the position of the Arg
    323      */
    324     private void determineArgPosition(Arg arg) {
    325
    326         int position = arg.getPosition();
    327
    328         // position has been explicity set
    329         if (position >= 0) {
    330             return;
    331         }
    332
    333         // first arg to be added
    334         if (args == null || args.length == 0) {
    335             arg.setPosition(0);
    336             return;
    337         }
    338
    339         // determine the position of the last argument with
    340         // the same name or the last default argument
    341         String key = arg.getName() == null ? DEFAULT_ARG : arg.getName();
    342         int lastPosition = -1;
    343         int lastDefault  = -1;
    344         for (int i = 0; i < args.length; i++) {
    345             if (args[i] != null && args[i].containsKey(key)) {
    346                 lastPosition = i;
    347             }
    348             if (args[i] != null && args[i].containsKey(DEFAULT_ARG)) {
    349                 lastDefault = i;
    350             }
    351         }
    352
    353         if (lastPosition < 0) {
    354             lastPosition = lastDefault;
    355         }
    356
    357         // allocate the next position
    358         arg.setPosition(++lastPosition);
    359
    360     }
    361
    362     /***
    363      * Ensures that the args array can hold the given arg.  Resizes the array as
    364      * necessary.
    365      * @param arg Determine if the args array is long enough to store this arg's
    366      * position.
    367      */
    368     private void ensureArgsCapacity(Arg arg) {
    369         if (arg.getPosition() >= this.args.length) {
    370             Map[] newArgs = new Map[arg.getPosition() + 1];
    371             System.arraycopy(this.args, 0, newArgs, 0, this.args.length);
    372             this.args = newArgs;
    373         }
    374     }
    375
    376     /***
    377      * Gets the default <code>Arg</code> object at the given position.
    378      * @param position Validation message argument's position.
    379      * @return The default Arg or null if not found.
    380      * @since Validator 1.1
    381      */
    382     public Arg getArg(int position) {
    383         return this.getArg(DEFAULT_ARG, position);
    384     }
    385
    386     /***
    387      * Gets the <code>Arg</code> object at the given position.  If the key
    388      * finds a <code>null</code> value then the default value will be
    389      * retrieved.
    390      * @param key The name the Arg is stored under.  If not found, the default
    391      * Arg for the given position (if any) will be retrieved.
    392      * @param position The Arg number to find.
    393      * @return The Arg with the given name and position or null if not found.
    394      * @since Validator 1.1
    395      */
    396     public Arg getArg(String key, int position) {
    397         if ((position >= this.args.length) || (this.args[position] == null)) {
    398             return null;
    399         }
    400
    401         Arg arg = (Arg) args[position].get(key);
    402
    403         // Didn't find default arg so exit, otherwise we would get into
    404         // infinite recursion
    405         if ((arg == null) && key.equals(DEFAULT_ARG)) {
    406             return null;
    407         }
    408
    409         return (arg == null) ? this.getArg(position) : arg;
    410     }
    411
    412     /***
    413      * Retrieves the Args for the given validator name.
    414      * @param key The validator's args to retrieve.
    415      * @return An Arg[] sorted by the Args' positions (i.e. the Arg at index 0
    416      * has a position of 0).
    417      * @since Validator 1.1.1
    418      */
    419     public Arg[] getArgs(String key){
    420         Arg[] args = new Arg[this.args.length];
    421
    422         for (int i = 0; i < this.args.length; i++) {
    423             args[i] = this.getArg(key, i);
    424         }
    425
    426         return args;
    427     }
    428
    429     /***
    430      * Add a <code>Var</code> to the <code>Field</code>.
    431      * @param v The Validator Argument.
    432      */
    433     public void addVar(Var v) {
    434         this.hVars.put(v.getName(), v);
    435     }
    436
    437     /***
    438      * Add a <code>Var</code>, based on the values passed in, to the
    439      * <code>Field</code>.
    440      * @param name Name of the validation.
    441      * @param value The Argument's value.
    442      * @param jsType The Javascript type.
    443      */
    444     public void addVar(String name, String value, String jsType) {
    445         this.addVar(new Var(name, value, jsType));
    446     }
    447
    448     /***
    449      * Retrieve a variable.
    450      * @param mainKey The Variable's key
    451      * @return the Variable
    452      */
    453     public Var getVar(String mainKey) {
    454         return (Var) hVars.get(mainKey);
    455     }
    456
    457     /***
    458      * Retrieve a variable's value.
    459      * @param mainKey The Variable's key
    460      * @return the Variable's value
    461      */
    462     public String getVarValue(String mainKey) {
    463         String value = null;
    464
    465         Object o = hVars.get(mainKey);
    466         if (o != null && o instanceof Var) {
    467             Var v = (Var) o;
    468             value = v.getValue();
    469         }
    470
    471         return value;
    472     }
    473
    474     /***
    475      * The <code>Field</code>'s variables are returned as an
    476      * unmodifiable <code>Map</code>.
    477      * @return the Map of Variable's for a Field.
    478      */
    479     public Map getVars() {
    480         return Collections.unmodifiableMap(hVars);
    481     }
    482
    483     /***
    484      * Gets a unique key based on the property and indexedProperty fields.
    485      * @return a unique key for the field.
    486      */
    487     public String getKey() {
    488         if (this.key == null) {
    489             this.generateKey();
    490         }
    491
    492         return this.key;
    493     }
    494
    495     /***
    496      * Sets a unique key for the field.  This can be used to change
    497      * the key temporarily to have a unique key for an indexed field.
    498      * @param key a unique key for the field
    499      */
    500     public void setKey(String key) {
    501         this.key = key;
    502     }
    503
    504     /***
    505      * If there is a value specified for the indexedProperty field then
    506      * <code>true</code> will be returned.  Otherwise it will be
    507      * <code>false</code>.
    508      * @return Whether the Field is indexed.
    509      */
    510     public boolean isIndexed() {
    511         return ((indexedListProperty != null && indexedListProperty.length() > 0));
    512     }
    513
    514     /***
    515      * Generate correct <code>key</code> value.
    516      */
    517     public void generateKey() {
    518         if (this.isIndexed()) {
    519             this.key = this.indexedListProperty + TOKEN_INDEXED + "." + this.property;
    520         } else {
    521             this.key = this.property;
    522         }
    523     }
    524
    525     /***
    526      * Replace constants with values in fields and process the depends field
    527      * to create the dependency <code>Map</code>.
    528      */
    529     void process(Map globalConstants, Map constants) {
    530         this.hMsgs.setFast(false);
    531         this.hVars.setFast(true);
    532
    533         this.generateKey();
    534
    535         // Process FormSet Constants
    536         for (Iterator i = constants.keySet().iterator(); i.hasNext();) {
    537             String key = (String) i.next();
    538             String key2 = TOKEN_START + key + TOKEN_END;
    539             String replaceValue = (String) constants.get(key);
    540
    541             property = ValidatorUtils.replace(property, key2, replaceValue);
    542
    543             processVars(key2, replaceValue);
    544
    545             this.processMessageComponents(key2, replaceValue);
    546         }
    547
    548         // Process Global Constants
    549         for (Iterator i = globalConstants.keySet().iterator(); i.hasNext();) {
    550             String key = (String) i.next();
    551             String key2 = TOKEN_START + key + TOKEN_END;
    552             String replaceValue = (String) globalConstants.get(key);
    553
    554             property = ValidatorUtils.replace(property, key2, replaceValue);
    555
    556             processVars(key2, replaceValue);
    557
    558             this.processMessageComponents(key2, replaceValue);
    559         }
    560
    561         // Process Var Constant Replacement
    562         for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
    563             String key = (String) i.next();
    564             String key2 = TOKEN_START + TOKEN_VAR + key + TOKEN_END;
    565             Var var = this.getVar(key);
    566             String replaceValue = var.getValue();
    567
    568             this.processMessageComponents(key2, replaceValue);
    569         }
    570
    571         hMsgs.setFast(true);
    572     }
    573
    574     /***
    575      * Replace the vars value with the key/value pairs passed in.
    576      */
    577     private void processVars(String key, String replaceValue) {
    578         Iterator i = this.hVars.keySet().iterator();
    579         while (i.hasNext()) {
    580             String varKey = (String) i.next();
    581             Var var = this.getVar(varKey);
    582
    583             var.setValue(ValidatorUtils.replace(var.getValue(), key, replaceValue));
    584         }
    585
    586     }
    587
    588     /***
    589      * Replace the args key value with the key/value pairs passed in.
    590      */
    591     private void processMessageComponents(String key, String replaceValue) {
    592         String varKey = TOKEN_START + TOKEN_VAR;
    593         // Process Messages
    594         if (key != null && !key.startsWith(varKey)) {
    595             for (Iterator i = hMsgs.values().iterator(); i.hasNext();) {
    596                 Msg msg = (Msg) i.next();
    597                 msg.setKey(ValidatorUtils.replace(msg.getKey(), key, replaceValue));
    598             }
    599         }
    600
    601         this.processArg(key, replaceValue);
    602     }
    603
    604     /***
    605      * Replace the arg <code>Collection</code> key value with the key/value
    606      * pairs passed in.
    607      */
    608     private void processArg(String key, String replaceValue) {
    609         for (int i = 0; i < this.args.length; i++) {
    610
    611             Map argMap = this.args[i];
    612             if (argMap == null) {
    613                 continue;
    614             }
    615
    616             Iterator iter = argMap.values().iterator();
    617             while (iter.hasNext()) {
    618                 Arg arg = (Arg) iter.next();
    619
    620                 if (arg != null) {
    621                     arg.setKey(
    622                             ValidatorUtils.replace(arg.getKey(), key, replaceValue));
    623                 }
    624             }
    625         }
    626     }
    627
    628     /***
    629      * Checks if the validator is listed as a dependency.
    630      * @param validatorName Name of the validator to check.
    631      * @return Whether the field is dependant on a validator.
    632      */
    633     public boolean isDependency(String validatorName) {
    634         return this.dependencyList.contains(validatorName);
    635     }
    636
    637     /***
    638      * Gets an unmodifiable <code>List</code> of the dependencies in the same
    639      * order they were defined in parameter passed to the setDepends() method.
    640      * @return A list of the Field's dependancies.
    641      */
    642     public List getDependencyList() {
    643         return Collections.unmodifiableList(this.dependencyList);
    644     }
    645
    646     /***
    647      * Creates and returns a copy of this object.
    648      * @return A copy of the Field.
    649      */
    650     public Object clone() {
    651         Field field = null;
    652         try {
    653             field = (Field) super.clone();
    654         } catch(CloneNotSupportedException e) {
    655             throw new RuntimeException(e.toString());
    656         }
    657
    658         field.args = new Map[this.args.length];
    659         for (int i = 0; i < this.args.length; i++) {
    660             if (this.args[i] == null) {
    661                 continue;
    662             }
    663
    664             Map argMap = new HashMap(this.args[i]);
    665             Iterator iter = argMap.keySet().iterator();
    666             while (iter.hasNext()) {
    667                 String validatorName = (String) iter.next();
    668                 Arg arg = (Arg) argMap.get(validatorName);
    669                 argMap.put(validatorName, arg.clone());
    670             }
    671             field.args[i] = argMap;
    672         }
    673
    674         field.hVars = ValidatorUtils.copyFastHashMap(hVars);
    675         field.hMsgs = ValidatorUtils.copyFastHashMap(hMsgs);
    676
    677         return field;
    678     }
    679
    680     /***
    681      * Returns a string representation of the object.
    682      * @return A string representation of the object.
    683      */
    684     public String toString() {
    685         StringBuffer results = new StringBuffer();
    686
    687         results.append("\t\tkey = " + key + "\n");
    688         results.append("\t\tproperty = " + property + "\n");
    689         results.append("\t\tindexedProperty = " + indexedProperty + "\n");
    690         results.append("\t\tindexedListProperty = " + indexedListProperty + "\n");
    691         results.append("\t\tdepends = " + depends + "\n");
    692         results.append("\t\tpage = " + page + "\n");
    693         results.append("\t\tfieldOrder = " + fieldOrder + "\n");
    694
    695         if (hVars != null) {
    696             results.append("\t\tVars:\n");
    697             for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
    698                 Object key = i.next();
    699                 results.append("\t\t\t");
    700                 results.append(key);
    701                 results.append("=");
    702                 results.append(hVars.get(key));
    703                 results.append("\n");
    704             }
    705         }
    706
    707         return results.toString();
    708     }
    709
    710     /***
    711      * Returns an indexed property from the object we're validating.
    712      *
    713      * @param bean The bean to extract the indexed values from.
    714      * @throws ValidatorException If there's an error looking up the property
    715      * or, the property found is not indexed.
    716      */
    717     Object[] getIndexedProperty(Object bean) throws ValidatorException {
    718         Object indexedProperty = null;
    719
    720         try {
    721             indexedProperty =
    722                 PropertyUtils.getProperty(bean, this.getIndexedListProperty());
    723
    724         } catch(IllegalAccessException e) {
    725             throw new ValidatorException(e.getMessage());
    726         } catch(InvocationTargetException e) {
    727             throw new ValidatorException(e.getMessage());
    728         } catch(NoSuchMethodException e) {
    729             throw new ValidatorException(e.getMessage());
    730         }
    731
    732         if (indexedProperty instanceof Collection) {
    733             return ((Collection) indexedProperty).toArray();
    734
    735         } else if (indexedProperty.getClass().isArray()) {
    736             return (Object[]) indexedProperty;
    737
    738         } else {
    739             throw new ValidatorException(this.getKey() + " is not indexed");
    740         }
    741
    742     }
    743
    744     /***
    745      * Executes the given ValidatorAction and all ValidatorActions that it
    746      * depends on.
    747      * @return true if the validation succeeded.
    748      */
    749     private boolean validateForRule(
    750         ValidatorAction va,
    751         ValidatorResults results,
    752         Map actions,
    753         Map params,
    754         int pos)
    755         throws ValidatorException {
    756
    757         ValidatorResult result = results.getValidatorResult(this.getKey());
    758         if (result != null && result.containsAction(va.getName())) {
    759             return result.isValid(va.getName());
    760         }
    761
    762         if (!this.runDependentValidators(va, results, actions, params, pos)) {
    763             return false;
    764         }
    765
    766         return va.executeValidationMethod(this, params, results, pos);
    767     }
    768
    769     /***
    770      * Calls all of the validators that this validator depends on.
    771      * TODO ValidatorAction should know how to run its own dependencies.
    772      * @param va Run dependent validators for this action.
    773      * @param results
    774      * @param actions
    775      * @param pos
    776      * @return true if all of the dependent validations passed.
    777      * @throws ValidatorException If there's an error running a validator
    778      */
    779     private boolean runDependentValidators(
    780         ValidatorAction va,
    781         ValidatorResults results,
    782         Map actions,
    783         Map params,
    784         int pos)
    785         throws ValidatorException {
    786
    787         List dependentValidators = va.getDependencyList();
    788
    789         if (dependentValidators.isEmpty()) {
    790             return true;
    791         }
    792
    793         Iterator iter = dependentValidators.iterator();
    794         while (iter.hasNext()) {
    795             String depend = (String) iter.next();
    796
    797             ValidatorAction action = (ValidatorAction) actions.get(depend);
    798             if (action == null) {
    799                 this.handleMissingAction(depend);
    800             }
    801
    802             if (!this.validateForRule(action, results, actions, params, pos)) {
    803                 return false;
    804             }
    805         }
    806
    807         return true;
    808     }
    809
    810     /***
    811      * Run the configured validations on this field.  Run all validations
    812      * in the depends clause over each item in turn, returning when the first
    813      * one fails.
    814      * @param params A Map of parameter class names to parameter values to pass
    815      * into validation methods.
    816      * @param actions A Map of validator names to ValidatorAction objects.
    817      * @return A ValidatorResults object containing validation messages for
    818      * this field.
    819      * @throws ValidatorException If an error occurs during validation.
    820      */
    821     public ValidatorResults validate(Map params, Map actions)
    822         throws ValidatorException {
    823
    824         if (this.getDepends() == null) {
    825             return new ValidatorResults();
    826         }
    827
    828         ValidatorResults allResults = new ValidatorResults();
    829
    830         Object bean = params.get(Validator.BEAN_PARAM);
    831         int numberOfFieldsToValidate =
    832             this.isIndexed() ? this.getIndexedProperty(bean).length : 1;
    833
    834         for (int fieldNumber = 0; fieldNumber < numberOfFieldsToValidate; fieldNumber++) {
    835
    836             Iterator dependencies = this.dependencyList.iterator();
    837             ValidatorResults results = new ValidatorResults();
    838             while (dependencies.hasNext()) {
    839                 String depend = (String) dependencies.next();
    840
    841                 ValidatorAction action = (ValidatorAction) actions.get(depend);
    842                 if (action == null) {
    843                     this.handleMissingAction(depend);
    844                 }
    845
    846                 boolean good =
    847                     validateForRule(action, results, actions, params, fieldNumber);
    848
    849                 if (!good) {
    850                     allResults.merge(results);
    851                     return allResults;
    852                 }
    853             }
    854             allResults.merge(results);
    855         }
    856
    857         return allResults;
    858     }
    859
    860     /***
    861      * Called when a validator name is used in a depends clause but there is
    862      * no know ValidatorAction configured for that name.
    863      * @param name The name of the validator in the depends list.
    864      * @throws ValidatorException
    865      */
    866     private void handleMissingAction(String name) throws ValidatorException {
    867         throw new ValidatorException("No ValidatorAction named " + name
    868                 + " found for field " + this.getProperty());
    869     }
    870
    871     /***
    872      * Returns a Map of String Msg names to Msg objects.
    873      * @since Validator 1.2.0
    874      * @return A Map of the Field's messages.
    875      */
    876     protected Map getMsgMap() {
    877         return hMsgs;
    878     }
    879
    880     /***
    881      * Returns a Map of String Var names to Var objects.
    882      * @since Validator 1.2.0
    883      * @return A Map of the Field's variables.
    884      */
    885     protected Map getVarMap() {
    886         return hVars;
    887     }
    888
    889 }
    890