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