View Javadoc

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