Coverage report

  %line %branch
org.apache.commons.validator.Field
61% 
88% 

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

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