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