1 package org.apache.fulcrum.intake.validator;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.Map;
23
24 import org.apache.avalon.framework.logger.LogEnabled;
25 import org.apache.avalon.framework.logger.Logger;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.fulcrum.intake.model.Field;
28
29 /**
30 * DefaultValidator that will compare a testValue against the following
31 * constraints:
32 *
33 * <table>
34 * <caption>Validation rules</caption>
35 * <tr><th>Name</th><th>Valid Values</th><th>Default Value</th></tr>
36 * <tr><td>required</td><td>true|false</td><td>false</td></tr>
37 * <tr><td>mask</td><td>regexp</td><td> </td></tr>
38 * <tr><td>minLength</td><td>integer</td><td>0</td></tr>
39 * <tr><td>maxLength</td><td>integer</td><td> </td></tr>
40 * </table>
41 *
42 * This validator can serve as the base class for more specific validators
43 *
44 * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
45 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
46 * @author <a href="mailto:Colin.Chalmers@maxware.nl">Colin Chalmers</a>
47 * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
48 * @version $Id$
49 */
50 abstract public class DefaultValidator<T>
51 implements Validator<T>, InitableByConstraintMap, LogEnabled
52 {
53 /** A boolean value to signify if the field is definitely required or not */
54 protected boolean required = false;
55
56 /** The message to show if field fails required test */
57 protected String requiredMessage = null;
58
59 /** The minimum length of the field */
60 protected int minLength = 0;
61
62 /** The message to show if field fails min-length test */
63 protected String minLengthMessage = null;
64
65 /** The maximum length of the field */
66 protected int maxLength = 0;
67
68 /** The message to show if field fails max-length test */
69 protected String maxLengthMessage = null;
70
71 /** Error message pertaining to Rule that was broken */
72 protected String errorMessage = null;
73
74 /** Logging */
75 protected Logger log;
76
77 /**
78 * Default constructor
79 */
80 public DefaultValidator()
81 {
82 //
83 }
84
85 /**
86 * Enable Avalon Logging
87 */
88 @Override
89 public void enableLogging(Logger logger)
90 {
91 this.log = logger.getChildLogger(getClass().getSimpleName());
92 }
93
94 /**
95 * Extract the relevant parameters from the constraints listed
96 * in <rule> tags within the intake.xml file.
97 *
98 * @param paramMap a <code>Map</code> of <code>Rule</code>'s
99 * containing constraints on the input.
100 * @throws InvalidMaskException An invalid mask was specified for one of the rules
101 */
102 @Override
103 public void init(Map<String, ? extends Constraint> paramMap)
104 throws InvalidMaskException
105 {
106 Constraint constraint = paramMap.get(REQUIRED_RULE_NAME);
107 if (constraint != null)
108 {
109 String param = constraint.getValue();
110 required = Boolean.valueOf(param).booleanValue();
111 requiredMessage = constraint.getMessage();
112 }
113
114 constraint = paramMap.get(MIN_LENGTH_RULE_NAME);
115 if (constraint != null)
116 {
117 String param = constraint.getValue();
118 minLength = Integer.parseInt(param);
119 minLengthMessage = constraint.getMessage();
120 }
121
122 constraint = paramMap.get(MAX_LENGTH_RULE_NAME);
123 if (constraint != null)
124 {
125 String param = constraint.getValue();
126 maxLength = Integer.parseInt(param);
127 maxLengthMessage = constraint.getMessage();
128 }
129 }
130
131 /**
132 * Determine whether a field meets the criteria specified
133 * in the constraints defined for this validator
134 *
135 * @param field a <code>Field</code> to be tested
136 * @return true if valid, false otherwise
137 */
138 @Override
139 public boolean isValid(Field<T> field)
140 {
141 boolean valid = false;
142 try
143 {
144 assertValidity(field);
145 valid = true;
146 }
147 catch (ValidationException ve)
148 {
149 valid = false;
150 }
151 return valid;
152 }
153
154 /**
155 * Determine whether a field meets the criteria specified
156 * in the constraints defined for this validator
157 *
158 * @param field a <code>Field</code> to be tested
159 * @throws ValidationException containing an error message if the
160 * testValue did not pass the validation tests.
161 */
162 @Override
163 public void assertValidity(Field<T> field)
164 throws ValidationException
165 {
166 if (field.isMultiValued())
167 {
168 String[] stringValues = (String[])field.getTestValue();
169
170 for (int i = 0; i < stringValues.length; i++)
171 {
172 assertValidity(stringValues[i]);
173 }
174 }
175 else
176 {
177 assertValidity((String)field.getTestValue());
178 }
179 }
180
181 /**
182 * Determine whether a testValue meets the criteria specified
183 * in the constraints defined for this validator
184 *
185 * @param testValue a <code>String</code> to be tested
186 * @return true if valid, false otherwise
187 *
188 * @deprecated use isValid(Field) instead
189 */
190 @Deprecated
191 @Override
192 public boolean isValid(String testValue)
193 {
194 boolean valid = false;
195 try
196 {
197 assertValidity(testValue);
198 valid = true;
199 }
200 catch (ValidationException ve)
201 {
202 valid = false;
203 }
204 return valid;
205 }
206
207 /**
208 * Determine whether a testValue meets the criteria specified
209 * in the constraints defined for this validator
210 *
211 * @param testValue a <code>String</code> to be tested
212 * @throws ValidationException containing an error message if the
213 * testValue did not pass the validation tests.
214 */
215 @Override
216 public void assertValidity(String testValue)
217 throws ValidationException
218 {
219 if (!required && StringUtils.isEmpty(testValue))
220 {
221 return;
222 }
223 if (required && StringUtils.isEmpty(testValue))
224 {
225 errorMessage = requiredMessage;
226 throw new ValidationException(requiredMessage);
227 }
228
229 if (minLength > 0 && testValue.length() < minLength)
230 {
231 errorMessage = minLengthMessage;
232 throw new ValidationException(minLengthMessage);
233 }
234 if (maxLength > 0 && testValue.length() > maxLength)
235 {
236 errorMessage = maxLengthMessage;
237 throw new ValidationException(maxLengthMessage);
238 }
239 }
240
241
242 /**
243 * Get the error message resulting from invalid input.
244 *
245 * @return a <code>String</code> message, or the empty String "".
246 */
247 @Override
248 public String getMessage()
249 {
250 String retValue = "";
251
252 if(errorMessage != null)
253 {
254 retValue = errorMessage;
255 }
256
257 return retValue;
258 }
259
260 // ************************************************************
261 // ** Bean accessor methods **
262 // ************************************************************
263
264 /**
265 * Get the value of required.
266 *
267 * @return value of required.
268 */
269 public boolean isRequired()
270 {
271 return required;
272 }
273
274 /**
275 * Set the value of required.
276 *
277 * @param required Value to assign to required.
278 */
279 public void setRequired(boolean required)
280 {
281 this.required = required;
282 }
283
284 /**
285 * Get the value of requiredMessage.
286 *
287 * @return value of requiredMessage.
288 */
289 public String getRequiredMessage()
290 {
291 return requiredMessage;
292 }
293
294 /**
295 * Set the value of requiredMessage.
296 *
297 * @param requiredMessage Value to assign to requiredMessage.
298 */
299 public void setRequiredMessage(String requiredMessage)
300 {
301 this.requiredMessage = requiredMessage;
302 }
303
304 /**
305 * Get the value of minLength.
306 *
307 * @return value of minLength.
308 */
309 public int getMinLength()
310 {
311 return minLength;
312 }
313
314 /**
315 * Set the value of minLength.
316 *
317 * @param minLength Value to assign to minLength.
318 */
319 public void setMinLength(int minLength)
320 {
321 this.minLength = minLength;
322 }
323
324 /**
325 * Get the value of minLengthMessage.
326 *
327 * @return value of minLengthMessage.
328 */
329 public String getMinLengthMessage()
330 {
331 return minLengthMessage;
332 }
333
334 /**
335 * Set the value of minLengthMessage.
336 *
337 * @param minLengthMessage Value to assign to minLengthMessage.
338 */
339 public void setMinLengthMessage(String minLengthMessage)
340 {
341 this.minLengthMessage = minLengthMessage;
342 }
343
344 /**
345 * Get the value of maxLength.
346 *
347 * @return value of maxLength.
348 */
349 public int getMaxLength()
350 {
351 return maxLength;
352 }
353
354 /**
355 * Set the value of maxLength.
356 *
357 * @param maxLength Value to assign to maxLength.
358 */
359 public void setMaxLength(int maxLength)
360 {
361 this.maxLength = maxLength;
362 }
363
364 /**
365 * Get the value of maxLengthMessage.
366 *
367 * @return value of maxLengthMessage.
368 */
369 public String getMaxLengthMessage()
370 {
371 return maxLengthMessage;
372 }
373
374 /**
375 * Set the value of maxLengthMessage.
376 *
377 * @param maxLengthMessage Value to assign to maxLengthMessage.
378 */
379 public void setMaxLengthMessage(String maxLengthMessage)
380 {
381 this.maxLengthMessage = maxLengthMessage;
382 }
383 }