001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.validation.validator;
018
019import java.text.SimpleDateFormat;
020import java.util.Date;
021import java.util.Locale;
022
023import org.apache.wicket.Session;
024import org.apache.wicket.validation.IValidatable;
025import org.apache.wicket.validation.IValidationError;
026import org.apache.wicket.validation.ValidationError;
027
028/**
029 * Validator for checking if a given date falls within [min,max] range.
030 * 
031 * If either min or max are {@code null} they are not checked.
032 * 
033 * <p>
034 * Resource keys:
035 * <ul>
036 * <li>{@code DateValidator.exact} if min==max</li>
037 * <li>{@code DateValidator.range} if both min and max are not {@code null}</li>
038 * <li>{@code DateValidator.minimum} if max is {@code null}</li>
039 * <li>{@code DateValidator.maximum} if min is {@code null}</li>
040 * </ul>
041 * </p>
042 * 
043 * <p>
044 * Error Message Variables:
045 * <ul>
046 * <li>{@code name}: the id of {@code Component} that failed</li>
047 * <li>{@code label}: the label of the {@code Component} (either comes from
048 * {@code FormComponent.labelModel} or resource key {@code <form-id>.<form-component-id>}</li>
049 * <li>{@code input}: the input value</li>
050 * <li>{@code inputdate}: the formatted input value</li>
051 * <li>{@code minimum}: the minimum allowed value</li>
052 * <li>{@code maximum}: the maximum allowed value</li>
053 * </ul>
054 * </p>
055 * 
056 * @author igor
057 */
058public class DateValidator extends RangeValidator<Date>
059{
060        private static final long serialVersionUID = 1L;
061
062        /**
063         * @param minimum
064         *            the minimum <code>Date</code>
065         * @param maximum
066         *            the maximum <code>Date</code>
067         * @return a {@link DateValidator} that validates if a date is between (inclusive) a minimum and
068         *         maximum
069         */
070        public static DateValidator range(Date minimum, Date maximum)
071        {
072                return new DateValidator(minimum, maximum);
073        }
074
075        /**
076         * @param minimum
077         *            the minimum <code>Date</code>
078         * @param maximum
079         *            the maximum <code>Date</code>
080         * @param format
081         *            The format string used to format the date with SimpleDateFormat
082         * 
083         * @return a {@link DateValidator} that validates if a date is between (inclusive) a minimum and
084         *         maximum
085         */
086        public static DateValidator range(Date minimum, Date maximum, String format)
087        {
088                return new DateValidator(minimum, maximum, format);
089        }
090
091        /**
092         * @param minimum
093         *            the minimum <code>Date</code>
094         * 
095         * @return a {@link DateValidator} that validates if a date is after or equal to a minimum date
096         */
097        public static DateValidator minimum(Date minimum)
098        {
099                return new DateValidator(minimum, null);
100        }
101
102        /**
103         * @param minimum
104         *            the minimum <code>Date</code>
105         * @param format
106         *            The format string used to format the date with SimpleDateFormat
107         * 
108         * @return a {@link DateValidator} that validates if a date is after or equal to a minimum date
109         */
110        public static DateValidator minimum(Date minimum, String format)
111        {
112                return new DateValidator(minimum, null, format);
113        }
114
115        /**
116         * @param maximum
117         *            the maximum <code>Date</code>
118         * 
119         * @return a {@link DateValidator} that validates if a date is before or equal to a maximum date
120         */
121        public static DateValidator maximum(Date maximum)
122        {
123                return new DateValidator(null, maximum);
124        }
125
126        /**
127         * @param maximum
128         *            the maximum <code>Date</code>
129         * @param format
130         *            The format string used to format the date with SimpleDateFormat
131         * 
132         * @return a {@link DateValidator} that validates if a date is before or equal to a maximum date
133         */
134        public static DateValidator maximum(Date maximum, String format)
135        {
136                return new DateValidator(null, maximum, format);
137        }
138
139        private String format;
140
141        /**
142         * Constructor that sets the minimum and maximum date values and a custom date formating.
143         * 
144         * @param minimum
145         *            the minimum date
146         * @param maximum
147         *            the maximum date
148         * @param format
149         *            The format string used to format the date with SimpleDateFormat
150         */
151        public DateValidator(Date minimum, Date maximum, String format)
152        {
153                super(minimum, maximum);
154                this.format = format;
155        }
156
157        /**
158         * Constructor that sets the minimum and maximum date values.
159         * 
160         * @param minimum
161         *            the minimum date
162         * @param maximum
163         *            the maximum date
164         */
165        public DateValidator(Date minimum, Date maximum)
166        {
167                this(minimum, maximum, null);
168        }
169
170        /**
171         * Constructor used for subclasses who want to set the range using
172         * {@link #setRange(Comparable, Comparable)}
173         */
174        protected DateValidator()
175        {
176        }
177
178        @Override
179        protected IValidationError decorate(IValidationError error, IValidatable<Date> validatable)
180        {
181                error = super.decorate(error, validatable);
182
183                if (error instanceof ValidationError)
184                {
185                        ValidationError ve = (ValidationError) error;
186                        ve.setVariable("inputdate", validatable.getValue());
187
188                        // format variables if format has been specified
189                        if (format != null)
190                        {
191                                Locale locale;
192                                
193                                if (Session.exists()) 
194                                {
195                                        Session session = Session.get();
196                                        locale = session.getLocale();
197                                        
198                                        if (locale == null)
199                                        {
200                                                locale = Locale.getDefault(Locale.Category.FORMAT);
201                                        }
202                                }
203                                else
204                                {
205                                        locale = Locale.getDefault(Locale.Category.FORMAT);
206                                }
207
208                                SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
209                                if (getMinimum() != null)
210                                {
211                                        ve.setVariable("minimum", sdf.format(getMinimum()));
212                                }
213                                if (getMaximum() != null)
214                                {
215                                        ve.setVariable("maximum", sdf.format(getMaximum()));
216                                }
217                                ve.setVariable("inputdate", sdf.format(validatable.getValue()));
218                        }
219                }
220
221                return error;
222        }
223}