Source for net.dpml.cli.validation.DateValidator

   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: }