View Javadoc

1   /*
2    * Copyright 2004-2009 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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      // the name of the associated property.
39      private String propertyName;
40  
41      // the wrapped validation rule.
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     //=================================================== Inner Classes ================================================
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 }