View Javadoc
1   /*******************************************************************************
2    * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
3    * Thomschke.
4    * 
5    * All Rights Reserved. This program and the accompanying materials
6    * are made available under the terms of the Eclipse Public License v1.0
7    * which accompanies this distribution, and is available at
8    * http://www.eclipse.org/legal/epl-v10.html
9    * 
10   * Contributors:
11   *     Sebastian Thomschke - initial implementation.
12   *******************************************************************************/
13  package net.sf.oval.constraint;
14  
15  import static net.sf.oval.Validator.getCollectionFactory;
16  
17  import java.text.DateFormat;
18  import java.text.ParseException;
19  import java.text.SimpleDateFormat;
20  import java.util.Calendar;
21  import java.util.Date;
22  import java.util.Map;
23  
24  import net.sf.oval.ConstraintTarget;
25  import net.sf.oval.Validator;
26  import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
27  import net.sf.oval.context.OValContext;
28  import net.sf.oval.exception.InvalidConfigurationException;
29  import net.sf.oval.internal.Log;
30  
31  /**
32   * @author Sebastian Thomschke
33   */
34  public class DateRangeCheck extends AbstractAnnotationCheck<DateRange>
35  {
36  	private static final Log LOG = Log.getLog(DateRangeCheck.class);
37  
38  	private static final long serialVersionUID = 1L;
39  
40  	private String format;
41  	private String max;
42  	private String min;
43  
44  	private transient Long maxMillis;
45  	private transient Long minMillis;
46  	private long tolerance;
47  
48  	/**
49  	 * {@inheritDoc}
50  	 */
51  	@Override
52  	public void configure(final DateRange constraintAnnotation)
53  	{
54  		super.configure(constraintAnnotation);
55  		setMin(constraintAnnotation.min());
56  		setMax(constraintAnnotation.max());
57  		setFormat(constraintAnnotation.format());
58  		setTolerance(constraintAnnotation.tolerance());
59  	}
60  
61  	/**
62  	 * {@inheritDoc}
63  	 */
64  	@Override
65  	protected Map<String, String> createMessageVariables()
66  	{
67  		final Map<String, String> messageVariables = getCollectionFactory().createMap(3);
68  		messageVariables.put("min", min == null ? ".." : min);
69  		messageVariables.put("max", max == null ? ".." : max);
70  		messageVariables.put("format", format);
71  		return messageVariables;
72  	}
73  
74  	/**
75  	 * {@inheritDoc}
76  	 */
77  	@Override
78  	protected ConstraintTarget[] getAppliesToDefault()
79  	{
80  		return new ConstraintTarget[]{ConstraintTarget.VALUES};
81  	}
82  
83  	/**
84  	 * @return the format
85  	 */
86  	public String getFormat()
87  	{
88  		return format;
89  	}
90  
91  	/**
92  	 * @return the max
93  	 */
94  	public String getMax()
95  	{
96  		return max;
97  	}
98  
99  	private long getMaxMillis() throws InvalidConfigurationException
100 	{
101 		if (maxMillis == null)
102 		{
103 			if (max == null || max.length() == 0) return Long.MAX_VALUE;
104 
105 			if ("now".equals(max)) return System.currentTimeMillis() + tolerance;
106 
107 			if ("today".equals(max))
108 			{
109 				final Calendar cal = Calendar.getInstance();
110 				cal.set(Calendar.HOUR_OF_DAY, 0);
111 				cal.set(Calendar.MINUTE, 0);
112 				cal.set(Calendar.SECOND, 0);
113 				cal.set(Calendar.MILLISECOND, 0);
114 				cal.add(Calendar.DAY_OF_YEAR, 1);
115 				cal.add(Calendar.MILLISECOND, -1);
116 				return cal.getTimeInMillis() + tolerance;
117 			}
118 
119 			if ("tomorrow".equals(max))
120 			{
121 				final Calendar cal = Calendar.getInstance();
122 				cal.set(Calendar.HOUR_OF_DAY, 0);
123 				cal.set(Calendar.MINUTE, 0);
124 				cal.set(Calendar.SECOND, 0);
125 				cal.set(Calendar.MILLISECOND, 0);
126 				cal.add(Calendar.DAY_OF_YEAR, 2);
127 				cal.add(Calendar.MILLISECOND, -1);
128 				return cal.getTimeInMillis() + tolerance;
129 			}
130 
131 			if ("yesterday".equals(max))
132 			{
133 				final Calendar cal = Calendar.getInstance();
134 				cal.set(Calendar.HOUR_OF_DAY, 0);
135 				cal.set(Calendar.MINUTE, 0);
136 				cal.set(Calendar.SECOND, 0);
137 				cal.set(Calendar.MILLISECOND, 0);
138 				cal.add(Calendar.MILLISECOND, -1);
139 				return cal.getTimeInMillis() + tolerance;
140 			}
141 
142 			if (format != null && format.length() > 0)
143 			{
144 				final SimpleDateFormat sdf = new SimpleDateFormat(format);
145 				try
146 				{
147 					maxMillis = sdf.parse(max).getTime() + tolerance;
148 				}
149 				catch (final ParseException e)
150 				{
151 					throw new InvalidConfigurationException("Unable to parse the max Date String", e);
152 				}
153 			}
154 			else
155 				try
156 				{
157 					maxMillis = DateFormat.getDateTimeInstance().parse(max).getTime() + tolerance;
158 				}
159 				catch (final ParseException e)
160 				{
161 					throw new InvalidConfigurationException("Unable to parse the max Date String", e);
162 				}
163 		}
164 		return maxMillis;
165 	}
166 
167 	/**
168 	 * @return the min
169 	 */
170 	public String getMin()
171 	{
172 		return min;
173 	}
174 
175 	private long getMinMillis() throws InvalidConfigurationException
176 	{
177 		if (minMillis == null)
178 		{
179 			if (min == null || min.length() == 0) return 0L;
180 
181 			if ("now".equals(min)) return System.currentTimeMillis() - tolerance;
182 
183 			if ("today".equals(min))
184 			{
185 				final Calendar cal = Calendar.getInstance();
186 				cal.set(Calendar.HOUR_OF_DAY, 0);
187 				cal.set(Calendar.MINUTE, 0);
188 				cal.set(Calendar.SECOND, 0);
189 				cal.set(Calendar.MILLISECOND, 0);
190 				return cal.getTimeInMillis() - tolerance;
191 			}
192 
193 			if ("tomorrow".equals(min))
194 			{
195 				final Calendar cal = Calendar.getInstance();
196 				cal.set(Calendar.HOUR_OF_DAY, 0);
197 				cal.set(Calendar.MINUTE, 0);
198 				cal.set(Calendar.SECOND, 0);
199 				cal.set(Calendar.MILLISECOND, 0);
200 				cal.add(Calendar.DAY_OF_YEAR, 1);
201 				return cal.getTimeInMillis() - tolerance;
202 			}
203 
204 			if ("yesterday".equals(min))
205 			{
206 				final Calendar cal = Calendar.getInstance();
207 				cal.set(Calendar.HOUR_OF_DAY, 0);
208 				cal.set(Calendar.MINUTE, 0);
209 				cal.set(Calendar.SECOND, 0);
210 				cal.set(Calendar.MILLISECOND, 0);
211 				cal.add(Calendar.DAY_OF_YEAR, -1);
212 				return cal.getTimeInMillis() - tolerance;
213 			}
214 
215 			if (format != null && format.length() > 0)
216 			{
217 				final SimpleDateFormat sdf = new SimpleDateFormat(format);
218 				try
219 				{
220 					minMillis = sdf.parse(min).getTime() - tolerance;
221 				}
222 				catch (final ParseException e)
223 				{
224 					throw new InvalidConfigurationException("Unable to parse the min Date String", e);
225 				}
226 			}
227 			else
228 				try
229 				{
230 					minMillis = DateFormat.getDateTimeInstance().parse(min).getTime() - tolerance;
231 				}
232 				catch (final ParseException e)
233 				{
234 					throw new InvalidConfigurationException("Unable to parse the min Date String", e);
235 				}
236 		}
237 		return minMillis;
238 	}
239 
240 	/**
241 	 * @return the tolerance
242 	 */
243 	public long getTolerance()
244 	{
245 		return tolerance;
246 	}
247 
248 	public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context,
249 			final Validator validator)
250 	{
251 		if (valueToValidate == null) return true;
252 
253 		long valueInMillis = -1;
254 
255 		// check if the value is a Date
256 		if (valueToValidate instanceof Date)
257 			valueInMillis = ((Date) valueToValidate).getTime();
258 		else if (valueToValidate instanceof Calendar)
259 			valueInMillis = ((Calendar) valueToValidate).getTime().getTime();
260 		else
261 		{
262 			// see if we can extract a date based on the object's String representation
263 			final String stringValue = valueToValidate.toString();
264 			try
265 			{
266 				if (format != null) try
267 				{
268 					valueInMillis = new SimpleDateFormat(format).parse(stringValue).getTime();
269 				}
270 				catch (final ParseException ex)
271 				{
272 					LOG.debug("valueToValidate not parsable with specified format {1}", format, ex);
273 				}
274 
275 				if (valueInMillis == -1) valueInMillis = DateFormat.getDateTimeInstance().parse(stringValue).getTime();
276 			}
277 			catch (final ParseException ex)
278 			{
279 				LOG.debug("valueToValidate is unparsable.", ex);
280 				return false;
281 			}
282 		}
283 
284 		return valueInMillis >= getMinMillis() && valueInMillis <= getMaxMillis();
285 	}
286 
287 	/**
288 	 * @param format the format to set
289 	 */
290 	public void setFormat(final String format)
291 	{
292 		this.format = format;
293 		requireMessageVariablesRecreation();
294 	}
295 
296 	/**
297 	 * @param max the max to set
298 	 */
299 	public void setMax(final String max)
300 	{
301 		this.max = max;
302 		maxMillis = null;
303 		requireMessageVariablesRecreation();
304 	}
305 
306 	/**
307 	 * @param min the min to set
308 	 */
309 	public void setMin(final String min)
310 	{
311 		this.min = min;
312 		minMillis = null;
313 		requireMessageVariablesRecreation();
314 	}
315 
316 	/**
317 	 * @param tolerance the tolerance to set
318 	 */
319 	public void setTolerance(final long tolerance)
320 	{
321 		this.tolerance = tolerance;
322 		minMillis = null;
323 		maxMillis = null;
324 	}
325 }