001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.util.args;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.Iterator;
033 import java.util.LinkedList;
034
035 import static org.opends.messages.UtilityMessages.*;
036
037 import org.opends.messages.MessageBuilder;
038 import static org.opends.server.util.StaticUtils.*;
039
040
041
042 /**
043 * This class defines a generic argument that may be used in the argument list
044 * for an application. This is an abstract class that must be subclassed in
045 * order to provide specific functionality.
046 */
047 public abstract class Argument
048 {
049 // Indicates whether this argument should be hidden in the usage information.
050 private boolean isHidden;
051
052 // Indicates whether this argument may be specified more than once for
053 // multiple values.
054 private boolean isMultiValued;
055
056 // Indicates whether this argument was provided in the set of command-line
057 // arguments.
058 private boolean isPresent;
059
060 // Indicates whether this argument is required to have a value.
061 private boolean isRequired;
062
063 // Indicates whether this argument requires a value.
064 private boolean needsValue;
065
066 // The single-character identifier for this argument.
067 private Character shortIdentifier;
068
069 // The unique ID of the description for this argument.
070 private Message description;
071
072 // The set of values for this argument.
073 private LinkedList<String> values;
074
075 // The default value for the argument if none other is provided.
076 private String defaultValue;
077
078 // The long identifier for this argument.
079 private String longIdentifier;
080
081 // The generic name that will be used to refer to this argument.
082 private String name;
083
084 // The name of the property that can be used to set the default value.
085 private String propertyName;
086
087 // The value placeholder for this argument, which will be used in usage
088 // information.
089 private Message valuePlaceholder;
090
091 // Indicates whether this argument was provided in the set of properties
092 // found is a properties file.
093 private boolean isValueSetByProperty;
094
095
096 /**
097 * Creates a new argument with the provided information.
098 *
099 * @param name The generic name that should be used to refer to
100 * this argument.
101 * @param shortIdentifier The single-character identifier for this
102 * argument, or <CODE>null</CODE> if there is none.
103 * @param longIdentifier The long identifier for this argument, or
104 * <CODE>null</CODE> if there is none.
105 * @param isRequired Indicates whether this argument must be specified
106 * on the command line.
107 * @param isMultiValued Indicates whether this argument may be specified
108 * more than once to provide multiple values.
109 * @param needsValue Indicates whether this argument requires a value.
110 * @param valuePlaceholder The placeholder for the argument value that will
111 * be displayed in usage information, or
112 * <CODE>null</CODE> if this argument does not
113 * require a value.
114 * @param defaultValue The default value that should be used for this
115 * argument if none is provided in a properties file
116 * or on the command line. This may be
117 * <CODE>null</CODE> if there is no generic default.
118 * @param propertyName The name of the property in a property file that
119 * may be used to override the default value but
120 * will be overridden by a command-line argument.
121 * @param description Message for the description of this
122 * argument.
123 *
124 * @throws ArgumentException If there is a problem with any of the
125 * parameters used to create this argument.
126 */
127 protected Argument(String name, Character shortIdentifier,
128 String longIdentifier, boolean isRequired,
129 boolean isMultiValued, boolean needsValue,
130 Message valuePlaceholder, String defaultValue,
131 String propertyName,
132 Message description)
133 throws ArgumentException
134 {
135 this.name = name;
136 this.shortIdentifier = shortIdentifier;
137 this.longIdentifier = longIdentifier;
138 this.isRequired = isRequired;
139 this.isMultiValued = isMultiValued;
140 this.needsValue = needsValue;
141 this.valuePlaceholder = valuePlaceholder;
142 this.defaultValue = defaultValue;
143 this.propertyName = propertyName;
144 this.description = description;
145 this.isValueSetByProperty = false ;
146
147 if ((shortIdentifier == null) && (longIdentifier == null))
148 {
149 Message message = ERR_ARG_NO_IDENTIFIER.get(name);
150 throw new ArgumentException(message);
151 }
152
153 if (needsValue && (valuePlaceholder == null))
154 {
155 Message message = ERR_ARG_NO_VALUE_PLACEHOLDER.get(name);
156 throw new ArgumentException(message);
157 }
158
159 values = new LinkedList<String>();
160 isPresent = false;
161 isHidden = false;
162 }
163
164
165
166 /**
167 * Retrieves the generic name that will be used to refer to this argument.
168 *
169 * @return The generic name that will be used to refer to this argument.
170 */
171 public String getName()
172 {
173 return name;
174 }
175
176
177
178 /**
179 * Retrieves the single-character identifier that may be used to specify the
180 * value of this argument.
181 *
182 * @return The single-character identifier that may be used to specify the
183 * value of this argument, or <CODE>null</CODE> if there is none.
184 */
185 public Character getShortIdentifier()
186 {
187 return shortIdentifier;
188 }
189
190
191
192 /**
193 * Retrieves the long (multi-character) identifier that may be used to specify
194 * the value of this argument.
195 *
196 * @return The long (multi-character) identifier that may be used to specify
197 * the value of this argument.
198 */
199 public String getLongIdentifier()
200 {
201 return longIdentifier;
202 }
203
204
205
206 /**
207 * Indicates whether this argument is required to have at least one value.
208 *
209 * @return <CODE>true</CODE> if this argument is required to have at least
210 * one value, or <CODE>false</CODE> if it does not need to have a
211 * value.
212 */
213 public boolean isRequired()
214 {
215 return isRequired;
216 }
217
218
219
220 /**
221 * Specifies whether this argument is required to have at least one value.
222 *
223 * @param isRequired Indicates whether this argument is required to have at
224 * least one value.
225 */
226 public void setRequired(boolean isRequired)
227 {
228 this.isRequired = isRequired;
229 }
230
231
232
233 /**
234 * Indicates whether this argument is present in the parsed set of
235 * command-line arguments.
236 *
237 * @return <CODE>true</CODE> if this argument is present in the parsed set of
238 * command-line arguments, or <CODE>false</CODE> if not.
239 */
240 public boolean isPresent()
241 {
242 return isPresent;
243 }
244
245
246
247 /**
248 * Specifies whether this argument is present in the parsed set of
249 * command-line arguments.
250 *
251 * @param isPresent Indicates whether this argument is present in the set of
252 * command-line arguments.
253 */
254 public void setPresent(boolean isPresent)
255 {
256 this.isPresent = isPresent;
257 }
258
259
260
261 /**
262 * Indicates whether this argument should be hidden from the usage
263 * information.
264 *
265 * @return <CODE>true</CODE> if this argument should be hidden from the usage
266 * information, or <CODE>false</CODE> if not.
267 */
268 public boolean isHidden()
269 {
270 return isHidden;
271 }
272
273
274
275 /**
276 * Specifies whether this argument should be hidden from the usage
277 * information.
278 *
279 * @param isHidden Indicates whether this argument should be hidden from the
280 * usage information.
281 */
282 public void setHidden(boolean isHidden)
283 {
284 this.isHidden = isHidden;
285 }
286
287
288
289 /**
290 * Indicates whether this argument may be provided more than once on the
291 * command line to specify multiple values.
292 *
293 * @return <CODE>true</CODE> if this argument may be provided more than once
294 * on the command line to specify multiple values, or
295 * <CODE>false</CODE> if it may have at most one value.
296 */
297 public boolean isMultiValued()
298 {
299 return isMultiValued;
300 }
301
302
303
304 /**
305 * Specifies whether this argument may be provided more than once on the
306 * command line to specify multiple values.
307 *
308 * @param isMultiValued Indicates whether this argument may be provided more
309 * than once on the command line to specify multiple
310 * values.
311 */
312 public void setMultiValued(boolean isMultiValued)
313 {
314 this.isMultiValued = isMultiValued;
315 }
316
317
318
319 /**
320 * Indicates whether a value must be provided with this argument if it is
321 * present.
322 *
323 * @return <CODE>true</CODE> if a value must be provided with the argument if
324 * it is present, or <CODE>false</CODE> if the argument does not take
325 * a value and the presence of the argument identifier itself is
326 * sufficient to convey the necessary information.
327 */
328 public boolean needsValue()
329 {
330 return needsValue;
331 }
332
333
334
335 /**
336 * Specifies whether a value must be provided with this argument if it is
337 * present. If this is changed from <CODE>false</CODE> to <CODE>true</CODE>,
338 * then a value placeholder must also be provided.
339 *
340 * @param needsValue Indicates whether a value must be provided with this
341 * argument if it is present.
342
343 */
344 public void setNeedsValue(boolean needsValue)
345 {
346 this.needsValue = needsValue;
347 }
348
349
350
351 /**
352 * Retrieves the value placeholder that will be displayed for this argument in
353 * the generated usage information.
354 *
355 * @return The value placeholder that will be displayed for this argument in
356 * the generated usage information, or <CODE>null</CODE> if there is
357 * none.
358 */
359 public Message getValuePlaceholder()
360 {
361 return valuePlaceholder;
362 }
363
364
365
366 /**
367 * Specifies the value placeholder that will be displayed for this argument in
368 * the generated usage information. It may be <CODE>null</CODE> only if
369 * <CODE>needsValue()</CODE> returns <CODE>false</CODE>.
370 *
371 * @param valuePlaceholder The value placeholder that will be displayed for
372 * this argument in the generated usage information.
373 */
374 public void setValuePlaceholder(Message valuePlaceholder)
375 {
376 this.valuePlaceholder = valuePlaceholder;
377 }
378
379
380
381 /**
382 * Retrieves the default value that will be used for this argument if it is
383 * not specified on the command line and it is not set from a properties file.
384 *
385 * @return The default value that will be used for this argument if it is not
386 * specified on the command line and it is not set from a properties
387 * file, or <CODE>null</CODE> if there is no default value.
388 */
389 public String getDefaultValue()
390 {
391 return defaultValue;
392 }
393
394
395
396 /**
397 * Specifies the default value that will be used for this argument if it is
398 * not specified on the command line and it is not set from a properties file.
399 *
400 * @param defaultValue The default value that will be used for this argument
401 * if it is not specified on the command line and it is
402 * not set from a properties file.
403 */
404 public void setDefaultValue(String defaultValue)
405 {
406 this.defaultValue = defaultValue;
407 }
408
409
410
411 /**
412 * Retrieves the name of a property in a properties file that may be used to
413 * set the default value for this argument if it is present. A value read
414 * from a properties file will override the default value returned from the
415 * <CODE>getDefaultValue</CODE>, but the properties file value will be
416 * overridden by a value supplied on the command line.
417 *
418 * @return The name of a property in a properties file that may be used to
419 * set the default value for this argument if it is present.
420 */
421 public String getPropertyName()
422 {
423 return propertyName;
424 }
425
426
427
428 /**
429 * Specifies the name of a property in a properties file that may be used to
430 * set the default value for this argument if it is present.
431 *
432 * @param propertyName The name of a property in a properties file that may
433 * be used to set the default value for this argument if
434 * it is present.
435 */
436 public void setPropertyName(String propertyName)
437 {
438 this.propertyName = propertyName;
439 }
440
441 /**
442 * Indicates whether this argument was provided in the set of
443 * properties found is a properties file.
444 *
445 * @return <CODE>true</CODE> if this argument was provided in the
446 * set of properties found is a properties file, or
447 * <CODE>false</CODE> if not.
448 */
449 public boolean isValueSetByProperty()
450 {
451 return isValueSetByProperty;
452 }
453
454 /**
455 * Specifies whether this argument was provided in the set of
456 * properties found is a properties file.
457 *
458 * @param isValueSetByProperty
459 * Specify whether this argument was provided in the set
460 * of properties found is a properties file.
461 */
462 public void setValueSetByProperty(boolean isValueSetByProperty)
463 {
464 this.isValueSetByProperty = isValueSetByProperty;
465 }
466
467 /**
468 * Retrieves the human-readable description for this argument.
469 *
470 * @return The human-readable description for this argument.
471 */
472 public Message getDescription()
473 {
474 return description != null ? description : Message.EMPTY;
475 }
476
477
478
479 /**
480 * Indicates whether this argument has at least one value.
481 *
482 * @return <CODE>true</CODE> if this argument has at least one value, or
483 * <CODE>false</CODE> if it does not have any values.
484 */
485 public boolean hasValue()
486 {
487 return (! values.isEmpty());
488 }
489
490
491
492 /**
493 * Retrieves the string vale for this argument. If it has multiple values,
494 * then the first will be returned. If it does not have any values, then the
495 * default value will be returned.
496 *
497 * @return The string value for this argument, or <CODE>null</CODE> if there
498 * are no values and no default value has been given.
499 */
500 public String getValue()
501 {
502 if (values.isEmpty())
503 {
504 return defaultValue;
505 }
506
507 return values.getFirst();
508 }
509
510
511
512 /**
513 * Retrieves the set of string values for this argument.
514 *
515 * @return The set of string values for this argument.
516 */
517 public LinkedList<String> getValues()
518 {
519 return values;
520 }
521
522
523
524 /**
525 * Retrieves the value of this argument as an integer.
526 *
527 * @return The value of this argument as an integer.
528 *
529 * @throws ArgumentException If there are multiple values, or the value
530 * cannot be parsed as an integer.
531 */
532 public int getIntValue()
533 throws ArgumentException
534 {
535 if (values.isEmpty())
536 {
537 Message message = ERR_ARG_NO_INT_VALUE.get(name);
538 throw new ArgumentException(message);
539 }
540
541 Iterator<String> iterator = values.iterator();
542 String valueString = iterator.next();
543
544 int intValue;
545 try
546 {
547 intValue = Integer.parseInt(valueString);
548 }
549 catch (Exception e)
550 {
551 Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name);
552 throw new ArgumentException(message, e);
553 }
554
555 if (iterator.hasNext())
556 {
557 Message message = ERR_ARG_INT_MULTIPLE_VALUES.get(name);
558 throw new ArgumentException(message);
559 }
560 else
561 {
562 return intValue;
563 }
564 }
565
566
567
568 /**
569 * Retrieves the set of values for this argument as a list of integers.
570 *
571 * @return A list of the integer representations of the values for this
572 * argument.
573 *
574 * @throws ArgumentException If any of the values cannot be parsed as an
575 * integer.
576 */
577 public LinkedList<Integer> getIntValues()
578 throws ArgumentException
579 {
580 LinkedList<Integer> intList = new LinkedList<Integer>();
581
582 Iterator<String> iterator = values.iterator();
583 while (iterator.hasNext())
584 {
585 String valueString = iterator.next();
586
587 try
588 {
589 intList.add(Integer.valueOf(valueString));
590 }
591 catch (Exception e)
592 {
593 Message message = ERR_ARG_CANNOT_DECODE_AS_INT.get(valueString, name);
594 throw new ArgumentException(message, e);
595 }
596 }
597
598 return intList;
599 }
600
601
602
603 /**
604 * Retrieves the value of this argument as a <CODE>Boolean</CODE>.
605 *
606 * @return The value of this argument as a <CODE>Boolean</CODE>.
607 *
608 * @throws ArgumentException If this argument cannot be interpreted as a
609 * Boolean value.
610 */
611 public boolean getBooleanValue()
612 throws ArgumentException
613 {
614 if (values.isEmpty())
615 {
616 Message message = ERR_ARG_NO_BOOLEAN_VALUE.get(name);
617 throw new ArgumentException(message);
618 }
619
620 Iterator<String> iterator = values.iterator();
621 String valueString = toLowerCase(iterator.next());
622
623 boolean booleanValue;
624 if (valueString.equals("true") || valueString.equals("yes") ||
625 valueString.equals("on") || valueString.equals("1"))
626 {
627 booleanValue = true;
628 }
629 else if (valueString.equals("false") || valueString.equals("no") ||
630 valueString.equals("off") || valueString.equals("0"))
631 {
632 booleanValue = false;
633 }
634 else
635 {
636 Message message = ERR_ARG_CANNOT_DECODE_AS_BOOLEAN.get(valueString, name);
637 throw new ArgumentException(message);
638 }
639
640 if (iterator.hasNext())
641 {
642 Message message = ERR_ARG_BOOLEAN_MULTIPLE_VALUES.get(name);
643 throw new ArgumentException(message);
644 }
645 else
646 {
647 return booleanValue;
648 }
649 }
650
651
652
653 /**
654 * Indicates whether the provided value is acceptable for use in this
655 * argument.
656 *
657 * @param valueString The value for which to make the determination.
658 * @param invalidReason A buffer into which the invalid reason may be
659 * written if the value is not acceptable.
660 *
661 * @return <CODE>true</CODE> if the value is acceptable, or
662 * <CODE>false</CODE> if it is not.
663 */
664 public abstract boolean valueIsAcceptable(String valueString,
665 MessageBuilder invalidReason);
666
667
668
669 /**
670 * Adds a value to the set of values for this argument. This should only be
671 * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
672 * method.
673 *
674 * @param valueString The string representation of the value to add to this
675 * argument.
676 */
677 public void addValue(String valueString)
678 {
679 values.add(valueString);
680 }
681
682
683
684 /**
685 * Clears the set of values assigned to this argument.
686 */
687 public void clearValues()
688 {
689 values.clear();
690 }
691 }
692