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