1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springmodules.validation.bean;
18
19 import java.util.*;
20 import java.util.Map.Entry;
21
22 import org.springframework.validation.Errors;
23 import org.springframework.validation.Validator;
24 import org.springmodules.validation.bean.rule.DefaultValidationRule;
25 import org.springmodules.validation.bean.rule.PropertyValidationRule;
26 import org.springmodules.validation.bean.rule.ValidationRule;
27 import org.springmodules.validation.util.condition.Condition;
28
29 /**
30 * A {@link org.springframework.validation.Validator} implementation which uses {@link org.springmodules.validation.bean.rule.ValidationRule}'s to define its
31 * validation execution. There are two types of validation rules this validator accepts:
32 * <ul>
33 * <li>
34 * Global Rules - Rules that apply on the validated objects and where all validation errors are registered
35 * globaly with the {@link Errors} object (i.e. {@link Errors#reject(String)}).
36 * </li>
37 * <li>
38 * Property Rules - Rules that apply on specific properties of the validated objects and where all validation
39 * errors are registered with the {@link Errors} object under the context of those properties
40 * (i.e. {@link Errors#rejectValue(String, String)}).
41 * </li>
42 * </ul>
43 *
44 * @author Uri Boness
45 */
46 public class RuleBasedValidator implements Validator {
47
48
49 private List globalRules;
50
51
52 private Map rulesByProperty;
53
54 /**
55 * Contrusts a new RuleBasedValidator for the given type. After contruction, this validator will initially hold
56 * no rules.
57 */
58 public RuleBasedValidator() {
59 globalRules = new ArrayList();
60 rulesByProperty = new HashMap();
61 }
62
63 /**
64 * This validator supports all classes. Any object can be validated by this validator as long as the validation rules
65 * apply to it.
66 *
67 * @see Validator#supports(Class)
68 */
69 public boolean supports(Class clazz) {
70 return true;
71 }
72
73 /**
74 * Validates the given object and registers all validation errors with the given errors object. The validation
75 * is done by applying all validation rules associated with this validator on the given object.
76 *
77 * @see org.springframework.validation.Validator#validate(Object, org.springframework.validation.Errors)
78 */
79 public void validate(Object obj, Errors errors) {
80
81
82 for (Iterator iter = globalRules.iterator(); iter.hasNext();) {
83 ValidationRule rule = (ValidationRule) iter.next();
84 if (rule.isApplicable(obj) && !rule.getCondition().check(obj)) {
85 errors.reject(rule.getErrorCode(), rule.getErrorArguments(obj), rule.getDefaultErrorMessage());
86 }
87 }
88
89
90 for (Iterator names = rulesByProperty.keySet().iterator(); names.hasNext();) {
91 String propertyName = (String) names.next();
92 List rules = (List) rulesByProperty.get(propertyName);
93 for (Iterator iter = rules.iterator(); iter.hasNext();) {
94 ValidationRule rule = (ValidationRule) iter.next();
95 if (rule.isApplicable(obj) && !rule.getCondition().check(obj)) {
96 errors.rejectValue(propertyName, rule.getErrorCode(), rule.getErrorArguments(obj), rule.getDefaultErrorMessage());
97 }
98 }
99 }
100 }
101
102
103
104 /**
105 * Sets extra global validation rules for this validator.
106 *
107 * @param globalRules The extra global validation rules to be added to this validator.
108 */
109 public void setExtraGlobalVadlidationRules(ValidationRule[] globalRules) {
110 for (int i = 0; i < globalRules.length; i++) {
111 addGlobalRule(globalRules[i]);
112 }
113 }
114
115 /**
116 * Sets extra property validation rules for this validator.
117 *
118 * @param rulesByProperty The extra property validation rules for this validator. The map should hold the property
119 * names as keys and {@link ValidationRule} instances as values.
120 */
121 public void setExtraPropertyValidationRules(Map rulesByProperty) {
122 for (Iterator entries = rulesByProperty.entrySet().iterator(); entries.hasNext();) {
123 Entry entry = (Entry) entries.next();
124 addPropertyRule((String) entry.getKey(), (ValidationRule) entry.getValue());
125 }
126 }
127
128
129
130 /**
131 * Adds the given property rule to this validator. A property rule is a condition and error information that is
132 * associated with a property name. When this rule is applied on an object, the condition is checked against the
133 * value of the associated property of the (validated) object. All validation errors of this rule will be registered
134 * with the {@link Errors} object under the context of the associated property. Note that the associated property
135 * may be a nested property - in that case, the nested property value will be resolved and the condition will be
136 * applied on the this value.
137 *
138 * @param propertyName The name of the property the added rule is associated with.
139 * @param fieldValueCondition The condition of the rule.
140 * @param errorCode The error code of the rule.
141 */
142 public void addPropertyRule(String propertyName, Condition fieldValueCondition, String errorCode) {
143 addPropertyRule(propertyName, fieldValueCondition, errorCode, errorCode, new Object[0]);
144 }
145
146 /**
147 * Adds the given property rule to this validator.
148 *
149 * @param propertyName The name of the property the added rule is associated with.
150 * @param fieldValueCondition The condition of the rule.
151 * @param errorCode The error code of the rule.
152 * @param args The arguments of the error code of the rule.
153 * @see #addPropertyRule(String, org.springmodules.validation.util.condition.Condition, String, Object[])
154 */
155 public void addPropertyRule(String propertyName, Condition fieldValueCondition, String errorCode, Object[] args) {
156 addPropertyRule(propertyName, fieldValueCondition, errorCode, errorCode, args);
157 }
158
159 /**
160 * Adds the given property rule to this validator.
161 *
162 * @param propertyName The name of the property the added rule is associated with.
163 * @param fieldValueCondition The condition of the rule.
164 * @param errorCode The error code of the rule.
165 * @param message The default error message of the rule.
166 * @param args The arguments of the error code of the rule.
167 * @see #addPropertyRule(String, org.springmodules.validation.util.condition.Condition, String, Object[])
168 */
169 public void addPropertyRule(
170 String propertyName,
171 Condition fieldValueCondition,
172 String errorCode,
173 String message,
174 Object[] args) {
175
176 addPropertyRule(propertyName, new DefaultValidationRule(fieldValueCondition, errorCode, message, args));
177 }
178
179 /**
180 * Adds the given property rule for the given property.
181 *
182 * @param propertyName The name of the property associated with the added rule.
183 * @param propertyRule The rule that should be applied on the value of the given property.
184 * @see #addPropertyRule(String, org.springmodules.validation.util.condition.Condition, String)
185 */
186 public void addPropertyRule(String propertyName, ValidationRule propertyRule) {
187 addPropertyGlobalRule(propertyName, new PropertyValidationRule(propertyName, propertyRule));
188 }
189
190 /**
191 * Adds a property rule for the given property. The given rule is actually a global rule, that is, it is being
192 * evaluated on the validated object, not on the property value. The only difference between this added rule and
193 * a global rule is that the validation errors of this rule are associated with the given property and are not
194 * associated globaly with the validated object.
195 * <p/>
196 * This type of rule comes in handy when a complex validation is required on the validation object, but the error
197 * is should only be associated with a specific property. An example would be when two properties of the validated
198 * object should match (i.e. have the same value), but if they don't, the error will only be associated with one
199 * of them (e.g. when a UserRegistration object holds a password and confirmPassword properties - this should
200 * generally match, but if they don't, the error will only be associated with the confirmPassword property).
201 *
202 * @param propertyName The name of the property to associated with the added rule.
203 * @param globalRule The global rule to be added.
204 */
205 public void addPropertyGlobalRule(String propertyName, ValidationRule globalRule) {
206 List rules = (List) rulesByProperty.get(propertyName);
207 if (rules == null) {
208 rules = new ArrayList();
209 rulesByProperty.put(propertyName, rules);
210 }
211 rules.add(globalRule);
212 }
213
214
215
216 /**
217 * Adds a new global validation rule to this validator. The global validation rule applied on the object level and
218 * all validation error of this rule will be registered with the {@link Errors} object globaly
219 * (see {@link Errors#reject(String)}).
220 *
221 * @param condition The condition of the added rule.
222 * @param errorCode The error code of the added rule.
223 */
224 public void addGlobalRule(Condition condition, String errorCode) {
225 addGlobalRule(condition, errorCode, errorCode, new Object[0]);
226 }
227
228 /**
229 * Adds a new global validation rule to this validator.
230 *
231 * @param condition The condition of the added rule.
232 * @param errorCode The error code of the added rule.
233 * @param args The arguments for the error of the added rule.
234 * @see #addGlobalRule(org.springmodules.validation.util.condition.Condition, String)
235 */
236 public void addGlobalRule(Condition condition, String errorCode, Object[] args) {
237 addGlobalRule(condition, errorCode, errorCode, args);
238 }
239
240 /**
241 * Adds a new global validation rule to this validator.
242 *
243 * @param condition The condition of the added rule.
244 * @param errorCode The error code of the added rule.
245 * @param message The error message of the added rule.
246 * @param args The arguments for the error of the added rule.
247 * @see #addGlobalRule(org.springmodules.validation.util.condition.Condition, String)
248 */
249 public void addGlobalRule(Condition condition, String errorCode, String message, Object[] args) {
250 addGlobalRule(new DefaultValidationRule(condition, errorCode, message, args));
251 }
252
253 /**
254 * Adds a new global validation rule to this validator.
255 *
256 * @param condition The condition of the added rule.
257 * @param errorCode The error code of the added rule.
258 * @param message The default error message of the added rule.
259 * @see #addGlobalRule(org.springmodules.validation.util.condition.Condition, String)
260 */
261 public void addGlobalRule(Condition condition, String errorCode, String message) {
262 addGlobalRule(new DefaultValidationRule(condition, errorCode, message, new Object[0]));
263 }
264
265 /**
266 * Adds the given validation rule as a global rule to this validator.
267 *
268 * @param globalRule The global rule to be added to this validator.
269 */
270 public void addGlobalRule(ValidationRule globalRule) {
271 globalRules.add(globalRule);
272 }
273
274 }