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: 478334 $ $Date: 2006-11-22 21:31:54 +0000 (Wed, 22 Nov 2006) $
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 = "org.apache.commons.validator.Field.DEFAULT";
054:
055: /**
056: * This indicates an indexed property is being referenced.
057: */
058: public static final String TOKEN_INDEXED = "[]";
059:
060: /**
061: * The start of a token.
062: */
063: protected static final String TOKEN_START = "${";
064:
065: /**
066: * The end of a token.
067: */
068: protected static final String TOKEN_END = "}";
069:
070: /**
071: * A Vriable token.
072: */
073: protected static final String TOKEN_VAR = "var:";
074:
075: /**
076: * The Field's property name.
077: */
078: protected String property = null;
079:
080: /**
081: * The Field's indexed property name.
082: */
083: protected String indexedProperty = null;
084:
085: /**
086: * The Field's indexed list property name.
087: */
088: protected String indexedListProperty = null;
089:
090: /**
091: * The Field's unique key.
092: */
093: protected String key = null;
094:
095: /**
096: * A comma separated list of validator's this field depends on.
097: */
098: protected String depends = null;
099:
100: /**
101: * The Page Number
102: */
103: protected int page = 0;
104:
105: /**
106: * The order of the Field in the Form.
107: */
108: protected int fieldOrder = 0;
109:
110: /**
111: * Internal representation of this.depends String as a List. This List
112: * gets updated whenever setDepends() gets called. This List is
113: * synchronized so a call to setDepends() (which clears the List) won't
114: * interfere with a call to isDependency().
115: */
116: private List dependencyList = Collections
117: .synchronizedList(new ArrayList());
118:
119: /**
120: * @deprecated Subclasses should use getVarMap() instead.
121: */
122: protected FastHashMap hVars = new FastHashMap();
123:
124: /**
125: * @deprecated Subclasses should use getMsgMap() instead.
126: */
127: 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: 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: 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: this .page = page;
153: }
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: 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: this .fieldOrder = fieldOrder;
169: }
170:
171: /**
172: * Gets the property name of the field.
173: * @return The field's property name.
174: */
175: public String getProperty() {
176: 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: this .property = property;
185: }
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: 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: this .indexedProperty = indexedProperty;
203: }
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: 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: this .indexedListProperty = indexedListProperty;
223: }
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: 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: this .depends = depends;
239:
240: this .dependencyList.clear();
241:
242: StringTokenizer st = new StringTokenizer(depends, ",");
243: while (st.hasMoreTokens()) {
244: String depend = st.nextToken().trim();
245:
246: if (depend != null && depend.length() > 0) {
247: this .dependencyList.add(depend);
248: }
249: }
250: }
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: hMsgs.put(msg.getName(), msg);
258: }
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: Msg msg = getMessage(key);
267: return (msg == null) ? 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: 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: 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: if (arg == null || arg.getKey() == null
298: || arg.getKey().length() == 0) {
299: return;
300: }
301:
302: determineArgPosition(arg);
303: ensureArgsCapacity(arg);
304:
305: Map argMap = this .args[arg.getPosition()];
306: if (argMap == null) {
307: argMap = new HashMap();
308: this .args[arg.getPosition()] = argMap;
309: }
310:
311: if (arg.getName() == null) {
312: argMap.put(DEFAULT_ARG, arg);
313: } else {
314: argMap.put(arg.getName(), arg);
315: }
316:
317: }
318:
319: /**
320: * Calculate the position of the Arg
321: */
322: private void determineArgPosition(Arg arg) {
323:
324: int position = arg.getPosition();
325:
326: // position has been explicity set
327: if (position >= 0) {
328: return;
329: }
330:
331: // first arg to be added
332: if (args == null || args.length == 0) {
333: arg.setPosition(0);
334: return;
335: }
336:
337: // determine the position of the last argument with
338: // the same name or the last default argument
339: String key = arg.getName() == null ? DEFAULT_ARG : arg
340: .getName();
341: int lastPosition = -1;
342: int lastDefault = -1;
343: for (int i = 0; i < args.length; i++) {
344: if (args[i] != null && args[i].containsKey(key)) {
345: lastPosition = i;
346: }
347: if (args[i] != null && args[i].containsKey(DEFAULT_ARG)) {
348: lastDefault = i;
349: }
350: }
351:
352: if (lastPosition < 0) {
353: lastPosition = lastDefault;
354: }
355:
356: // allocate the next position
357: arg.setPosition(++lastPosition);
358:
359: }
360:
361: /**
362: * Ensures that the args array can hold the given arg. Resizes the array as
363: * necessary.
364: * @param arg Determine if the args array is long enough to store this arg's
365: * position.
366: */
367: private void ensureArgsCapacity(Arg arg) {
368: if (arg.getPosition() >= this .args.length) {
369: Map[] newArgs = new Map[arg.getPosition() + 1];
370: System
371: .arraycopy(this .args, 0, newArgs, 0,
372: this .args.length);
373: this .args = newArgs;
374: }
375: }
376:
377: /**
378: * Gets the default <code>Arg</code> object at the given position.
379: * @param position Validation message argument's position.
380: * @return The default Arg or null if not found.
381: * @since Validator 1.1
382: */
383: public Arg getArg(int position) {
384: return this .getArg(DEFAULT_ARG, position);
385: }
386:
387: /**
388: * Gets the <code>Arg</code> object at the given position. If the key
389: * finds a <code>null</code> value then the default value will be
390: * retrieved.
391: * @param key The name the Arg is stored under. If not found, the default
392: * Arg for the given position (if any) will be retrieved.
393: * @param position The Arg number to find.
394: * @return The Arg with the given name and position or null if not found.
395: * @since Validator 1.1
396: */
397: public Arg getArg(String key, int position) {
398: if ((position >= this .args.length)
399: || (this .args[position] == null)) {
400: return null;
401: }
402:
403: Arg arg = (Arg) args[position].get(key);
404:
405: // Didn't find default arg so exit, otherwise we would get into
406: // infinite recursion
407: if ((arg == null) && key.equals(DEFAULT_ARG)) {
408: return null;
409: }
410:
411: return (arg == null) ? this .getArg(position) : arg;
412: }
413:
414: /**
415: * Retrieves the Args for the given validator name.
416: * @param key The validator's args to retrieve.
417: * @return An Arg[] sorted by the Args' positions (i.e. the Arg at index 0
418: * has a position of 0).
419: * @since Validator 1.1.1
420: */
421: public Arg[] getArgs(String key) {
422: Arg[] args = new Arg[this .args.length];
423:
424: for (int i = 0; i < this .args.length; i++) {
425: args[i] = this .getArg(key, i);
426: }
427:
428: return args;
429: }
430:
431: /**
432: * Add a <code>Var</code> to the <code>Field</code>.
433: * @param v The Validator Argument.
434: */
435: public void addVar(Var v) {
436: this .hVars.put(v.getName(), v);
437: }
438:
439: /**
440: * Add a <code>Var</code>, based on the values passed in, to the
441: * <code>Field</code>.
442: * @param name Name of the validation.
443: * @param value The Argument's value.
444: * @param jsType The Javascript type.
445: */
446: public void addVar(String name, String value, String jsType) {
447: this .addVar(new Var(name, value, jsType));
448: }
449:
450: /**
451: * Retrieve a variable.
452: * @param mainKey The Variable's key
453: * @return the Variable
454: */
455: public Var getVar(String mainKey) {
456: return (Var) hVars.get(mainKey);
457: }
458:
459: /**
460: * Retrieve a variable's value.
461: * @param mainKey The Variable's key
462: * @return the Variable's value
463: */
464: public String getVarValue(String mainKey) {
465: String value = null;
466:
467: Object o = hVars.get(mainKey);
468: if (o != null && o instanceof Var) {
469: Var v = (Var) o;
470: value = v.getValue();
471: }
472:
473: return value;
474: }
475:
476: /**
477: * The <code>Field</code>'s variables are returned as an
478: * unmodifiable <code>Map</code>.
479: * @return the Map of Variable's for a Field.
480: */
481: public Map getVars() {
482: return Collections.unmodifiableMap(hVars);
483: }
484:
485: /**
486: * Gets a unique key based on the property and indexedProperty fields.
487: * @return a unique key for the field.
488: */
489: public String getKey() {
490: if (this .key == null) {
491: this .generateKey();
492: }
493:
494: return this .key;
495: }
496:
497: /**
498: * Sets a unique key for the field. This can be used to change
499: * the key temporarily to have a unique key for an indexed field.
500: * @param key a unique key for the field
501: */
502: public void setKey(String key) {
503: this .key = key;
504: }
505:
506: /**
507: * If there is a value specified for the indexedProperty field then
508: * <code>true</code> will be returned. Otherwise it will be
509: * <code>false</code>.
510: * @return Whether the Field is indexed.
511: */
512: public boolean isIndexed() {
513: return ((indexedListProperty != null && indexedListProperty
514: .length() > 0));
515: }
516:
517: /**
518: * Generate correct <code>key</code> value.
519: */
520: public void generateKey() {
521: if (this .isIndexed()) {
522: this .key = this .indexedListProperty + TOKEN_INDEXED + "."
523: + this .property;
524: } else {
525: this .key = this .property;
526: }
527: }
528:
529: /**
530: * Replace constants with values in fields and process the depends field
531: * to create the dependency <code>Map</code>.
532: */
533: void process(Map globalConstants, Map constants) {
534: this .hMsgs.setFast(false);
535: this .hVars.setFast(true);
536:
537: this .generateKey();
538:
539: // Process FormSet Constants
540: for (Iterator i = constants.keySet().iterator(); i.hasNext();) {
541: String key = (String) i.next();
542: String key2 = TOKEN_START + key + TOKEN_END;
543: String replaceValue = (String) constants.get(key);
544:
545: property = ValidatorUtils.replace(property, key2,
546: replaceValue);
547:
548: processVars(key2, replaceValue);
549:
550: this .processMessageComponents(key2, replaceValue);
551: }
552:
553: // Process Global Constants
554: for (Iterator i = globalConstants.keySet().iterator(); i
555: .hasNext();) {
556: String key = (String) i.next();
557: String key2 = TOKEN_START + key + TOKEN_END;
558: String replaceValue = (String) globalConstants.get(key);
559:
560: property = ValidatorUtils.replace(property, key2,
561: replaceValue);
562:
563: processVars(key2, replaceValue);
564:
565: this .processMessageComponents(key2, replaceValue);
566: }
567:
568: // Process Var Constant Replacement
569: for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
570: String key = (String) i.next();
571: String key2 = TOKEN_START + TOKEN_VAR + key + TOKEN_END;
572: Var var = this .getVar(key);
573: String replaceValue = var.getValue();
574:
575: this .processMessageComponents(key2, replaceValue);
576: }
577:
578: hMsgs.setFast(true);
579: }
580:
581: /**
582: * Replace the vars value with the key/value pairs passed in.
583: */
584: private void processVars(String key, String replaceValue) {
585: Iterator i = this .hVars.keySet().iterator();
586: while (i.hasNext()) {
587: String varKey = (String) i.next();
588: Var var = this .getVar(varKey);
589:
590: var.setValue(ValidatorUtils.replace(var.getValue(), key,
591: replaceValue));
592: }
593:
594: }
595:
596: /**
597: * Replace the args key value with the key/value pairs passed in.
598: */
599: private void processMessageComponents(String key,
600: String replaceValue) {
601: String varKey = TOKEN_START + TOKEN_VAR;
602: // Process Messages
603: if (key != null && !key.startsWith(varKey)) {
604: for (Iterator i = hMsgs.values().iterator(); i.hasNext();) {
605: Msg msg = (Msg) i.next();
606: msg.setKey(ValidatorUtils.replace(msg.getKey(), key,
607: replaceValue));
608: }
609: }
610:
611: this .processArg(key, replaceValue);
612: }
613:
614: /**
615: * Replace the arg <code>Collection</code> key value with the key/value
616: * pairs passed in.
617: */
618: private void processArg(String key, String replaceValue) {
619: for (int i = 0; i < this .args.length; i++) {
620:
621: Map argMap = this .args[i];
622: if (argMap == null) {
623: continue;
624: }
625:
626: Iterator iter = argMap.values().iterator();
627: while (iter.hasNext()) {
628: Arg arg = (Arg) iter.next();
629:
630: if (arg != null) {
631: arg.setKey(ValidatorUtils.replace(arg.getKey(),
632: key, replaceValue));
633: }
634: }
635: }
636: }
637:
638: /**
639: * Checks if the validator is listed as a dependency.
640: * @param validatorName Name of the validator to check.
641: * @return Whether the field is dependant on a validator.
642: */
643: public boolean isDependency(String validatorName) {
644: return this .dependencyList.contains(validatorName);
645: }
646:
647: /**
648: * Gets an unmodifiable <code>List</code> of the dependencies in the same
649: * order they were defined in parameter passed to the setDepends() method.
650: * @return A list of the Field's dependancies.
651: */
652: public List getDependencyList() {
653: return Collections.unmodifiableList(this .dependencyList);
654: }
655:
656: /**
657: * Creates and returns a copy of this object.
658: * @return A copy of the Field.
659: */
660: public Object clone() {
661: Field field = null;
662: try {
663: field = (Field) super .clone();
664: } catch (CloneNotSupportedException e) {
665: throw new RuntimeException(e.toString());
666: }
667:
668: field.args = new Map[this .args.length];
669: for (int i = 0; i < this .args.length; i++) {
670: if (this .args[i] == null) {
671: continue;
672: }
673:
674: Map argMap = new HashMap(this .args[i]);
675: Iterator iter = argMap.keySet().iterator();
676: while (iter.hasNext()) {
677: String validatorName = (String) iter.next();
678: Arg arg = (Arg) argMap.get(validatorName);
679: argMap.put(validatorName, arg.clone());
680: }
681: field.args[i] = argMap;
682: }
683:
684: field.hVars = ValidatorUtils.copyFastHashMap(hVars);
685: field.hMsgs = ValidatorUtils.copyFastHashMap(hMsgs);
686:
687: return field;
688: }
689:
690: /**
691: * Returns a string representation of the object.
692: * @return A string representation of the object.
693: */
694: public String toString() {
695: StringBuffer results = new StringBuffer();
696:
697: results.append("\t\tkey = " + key + "\n");
698: results.append("\t\tproperty = " + property + "\n");
699: results.append("\t\tindexedProperty = " + indexedProperty
700: + "\n");
701: results.append("\t\tindexedListProperty = "
702: + indexedListProperty + "\n");
703: results.append("\t\tdepends = " + depends + "\n");
704: results.append("\t\tpage = " + page + "\n");
705: results.append("\t\tfieldOrder = " + fieldOrder + "\n");
706:
707: if (hVars != null) {
708: results.append("\t\tVars:\n");
709: for (Iterator i = hVars.keySet().iterator(); i.hasNext();) {
710: Object key = i.next();
711: results.append("\t\t\t");
712: results.append(key);
713: results.append("=");
714: results.append(hVars.get(key));
715: results.append("\n");
716: }
717: }
718:
719: return results.toString();
720: }
721:
722: /**
723: * Returns an indexed property from the object we're validating.
724: *
725: * @param bean The bean to extract the indexed values from.
726: * @throws ValidatorException If there's an error looking up the property
727: * or, the property found is not indexed.
728: */
729: Object[] getIndexedProperty(Object bean) throws ValidatorException {
730: Object indexedProperty = null;
731:
732: try {
733: indexedProperty = PropertyUtils.getProperty(bean, this
734: .getIndexedListProperty());
735:
736: } catch (IllegalAccessException e) {
737: throw new ValidatorException(e.getMessage());
738: } catch (InvocationTargetException e) {
739: throw new ValidatorException(e.getMessage());
740: } catch (NoSuchMethodException e) {
741: throw new ValidatorException(e.getMessage());
742: }
743:
744: if (indexedProperty instanceof Collection) {
745: return ((Collection) indexedProperty).toArray();
746:
747: } else if (indexedProperty.getClass().isArray()) {
748: return (Object[]) indexedProperty;
749:
750: } else {
751: throw new ValidatorException(this .getKey()
752: + " is not indexed");
753: }
754:
755: }
756:
757: /**
758: * Returns the size of an indexed property from the object we're validating.
759: *
760: * @param bean The bean to extract the indexed values from.
761: * @throws ValidatorException If there's an error looking up the property
762: * or, the property found is not indexed.
763: */
764: private int getIndexedPropertySize(Object bean)
765: throws ValidatorException {
766: Object indexedProperty = null;
767:
768: try {
769: indexedProperty = PropertyUtils.getProperty(bean, this
770: .getIndexedListProperty());
771:
772: } catch (IllegalAccessException e) {
773: throw new ValidatorException(e.getMessage());
774: } catch (InvocationTargetException e) {
775: throw new ValidatorException(e.getMessage());
776: } catch (NoSuchMethodException e) {
777: throw new ValidatorException(e.getMessage());
778: }
779:
780: if (indexedProperty == null) {
781: return 0;
782: } else if (indexedProperty instanceof Collection) {
783: return ((Collection) indexedProperty).size();
784: } else if (indexedProperty.getClass().isArray()) {
785: return ((Object[]) indexedProperty).length;
786: } else {
787: throw new ValidatorException(this .getKey()
788: + " is not indexed");
789: }
790:
791: }
792:
793: /**
794: * Executes the given ValidatorAction and all ValidatorActions that it
795: * depends on.
796: * @return true if the validation succeeded.
797: */
798: private boolean validateForRule(ValidatorAction va,
799: ValidatorResults results, Map actions, Map params, int pos)
800: throws ValidatorException {
801:
802: ValidatorResult result = results.getValidatorResult(this
803: .getKey());
804: if (result != null && result.containsAction(va.getName())) {
805: return result.isValid(va.getName());
806: }
807:
808: if (!this .runDependentValidators(va, results, actions, params,
809: pos)) {
810: return false;
811: }
812:
813: return va.executeValidationMethod(this , params, results, pos);
814: }
815:
816: /**
817: * Calls all of the validators that this validator depends on.
818: * TODO ValidatorAction should know how to run its own dependencies.
819: * @param va Run dependent validators for this action.
820: * @param results
821: * @param actions
822: * @param pos
823: * @return true if all of the dependent validations passed.
824: * @throws ValidatorException If there's an error running a validator
825: */
826: private boolean runDependentValidators(ValidatorAction va,
827: ValidatorResults results, Map actions, Map params, int pos)
828: throws ValidatorException {
829:
830: List dependentValidators = va.getDependencyList();
831:
832: if (dependentValidators.isEmpty()) {
833: return true;
834: }
835:
836: Iterator iter = dependentValidators.iterator();
837: while (iter.hasNext()) {
838: String depend = (String) iter.next();
839:
840: ValidatorAction action = (ValidatorAction) actions
841: .get(depend);
842: if (action == null) {
843: this .handleMissingAction(depend);
844: }
845:
846: if (!this .validateForRule(action, results, actions, params,
847: pos)) {
848: return false;
849: }
850: }
851:
852: return true;
853: }
854:
855: /**
856: * Run the configured validations on this field. Run all validations
857: * in the depends clause over each item in turn, returning when the first
858: * one fails.
859: * @param params A Map of parameter class names to parameter values to pass
860: * into validation methods.
861: * @param actions A Map of validator names to ValidatorAction objects.
862: * @return A ValidatorResults object containing validation messages for
863: * this field.
864: * @throws ValidatorException If an error occurs during validation.
865: */
866: public ValidatorResults validate(Map params, Map actions)
867: throws ValidatorException {
868:
869: if (this .getDepends() == null) {
870: return new ValidatorResults();
871: }
872:
873: ValidatorResults allResults = new ValidatorResults();
874:
875: Object bean = params.get(Validator.BEAN_PARAM);
876: int numberOfFieldsToValidate = this .isIndexed() ? this
877: .getIndexedPropertySize(bean) : 1;
878:
879: for (int fieldNumber = 0; fieldNumber < numberOfFieldsToValidate; fieldNumber++) {
880:
881: Iterator dependencies = this .dependencyList.iterator();
882: ValidatorResults results = new ValidatorResults();
883: while (dependencies.hasNext()) {
884: String depend = (String) dependencies.next();
885:
886: ValidatorAction action = (ValidatorAction) actions
887: .get(depend);
888: if (action == null) {
889: this .handleMissingAction(depend);
890: }
891:
892: boolean good = validateForRule(action, results,
893: actions, params, fieldNumber);
894:
895: if (!good) {
896: allResults.merge(results);
897: return allResults;
898: }
899: }
900: allResults.merge(results);
901: }
902:
903: return allResults;
904: }
905:
906: /**
907: * Called when a validator name is used in a depends clause but there is
908: * no know ValidatorAction configured for that name.
909: * @param name The name of the validator in the depends list.
910: * @throws ValidatorException
911: */
912: private void handleMissingAction(String name)
913: throws ValidatorException {
914: throw new ValidatorException("No ValidatorAction named " + name
915: + " found for field " + this .getProperty());
916: }
917:
918: /**
919: * Returns a Map of String Msg names to Msg objects.
920: * @since Validator 1.2.0
921: * @return A Map of the Field's messages.
922: */
923: protected Map getMsgMap() {
924: return hMsgs;
925: }
926:
927: /**
928: * Returns a Map of String Var names to Var objects.
929: * @since Validator 1.2.0
930: * @return A Map of the Field's variables.
931: */
932: protected Map getVarMap() {
933: return hVars;
934: }
935:
936: }
|