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 <form> 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 }