Coverage report

  %line %branch
org.apache.commons.validator.Field
64% 
91% 

 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  
  * <field> 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  1026
 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  513
     protected String property = null;
 83  
 
 84  
     /**
 85  
      * The Field's indexed property name.
 86  
      */
 87  513
     protected String indexedProperty = null;
 88  
 
 89  
     /**
 90  
      * The Field's indexed list property name.
 91  
      */
 92  513
     protected String indexedListProperty = null;
 93  
 
 94  
     /**
 95  
      * The Field's unique key.
 96  
      */
 97  513
     protected String key = null;
 98  
 
 99  
     /**
 100  
      * A comma separated list of validator's this field depends on.
 101  
      */
 102  513
     protected String depends = null;
 103  
 
 104  
     /**
 105  
      * The Page Number
 106  
      */
 107  513
     protected int page = 0;
 108  
     
 109  
     /**
 110  
      * The order of the Field in the Form.
 111  
      */
 112  513
     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  513
     private List dependencyList = Collections.synchronizedList(new ArrayList());
 121  
 
 122  
     /**
 123  
      * @deprecated Subclasses should use getVarMap() instead. 
 124  
      */
 125  513
     protected FastHashMap hVars = new FastHashMap();
 126  
 
 127  
     /**
 128  
      * @deprecated Subclasses should use getMsgMap() instead.
 129  
      */
 130  513
     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  513
     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  162
         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  0
         this.page = page;
 156  0
     }
 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  0
         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  0
         this.fieldOrder = fieldOrder;
 172  0
     }
 173  
 
 174  
     /**
 175  
      * Gets the property name of the field.
 176  
      * @return The field's property name.
 177  
      */
 178  
     public String getProperty() {
 179  167
         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  504
         this.property = property;
 188  504
     }
 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  0
         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  0
         this.indexedProperty = indexedProperty;
 206  0
     }
 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  0
         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  0
         this.indexedListProperty = indexedListProperty;
 226  0
     }
 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  162
         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  504
         this.depends = depends;
 242  
 
 243  504
         this.dependencyList.clear();
 244  
 
 245  504
         StringTokenizer st = new StringTokenizer(depends, ",");
 246  1503
         while (st.hasMoreTokens()) {
 247  495
             String depend = st.nextToken().trim();
 248  
 
 249  495
             if (depend != null && depend.length() > 0) {
 250  495
                 this.dependencyList.add(depend);
 251  
             }
 252  
         }
 253  504
     }
 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  0
         hMsgs.put(msg.getName(), msg);
 261  0
     }
 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  0
         Msg msg = getMessage(key);
 270  0
         return (msg == null) ? class="keyword">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  0
         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  0
         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  139
         if (arg == null || arg.getKey() == class="keyword">null || arg.getKey().length() == 0) {
 301  0
             return;
 302  
         }
 303  
 
 304  139
         determineArgPosition(arg);
 305  139
         ensureArgsCapacity(arg);
 306  
 
 307  139
         Map argMap = this.args[arg.getPosition()];
 308  139
         if (argMap == null) {
 309  134
             argMap = new HashMap();
 310  134
             this.args[arg.getPosition()] = argMap;
 311  
         }
 312  
 
 313  139
         if (arg.getName() == null) {
 314  130
             argMap.put(DEFAULT_ARG, arg);
 315  
         } else {
 316  9
             argMap.put(arg.getName(), arg);
 317  
         }
 318  
 
 319  139
     }
 320  
 
 321  
     /**
 322  
      * Calculate the position of the Arg
 323  
      */
 324  
     private void determineArgPosition(Arg arg) {
 325  
         
 326  139
         int position = arg.getPosition();
 327  
 
 328  
         // position has been explicity set
 329  139
         if (position >= 0) {
 330  16
             return;
 331  
         }
 332  
 
 333  
         // first arg to be added
 334  123
         if (args == null || args.length == 0) {
 335  107
             arg.setPosition(0);
 336  107
             return;
 337  
         }
 338  
 
 339  
         // determine the position of the last argument with
 340  
         // the same name or the last default argument
 341  16
         String key = arg.getName() == null ? DEFAULT_ARG : arg.getName();
 342  16
         int lastPosition = -1;
 343  16
         int lastDefault  = -1;
 344  55
         for (int i = 0; i < args.length; i++) {
 345  39
             if (args[i] != null && args[i].containsKey(key)) {
 346  18
                 lastPosition = i;
 347  
             }
 348  39
             if (args[i] != null && args[i].containsKey(DEFAULT_ARG)) {
 349  25
                 lastDefault = i;
 350  
             }
 351  
         }
 352  
 
 353  16
         if (lastPosition < 0) { 
 354  4
             lastPosition = lastDefault;
 355  
         }
 356  
 
 357  
         // allocate the next position
 358  16
         arg.setPosition(++lastPosition);
 359  
 
 360  16
     }
 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  139
         if (arg.getPosition() >= this.args.length) {
 370  129
             Map[] newArgs = new Map[arg.getPosition() + 1];
 371  129
             System.arraycopy(this.args, 0, newArgs, 0, class="keyword">this.args.length);
 372  129
             this.args = newArgs;
 373  
         }
 374  139
     }
 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  69
         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  149
         if ((position >= this.args.length) || (class="keyword">this.args[position] == null)) {
 398  2
             return null;
 399  
         }
 400  
 
 401  147
         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  147
         if ((arg == null) && key.equals(DEFAULT_ARG)) {
 406  9
             return null;
 407  
         }
 408  
 
 409  138
         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  13
         Arg[] args = new Arg[this.args.length];
 421  
         
 422  55
         for (int i = 0; i < this.args.length; i++) {
 423  42
             args[i] = this.getArg(key, i);
 424  
         }
 425  
         
 426  13
         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  125
         this.hVars.put(v.getName(), v);
 435  125
     }
 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  0
         this.addVar(new Var(name, value, jsType));
 446  0
     }
 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  208
         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  106
         String value = null;
 464  
 
 465  106
         Object o = hVars.get(mainKey);
 466  106
         if (o != null && o instanceof Var) {
 467  64
             Var v = (Var) o;
 468  64
             value = v.getValue();
 469  
         }
 470  
 
 471  106
         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  0
         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  1095
         if (this.key == null) {
 489  504
             this.generateKey();
 490  
         }
 491  
 
 492  1095
         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  0
         this.key = key;
 502  0
     }
 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  1345
         return ((indexedListProperty != null && indexedListProperty.length() > 0));
 512  
     }
 513  
 
 514  
     /**
 515  
      * Generate correct <code>key</code> value.
 516  
      */
 517  
     public void generateKey() {
 518  1008
         if (this.isIndexed()) {
 519  0
             this.key = class="keyword">this.indexedListProperty + TOKEN_INDEXED + "." + this.property;
 520  
         } else {
 521  1008
             this.key = class="keyword">this.property;
 522  
         }
 523  1008
     }
 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  504
         this.hMsgs.setFast(false);
 531  504
         this.hVars.setFast(true);
 532  
 
 533  504
         this.generateKey();
 534  
 
 535  
         // Process FormSet Constants
 536  1068
         for (Iterator i = constants.keySet().iterator(); i.hasNext();) {
 537  60
             String key = (String) i.next();
 538  60
             String key2 = TOKEN_START + key + TOKEN_END;
 539  60
             String replaceValue = (String) constants.get(key);
 540  
 
 541  60
             property = ValidatorUtils.replace(property, key2, replaceValue);
 542  
 
 543  60
             processVars(key2, replaceValue);
 544  
 
 545  60
             this.processMessageComponents(key2, replaceValue);
 546  
         }
 547  
 
 548  
         // Process Global Constants
 549  1008
         for (Iterator i = globalConstants.keySet().iterator(); i.hasNext();) {
 550  0
             String key = (String) i.next();
 551  0
             String key2 = TOKEN_START + key + TOKEN_END;
 552  0
             String replaceValue = (String) globalConstants.get(key);
 553  
 
 554  0
             property = ValidatorUtils.replace(property, key2, replaceValue);
 555  
 
 556  0
             processVars(key2, replaceValue);
 557  
 
 558  0
             this.processMessageComponents(key2, replaceValue);
 559  
         }
 560  
 
 561  
         // Process Var Constant Replacement
 562  1133
         for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
 563  125
             String key = (String) i.next();
 564  125
             String key2 = TOKEN_START + TOKEN_VAR + key + TOKEN_END;
 565  125
             Var var = this.getVar(key);
 566  125
             String replaceValue = var.getValue();
 567  
 
 568  125
             this.processMessageComponents(key2, replaceValue);
 569  
         }
 570  
 
 571  504
         hMsgs.setFast(true);
 572  504
     }
 573  
 
 574  
     /**
 575  
      * Replace the vars value with the key/value pairs passed in.
 576  
      */
 577  
     private void processVars(String key, String replaceValue) {
 578  60
         Iterator i = this.hVars.keySet().iterator();
 579  200
         while (i.hasNext()) {
 580  80
             String varKey = (String) i.next();
 581  80
             Var var = this.getVar(class="keyword">varKey);
 582  
 
 583  80
             var.setValue(ValidatorUtils.replace(class="keyword">var.getValue(), key, replaceValue));
 584  
         }
 585  
 
 586  60
     }
 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  185
         String varKey = TOKEN_START + TOKEN_VAR;
 593  
         // Process Messages
 594  185
         if (key != null && !key.startsWith(varKey)) {
 595  120
             for (Iterator i = hMsgs.values().iterator(); i.hasNext();) {
 596  0
                 Msg msg = (Msg) i.next();
 597  0
                 msg.setKey(ValidatorUtils.replace(msg.getKey(), key, replaceValue));
 598  
             }
 599  
         }
 600  
 
 601  185
         this.processArg(key, replaceValue);
 602  185
     }
 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  225
         for (int i = 0; i < this.args.length; i++) {
 610  
 
 611  40
             Map argMap = this.args[i];
 612  40
             if (argMap == null) {
 613  0
                 continue;
 614  
             }
 615  
 
 616  40
             Iterator iter = argMap.values().iterator();
 617  120
             while (iter.hasNext()) {
 618  40
                 Arg arg = (Arg) iter.next();
 619  
 
 620  40
                 if (arg != null) {
 621  40
                     arg.setKey(
 622  
                             ValidatorUtils.replace(arg.getKey(), key, replaceValue));
 623  
                 }
 624  
             }
 625  
         }
 626  185
     }
 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  0
         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  0
         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  0
         Field field = null;
 652  
         try {
 653  0
             field = (Field) super.clone();
 654  0
         } catch(CloneNotSupportedException e) {
 655  0
             throw new RuntimeException(e.toString());
 656  
         }
 657  
 
 658  0
         field.args = new Map[this.args.length];
 659  0
         for (int i = 0; i < this.args.length; i++) {
 660  0
             if (this.args[i] == null) {
 661  0
                 continue;
 662  
             }
 663  
 
 664  0
             Map argMap = new HashMap(this.args[i]);
 665  0
             Iterator iter = argMap.keySet().iterator();
 666  0
             while (iter.hasNext()) {
 667  0
                 String validatorName = (String) iter.next();
 668  0
                 Arg arg = (Arg) argMap.get(validatorName);
 669  0
                 argMap.put(validatorName, arg.clone());
 670  
             }
 671  0
             field.args[i] = argMap;
 672  
         }
 673  
 
 674  0
         field.hVars = ValidatorUtils.copyFastHashMap(hVars);
 675  0
         field.hMsgs = ValidatorUtils.copyFastHashMap(hMsgs);
 676  
 
 677  0
         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  0
         StringBuffer results = new StringBuffer();
 686  
 
 687  0
         results.append("\t\tkey = " + key + "\n");
 688  0
         results.append("\t\tproperty = " + property + "\n");
 689  0
         results.append("\t\tindexedProperty = " + indexedProperty + "\n");
 690  0
         results.append("\t\tindexedListProperty = " + indexedListProperty + "\n");
 691  0
         results.append("\t\tdepends = " + depends + "\n");
 692  0
         results.append("\t\tpage = " + page + "\n");
 693  0
         results.append("\t\tfieldOrder = " + fieldOrder + "\n");
 694  
 
 695  0
         if (hVars != null) {
 696  0
             results.append("\t\tVars:\n");
 697  0
             for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
 698  0
                 Object key = i.next();
 699  0
                 results.append("\t\t\t");
 700  0
                 results.append(key);
 701  0
                 results.append("=");
 702  0
                 results.append(hVars.get(key));
 703  0
                 results.append("\n");
 704  
             }
 705  
         }
 706  
 
 707  0
         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  0
         Object indexedProperty = null;
 719  
 
 720  
         try {
 721  0
             indexedProperty =
 722  
                 PropertyUtils.getProperty(bean, this.getIndexedListProperty());
 723  
 
 724  0
         } catch(IllegalAccessException e) {
 725  0
             throw new ValidatorException(e.getMessage());
 726  
         } catch(InvocationTargetException e) {
 727  0
             throw new ValidatorException(e.getMessage());
 728  
         } catch(NoSuchMethodException e) {
 729  0
             throw new ValidatorException(e.getMessage());
 730  
         }
 731  
 
 732  0
         if (indexedProperty instanceof Collection) {
 733  0
             return ((Collection) indexedProperty).toArray();
 734  
 
 735  0
         } else if (indexedProperty.getClass().isArray()) {
 736  0
             return (Object[]) indexedProperty;
 737  
 
 738  
         } else {
 739  0
             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  166
         ValidatorResult result = results.getValidatorResult(this.getKey());
 758  166
         if (result != null && result.containsAction(va.getName())) {
 759  0
             return result.isValid(va.getName());
 760  
         }
 761  
 
 762  166
         if (!this.runDependentValidators(va, results, actions, params, pos)) {
 763  1
             return false;
 764  
         }
 765  
 
 766  165
         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  166
         List dependentValidators = va.getDependencyList();
 788  
 
 789  166
         if (dependentValidators.isEmpty()) {
 790  164
             return true;
 791  
         }
 792  
 
 793  2
         Iterator iter = dependentValidators.iterator();
 794  5
         while (iter.hasNext()) {
 795  2
             String depend = (String) iter.next();
 796  
 
 797  2
             ValidatorAction action = (ValidatorAction) actions.get(depend);
 798  2
             if (action == null) {
 799  0
                 this.handleMissingAction(depend);
 800  
             }
 801  
 
 802  2
             if (!this.validateForRule(action, results, actions, params, pos)) {
 803  1
                 return false;
 804  
             }
 805  
         }
 806  
 
 807  1
         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  162
         if (this.getDepends() == null) {
 825  0
             return new ValidatorResults();
 826  
         }
 827  
 
 828  162
         ValidatorResults allResults = new ValidatorResults();
 829  
 
 830  162
         Object bean = params.get(Validator.BEAN_PARAM);
 831  162
         int numberOfFieldsToValidate =
 832  
             this.isIndexed() ? class="keyword">this.getIndexedProperty(bean).length : 1;
 833  
 
 834  249
         for (int fieldNumber = 0; fieldNumber < numberOfFieldsToValidate; fieldNumber++) {
 835  
             
 836  162
             Iterator dependencies = this.dependencyList.iterator();
 837  162
             ValidatorResults results = new ValidatorResults();
 838  413
             while (dependencies.hasNext()) {
 839  164
                 String depend = (String) dependencies.next();
 840  
 
 841  164
                 ValidatorAction action = (ValidatorAction) actions.get(depend);
 842  164
                 if (action == null) {
 843  0
                     this.handleMissingAction(depend);
 844  
                 }
 845  
 
 846  164
                 boolean good =
 847  
                     validateForRule(action, results, actions, params, fieldNumber);
 848  
 
 849  163
                 if (!good) {
 850  74
                     allResults.merge(results);
 851  74
                     return allResults;
 852  
                 }
 853  
             }
 854  87
             allResults.merge(results);
 855  
         }
 856  
         
 857  87
         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  0
         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  0
         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  0
         return hVars;
 887  
     }
 888  
 
 889  
 }
 890  
 

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.