001    package org.apache.fulcrum.intake.validator;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.Map;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.fulcrum.intake.model.Field;
028    
029    /**
030     * DefaultValidator that will compare a testValue against the following
031     * constraints:
032     *
033     * <table>
034     * <tr><th>Name</th><th>Valid Values</th><th>Default Value</th></tr>
035     * <tr><td>required</td><td>true|false</td><td>false</td></tr>
036     * <tr><td>mask</td><td>regexp</td><td>&nbsp;</td></tr>
037     * <tr><td>minLength</td><td>integer</td><td>0</td></tr>
038     * <tr><td>maxLength</td><td>integer</td><td>&nbsp;</td></tr>
039     * </table>
040     *
041     * This validator can serve as the base class for more specific validators
042     *
043     * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
044     * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
045     * @author <a href="mailto:Colin.Chalmers@maxware.nl">Colin Chalmers</a>
046     * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
047     * @version $Id: DefaultValidator.java 670328 2008-06-22 09:34:11Z tv $
048     */
049    abstract public class DefaultValidator
050            implements Validator, InitableByConstraintMap
051    {
052        /** A boolean value to signify if the field is definately required or not */
053        protected boolean required = false;
054    
055        /** The message to show if field fails required test */
056        protected String requiredMessage = null;
057    
058        /** The minimum length of the field */
059        protected int minLength = 0;
060    
061        /** The message to show if field fails min-length test */
062        protected String minLengthMessage = null;
063    
064        /** The maximum length of the field */
065        protected int maxLength = 0;
066    
067        /** The message to show if field fails max-length test */
068        protected String maxLengthMessage = null;
069    
070        /** Error message pertaining to Rule that was broken */
071        protected String errorMessage = null;
072    
073        /** Logging */
074        protected Log log = LogFactory.getLog(this.getClass());
075    
076        /**
077         * Constructor
078         *
079         * @param paramMap a <code>Map</code> of <code>Rule</code>'s
080         * containing constraints on the input.
081         * @exception InvalidMaskException An invalid mask was specified for one of the rules
082    
083        */
084        public DefaultValidator(Map paramMap)
085                throws InvalidMaskException
086        {
087            init(paramMap);
088        }
089    
090        /**
091         * Default constructor
092         */
093        public DefaultValidator()
094        {
095            //
096        }
097    
098        /**
099         * Extract the relevant parameters from the constraints listed
100         * in <rule> tags within the intake.xml file.
101         *
102         * @param paramMap a <code>Map</code> of <code>Rule</code>'s
103         * containing constraints on the input.
104         * @exception InvalidMaskException An invalid mask was specified for one of the rules
105         */
106        public void init(Map paramMap)
107                throws InvalidMaskException
108        {
109            Constraint constraint = (Constraint) paramMap.get(REQUIRED_RULE_NAME);
110            if (constraint != null)
111            {
112                String param = constraint.getValue();
113                required = Boolean.valueOf(param).booleanValue();
114                requiredMessage = constraint.getMessage();
115            }
116    
117            constraint = (Constraint) paramMap.get(MIN_LENGTH_RULE_NAME);
118            if (constraint != null)
119            {
120                String param = constraint.getValue();
121                minLength = Integer.parseInt(param);
122                minLengthMessage = constraint.getMessage();
123            }
124    
125            constraint = (Constraint) paramMap.get(MAX_LENGTH_RULE_NAME);
126            if (constraint != null)
127            {
128                String param = constraint.getValue();
129                maxLength = Integer.parseInt(param);
130                maxLengthMessage = constraint.getMessage();
131            }
132        }
133    
134        /**
135         * Determine whether a field meets the criteria specified
136         * in the constraints defined for this validator
137         *
138         * @param field a <code>Field</code> to be tested
139         * @return true if valid, false otherwise
140         */
141        public boolean isValid(Field field)
142        {
143            boolean valid = false;
144            try
145            {
146                assertValidity(field);
147                valid = true;
148            }
149            catch (ValidationException ve)
150            {
151                valid = false;
152            }
153            return valid;
154        }
155    
156        /**
157         * Determine whether a field meets the criteria specified
158         * in the constraints defined for this validator
159         *
160         * @param field a <code>Field</code> to be tested
161         * @exception ValidationException containing an error message if the
162         * testValue did not pass the validation tests.
163         */
164        public void assertValidity(Field field)
165                throws ValidationException
166        {
167            if (field.isMultiValued())
168            {
169                    String[] stringValues = (String[])field.getTestValue();
170    
171                    for (int i = 0; i < stringValues.length; i++)
172                    {
173                            assertValidity(stringValues[i]);
174                    }
175            }
176            else
177            {
178                    assertValidity((String)field.getTestValue());
179            }
180        }
181    
182        /**
183         * Determine whether a testValue meets the criteria specified
184         * in the constraints defined for this validator
185         *
186         * @param testValue a <code>String</code> to be tested
187         * @return true if valid, false otherwise
188         *
189         * @deprecated use isValid(Field) instead
190         */
191        public boolean isValid(String testValue)
192        {
193            boolean valid = false;
194            try
195            {
196                assertValidity(testValue);
197                valid = true;
198            }
199            catch (ValidationException ve)
200            {
201                valid = false;
202            }
203            return valid;
204        }
205    
206        /**
207         * Determine whether a testValue meets the criteria specified
208         * in the constraints defined for this validator
209         *
210         * @param testValue a <code>String</code> to be tested
211         * @exception ValidationException containing an error message if the
212         * testValue did not pass the validation tests.
213         */
214        public void assertValidity(String testValue)
215                throws ValidationException
216        {
217            if (!required && StringUtils.isEmpty(testValue))
218            {
219                return;
220            }
221            if (required && StringUtils.isEmpty(testValue))
222            {
223                errorMessage = requiredMessage;
224                throw new ValidationException(requiredMessage);
225            }
226    
227            if (minLength > 0 && testValue.length() < minLength)
228            {
229                errorMessage = minLengthMessage;
230                throw new ValidationException(minLengthMessage);
231            }
232            if (maxLength > 0 && testValue.length() > maxLength)
233            {
234                errorMessage = maxLengthMessage;
235                throw new ValidationException(maxLengthMessage);
236            }
237        }
238    
239    
240        /**
241         * Get the error message resulting from invalid input.
242         *
243         * @return a <code>String</code> message, or the empty String "".
244         */
245        public String getMessage()
246        {
247            String retValue = "";
248    
249            if(errorMessage != null)
250            {
251                retValue = errorMessage;
252            }
253    
254            return retValue;
255        }
256    
257        // ************************************************************
258        // **                Bean accessor methods                   **
259        // ************************************************************
260    
261        /**
262         * Get the value of required.
263         *
264         * @return value of required.
265         */
266        public boolean isRequired()
267        {
268            return required;
269        }
270    
271        /**
272         * Set the value of required.
273         *
274         * @param required  Value to assign to required.
275         */
276        public void setRequired(boolean required)
277        {
278            this.required = required;
279        }
280    
281        /**
282         * Get the value of requiredMessage.
283         *
284         * @return value of requiredMessage.
285         */
286        public String getRequiredMessage()
287        {
288            return requiredMessage;
289        }
290    
291        /**
292         * Set the value of requiredMessage.
293         *
294         * @param requiredMessage  Value to assign to requiredMessage.
295         */
296        public void setRequiredMessage(String requiredMessage)
297        {
298            this.requiredMessage = requiredMessage;
299        }
300    
301        /**
302         * Get the value of minLength.
303         *
304         * @return value of minLength.
305         */
306        public int getMinLength()
307        {
308            return minLength;
309        }
310    
311        /**
312         * Set the value of minLength.
313         *
314         * @param minLength  Value to assign to minLength.
315         */
316        public void setMinLength(int minLength)
317        {
318            this.minLength = minLength;
319        }
320    
321        /**
322         * Get the value of minLengthMessage.
323         *
324         * @return value of minLengthMessage.
325         */
326        public String getMinLengthMessage()
327        {
328            return minLengthMessage;
329        }
330    
331        /**
332         * Set the value of minLengthMessage.
333         *
334         * @param minLengthMessage  Value to assign to minLengthMessage.
335         */
336        public void setMinLengthMessage(String minLengthMessage)
337        {
338            this.minLengthMessage = minLengthMessage;
339        }
340    
341        /**
342         * Get the value of maxLength.
343         *
344         * @return value of maxLength.
345         */
346        public int getMaxLength()
347        {
348            return maxLength;
349        }
350    
351        /**
352         * Set the value of maxLength.
353         *
354         * @param maxLength  Value to assign to maxLength.
355         */
356        public void setMaxLength(int maxLength)
357        {
358            this.maxLength = maxLength;
359        }
360    
361        /**
362         * Get the value of maxLengthMessage.
363         *
364         * @return value of maxLengthMessage.
365         */
366        public String getMaxLengthMessage()
367        {
368            return maxLengthMessage;
369        }
370    
371        /**
372         * Set the value of maxLengthMessage.
373         *
374         * @param maxLengthMessage  Value to assign to maxLengthMessage.
375         */
376        public void setMaxLengthMessage(String maxLengthMessage)
377        {
378            this.maxLengthMessage = maxLengthMessage;
379        }
380    }