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