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.text.ParseException;
023    import java.util.ArrayList;
024    import java.util.Date;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.apache.commons.lang.StringUtils;
030    import org.apache.fulcrum.intake.IntakeException;
031    import org.apache.fulcrum.intake.model.Field;
032    import org.apache.fulcrum.intake.model.Group;
033    
034    /**
035     * Validates a DateString field in dependency on another DateString field.
036     *
037     * <table>
038     * <tr>
039     *   <th>Name</th><th>Valid Values</th><th>Default Value</th>
040     * </tr>
041     * <tr>
042     *   <td>less-than</td>
043     *   <td>&lt;name of other field&gt;</td>
044     *   <td>&nbsp;</td>
045     * </tr>
046     * <tr>
047     *   <td>greater-than</td>
048     *   <td>&lt;name of other field&gt;</td>
049     *   <td>&nbsp;</td>
050     * </tr>
051     * <tr>
052     *   <td>less-than-or-equal</td>
053     *   <td>&lt;name of other field&gt;</td>
054     *   <td>&nbsp;</td>
055     * </tr>
056     * <tr>
057     *   <td>greater-than-or-equal</td>
058     *   <td>&lt;name of other field&gt;</td>
059     *   <td>&nbsp;</td>
060     * </tr>
061     * </table>
062     *
063     * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
064     * @version $Id: DateStringValidator.java 534527 2007-05-02 16:10:59Z tv $
065     */
066    public class DateRangeValidator
067            extends DateStringValidator
068    {
069        /** List of FieldReferences for multiple comparisons */
070        List fieldReferences; 
071    
072        /** Callback for the actual compare operation */
073        CompareCallback compareCallback; 
074    
075        public DateRangeValidator(final Map paramMap)
076                throws IntakeException
077        {
078            init(paramMap);
079        }
080    
081        /**
082         *  Default constructor
083         */
084        public DateRangeValidator()
085        {
086            super();
087        }
088    
089        /**
090         * Constructor to use when initialising Object
091         *
092         * @param paramMap
093         * @throws InvalidMaskException
094         */
095        public void init(final Map paramMap)
096                throws InvalidMaskException
097        {
098            super.init(paramMap);
099            
100            compareCallback = new CompareCallback()
101                {
102                    /**
103                     * Compare the given values using the compare operation provided
104                     * 
105                     * @param compare type of compare operation
106                     * @param thisValue value of this field
107                     * @param refValue value of the reference field
108                     * 
109                     * @return the result of the comparison
110                     */
111                    public boolean compareValues(int compare, Object thisValue, Object refValue)
112                        throws ClassCastException
113                    {
114                        boolean result = true;
115                        
116                        Date thisDate = (Date)thisValue;
117                        Date otherDate = (Date)refValue;
118                        
119                        switch (compare)
120                        {
121                            case FieldReference.COMPARE_LT:
122                                result = thisDate.before(otherDate);
123                                break;
124                                
125                            case FieldReference.COMPARE_LTE:
126                                result = !thisDate.after(otherDate);
127                                break;
128                                
129                            case FieldReference.COMPARE_GT:
130                                result = thisDate.after(otherDate);
131                                break;
132                                
133                            case FieldReference.COMPARE_GTE:
134                                result = !thisDate.before(otherDate);
135                                break;
136                        }
137                        
138                        return result;
139                    }
140                };
141            
142            fieldReferences = new ArrayList(10);
143    
144            for (Iterator i = paramMap.entrySet().iterator(); i.hasNext();)
145            {
146                Map.Entry entry = (Map.Entry)i.next();
147                String key = (String)entry.getKey();
148                Constraint constraint = (Constraint)entry.getValue();
149    
150                int compare = FieldReference.getCompareType(key);
151                
152                if (compare != 0)
153                {
154                    // found matching constraint
155                    FieldReference fieldref = new FieldReference();
156                    fieldref.setCompare(compare);
157                    fieldref.setFieldName(constraint.getValue());
158                    fieldref.setMessage(constraint.getMessage());
159                    
160                    fieldReferences.add(fieldref);
161                }
162            }
163            
164            if (fieldReferences.isEmpty())
165            {
166                log.warn("No reference field rules have been found.");
167            }
168        }
169        
170        /**
171         * Determine whether a testValue meets the criteria specified
172         * in the constraints defined for this validator
173         *
174         * @param testField a <code>Field</code> to be tested
175         * @exception ValidationException containing an error message if the
176         * testValue did not pass the validation tests.
177         */
178        public void assertValidity(final Field testField)
179            throws ValidationException
180        {
181            super.assertValidity(testField);
182            
183            Group thisGroup = testField.getGroup();
184    
185            if (testField.isMultiValued())
186            {
187                String[] stringValues = (String[])testField.getTestValue();
188    
189                for (int i = 0; i < stringValues.length; i++)
190                {
191                    assertValidity(stringValues[i], thisGroup);
192                }
193            }
194            else
195            {
196                String testValue = (String)testField.getTestValue();
197            
198                assertValidity(testValue, thisGroup);
199            }
200        }
201    
202        /**
203         * Determine whether a testValue meets the criteria specified
204         * in the constraints defined for this validator
205         *
206         * @param testValue a <code>String</code> to be tested
207         * @param group the group this field belongs to
208         * 
209         * @exception ValidationException containing an error message if the
210         * testValue did not pass the validation tests.
211         */
212        public void assertValidity(final String testValue, final Group group)
213            throws ValidationException
214        {
215            if (required || StringUtils.isNotEmpty(testValue))
216            {
217                Date testDate = null;
218                
219                try
220                {
221                    testDate = parse(testValue);
222                }
223                catch (ParseException e)
224                {
225                    // This should not happen because we succeded with this before, 
226                    // but we need to catch the exception anyway
227                    errorMessage = getDateFormatMessage();
228                    throw new ValidationException(errorMessage);
229                }
230                
231                try
232                {
233                    FieldReference.checkReferences(fieldReferences, compareCallback, 
234                            testDate, group);
235                }
236                catch (ValidationException e)
237                {
238                    errorMessage = e.getMessage();
239                    throw e;
240                }
241            }
242        }
243    }