1 /*
2  * TimeParam.java
3  *
4  * jcmdline Rel. @VERSION@ $Id: TimeParam.java,v 1.4 2009/08/07 16:13:28 lglawrence Exp $
5  *
6  * Classes:
7  *   public   TimeParam
8  *
9  * ***** BEGIN LICENSE BLOCK *****
10  * Version: MPL 1.1
11  *
12  * The contents of this file are subject to the Mozilla Public License Version
13  * 1.1 (the "License"); you may not use this file except in compliance with
14  * the License. You may obtain a copy of the License at
15  * http://www.mozilla.org/MPL/
16  *
17  * Software distributed under the License is distributed on an "AS IS" basis,
18  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
19  * for the specific language governing rights and limitations under the
20  * License.
21  *
22  * The Original Code is the Java jcmdline (command line management) package.
23  *
24  * The Initial Developer of the Original Code is Lynne Lawrence.
25  *
26  * Portions created by the Initial Developer are Copyright (C) 2002
27  * the Initial Developer. All Rights Reserved.
28  *
29  * Contributor(s):  Lynne Lawrence <lgl@visuallink.com>
30  *
31  * ***** END LICENSE BLOCK *****
32  */
33 
34 package jcmdline;
35 
36 import java.text.ParseException;
37 import java.text.SimpleDateFormat;
38 import java.util.Date;
39 
40 /**
41  * A parameter that accepts a time as its value.
42  * <p>
43  * The format for the time is "HH:mm:ss:SSS", where the seconds and/or
44  * milliseconds portion may be left off by the user, in which case they will be
45  * defaulted.
46  * <P>
47  * Sample Usage:
48  *
49  * <pre>
50  *     TimeParam startTimeParam =
51  *         new TimeParam(&quot;startTime&quot;,
52  *                       &quot;start time of report&quot;,
53  *                       TimeParam.REQUIRED);
54  *     TimeParam endTimeParam =
55  *         new TimeParam(&quot;endTime&quot;,
56  *                       &quot;end time of report&quot;,
57  *                       TimeParam.REQUIRED);
58  *
59  *     // Seconds and millis for startTime will both be 0 by default.
60  *     // Set the seconds and millis for the end of the report to be the end
61  *     // of a minute.  The date portion will be the current day, which is
62  *     // the default.
63  *     endTimeParam.setDefaultSeconds(59);
64  *     endTimeParam.setDefaultMilliSeconds(999);
65  *
66  *     CmdLineHandler cl = new DefaultCmdLineHandler(
67  *         &quot;myreport&quot;, &quot;generate current activity report&quot;,
68  *         new Parameter[] {},
69  *         new Parameter[] { startTimeParam, endTimeParam });
70  *
71  *     cl.parse();
72  *
73  *     // Don't need to check isSet() because params are REQUIRED
74  *     Date stTime = startTimeParam.getValue();
75  *     Date enTime = endTimeParam.getValue();
76  *     .
77  *     .
78  * </pre>
79  *
80  * This will result in a command line that may be executed as:
81  *
82  * <pre>
83  *   myreport &quot;10:12&quot; &quot;23:34&quot;
84  * </pre>
85  *
86  * or
87  *
88  * <pre>
89  *   myreport &quot;10:12:34:567&quot; &quot;23:34:34:567&quot;
90  * </pre>
91  *
92  * @author Lynne Lawrence
93  * @version jcmdline Rel. @VERSION@ $Id: TimeParam.java,v 1.2 2002/12/07
94  *          14:22:06 lglawrence Exp $
95  * @see DateParam
96  * @see TimeParam
97  */
98 public class TimeParam extends AbstractParameter<Date> {
99 
100 	private static final String sTimeFmt = "HH:mm:ss:SSS";
101 	private static final String sTimeFmtDisplay = "HH:mm[:ss[:SSS]]";
102 
103 	/**
104 	 * The date, whose month, day, and year will be used to form the full Date
105 	 * associated with values of this Parameter.
106 	 */
107 	private Date datePortion = new Date();
108 
109 	/**
110 	 * The default millisecond value to use if not specified by the user. This
111 	 * will default to 0 if never specified for a TimeParam object.
112 	 *
113 	 * @see #setDefaultMilliSeconds(int) setDefaultMilliSeconds()
114 	 * @see #getDefaultMilliSeconds()
115 	 */
116 	private int defaultMilliSeconds = 0;
117 
118 	/**
119 	 * The seconds default to use if not specified by the user. This will
120 	 * default to 0 if never specified for a TimeParam object.
121 	 *
122 	 * @see #setDefaultSeconds(int) setDefaultSeconds()
123 	 * @see #getDefaultSeconds()
124 	 */
125 	private int defaultSeconds = 0;
126 
127 	/**
128 	 * constructor - creates single-valued, optional, public parameter, with a
129 	 * default datePortion of the current day
130 	 *
131 	 * @param tag
132 	 *            a unique identifier for this parameter
133 	 * @param desc
134 	 *            a description of the parameter, suitable for display in a
135 	 *            usage statement
136 	 * @throws IllegalArgumentException
137 	 *             if <code>tag</code> or <desc> are invalid.
138 	 * @see AbstractParameter#setTag(String) setTag()
139 	 * @see AbstractParameter#setDesc(String) setDesc()
140 	 */
TimeParam(String tag, String desc)141 	public TimeParam(String tag, String desc) {
142 		this(tag, desc, OPTIONAL, SINGLE_VALUED, PUBLIC);
143 	}
144 
145 	/**
146 	 * constructor - creates single-valued, public parameter which will will be
147 	 * either optional or required, as specified, with a default datePortion of
148 	 * the current day
149 	 *
150 	 * @param tag
151 	 *            a unique identifier for this parameter
152 	 * @param desc
153 	 *            a description of the parameter, suitable for display in a
154 	 *            usage statement
155 	 * @param optional
156 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
157 	 *            {@link Parameter#REQUIRED REQUIRED} if required
158 	 * @throws IllegalArgumentException
159 	 *             if any of the specified parameters are invalid.
160 	 * @see AbstractParameter#setTag(String) setTag()
161 	 * @see AbstractParameter#setDesc(String) setDesc()
162 	 */
TimeParam(String tag, String desc, boolean optional)163 	public TimeParam(String tag, String desc, boolean optional) {
164 		this(tag, desc, optional, SINGLE_VALUED, PUBLIC);
165 	}
166 
167 	/**
168 	 * constructor - creates a public parameter which will will be either
169 	 * optional or required, and/or multi-valued, as specified, with a default
170 	 * datePortion of the current day
171 	 *
172 	 * @param tag
173 	 *            a unique identifier for this parameter
174 	 * @param desc
175 	 *            a description of the parameter, suitable for display in a
176 	 *            usage statement
177 	 * @param optional
178 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
179 	 *            {@link Parameter#REQUIRED REQUIRED} if required
180 	 * @param multiValued
181 	 *            {@link Parameter#MULTI_VALUED MULTI_VALUED} if the parameter
182 	 *            can accept multiple values, {@link Parameter#SINGLE_VALUED
183 	 *            SINGLE_VALUED} if the parameter can contain only a single
184 	 *            value
185 	 * @throws IllegalArgumentException
186 	 *             if any of the specified parameters are invalid.
187 	 * @see AbstractParameter#setTag(String) setTag()
188 	 * @see AbstractParameter#setDesc(String) setDesc()
189 	 * @see Parameter#SINGLE_VALUED SINGLE_VALUED
190 	 * @see Parameter#MULTI_VALUED MULTI_VALUED
191 	 */
TimeParam(String tag, String desc, boolean optional, boolean multiValued)192 	public TimeParam(String tag, String desc, boolean optional,
193 			boolean multiValued) {
194 		this(tag, desc, optional, multiValued, PUBLIC);
195 	}
196 
197 	/**
198 	 * constructor - creates a parameter which will will be either optional or
199 	 * required, single or multi-valued, and hidden or public as specified, with
200 	 * a default datePortion of the current day
201 	 *
202 	 * @param tag
203 	 *            a unique identifier for this parameter
204 	 * @param desc
205 	 *            a description of the parameter, suitable for display in a
206 	 *            usage statement
207 	 * @param optional
208 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
209 	 *            {@link Parameter#REQUIRED REQUIRED} if required
210 	 * @param multiValued
211 	 *            {@link Parameter#MULTI_VALUED MULTI_VALUED} if the parameter
212 	 *            can accept multiple values, {@link Parameter#SINGLE_VALUED
213 	 *            SINGLE_VALUED} if the parameter can contain only a single
214 	 *            value
215 	 * @param hidden
216 	 *            {@link Parameter#HIDDEN HIDDEN} if parameter is not to be
217 	 *            listed in the usage, {@link Parameter#PUBLIC PUBLIC}
218 	 *            otherwise.
219 	 * @throws IllegalArgumentException
220 	 *             if any of the specified parameters are invalid.
221 	 * @see AbstractParameter#setTag(String) setTag()
222 	 * @see AbstractParameter#setDesc(String) setDesc()
223 	 * @see Parameter#SINGLE_VALUED SINGLE_VALUED
224 	 * @see Parameter#MULTI_VALUED MULTI_VALUED
225 	 * @see Parameter#HIDDEN HIDDEN
226 	 * @see Parameter#PUBLIC PUBLIC
227 	 */
TimeParam(String tag, String desc, boolean optional, boolean multiValued, boolean hidden)228 	public TimeParam(String tag, String desc, boolean optional,
229 			boolean multiValued, boolean hidden) {
230 
231 		this.setTag(tag);
232 		this.setDesc(desc);
233 		this.setOptional(optional);
234 		this.setMultiValued(multiValued);
235 		this.setHidden(hidden);
236 		this.setOptionLabel(sTimeFmtDisplay);
237 	}
238 
239 	/**
240 	 * constructor - creates a single-valued, optional, public, number parameter
241 	 * whose value must be one of the specified values, with a default
242 	 * datePortion of the current day
243 	 *
244 	 * @param tag
245 	 *            the tag associated with this parameter
246 	 * @param desc
247 	 *            a description of the parameter, suitable for display in a
248 	 *            usage statement
249 	 * @param acceptableValues
250 	 *            the acceptable values for the parameter
251 	 * @throws IllegalArgumentException
252 	 *             if any parameter is invalid.
253 	 * @see AbstractParameter#setTag(String) setTag()
254 	 * @see AbstractParameter#setDesc(String) setDesc()
255 	 * @see AbstractParameter#setAcceptableValues(Object[]) setAcceptableValues()
256 	 */
TimeParam(String tag, String desc, Date[] acceptableValues)257 	public TimeParam(String tag, String desc, Date[] acceptableValues) {
258 		this(tag, desc, acceptableValues, OPTIONAL, SINGLE_VALUED, PUBLIC);
259 	}
260 
261 	/**
262 	 * constructor - creates a single-valued, public, number parameter whose
263 	 * value must be one of the specified values, and which is required or
264 	 * optional, as specified, with a default datePortion of the current day
265 	 *
266 	 * @param tag
267 	 *            the tag associated with this parameter
268 	 * @param desc
269 	 *            a description of the parameter, suitable for display in a
270 	 *            usage statement
271 	 * @param acceptableValues
272 	 *            the acceptable values for the parameter
273 	 * @param optional
274 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
275 	 *            {@link Parameter#REQUIRED REQUIRED} if required
276 	 * @throws IllegalArgumentException
277 	 *             if any parameter is invalid.
278 	 * @see AbstractParameter#setTag(String) setTag()
279 	 * @see AbstractParameter#setDesc(String) setDesc()
280 	 * @see AbstractParameter#setAcceptableValues(Object[]) setAcceptableValues()
281 	 * @see Parameter#OPTIONAL OPTIONAL
282 	 * @see Parameter#REQUIRED REQUIRED
283 	 */
TimeParam(String tag, String desc, Date[] acceptableValues, boolean optional)284 	public TimeParam(String tag, String desc, Date[] acceptableValues,
285 			boolean optional) {
286 		this(tag, desc, acceptableValues, optional, SINGLE_VALUED, PUBLIC);
287 	}
288 
289 	/**
290 	 * constructor - creates a public number parameter whose value must be one
291 	 * of the specified values, and which is required or optional and/or
292 	 * multi-valued, as specified, with a default datePortion of the current day
293 	 *
294 	 * @param tag
295 	 *            the tag associated with this parameter
296 	 * @param desc
297 	 *            a description of the parameter, suitable for display in a
298 	 *            usage statement
299 	 * @param acceptableValues
300 	 *            the acceptable values for the parameter
301 	 * @param optional
302 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
303 	 *            {@link Parameter#REQUIRED REQUIRED} if required
304 	 * @param multiValued
305 	 *            {@link Parameter#MULTI_VALUED MULTI_VALUED} if the parameter
306 	 *            can accept multiple values, {@link Parameter#SINGLE_VALUED
307 	 *            SINGLE_VALUED} if the parameter can contain only a single
308 	 *            value
309 	 * @throws IllegalArgumentException
310 	 *             if any parameter is invalid.
311 	 * @see AbstractParameter#setTag(String) setTag()
312 	 * @see AbstractParameter#setDesc(String) setDesc()
313 	 * @see AbstractParameter#setAcceptableValues(Object[]) setAcceptableValues()
314 	 * @see Parameter#OPTIONAL OPTIONAL
315 	 * @see Parameter#REQUIRED REQUIRED
316 	 * @see Parameter#SINGLE_VALUED SINGLE_VALUED
317 	 * @see Parameter#MULTI_VALUED MULTI_VALUED
318 	 */
TimeParam(String tag, String desc, Date[] acceptableValues, boolean optional, boolean multiValued)319 	public TimeParam(String tag, String desc, Date[] acceptableValues,
320 			boolean optional, boolean multiValued) {
321 		this(tag, desc, acceptableValues, optional, multiValued, PUBLIC);
322 	}
323 
324 	/**
325 	 * constructor - creates a Parameter, all of whose options are specified,
326 	 * with a default datePortion of the current day
327 	 *
328 	 * @param tag
329 	 *            the tag associated with this parameter
330 	 * @param desc
331 	 *            a description of the parameter, suitable for display in a
332 	 *            usage statement
333 	 * @param acceptableValues
334 	 *            the acceptable values for the parameter
335 	 * @param optional
336 	 *            {@link Parameter#OPTIONAL OPTIONAL} if optional,
337 	 *            {@link Parameter#REQUIRED REQUIRED} if required
338 	 * @param multiValued
339 	 *            {@link Parameter#MULTI_VALUED MULTI_VALUED} if the parameter
340 	 *            can accept multiple values, {@link Parameter#SINGLE_VALUED
341 	 *            SINGLE_VALUED} if the parameter can contain only a single
342 	 *            value
343 	 * @param hidden
344 	 *            {@link Parameter#HIDDEN HIDDEN} if parameter is not to be
345 	 *            listed in the usage, {@link Parameter#PUBLIC PUBLIC}
346 	 *            otherwise.
347 	 * @throws IllegalArgumentException
348 	 *             if any parameter is invalid.
349 	 * @see AbstractParameter#setTag(String) setTag()
350 	 * @see AbstractParameter#setDesc(String) setDesc()
351 	 * @see AbstractParameter#setAcceptableValues(Object[]) setAcceptableValues()
352 	 * @see Parameter#OPTIONAL OPTIONAL
353 	 * @see Parameter#REQUIRED REQUIRED
354 	 * @see Parameter#SINGLE_VALUED SINGLE_VALUED
355 	 * @see Parameter#MULTI_VALUED MULTI_VALUED
356 	 * @see Parameter#HIDDEN HIDDEN
357 	 * @see Parameter#PUBLIC PUBLIC
358 	 */
TimeParam(String tag, String desc, Date[] acceptableValues, boolean optional, boolean multiValued, boolean hidden)359 	public TimeParam(String tag, String desc, Date[] acceptableValues,
360 			boolean optional, boolean multiValued, boolean hidden) {
361 		this.setTag(tag);
362 		this.setAcceptableValues(acceptableValues);
363 		this.setDesc(desc);
364 		this.setOptional(optional);
365 		this.setMultiValued(multiValued);
366 		this.setHidden(hidden);
367 		this.setOptionLabel(sTimeFmtDisplay);
368 	}
369 
370 	/**
371 	 * @see jcmdline.AbstractParameter#convertValue(java.lang.String)
372 	 */
373 	@Override
convertValue(String strVal)374 	public Date convertValue(String strVal) throws CmdLineException {
375 		String fullval = fullTime(strVal);
376 		try {
377 			if (fullval.length() > 12) {
378 				throw new Exception();
379 			}
380 			int n = Integer.parseInt(fullval.substring(0, 2));
381 			if (n < 0 || n > 23) {
382 				throw new Exception();
383 			}
384 			n = Integer.parseInt(fullval.substring(3, 5));
385 			if (n < 0 || n > 59) {
386 				throw new Exception();
387 			}
388 			n = Integer.parseInt(fullval.substring(6, 8));
389 			if (n < 0 || n > 59) {
390 				throw new Exception();
391 			}
392 			n = Integer.parseInt(fullval.substring(9, 12));
393 			if (n < 0 || n > 999) {
394 				throw new Exception();
395 			}
396 		} catch (Exception e) {
397 			throw new CmdLineException(Strings.get(
398 					"TimeParam.invalidTimeFormat", new Object[] { strVal,
399 							sTimeFmtDisplay }));
400 		}
401 
402 		// Combine with date portion to make up a full Date
403 		String dtfmt = "MM/dd/yy";
404 		SimpleDateFormat fmt = new SimpleDateFormat(dtfmt);
405 		String sDate = fmt.format(datePortion);
406 		Date ret;
407 		try {
408 			fmt = new SimpleDateFormat(dtfmt + " " + sTimeFmt);
409 			ret = fmt.parse(sDate + " " + fullval);
410 		} catch (ParseException e) {
411 			// should never happen!!
412 			throw new RuntimeException(e);
413 		}
414 		return ret;
415 	}
416 
417 	/**
418 	 * @return the datePortion
419 	 */
getDatePortion()420 	public Date getDatePortion() {
421 		return datePortion;
422 	}
423 
424 	/**
425 	 * Gets the default millisecond value to use if not specified by the user.
426 	 * This will default to 0 if never specified for a TimeParam object.
427 	 *
428 	 * @return the default millisecond value to use if not specified by the user
429 	 * @see #setDefaultMilliSeconds(int) setDefaultMilliSeconds()
430 	 */
getDefaultMilliSeconds()431 	public int getDefaultMilliSeconds() {
432 		return defaultMilliSeconds;
433 	}
434 
435 	/**
436 	 * Gets the seconds default to use if not specified by the user. This will
437 	 * default to 0 if never specified for a TimeParam object.
438 	 *
439 	 * @return the seconds default to use if not specified by the user
440 	 * @see #setDefaultSeconds(int) setDefaultSeconds()
441 	 */
getDefaultSeconds()442 	public int getDefaultSeconds() {
443 		return defaultSeconds;
444 	}
445 
446 	/**
447 	 * @param datePortion
448 	 *            the datePortion to set
449 	 */
setDatePortion(Date datePortion)450 	public void setDatePortion(Date datePortion) {
451 		this.datePortion = datePortion;
452 	}
453 
454 	/**
455 	 * Sets the default millisecond value to use if not specified by the user.
456 	 * This will default to 0 if never specified for a TimeParam object.
457 	 *
458 	 * @param defaultMilliSeconds
459 	 *            the default millisecond value to use if not specified by the
460 	 *            user
461 	 * @see #getDefaultMilliSeconds()
462 	 */
setDefaultMilliSeconds(int defaultMilliSeconds)463 	public void setDefaultMilliSeconds(int defaultMilliSeconds) {
464 		if (defaultMilliSeconds < 0 || defaultMilliSeconds > 999) {
465 			throw new IllegalArgumentException(Strings.get(
466 					"TimeParam.invalidMilliSeconds",
467 					new Object[] { new Integer(defaultMilliSeconds) }));
468 		}
469 		this.defaultMilliSeconds = defaultMilliSeconds;
470 	}
471 
472 	/**
473 	 * Sets the seconds default to use if not specified by the user. This will
474 	 * default to 0 if never specified for a TimeParam object.
475 	 *
476 	 * @param defaultSeconds
477 	 *            the seconds default to use if not specified by the user
478 	 * @see #getDefaultSeconds()
479 	 */
setDefaultSeconds(int defaultSeconds)480 	public void setDefaultSeconds(int defaultSeconds) {
481 		if (defaultSeconds < 0 || defaultSeconds > 59) {
482 			throw new IllegalArgumentException(Strings.get(
483 					"TimeParam.invalidSeconds", new Object[] { new Integer(
484 							defaultSeconds) }));
485 		}
486 		this.defaultSeconds = defaultSeconds;
487 	}
488 
489 	/**
490 	 * @see jcmdline.AbstractParameter#validateValue(java.lang.Object)
491 	 */
validateValue(Date val)492 	public void validateValue(Date val) throws CmdLineException {
493 		super.validateValue(val);
494 	}
495 
496 	/**
497 	 * Converts a String value to its Date equivalent, filling in default
498 	 * seconds and milliseconds as necessary.
499 	 *
500 	 * @param val
501 	 *            the String to be converted
502 	 * @return the Date object represented by <code>val</code>
503 	 */
fullTime(String val)504 	private String fullTime(String val) {
505 		if (val.length() == 5) {
506 			val = String.format("%s:%02d", val, defaultSeconds);
507 		}
508 		if (val.length() == 8) {
509 			val = String.format("%s:%03d", val, defaultMilliSeconds);
510 		}
511 		return val;
512 	}
513 }
514