Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
DateValidator |
|
| 1.631578947368421;1.632 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | package org.apache.commons.cli2.validation; | |
18 | ||
19 | import java.text.DateFormat; | |
20 | import java.text.ParsePosition; | |
21 | ||
22 | import java.util.Date; | |
23 | import java.util.List; | |
24 | import java.util.ListIterator; | |
25 | ||
26 | import org.apache.commons.cli2.resource.ResourceConstants; | |
27 | import org.apache.commons.cli2.resource.ResourceHelper; | |
28 | ||
29 | /** | |
30 | * The <code>DateValidator</code> validates the argument values | |
31 | * are date or time value(s). | |
32 | * | |
33 | * The following example shows how to validate that | |
34 | * an argument value(s) is a Date of the following | |
35 | * type: d/M/yy (see {@link java.text.DateFormat}). | |
36 | * | |
37 | * <pre> | |
38 | * DateFormat date = new SimpleDateFormat("d/M/yy"); | |
39 | * ... | |
40 | * ArgumentBuilder builder = new ArgumentBuilder(); | |
41 | * Argument dateFormat = | |
42 | * builder.withName("date"); | |
43 | * .withValidator(new DateValidator(dateFormat)); | |
44 | * </pre> | |
45 | * | |
46 | * The following example shows how to validate that | |
47 | * an argument value(s) is a time of the following | |
48 | * type: HH:mm:ss (see {@link java.text.DateFormat}). | |
49 | * | |
50 | * <pre> | |
51 | * DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); | |
52 | * ... | |
53 | * ArgumentBuilder builder = new ArgumentBuilder(); | |
54 | * Argument time = | |
55 | * builder.withName("time"); | |
56 | * .withValidator(new DateValidator(timeFormat)); | |
57 | * </pre> | |
58 | * | |
59 | * @author John Keyes | |
60 | * | |
61 | * @see java.text.DateFormat | |
62 | */ | |
63 | public class DateValidator implements Validator { | |
64 | /** i18n */ | |
65 | 1 | private static final ResourceHelper resources = ResourceHelper.getResourceHelper(); |
66 | ||
67 | /** an array of permitted DateFormats */ | |
68 | private DateFormat[] formats; | |
69 | ||
70 | /** minimum Date allowed i.e: a valid date occurs later than this date */ | |
71 | private Date minimum; | |
72 | ||
73 | /** maximum Date allowed i.e: a valid date occurs earlier than this date */ | |
74 | private Date maximum; | |
75 | ||
76 | /** leniant parsing */ | |
77 | private boolean isLenient; | |
78 | ||
79 | /** | |
80 | * Creates a Validator for the default date/time format | |
81 | */ | |
82 | public DateValidator() { | |
83 | 0 | this(DateFormat.getInstance()); |
84 | 0 | } |
85 | ||
86 | /** | |
87 | * Creates a Validator for the specified DateFormat. | |
88 | * | |
89 | * @param format | |
90 | * a DateFormat which dates must conform to | |
91 | */ | |
92 | 12 | public DateValidator(final DateFormat format) { |
93 | 12 | setFormat(format); |
94 | 12 | } |
95 | ||
96 | /** | |
97 | * Creates a Validator for the List of specified DateFormats. | |
98 | * | |
99 | * @param formats | |
100 | * a List of DateFormats which dates must conform to | |
101 | */ | |
102 | 4 | public DateValidator(final List formats) { |
103 | 4 | setFormats(formats); |
104 | 4 | } |
105 | ||
106 | /** | |
107 | * Creates a Validator for dates. | |
108 | * | |
109 | * @return DateValidator a Validator for dates | |
110 | */ | |
111 | public static DateValidator getDateInstance() { | |
112 | 1 | return new DateValidator(DateFormat.getDateInstance()); |
113 | } | |
114 | ||
115 | /** | |
116 | * Creates a Validator for times. | |
117 | * | |
118 | * @return DateValidator a Validator for times | |
119 | */ | |
120 | public static DateValidator getTimeInstance() { | |
121 | 0 | return new DateValidator(DateFormat.getTimeInstance()); |
122 | } | |
123 | ||
124 | /** | |
125 | * Creates a Validator for date/times | |
126 | * | |
127 | * @return DateValidator a Validator for date/times | |
128 | */ | |
129 | public static DateValidator getDateTimeInstance() { | |
130 | 0 | return new DateValidator(DateFormat.getDateTimeInstance()); |
131 | } | |
132 | ||
133 | /** | |
134 | * Validate each String value in the specified List against this instances | |
135 | * permitted DateFormats. | |
136 | * | |
137 | * If a value is valid then it's <code>String</code> value in the list is | |
138 | * replaced with it's <code>Date</code> value. | |
139 | * | |
140 | * @see org.apache.commons.cli2.validation.Validator#validate(java.util.List) | |
141 | */ | |
142 | public void validate(final List values) | |
143 | throws InvalidArgumentException { | |
144 | // for each value | |
145 | 12 | for (final ListIterator i = values.listIterator(); i.hasNext();) { |
146 | 17 | final String value = (String) i.next(); |
147 | ||
148 | 17 | Date date = null; |
149 | ||
150 | // create a resuable ParsePosition instance | |
151 | 17 | final ParsePosition pp = new ParsePosition(0); |
152 | ||
153 | // for each permitted DateFormat | |
154 | 39 | for (int f = 0; (f < this.formats.length) && (date == null); ++f) { |
155 | // reset the parse position | |
156 | 22 | pp.setIndex(0); |
157 | 22 | date = this.formats[f].parse(value, pp); |
158 | ||
159 | // if the wrong number of characters have been parsed | |
160 | 22 | if (pp.getIndex() < value.length()) { |
161 | 6 | date = null; |
162 | } | |
163 | } | |
164 | ||
165 | // if date has not been set throw an InvalidArgumentException | |
166 | 17 | if (date == null) { |
167 | 1 | throw new InvalidArgumentException(value); |
168 | } | |
169 | ||
170 | // if the date is outside the bounds | |
171 | 16 | if (isDateEarlier(date) || isDateLater(date)) { |
172 | 2 | throw new InvalidArgumentException(resources.getMessage(ResourceConstants.DATEVALIDATOR_DATE_OUTOFRANGE, |
173 | value)); | |
174 | } | |
175 | ||
176 | // replace the value in the list with the actual Date | |
177 | 14 | i.set(date); |
178 | 14 | } |
179 | 9 | } |
180 | ||
181 | /** | |
182 | * Sets whether this validator uses lenient parsing. | |
183 | * | |
184 | * @param lenient whether this validator uses lenient parsing | |
185 | */ | |
186 | public void setLenient(final boolean lenient) { | |
187 | 36 | for (int i = 0; i < this.formats.length; i++) { |
188 | 20 | this.formats[i].setLenient(lenient); |
189 | } | |
190 | ||
191 | 16 | this.isLenient = lenient; |
192 | 16 | } |
193 | ||
194 | /** | |
195 | * Returns whether this validator uses lenient parsing. | |
196 | * | |
197 | * @return whether this validator uses lenient parsing | |
198 | */ | |
199 | public boolean isLenient() { | |
200 | 0 | return this.isLenient; |
201 | } | |
202 | ||
203 | /** | |
204 | * Returns the maximum date permitted. | |
205 | * | |
206 | * @return Date the maximum date permitted. If no maximum date has been | |
207 | * specified then return <code>null</code>. | |
208 | */ | |
209 | public Date getMaximum() { | |
210 | 2 | return maximum; |
211 | } | |
212 | ||
213 | /** | |
214 | * Sets the maximum Date to the specified value. | |
215 | * | |
216 | * @param maximum | |
217 | * the maximum Date permitted | |
218 | */ | |
219 | public void setMaximum(final Date maximum) { | |
220 | 2 | this.maximum = maximum; |
221 | 2 | } |
222 | ||
223 | /** | |
224 | * Returns the minimum date permitted. | |
225 | * | |
226 | * @return Date the minimum date permitted. If no minimum date has been | |
227 | * specified then return <code>null</code>. | |
228 | */ | |
229 | public Date getMinimum() { | |
230 | 2 | return minimum; |
231 | } | |
232 | ||
233 | /** | |
234 | * Sets the minimum Date to the specified value. | |
235 | * | |
236 | * @param minimum | |
237 | * the minimum Date permitted | |
238 | */ | |
239 | public void setMinimum(Date minimum) { | |
240 | 2 | this.minimum = minimum; |
241 | 2 | } |
242 | ||
243 | /** | |
244 | * Returns whether the specified Date is later than the maximum date. | |
245 | * | |
246 | * @param date | |
247 | * the Date to evaluate | |
248 | * | |
249 | * @return boolean whether <code>date</code> is earlier than the maximum | |
250 | * date | |
251 | */ | |
252 | private boolean isDateLater(Date date) { | |
253 | 15 | return (maximum != null) && (date.getTime() > maximum.getTime()); |
254 | } | |
255 | ||
256 | /** | |
257 | * Returns whether the specified Date is earlier than the minimum date. | |
258 | * | |
259 | * @param date | |
260 | * the Date to evaluate | |
261 | * | |
262 | * @return boolean whether <code>date</code> is earlier than the minimum | |
263 | * date | |
264 | */ | |
265 | private boolean isDateEarlier(Date date) { | |
266 | 16 | return (minimum != null) && (date.getTime() < minimum.getTime()); |
267 | } | |
268 | ||
269 | /** | |
270 | * Sets the date format permitted. | |
271 | * | |
272 | * @param format | |
273 | * the format to use | |
274 | */ | |
275 | public void setFormat(final DateFormat format) { | |
276 | 12 | setFormats(new DateFormat[] { format }); |
277 | 12 | } |
278 | ||
279 | /** | |
280 | * Sets the date formats permitted. | |
281 | * | |
282 | * @param formats | |
283 | * the List of DateFormats to use | |
284 | */ | |
285 | public void setFormats(final List formats) { | |
286 | 4 | setFormats((DateFormat[]) formats.toArray(new DateFormat[formats.size()])); |
287 | 4 | } |
288 | ||
289 | /** | |
290 | * Sets the date formats permitted. | |
291 | * | |
292 | * @param formats | |
293 | * the array of DateFormats to use | |
294 | */ | |
295 | public void setFormats(final DateFormat[] formats) { | |
296 | 16 | this.formats = formats; |
297 | 16 | setLenient(this.isLenient); |
298 | 16 | } |
299 | ||
300 | /** | |
301 | * Gets the date formats permitted. | |
302 | * | |
303 | * @return the permitted formats | |
304 | */ | |
305 | public DateFormat[] getFormats() { | |
306 | 2 | return this.formats; |
307 | } | |
308 | } |