View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.commons.validator;
20  
21  import java.util.Calendar;
22  import java.util.Date;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import javax.faces.application.FacesMessage;
30  import javax.faces.component.UIComponent;
31  import javax.faces.component.ValueHolder;
32  import javax.faces.context.FacesContext;
33  import javax.faces.convert.Converter;
34  import javax.faces.convert.DateTimeConverter;
35  import javax.faces.validator.Validator;
36  import javax.faces.validator.ValidatorException;
37  
38  import org.apache.myfaces.commons.validator.model.DateListProvider;
39  
40  /**
41   * Validate that the date entered is within a given restriction.
42   * 
43   * @JSFValidator
44   *   name = "mcv:validateDateRestriction"
45   *   class = "org.apache.myfaces.commons.validator.DateRestrictionValidator"
46   *   bodyContent = "empty"
47   *   tagClass = "org.apache.myfaces.commons.validator.ValidateDateRestrictionTag"
48   *   serialuidtag = "6805174635196400967L"
49   *
50   */
51  public abstract class AbstractDateRestrictionValidator extends ValidatorBase
52  {
53  
54      public static final String VALIDATOR_ID = "org.apache.myfaces.commons.validator.DateRestriction";
55  
56      /**
57       * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
58       * to be created if the valid days  value check fails.  The message format
59       * string for this message may optionally include <code>{0}</code>,
60       * <code>{1}</code> and <code>{3}</code> placeholders,
61       * which will be replaced by user input, component label and configured
62       * days value.</p>
63       */
64      public static final String DAY_MESSAGE_ID = "org.apache.myfaces.commons.validator.DateRestrictionValidator.DAY";
65  
66      /**
67       * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
68       * to be created if the valid month value check fails.  The message format
69       * string for this message may optionally include <code>{0}</code>,
70       * <code>{1}</code> and <code>{3}</code> placeholders,
71       * which will be replaced by user input, component label and configured
72       * month value.</p>
73       */
74      public static final String MONTH_MESSAGE_ID = "org.apache.myfaces.commons.validator.DateRestrictionValidator.MONTH";
75  
76      /**
77       * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
78       * to be created if the valid weekdays value check fails.  The message format
79       * string for this message may optionally include <code>{0}</code>,
80       * <code>{1}</code> and <code>{3}</code> placeholders,
81       * which will be replaced by user input, component label and configured
82       * weekdays value.</p>
83       */
84      public static final String WEEKDAY_MESSAGE_ID = "org.apache.myfaces.commons.validator.DateRestrictionValidator.WEEKDAY";
85  
86      /**
87       * Construct a {@link Validator} with no preconfigured limits.
88       */
89      public AbstractDateRestrictionValidator()
90      {
91          super();
92          _initMaps();
93      }
94  
95      /**
96       * Specify the month which are invalid for your use case.
97       * The attribute takes a whitespace delimited list of months.
98       * Possible values are jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec.
99       * 
100      * @JSFProperty
101      */
102     public abstract String[] getInvalidMonths();
103 
104     public abstract void setInvalidMonths(String[] invalidMonths);
105 
106     /**
107      * Specify the weekdays which are invalid for your use case.
108      * The attribute takes whitespace delimited list of weekdays.
109      * Possible values are sun, mon, tue, wed, thu, fri, sat.
110      * 
111      * @JSFProperty
112      */
113     public abstract String[] getInvalidDaysOfWeek();
114 
115     public abstract void setInvalidDaysOfWeek(String[] invalidDaysOfWeek);
116 
117     /**
118      * To specifiy a concrete List of Dates, use the invalidDays attribute and wire it
119      * to a DateListProvider implementation. This returns a list of dates, which are invalid.
120      * 
121      * @JSFProperty
122      */
123     public abstract DateListProvider getInvalidDays();
124 
125     public abstract void setInvalidDays(DateListProvider invalidDays);
126 
127     /**
128      * @exception IllegalArgumentException if <code>value</code> is not of type
129      * {@link java.util.Date}
130      */
131     public void validate(FacesContext context, UIComponent component,
132             Object value) throws ValidatorException
133     {
134         if ((context == null) || (component == null))
135         {
136             throw new NullPointerException(("NULL_FACESCONTEXT_OR_UICOMPONENT"));
137         }
138 
139         if (value != null)
140         {
141             Calendar calendar = getCalendar();
142             calendar.setTime(getDateValue(value));
143             Date convertedDate = calendar.getTime();
144 
145             String weekday = _dayMap.get(calendar.get(Calendar.DAY_OF_WEEK));
146             if (_getInvalidDaysOfWeek().contains(weekday))
147             {
148                 throw new ValidatorException(getWrongWeekDayMessage(context,
149                         component, value, weekday));
150             }
151 
152             String month = _monthMap.get(calendar.get(Calendar.MONTH));
153             if (_getInvalidMonths().contains(month))
154             {
155                 throw new ValidatorException(getWrongMonthMessage(context,
156                         component, value, month));
157             }
158 
159             DateListProvider dlp = getInvalidDays();
160             List<Date> dates = null;
161             if (dlp != null)
162             {
163                 dates = dlp.getDateList(context, calendar, calendar.getTime(),
164                         calendar.getTime());
165             }
166 
167             if (dates != null)
168             {
169                 for (Date date : dates)
170                 {
171                     //range is only one submitted day...
172                     if (!date.before(convertedDate)
173                             && !date.after(convertedDate))
174                     {
175                         throw new ValidatorException(getWrongDayMessage(
176                                 context, component, value, date));
177                     }
178                 }
179             }
180         }
181     }
182 
183     private Converter getConverter(FacesContext context, UIComponent component)
184     {
185         Converter converter = null;
186         if (component instanceof ValueHolder)
187         {
188             converter = ((ValueHolder) component).getConverter();
189         }
190 
191         if (converter == null)
192         {
193             // Use the DateTimeConverter's CONVERTER_ID, not Date.class,
194             // because there is in fact not usually a converter registered
195             // at Date.class
196             converter = context.getApplication().createConverter(
197                     DateTimeConverter.CONVERTER_ID);
198         }
199 
200         assert (converter != null);
201 
202         return converter;
203     }
204 
205     protected Calendar getCalendar()
206     {
207         //TODO: make it better
208         return Calendar.getInstance();
209 
210     }
211 
212     /**
213      * Parses the already converted value to a <code>java.util.Date</code>.
214      * @param value converted value
215      * @return fulltyped <code>java.util.Date</code>
216      * @throws IllegalArgumentException
217      */
218     protected static Date getDateValue(Object value)
219             throws IllegalArgumentException
220     {
221         if (value instanceof Date)
222         {
223             return ((Date) value);
224         }
225 
226         throw new IllegalArgumentException("value is not a date type");
227     }
228 
229     private FacesMessage getWrongWeekDayMessage(FacesContext context,
230             UIComponent component, Object value, Object weekday)
231     {
232         Converter converter = getConverter(context, component);
233         Object cWeekday = _getConvertedValue(context, component, converter,
234                 weekday);
235         Object[] params = { cWeekday };
236         return getFacesMessage(WEEKDAY_MESSAGE_ID, params);
237     }
238 
239     private FacesMessage getWrongMonthMessage(FacesContext context,
240             UIComponent component, Object value, Object month)
241     {
242         Converter converter = getConverter(context, component);
243         Object cMonth = _getConvertedValue(context, component, converter, month);
244         Object[] params = { cMonth };
245         return getFacesMessage(MONTH_MESSAGE_ID, params);
246     }
247 
248     private FacesMessage getWrongDayMessage(FacesContext context,
249             UIComponent component, Object value, Object day)
250     {
251         Converter converter = getConverter(context, component);
252 
253         Object cValue = _getConvertedValue(context, component, converter, value);
254         Object cDay = _getConvertedValue(context, component, converter, day);
255 
256         Object[] params = { cValue, cDay };
257 
258         return getFacesMessage(DAY_MESSAGE_ID, params);
259     }
260 
261     private Object _getConvertedValue(FacesContext context,
262             UIComponent component, Converter converter, Object value)
263     {
264         return converter.getAsString(context, component, value);
265     }
266 
267     private final Set<String> _getInvalidMonths()
268     {
269         Set<String> monthSet = new HashSet<String>();
270         String[] month = getInvalidMonths();
271         if (month != null)
272         {
273 
274             for (int i = 0; i < month.length; i++)
275             {
276                 monthSet.add(month[i].toLowerCase());
277             }
278         }
279 
280         return monthSet;
281     }
282 
283     private final Set<String> _getInvalidDaysOfWeek()
284     {
285         Set<String> daysOfWeekSet = new HashSet<String>();
286         String[] daysOfWeek = getInvalidDaysOfWeek();
287         if (daysOfWeek != null)
288         {
289 
290             for (int i = 0; i < daysOfWeek.length; i++)
291             {
292                 daysOfWeekSet.add(daysOfWeek[i].toLowerCase());
293             }
294         }
295 
296         return daysOfWeekSet;
297     }
298 
299     private void _initMaps()
300     {
301         _dayMap = new HashMap<Integer, String>();
302         _dayMap.put(Calendar.SUNDAY, "sun");
303         _dayMap.put(Calendar.MONDAY, "mon");
304         _dayMap.put(Calendar.TUESDAY, "tue");
305         _dayMap.put(Calendar.WEDNESDAY, "wed");
306         _dayMap.put(Calendar.THURSDAY, "thu");
307         _dayMap.put(Calendar.FRIDAY, "fri");
308         _dayMap.put(Calendar.SATURDAY, "sat");
309 
310         _monthMap = new HashMap<Integer, String>();
311         _monthMap.put(Calendar.JANUARY, "jan");
312         _monthMap.put(Calendar.FEBRUARY, "feb");
313         _monthMap.put(Calendar.MARCH, "mar");
314         _monthMap.put(Calendar.APRIL, "apr");
315         _monthMap.put(Calendar.MAY, "may");
316         _monthMap.put(Calendar.JUNE, "jun");
317         _monthMap.put(Calendar.JULY, "jul");
318         _monthMap.put(Calendar.AUGUST, "aug");
319         _monthMap.put(Calendar.SEPTEMBER, "sep");
320         _monthMap.put(Calendar.OCTOBER, "oct");
321         _monthMap.put(Calendar.NOVEMBER, "nov");
322         _monthMap.put(Calendar.DECEMBER, "dec");
323     }
324 
325     private Map<Integer, String> _dayMap = null;
326     private Map<Integer, String> _monthMap = null;
327 }