001 /******************************************************************************* 002 * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian 003 * Thomschke. 004 * 005 * All Rights Reserved. This program and the accompanying materials 006 * are made available under the terms of the Eclipse Public License v1.0 007 * which accompanies this distribution, and is available at 008 * http://www.eclipse.org/legal/epl-v10.html 009 * 010 * Contributors: 011 * Sebastian Thomschke - initial implementation. 012 *******************************************************************************/ 013 package net.sf.oval.constraint; 014 015 import static net.sf.oval.Validator.getCollectionFactory; 016 017 import java.text.DateFormat; 018 import java.text.ParseException; 019 import java.text.SimpleDateFormat; 020 import java.util.Calendar; 021 import java.util.Date; 022 import java.util.Map; 023 024 import net.sf.oval.ConstraintTarget; 025 import net.sf.oval.Validator; 026 import net.sf.oval.configuration.annotation.AbstractAnnotationCheck; 027 import net.sf.oval.context.OValContext; 028 import net.sf.oval.exception.InvalidConfigurationException; 029 import net.sf.oval.internal.Log; 030 031 /** 032 * @author Sebastian Thomschke 033 */ 034 public class DateRangeCheck extends AbstractAnnotationCheck<DateRange> 035 { 036 private static final Log LOG = Log.getLog(DateRangeCheck.class); 037 038 private static final long serialVersionUID = 1L; 039 040 private String format; 041 private String max; 042 private String min; 043 044 private transient Long maxMillis; 045 private transient Long minMillis; 046 private long tolerance; 047 048 /** 049 * {@inheritDoc} 050 */ 051 @Override 052 public void configure(final DateRange constraintAnnotation) 053 { 054 super.configure(constraintAnnotation); 055 setMin(constraintAnnotation.min()); 056 setMax(constraintAnnotation.max()); 057 setFormat(constraintAnnotation.format()); 058 setTolerance(constraintAnnotation.tolerance()); 059 } 060 061 /** 062 * {@inheritDoc} 063 */ 064 @Override 065 protected Map<String, String> createMessageVariables() 066 { 067 final Map<String, String> messageVariables = getCollectionFactory().createMap(3); 068 messageVariables.put("min", min == null ? ".." : min); 069 messageVariables.put("max", max == null ? ".." : max); 070 messageVariables.put("format", format); 071 return messageVariables; 072 } 073 074 /** 075 * {@inheritDoc} 076 */ 077 @Override 078 protected ConstraintTarget[] getAppliesToDefault() 079 { 080 return new ConstraintTarget[]{ConstraintTarget.VALUES}; 081 } 082 083 /** 084 * @return the format 085 */ 086 public String getFormat() 087 { 088 return format; 089 } 090 091 /** 092 * @return the max 093 */ 094 public String getMax() 095 { 096 return max; 097 } 098 099 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 }