Frames | No Frames |
1: /* 2: * Copyright 2003-2005 The Apache Software Foundation 3: * Copyright 2005 Stephen McConnell 4: * 5: * Licensed under the Apache License, Version 2.0 (the "License"); 6: * you may not use this file except in compliance with the License. 7: * 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 net.dpml.cli.validation; 18: 19: import java.text.DateFormat; 20: import java.text.ParsePosition; 21: 22: import java.util.Date; 23: import java.util.Iterator; 24: import java.util.List; 25: import java.util.ListIterator; 26: 27: import net.dpml.cli.resource.ResourceConstants; 28: import net.dpml.cli.resource.ResourceHelper; 29: 30: /** 31: * The <code>DateValidator</code> validates the argument values 32: * are date or time value(s). 33: * 34: * The following example shows how to validate that 35: * an argument value(s) is a Date of the following 36: * type: d/M/yy (see {@link java.text.DateFormat}). 37: * 38: * <pre> 39: * DateFormat date = new SimpleDateFormat("d/M/yy"); 40: * ... 41: * ArgumentBuilder builder = new ArgumentBuilder(); 42: * Argument dateFormat = 43: * builder.withName("date"); 44: * .withValidator(new DateValidator(dateFormat)); 45: * </pre> 46: * 47: * The following example shows how to validate that 48: * an argument value(s) is a time of the following 49: * type: HH:mm:ss (see {@link java.text.DateFormat}). 50: * 51: * <pre> 52: * DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); 53: * ... 54: * ArgumentBuilder builder = new ArgumentBuilder(); 55: * Argument time = 56: * builder.withName("time"); 57: * .withValidator(new DateValidator(timeFormat)); 58: * </pre> 59: * 60: * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a> 61: * @version @PROJECT-VERSION@ 62: * @see java.text.DateFormat 63: */ 64: public class DateValidator implements Validator 65: { 66: /** i18n */ 67: private static final ResourceHelper RESOURCES = 68: ResourceHelper.getResourceHelper(); 69: 70: /** an array of permitted DateFormats */ 71: private DateFormat[] m_formats; 72: 73: /** minimum Date allowed i.e: a valid date occurs later than this date */ 74: private Date m_minimum; 75: 76: /** maximum Date allowed i.e: a valid date occurs earlier than this date */ 77: private Date m_maximum; 78: 79: /** leniant parsing */ 80: private boolean m_isLenient; 81: 82: /** 83: * Creates a Validator for the default date/time format 84: */ 85: public DateValidator() 86: { 87: this( DateFormat.getInstance() ); 88: } 89: 90: /** 91: * Creates a Validator for the specified DateFormat. 92: * 93: * @param format 94: * a DateFormat which dates must conform to 95: */ 96: public DateValidator( final DateFormat format ) 97: { 98: setFormat( format ); 99: } 100: 101: /** 102: * Creates a Validator for the List of specified DateFormats. 103: * 104: * @param formats a List of DateFormats which dates must conform to 105: */ 106: public DateValidator( final List formats ) 107: { 108: for( Iterator iter = formats.iterator(); iter.hasNext();) 109: { 110: DateFormat format = (DateFormat) iter.next(); 111: } 112: setFormats( formats ); 113: } 114: 115: /** 116: * Creates a Validator for dates. 117: * 118: * @return DateValidator a Validator for dates 119: */ 120: public static DateValidator getDateInstance() 121: { 122: return new DateValidator( DateFormat.getDateInstance() ); 123: } 124: 125: /** 126: * Creates a Validator for times. 127: * 128: * @return DateValidator a Validator for times 129: */ 130: public static DateValidator getTimeInstance() 131: { 132: return new DateValidator( DateFormat.getTimeInstance() ); 133: } 134: 135: /** 136: * Creates a Validator for date/times 137: * 138: * @return DateValidator a Validator for date/times 139: */ 140: public static DateValidator getDateTimeInstance() 141: { 142: return new DateValidator( DateFormat.getDateTimeInstance() ); 143: } 144: 145: /** 146: * Validate each String value in the specified List against this instances 147: * permitted DateFormats. 148: * 149: * If a value is valid then it's <code>String</code> value in the list is 150: * replaced with it's <code>Date</code> value. 151: * 152: * @param values the list of values to validate 153: * @exception InvalidArgumentException if a value is invalid 154: * @see net.dpml.cli.validation.Validator#validate(java.util.List) 155: */ 156: public void validate( final List values ) throws InvalidArgumentException 157: { 158: // for each value 159: for( final ListIterator i = values.listIterator(); i.hasNext();) 160: { 161: final Object next = i.next(); 162: if( next instanceof Date ) 163: { 164: return; 165: } 166: 167: final String value = (String) next; 168: 169: Date date = null; 170: 171: // create a resuable ParsePosition instance 172: final ParsePosition pp = new ParsePosition( 0 ); 173: 174: // for each permitted DateFormat 175: for( int f=0; ( f<m_formats.length ) && ( date == null ); ++f ) 176: { 177: // reset the parse position 178: pp.setIndex( 0 ); 179: date = m_formats[f].parse( value, pp ); 180: 181: // if the wrong number of characters have been parsed 182: if( pp.getIndex() < value.length() ) 183: { 184: date = null; 185: } 186: } 187: 188: // if date has not been set throw an InvalidArgumentException 189: if( date == null ) 190: { 191: throw new InvalidArgumentException( value ); 192: } 193: 194: // if the date is outside the bounds 195: if( isDateEarlier( date ) || isDateLater( date ) ) 196: { 197: throw new InvalidArgumentException( 198: RESOURCES.getMessage( 199: ResourceConstants.DATEVALIDATOR_DATE_OUTOFRANGE, 200: value ) ); 201: } 202: 203: // replace the value in the list with the actual Date 204: i.set( date ); 205: } 206: } 207: 208: /** 209: * Set the leaniant flag. 210: * @param lenient true if leniant 211: */ 212: public void setLeniant( final boolean lenient ) 213: { 214: for( int i=0; i<m_formats.length; i++ ) 215: { 216: m_formats[i].setLenient( lenient ); 217: } 218: m_isLenient = lenient; 219: } 220: 221: /** 222: * Return the leaniant flag. 223: * @return true if leniant 224: */ 225: public boolean isLeniant() 226: { 227: return m_isLenient; 228: } 229: 230: /** 231: * Returns the maximum date permitted. 232: * 233: * @return Date the maximum date permitted. If no maximum date has been 234: * specified then return <code>null</code>. 235: */ 236: public Date getMaximum() 237: { 238: return m_maximum; 239: } 240: 241: /** 242: * Sets the maximum Date to the specified value. 243: * 244: * @param maximum 245: * the maximum Date permitted 246: */ 247: public void setMaximum( final Date maximum ) 248: { 249: m_maximum = maximum; 250: } 251: 252: /** 253: * Returns the minimum date permitted. 254: * 255: * @return Date the minimum date permitted. If no minimum date has been 256: * specified then return <code>null</code>. 257: */ 258: public Date getMinimum() 259: { 260: return m_minimum; 261: } 262: 263: /** 264: * Sets the minimum Date to the specified value. 265: * 266: * @param minimum 267: * the minimum Date permitted 268: */ 269: public void setMinimum( Date minimum ) 270: { 271: m_minimum = minimum; 272: } 273: 274: /** 275: * Returns whether the specified Date is later than the maximum date. 276: * 277: * @param date 278: * the Date to evaluate 279: * 280: * @return boolean whether <code>date</code> is earlier than the maximum 281: * date 282: */ 283: private boolean isDateLater( Date date ) 284: { 285: return ( m_maximum != null ) && ( date.getTime() > m_maximum.getTime() ); 286: } 287: 288: /** 289: * Returns whether the specified Date is earlier than the minimum date. 290: * 291: * @param date the Date to evaluate 292: * @return boolean whether <code>date</code> is earlier than the minimum 293: * date 294: */ 295: private boolean isDateEarlier( Date date ) 296: { 297: return ( m_minimum != null ) && ( date.getTime() < m_minimum.getTime() ); 298: } 299: 300: /** 301: * Sets the date format permitted. 302: * 303: * @param format 304: * the format to use 305: */ 306: public void setFormat( final DateFormat format ) 307: { 308: setFormats( new DateFormat[]{format} ); 309: } 310: 311: /** 312: * Sets the date formats permitted. 313: * 314: * @param formats 315: * the List of DateFormats to use 316: */ 317: public void setFormats( final List formats ) 318: { 319: setFormats( (DateFormat[]) formats.toArray( new DateFormat[formats.size()] ) ); 320: } 321: 322: /** 323: * Sets the date formats permitted. 324: * 325: * @param formats the array of DateFormats to use 326: */ 327: public void setFormats( final DateFormat[] formats ) 328: { 329: m_formats = formats; 330: setLeniant( m_isLenient ); 331: } 332: 333: /** 334: * Gets the date formats permitted. 335: * 336: * @return the permitted formats 337: */ 338: public DateFormat[] getFormats() 339: { 340: return m_formats; 341: } 342: }