1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springmodules.validation.bean.rule;
18
19 import java.beans.PropertyDescriptor;
20
21 import org.springframework.beans.BeanUtils;
22 import org.springframework.beans.BeanWrapperImpl;
23 import org.springmodules.validation.util.condition.AbstractCondition;
24 import org.springmodules.validation.util.condition.Condition;
25 import org.springmodules.validation.util.condition.Conditions;
26 import org.springmodules.validation.bean.context.ValidationContextUtils;
27
28 /**
29 * A {@link ValidationRule} implementation that wraps another validation rule and is associated with a specific
30 * property name. This validation rule is applicable on an object only if the object has the associated property and
31 * if wrapped rule is applicable on the value of that property. The condition of the rule is condition of the wrapped
32 * rule applied on the value of the associated property of the object.
33 *
34 * @author Uri Boness
35 */
36 public class PropertyValidationRule implements ValidationRule {
37
38
39 private String propertyName;
40
41
42 private ValidationRule rule;
43
44 private Condition applicabilityCondition;
45
46 private String[] contextTokens;
47
48 /**
49 * Constructs a new PropertyValidationRule (javabean support).
50 */
51 public PropertyValidationRule() {
52 this(null, null);
53 }
54
55 /**
56 * Constructs a new PropertyValidationRule with a given property and a wrapped validation rule.
57 *
58 * @param propertyName The name of the associated property.
59 * @param rule The validation rule to be wrapped.
60 */
61 public PropertyValidationRule(String propertyName, ValidationRule rule) {
62 this.propertyName = propertyName;
63 this.rule = rule;
64 applicabilityCondition = new DefaultApplicabilityCondition(propertyName, rule);
65 contextTokens = null;
66 }
67
68 /**
69 * Determines whether this rule is applicable on the given object. In practice, this validation rule is applicable
70 * only if the given object a property that match the property associated with this rule and if the wrapped rule
71 * is applicable on the value of that property.
72 *
73 * @param obj The object to be validated.
74 * @return <code>true</code> if this rule is applicable on the given object, <code>false</code> otherwise.
75 * @see ValidationRule#isApplicable(Object)
76 */
77 public boolean isApplicable(Object obj) {
78 return checkContext(contextTokens) && applicabilityCondition.check(obj);
79 }
80
81 /**
82 * Returns the conditoin of this validation rule. In practice, applying this condition means applying the
83 * condition of the wrapped rule on the value of the associated property of the validated object.
84 *
85 * @return The condition of this validation rule.
86 * @see ValidationRule#getCondition()
87 */
88 public Condition getCondition() {
89 return Conditions.property(propertyName, rule.getCondition());
90 }
91
92 /**
93 * Returns the error code of this condition. This error code is the same as the error code of the wrapped rule.
94 *
95 * @return The error code of this condition.
96 */
97 public String getErrorCode() {
98 return rule.getErrorCode();
99 }
100
101 /**
102 * Returns the arguments for the error of this validation rule. These arguments are the same as the ones of the
103 * wrapped rule.
104 *
105 * @param obj The validated object.
106 * @return The arguments for the error of this validation rule.
107 */
108 public Object[] getErrorArguments(Object obj) {
109 return rule.getErrorArguments(obj);
110 }
111
112 /**
113 * Returns the default error message of this validation rule. This error message is the same as the error message
114 * of the wrapped rule.
115 *
116 * @return The default error message of this validation rule.
117 */
118 public String getDefaultErrorMessage() {
119 return rule.getDefaultErrorMessage();
120 }
121
122
123 public void setApplicabilityCondition(Condition applicabilityCondition) {
124 this.applicabilityCondition = applicabilityCondition;
125 }
126
127 public void setContextTokens(String[] contextTokens) {
128 this.contextTokens = contextTokens;
129 }
130
131 protected static boolean checkContext(String[] tokens) {
132 return ValidationContextUtils.tokensSupportedByCurrentContext(tokens);
133 }
134
135
136
137 protected static class DefaultApplicabilityCondition extends AbstractCondition {
138
139 private String propertyName;
140 private ValidationRule rule;
141
142 public DefaultApplicabilityCondition(String propertyName, ValidationRule rule) {
143 this.propertyName = propertyName;
144 this.rule = rule;
145 }
146
147 public boolean doCheck(Object obj) {
148 PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(obj.getClass(), propertyName);
149 if (propertyDescriptor == null) {
150 return false;
151 }
152 Object value = new BeanWrapperImpl(obj).getPropertyValue(propertyName);
153 return rule.isApplicable(value);
154 }
155
156 }
157 }