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