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.util.ArrayList;
021    import java.util.Collections;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.commons.collections.FastHashMap;// DEPRECATED
027    
028    /**
029     * <p>
030     *
031     * This contains a set of validation rules for a form/JavaBean. The information
032     * is contained in a list of <code>Field</code> objects. Instances of this class
033     * are configured with a &lt;form&gt; xml element. </p> <p>
034     *
035     * The use of FastHashMap is deprecated and will be replaced in a future
036     * release. </p>
037     *
038     * @version $Revision: 493905 $ $Date: 2007-01-08 03:11:38 +0100 (Mo, 08. Jan 2007) $
039     */
040    public class Form implements Serializable {
041    
042        /** The name/key the set of validation rules is stored under. */
043        protected String name = null;
044    
045        /**
046         * List of <code>Field</code>s. Used to maintain the order they were added
047         * in although individual <code>Field</code>s can be retrieved using <code>Map</code>
048         * of <code>Field</code>s.
049         */
050        protected List lFields = new ArrayList();
051    
052        /**
053         * Map of <code>Field</code>s keyed on their property value.
054         *
055         * @deprecated   Subclasses should use getFieldMap() instead.
056         */
057        protected FastHashMap hFields = new FastHashMap();
058    
059        /**
060         * The name/key of the form which this form extends from.
061         *
062         * @since   Validator 1.2.0
063         */
064        protected String inherit = null;
065    
066        /**
067         * Whether or not the this <code>Form</code> was processed for replacing
068         * variables in strings with their values.
069         */
070        private boolean processed = false;
071    
072        /**
073         * Gets the name/key of the set of validation rules.
074         *
075         * @return   The name value
076         */
077        public String getName() {
078            return name;
079        }
080    
081        /**
082         * Sets the name/key of the set of validation rules.
083         *
084         * @param name  The new name value
085         */
086        public void setName(String name) {
087            this.name = name;
088        }
089    
090        /**
091         * Add a <code>Field</code> to the <code>Form</code>.
092         *
093         * @param f  The field
094         */
095        public void addField(Field f) {
096            this.lFields.add(f);
097            this.hFields.put(f.getKey(), f);
098        }
099    
100        /**
101         * A <code>List</code> of <code>Field</code>s is returned as an unmodifiable
102         * <code>List</code>.
103         *
104         * @return   The fields value
105         */
106        public List getFields() {
107            return Collections.unmodifiableList(lFields);
108        }
109    
110        /**
111         * Returns the Field with the given name or null if this Form has no such
112         * field.
113         *
114         * @param fieldName  The field name
115         * @return           The field value
116         * @since            Validator 1.1
117         */
118        public Field getField(String fieldName) {
119            return (Field) this.hFields.get(fieldName);
120        }
121    
122        /**
123         * Returns true if this Form contains a Field with the given name.
124         *
125         * @param fieldName  The field name
126         * @return           True if this form contains the field by the given name
127         * @since            Validator 1.1
128         */
129        public boolean containsField(String fieldName) {
130            return this.hFields.containsKey(fieldName);
131        }
132    
133        /**
134         * Merges the given form into this one. For any field in <code>depends</code>
135         * not present in this form, include it. <code>depends</code> has precedence
136         * in the way the fields are ordered.
137         *
138         * @param depends  the form we want to merge
139         * @since          Validator 1.2.0
140         */
141        protected void merge(Form depends) {
142    
143            List templFields = new ArrayList();
144            Map temphFields = new FastHashMap();
145            Iterator dependsIt = depends.getFields().iterator();
146            while (dependsIt.hasNext()) {
147                Field defaultField = (Field) dependsIt.next();
148                if (defaultField != null) {
149                    String fieldKey = defaultField.getKey();
150                    if (!this.containsField(fieldKey)) {
151                        templFields.add(defaultField);
152                        temphFields.put(fieldKey, defaultField);
153                    }
154                    else {
155                        Field old = getField(fieldKey);
156                        hFields.remove(fieldKey);
157                        lFields.remove(old);
158                        templFields.add(old);
159                        temphFields.put(fieldKey, old);
160                    }
161                }
162            }
163            lFields.addAll(0, templFields);
164            hFields.putAll(temphFields);
165        }
166    
167        /**
168         * Processes all of the <code>Form</code>'s <code>Field</code>s.
169         *
170         * @param globalConstants  A map of global constants
171         * @param constants        Local constants
172         * @param forms            Map of forms
173         * @since                  Validator 1.2.0
174         */
175        protected void process(Map globalConstants, Map constants, Map forms) {
176            if (isProcessed()) {
177                return;
178            }
179    
180            int n = 0;//we want the fields from its parent first
181            if (isExtending()) {
182                Form parent = (Form) forms.get(inherit);
183                if (parent != null) {
184                    if (!parent.isProcessed()) {
185                        //we want to go all the way up the tree
186                        parent.process(constants, globalConstants, forms);
187                    }
188                    for (Iterator i = parent.getFields().iterator(); i.hasNext(); ) {
189                        Field f = (Field) i.next();
190                        //we want to be able to override any fields we like
191                        if (hFields.get(f.getKey()) == null) {
192                            lFields.add(n, f);
193                            hFields.put(f.getKey(), f);
194                            n++;
195                        }
196                    }
197                }
198            }
199            hFields.setFast(true);
200            //no need to reprocess parent's fields, we iterate from 'n'
201            for (Iterator i = lFields.listIterator(n); i.hasNext(); ) {
202                Field f = (Field) i.next();
203                f.process(globalConstants, constants);
204            }
205    
206            processed = true;
207        }
208    
209        /**
210         * Returns a string representation of the object.
211         *
212         * @return string representation
213         */
214        public String toString() {
215            StringBuffer results = new StringBuffer();
216    
217            results.append("Form: ");
218            results.append(name);
219            results.append("\n");
220    
221            for (Iterator i = lFields.iterator(); i.hasNext(); ) {
222                results.append("\tField: \n");
223                results.append(i.next());
224                results.append("\n");
225            }
226    
227            return results.toString();
228        }
229    
230        /**
231         * Validate all Fields in this Form on the given page and below.
232         *
233         * @param params               A Map of parameter class names to parameter
234         *      values to pass into validation methods.
235         * @param actions              A Map of validator names to ValidatorAction
236         *      objects.
237         * @param page                 Fields on pages higher than this will not be
238         *      validated.
239         * @return                     A ValidatorResults object containing all
240         *      validation messages.
241         * @throws ValidatorException
242         */
243        ValidatorResults validate(Map params, Map actions, int page)
244            throws ValidatorException {
245            return validate(params, actions, page, null);
246        }
247        
248        /**
249         * Validate all Fields in this Form on the given page and below.
250         *
251         * @param params               A Map of parameter class names to parameter
252         *      values to pass into validation methods.
253         * @param actions              A Map of validator names to ValidatorAction
254         *      objects.
255         * @param page                 Fields on pages higher than this will not be
256         *      validated.
257         * @return                     A ValidatorResults object containing all
258         *      validation messages.
259         * @throws ValidatorException
260         * @since 1.2.0
261         */
262        ValidatorResults validate(Map params, Map actions, int page, String fieldName)
263            throws ValidatorException {
264    
265            ValidatorResults results = new ValidatorResults();
266            params.put(Validator.VALIDATOR_RESULTS_PARAM, results);
267    
268            // Only validate a single field if specified
269            if (fieldName != null) {
270                Field field = (Field) this.hFields.get(fieldName);
271                
272                if (field == null) {
273                   throw new ValidatorException("Unknown field "+fieldName+" in form "+getName());
274                }
275                params.put(Validator.FIELD_PARAM, field);
276                
277                if (field.getPage() <= page) {
278                   results.merge(field.validate(params, actions));
279                }
280            } else {
281                Iterator fields = this.lFields.iterator();
282                while (fields.hasNext()) {
283                    Field field = (Field) fields.next();
284        
285                    params.put(Validator.FIELD_PARAM, field);
286        
287                    if (field.getPage() <= page) {
288                        results.merge(field.validate(params, actions));
289                    }
290                }
291            }
292    
293            return results;
294        }
295    
296        /**
297         * Whether or not the this <code>Form</code> was processed for replacing
298         * variables in strings with their values.
299         *
300         * @return   The processed value
301         * @since    Validator 1.2.0
302         */
303        public boolean isProcessed() {
304            return processed;
305        }
306    
307        /**
308         * Gets the name/key of the parent set of validation rules.
309         *
310         * @return   The extends value
311         * @since    Validator 1.2.0
312         */
313        public String getExtends() {
314            return inherit;
315        }
316    
317        /**
318         * Sets the name/key of the parent set of validation rules.
319         *
320         * @param inherit  The new extends value
321         * @since          Validator 1.2.0
322         */
323        public void setExtends(String inherit) {
324            this.inherit = inherit;
325        }
326    
327        /**
328         * Get extends flag.
329         *
330         * @return   The extending value
331         * @since    Validator 1.2.0
332         */
333        public boolean isExtending() {
334            return inherit != null;
335        }
336    
337        /**
338         * Returns a Map of String field keys to Field objects.
339         *
340         * @return   The fieldMap value
341         * @since    Validator 1.2.0
342         */
343        protected Map getFieldMap() {
344            return hFields;
345        }
346    }