View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
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  package net.sf.jguiraffe.transform;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.apache.commons.lang.BooleanUtils;
23  
24  /**
25   * <p>
26   * A special {@link Validator} implementation that allows combining multiple
27   * primitive validators.
28   * </p>
29   * <p>
30   * An instance of this class can be initialized with an arbitrary number of
31   * child validators. In its implementation of the <code>isValid()</code> method
32   * the child validators are invoked one after the other. Configuration options
33   * control whether validation should stop when the first validation error was
34   * detected or whether in any case all child validators are to be invoked (in
35   * the latter case really all error messages caused by validation errors can be
36   * collected.)
37   * </p>
38   * <p>
39   * In the {@link TransformerContext} passed to this validator's
40   * <code>isValid()</code> method the {@link #PROP_SHORT_EVAL}
41   * property will be checked. If it is defined, it overrides the flag set using
42   * the {@link #setShortEvaluation(boolean)} method.
43   * </p>
44   *
45   * @author Oliver Heger
46   * @version $Id: ChainValidator.java 205 2012-01-29 18:29:57Z oheger $
47   */
48  public class ChainValidator implements Validator
49  {
50      /** Constant for the short evaluation property. */
51      public static final String PROP_SHORT_EVAL = "shortEval";
52  
53      /** Stores a list with the child validators. */
54      private List<ChildValidatorData> validators;
55  
56      /** The short evaluation flag. */
57      private boolean shortEvaluation;
58  
59      /**
60       * Creates a new instance of <code>ChainValidator</code>.
61       */
62      public ChainValidator()
63      {
64          validators = new ArrayList<ChildValidatorData>();
65          setShortEvaluation(true);
66      }
67  
68      /**
69       * Returns the <code>shortEvaluation</code> flag.
70       *
71       * @return the flag for short evaluation
72       */
73      public boolean isShortEvaluation()
74      {
75          return shortEvaluation;
76      }
77  
78      /**
79       * Sets the <code>shortEvaluation</code> flag. This flag controls the
80       * behavior of the <code>isValid()</code> method in case of validation
81       * errors. If it is set, validation is aborted when the first child
82       * validator detects an error. Otherwise all child validators will be
83       * invoked and the results are collected.
84       *
85       * @param shortEvaluation the value of the flag
86       */
87      public void setShortEvaluation(boolean shortEvaluation)
88      {
89          this.shortEvaluation = shortEvaluation;
90      }
91  
92      /**
93       * Adds a child validator to this chain validator.
94       *
95       * @param child the child validator to be added (must not be <b>null</b>)
96       * @throws IllegalArgumentException if the validator to be added is <b>null</b>
97       */
98      public void addChildValidator(Validator child)
99      {
100         addChildValidator(child, null);
101     }
102 
103     /**
104      * Adds a child validator to this chain validator and sets special
105      * properties for the new child. If defined, these properties will be
106      * available through the <code>TransformerContext</code> passed to the
107      * <code>isValid()</code> method of the child.
108      *
109      * @param child the child validator to be added (must not be <b>null</b>)
110      * @param props a map with properties for the new child validator
111      * @throws IllegalArgumentException if the validator to be added is <b>null</b>
112      */
113     public void addChildValidator(Validator child, Map<String, Object> props)
114     {
115         if (child == null)
116         {
117             throw new IllegalArgumentException(
118                     "Child validator must not be null!");
119         }
120 
121         validators.add(new ChildValidatorData(child, props));
122     }
123 
124     /**
125      * Returns the number of child validators.
126      *
127      * @return the number of child validators
128      */
129     public int size()
130     {
131         return validators.size();
132     }
133 
134     /**
135      * Returns the child validator at the given index. The index is 0-based and
136      * can be in the range 0 &lt;= <code>index</code> &lt; <code>size()</code>.
137      *
138      * @param index the index of the child validator
139      * @return the child at this index
140      * @throws IndexOutOfBoundsException if the index is invalid
141      */
142     public Validator getChildValidator(int index)
143     {
144         return validators.get(index).getValidator();
145     }
146 
147     /**
148      * Validates the passed in object. This implementation delegates to the
149      * child validators.
150      *
151      * @param o the object to be validated
152      * @param ctx the transformer context
153      * @return an object with the results of the validation
154      */
155     public ValidationResult isValid(Object o, TransformerContext ctx)
156     {
157         ValidationResult result = DefaultValidationResult.VALID;
158         int cnt = size();
159 
160         if (cnt > 0)
161         {
162             boolean shortEval = doShortEvaluation(ctx);
163             for (int i = 0; i < cnt; i++)
164             {
165                 Validator v = getChildValidator(i);
166                 TransformerContext currentCtx = getContextForChildValidator(i,
167                         ctx);
168                 ValidationResult vr = v.isValid(o, currentCtx);
169 
170                 if (shortEval && !vr.isValid())
171                 {
172                     result = vr;
173                     break;
174                 }
175                 result = DefaultValidationResult.merge(result, vr);
176             }
177         }
178 
179         return result;
180     }
181 
182     /**
183      * Returns the <code>TransformerContext</code> to be used for the
184      * specified child validator. If the child was added with custom properties,
185      * a specialized context will be created allowing access to these
186      * properties. Otherwise the default context will be returned.
187      *
188      * @param index the index of the child validator
189      * @param ctx the original context
190      * @return a context for this child validator
191      * @throws IndexOutOfBoundsException if the index is invalid
192      */
193     protected TransformerContext getContextForChildValidator(int index,
194             TransformerContext ctx)
195     {
196         return validators.get(index).getContextForValidator(ctx);
197     }
198 
199     /**
200      * Checks whether short evaluation should be performed by the
201      * <code>isValid()</code> method. This implementation checks whether the
202      * {@link #PROP_SHORT_EVAL} property is defined in the passed
203      * in context. If not, <code>isShortEvaluation()</code> will be called.
204      *
205      * @param ctx the current transformer context
206      * @return a flag whether short evaluation should be performed
207      */
208     protected boolean doShortEvaluation(TransformerContext ctx)
209     {
210         Map<String, Object> props = ctx.properties();
211         if (props.containsKey(PROP_SHORT_EVAL))
212         {
213             return BooleanUtils.toBoolean(String.valueOf(props
214                     .get(PROP_SHORT_EVAL)));
215         }
216         else
217         {
218             return isShortEvaluation();
219         }
220     }
221 
222     /**
223      * A helper class for storing information about a child validator.
224      */
225     private static class ChildValidatorData
226     {
227         /** Stores the validator. */
228         private Validator validator;
229 
230         /** Stores properties for this validator. */
231         private Map<String, Object> properties;
232 
233         /**
234          * Creates a new instance of <code>ChildValidatorData</code> and
235          * initializes it.
236          *
237          * @param v the validator
238          * @param props the properties for this validator
239          */
240         public ChildValidatorData(Validator v, Map<String, Object> props)
241         {
242             validator = v;
243             properties = props;
244         }
245 
246         /**
247          * Returns the child validator.
248          *
249          * @return the validator
250          */
251         public Validator getValidator()
252         {
253             return validator;
254         }
255 
256         /**
257          * Returns the transformer context to use for this child validator. If
258          * properties are set, a wrapped context will be returned.
259          *
260          * @param ctx the current context
261          * @return the context to use
262          */
263         public TransformerContext getContextForValidator(TransformerContext ctx)
264         {
265             return (properties != null) ? new TransformerContextPropertiesWrapper(
266                     ctx, properties)
267                     : ctx;
268         }
269     }
270 }