mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
28.47.2010 f2160f4bd1c8ac67e5a86a6710d431e8932877f9
sdk/src/com/sun/opends/sdk/tools/ArgumentParser.java
@@ -30,8 +30,12 @@
import static com.sun.opends.sdk.messages.Messages.*;
import static com.sun.opends.sdk.tools.ToolConstants.*;
import static com.sun.opends.sdk.tools.Utils.*;
import static com.sun.opends.sdk.util.StaticUtils.*;
import static com.sun.opends.sdk.tools.Utils.PROPERTY_SCRIPT_NAME;
import static com.sun.opends.sdk.tools.Utils.wrapText;
import static com.sun.opends.sdk.util.StaticUtils.EOL;
import static com.sun.opends.sdk.util.StaticUtils.getBytes;
import static com.sun.opends.sdk.util.StaticUtils.getExceptionMessage;
import static com.sun.opends.sdk.util.StaticUtils.toLowerCase;
import java.io.File;
import java.io.FileInputStream;
@@ -44,17 +48,15 @@
/**
 * This class defines a utility that can be used to deal with
 * command-line arguments for applications in a CLIP-compliant manner
 * using either short one-character or longer word-based arguments. It
 * is also integrated with the Directory Server message catalog so that
 * it can display messages in an internationalizeable format, can
 * automatically generate usage information, can detect conflicts
 * between arguments, and can interact with a properties file to obtain
 * default values for arguments there if they are not specified on the
 * command-line.
 * This class defines a utility that can be used to deal with command-line
 * arguments for applications in a CLIP-compliant manner using either short
 * one-character or longer word-based arguments. It is also integrated with the
 * Directory Server message catalog so that it can display messages in an
 * internationalizeable format, can automatically generate usage information,
 * can detect conflicts between arguments, and can interact with a properties
 * file to obtain default values for arguments there if they are not specified
 * on the command-line.
 */
final class ArgumentParser
{
@@ -64,8 +66,8 @@
  private StringArgument filePropertiesPathArgument;
  /**
   * The argument that will be used to indicate that we'll not look for
   * default properties file.
   * The argument that will be used to indicate that we'll not look for default
   * properties file.
   */
  private BooleanArgument noPropertiesFileArgument;
@@ -79,17 +81,17 @@
  // The set of unnamed trailing arguments that were provided for this
  // parser.
  private ArrayList<String> trailingArguments;
  private final ArrayList<String> trailingArguments;
  // Indicates whether this parser will allow additional unnamed
  // arguments at
  // the end of the list.
  private boolean allowsTrailingArguments;
  private final boolean allowsTrailingArguments;
  // Indicates whether long arguments should be treated in a
  // case-sensitive
  // manner.
  private boolean longArgumentsCaseSensitive;
  private final boolean longArgumentsCaseSensitive;
  // Indicates whether the usage or version information has been
  // displayed.
@@ -100,26 +102,26 @@
  // The set of arguments defined for this parser, referenced by short
  // ID.
  private HashMap<Character, Argument> shortIDMap;
  private final HashMap<Character, Argument> shortIDMap;
  // The set of arguments defined for this parser, referenced by
  // argument name.
  private HashMap<String, Argument> argumentMap;
  private final HashMap<String, Argument> argumentMap;
  // The set of arguments defined for this parser, referenced by long
  // ID.
  private HashMap<String, Argument> longIDMap;
  private final HashMap<String, Argument> longIDMap;
  // The maximum number of unnamed trailing arguments that may be
  // provided.
  private int maxTrailingArguments;
  private final int maxTrailingArguments;
  // The minimum number of unnamed trailing arguments that may be
  // provided.
  private int minTrailingArguments;
  private final int minTrailingArguments;
  // The total set of arguments defined for this parser.
  private LinkedList<Argument> argumentList;
  private final LinkedList<Argument> argumentList;
  // The output stream to which usage information should be printed.
  private OutputStream usageOutputStream;
@@ -127,17 +129,17 @@
  // The fully-qualified name of the Java class that should be invoked
  // to launch
  // the program with which this argument parser is associated.
  private String mainClassName;
  private final String mainClassName;
  // A human-readable description for the tool, which will be included
  // when
  // displaying usage information.
  private LocalizableMessage toolDescription;
  private final LocalizableMessage toolDescription;
  // The display name that will be used for the trailing arguments in
  // the usage
  // information.
  private String trailingArgsDisplayName;
  private final String trailingArgsDisplayName;
  // The raw set of command-line arguments that were provided.
  private String[] rawArguments;
@@ -146,33 +148,32 @@
  private Set<ArgumentGroup> argumentGroups;
  /**
   * Group for arguments that have not been explicitly grouped. These
   * will appear at the top of the usage statement without a header.
   * Group for arguments that have not been explicitly grouped. These will
   * appear at the top of the usage statement without a header.
   */
  private ArgumentGroup defaultArgGroup = new ArgumentGroup(
  private final ArgumentGroup defaultArgGroup = new ArgumentGroup(
      LocalizableMessage.EMPTY, Integer.MAX_VALUE);
  /**
   * Group for arguments that are related to connection through LDAP.
   * This includes options like the bind DN, the port, etc.
   * Group for arguments that are related to connection through LDAP. This
   * includes options like the bind DN, the port, etc.
   */
  private ArgumentGroup ldapArgGroup = new ArgumentGroup(
      INFO_DESCRIPTION_LDAP_CONNECTION_ARGS.get(),
      Integer.MIN_VALUE + 2);
  private final ArgumentGroup ldapArgGroup = new ArgumentGroup(
      INFO_DESCRIPTION_LDAP_CONNECTION_ARGS.get(), Integer.MIN_VALUE + 2);
  /**
   * Group for arguments that are related to utility input/output like
   * properties file, no-prompt etc. These will appear toward the bottom
   * of the usage statement.
   * properties file, no-prompt etc. These will appear toward the bottom of the
   * usage statement.
   */
  private ArgumentGroup ioArgGroup = new ArgumentGroup(
  private final ArgumentGroup ioArgGroup = new ArgumentGroup(
      INFO_DESCRIPTION_IO_ARGS.get(), Integer.MIN_VALUE + 1);
  /**
   * Group for arguments that are general like help, version etc. These
   * will appear at the end of the usage statement.
   * Group for arguments that are general like help, version etc. These will
   * appear at the end of the usage statement.
   */
  private ArgumentGroup generalArgGroup = new ArgumentGroup(
  private final ArgumentGroup generalArgGroup = new ArgumentGroup(
      INFO_DESCRIPTION_GENERAL_ARGS.get(), Integer.MIN_VALUE);
  private final static String INDENT = "    ";
@@ -182,22 +183,23 @@
  /**
   * Creates a new instance of this argument parser with no arguments.
   * Unnamed trailing arguments will not be allowed.
   * Creates a new instance of this argument parser with no arguments. Unnamed
   * trailing arguments will not be allowed.
   *
   * @param mainClassName
   *          The fully-qualified name of the Java class that should be
   *          invoked to launch the program with which this argument
   *          parser is associated.
   *          The fully-qualified name of the Java class that should be invoked
   *          to launch the program with which this argument parser is
   *          associated.
   * @param toolDescription
   *          A human-readable description for the tool, which will be
   *          included when displaying usage information.
   *          A human-readable description for the tool, which will be included
   *          when displaying usage information.
   * @param longArgumentsCaseSensitive
   *          Indicates whether long arguments should be treated in a
   *          case-sensitive manner.
   */
  ArgumentParser(String mainClassName, LocalizableMessage toolDescription,
      boolean longArgumentsCaseSensitive)
  ArgumentParser(final String mainClassName,
      final LocalizableMessage toolDescription,
      final boolean longArgumentsCaseSensitive)
  {
    this.mainClassName = mainClassName;
    this.toolDescription = toolDescription;
@@ -225,39 +227,39 @@
  /**
   * Creates a new instance of this argument parser with no arguments
   * that may or may not be allowed to have unnamed trailing arguments.
   * Creates a new instance of this argument parser with no arguments that may
   * or may not be allowed to have unnamed trailing arguments.
   *
   * @param mainClassName
   *          The fully-qualified name of the Java class that should be
   *          invoked to launch the program with which this argument
   *          parser is associated.
   *          The fully-qualified name of the Java class that should be invoked
   *          to launch the program with which this argument parser is
   *          associated.
   * @param toolDescription
   *          A human-readable description for the tool, which will be
   *          included when displaying usage information.
   *          A human-readable description for the tool, which will be included
   *          when displaying usage information.
   * @param longArgumentsCaseSensitive
   *          Indicates whether long arguments should be treated in a
   *          case-sensitive manner.
   * @param allowsTrailingArguments
   *          Indicates whether this parser allows unnamed trailing
   *          arguments to be provided.
   *          Indicates whether this parser allows unnamed trailing arguments to
   *          be provided.
   * @param minTrailingArguments
   *          The minimum number of unnamed trailing arguments that must
   *          be provided. A value less than or equal to zero indicates
   *          that no minimum will be enforced.
   *          The minimum number of unnamed trailing arguments that must be
   *          provided. A value less than or equal to zero indicates that no
   *          minimum will be enforced.
   * @param maxTrailingArguments
   *          The maximum number of unnamed trailing arguments that may
   *          be provided. A value less than or equal to zero indicates
   *          that no maximum will be enforced.
   *          The maximum number of unnamed trailing arguments that may be
   *          provided. A value less than or equal to zero indicates that no
   *          maximum will be enforced.
   * @param trailingArgsDisplayName
   *          The display name that should be used as a placeholder for
   *          unnamed trailing arguments in the generated usage
   *          information.
   *          The display name that should be used as a placeholder for unnamed
   *          trailing arguments in the generated usage information.
   */
  ArgumentParser(String mainClassName, LocalizableMessage toolDescription,
      boolean longArgumentsCaseSensitive,
      boolean allowsTrailingArguments, int minTrailingArguments,
      int maxTrailingArguments, String trailingArgsDisplayName)
  ArgumentParser(final String mainClassName,
      final LocalizableMessage toolDescription,
      final boolean longArgumentsCaseSensitive,
      final boolean allowsTrailingArguments, final int minTrailingArguments,
      final int maxTrailingArguments, final String trailingArgsDisplayName)
  {
    this.mainClassName = mainClassName;
    this.toolDescription = toolDescription;
@@ -283,264 +285,15 @@
  /**
   * Retrieves the fully-qualified name of the Java class that should be
   * invoked to launch the program with which this argument parser is
   * associated.
   *
   * @return The fully-qualified name of the Java class that should be
   *         invoked to launch the program with which this argument
   *         parser is associated.
   */
  String getMainClassName()
  {
    return mainClassName;
  }
  /**
   * Retrieves a human-readable description for this tool, which should
   * be included at the top of the command-line usage information.
   *
   * @return A human-readable description for this tool, or {@code null}
   *         if none is available.
   */
  LocalizableMessage getToolDescription()
  {
    return toolDescription;
  }
  /**
   * Indicates whether this parser will allow unnamed trailing
   * arguments. These will be arguments at the end of the list that are
   * not preceded by either a long or short identifier and will need to
   * be manually parsed by the application using this parser. Note that
   * once an unnamed trailing argument has been identified, all
   * remaining arguments will be classified as such.
   *
   * @return <CODE>true</CODE> if this parser allows unnamed trailing
   *         arguments, or <CODE>false</CODE> if it does not.
   */
  boolean allowsTrailingArguments()
  {
    return allowsTrailingArguments;
  }
  /**
   * Retrieves the minimum number of unnamed trailing arguments that
   * must be provided.
   *
   * @return The minimum number of unnamed trailing arguments that must
   *         be provided, or a value less than or equal to zero if no
   *         minimum will be enforced.
   */
  int getMinTrailingArguments()
  {
    return minTrailingArguments;
  }
  /**
   * Retrieves the maximum number of unnamed trailing arguments that may
   * be provided.
   *
   * @return The maximum number of unnamed trailing arguments that may
   *         be provided, or a value less than or equal to zero if no
   *         maximum will be enforced.
   */
  int getMaxTrailingArguments()
  {
    return maxTrailingArguments;
  }
  /**
   * Retrieves the list of all arguments that have been defined for this
   * argument parser.
   *
   * @return The list of all arguments that have been defined for this
   *         argument parser.
   */
  LinkedList<Argument> getArgumentList()
  {
    return argumentList;
  }
  /**
   * Retrieves the argument with the specified name.
   *
   * @param name
   *          The name of the argument to retrieve.
   * @return The argument with the specified name, or <CODE>null</CODE>
   *         if there is no such argument.
   */
  Argument getArgument(String name)
  {
    return argumentMap.get(name);
  }
  /**
   * Retrieves the set of arguments mapped by the short identifier that
   * may be used to reference them. Note that arguments that do not have
   * a short identifier will not be present in this list.
   *
   * @return The set of arguments mapped by the short identifier that
   *         may be used to reference them.
   */
  HashMap<Character, Argument> getArgumentsByShortID()
  {
    return shortIDMap;
  }
  /**
   * Retrieves the argument with the specified short identifier.
   *
   * @param shortID
   *          The short ID for the argument to retrieve.
   * @return The argument with the specified short identifier, or
   *         <CODE>null</CODE> if there is no such argument.
   */
  Argument getArgumentForShortID(Character shortID)
  {
    return shortIDMap.get(shortID);
  }
  /**
   * Retrieves the set of arguments mapped by the long identifier that
   * may be used to reference them. Note that arguments that do not have
   * a long identifier will not be present in this list.
   *
   * @return The set of arguments mapped by the long identifier that may
   *         be used to reference them.
   */
  HashMap<String, Argument> getArgumentsByLongID()
  {
    return longIDMap;
  }
  /**
   * Retrieves the argument with the specified long identifier.
   *
   * @param longID
   *          The long identifier of the argument to retrieve.
   * @return The argument with the specified long identifier, or
   *         <CODE>null</CODE> if there is no such argument.
   */
  Argument getArgumentForLongID(String longID)
  {
    return longIDMap.get(longID);
  }
  /**
   * Retrieves the set of unnamed trailing arguments that were provided
   * on the command line.
   *
   * @return The set of unnamed trailing arguments that were provided on
   *         the command line.
   */
  ArrayList<String> getTrailingArguments()
  {
    return trailingArguments;
  }
  /**
   * Retrieves the raw set of arguments that were provided.
   *
   * @return The raw set of arguments that were provided, or
   *         <CODE>null</CODE> if the argument list has not yet been
   *         parsed.
   */
  String[] getRawArguments()
  {
    return rawArguments;
  }
  /**
   * Sets the usage group description for the default argument group.
   *
   * @param description
   *          for the default group
   */
  void setDefaultArgumentGroupDescription(LocalizableMessage description)
  {
    this.defaultArgGroup.setDescription(description);
  }
  /**
   * Sets the usage group description for the LDAP argument group.
   *
   * @param description
   *          for the LDAP group
   */
  void setLdapArgumentGroupDescription(LocalizableMessage description)
  {
    this.ldapArgGroup.setDescription(description);
  }
  /**
   * Sets the usage group description for the input/output argument
   * group.
   *
   * @param description
   *          for the input/output group
   */
  void setInputOutputArgumentGroupDescription(LocalizableMessage description)
  {
    this.ioArgGroup.setDescription(description);
  }
  /**
   * Sets the usage group description for the general argument group.
   *
   * @param description
   *          for the general group
   */
  void setGeneralArgumentGroupDescription(LocalizableMessage description)
  {
    this.generalArgGroup.setDescription(description);
  }
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser.
   * Adds the provided argument to the set of arguments handled by this parser.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void addArgument(Argument argument) throws ArgumentException
  void addArgument(final Argument argument) throws ArgumentException
  {
    addArgument(argument, null);
  }
@@ -548,98 +301,27 @@
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser and puts the arguement in the default group.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   */
  void addDefaultArgument(Argument argument) throws ArgumentException
  {
    addArgument(argument, defaultArgGroup);
  }
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser and puts the argument in the LDAP connection group.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   */
  void addLdapConnectionArgument(Argument argument)
      throws ArgumentException
  {
    addArgument(argument, ldapArgGroup);
  }
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser and puts the argument in the input/output group.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   */
  void addInputOutputArgument(Argument argument)
      throws ArgumentException
  {
    addArgument(argument, ioArgGroup);
  }
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser and puts the arguement in the general group.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   */
  void addGeneralArgument(Argument argument) throws ArgumentException
  {
    addArgument(argument, generalArgGroup);
  }
  /**
   * Adds the provided argument to the set of arguments handled by this
   * parser.
   * Adds the provided argument to the set of arguments handled by this parser.
   *
   * @param argument
   *          The argument to be added.
   * @param group
   *          The argument group to which the argument belongs.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument
   *           that has already been defined.
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void addArgument(Argument argument, ArgumentGroup group)
  void addArgument(final Argument argument, ArgumentGroup group)
      throws ArgumentException
  {
    Character shortID = argument.getShortIdentifier();
    final Character shortID = argument.getShortIdentifier();
    if ((shortID != null) && shortIDMap.containsKey(shortID))
    {
      String conflictingName = shortIDMap.get(shortID).getName();
      final String conflictingName = shortIDMap.get(shortID).getName();
      LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_SHORT_ID.get(argument
          .getName(), String.valueOf(shortID), conflictingName);
      final LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_SHORT_ID.get(
          argument.getName(), String.valueOf(shortID), conflictingName);
      throw new ArgumentException(message);
    }
@@ -651,13 +333,12 @@
        // identifier.
        try
        {
          versionArgument = new BooleanArgument(
              OPTION_LONG_PRODUCT_VERSION, null,
              OPTION_LONG_PRODUCT_VERSION,
          versionArgument = new BooleanArgument(OPTION_LONG_PRODUCT_VERSION,
              null, OPTION_LONG_PRODUCT_VERSION,
              INFO_DESCRIPTION_PRODUCT_VERSION.get());
          this.generalArgGroup.addArgument(versionArgument);
        }
        catch (ArgumentException e)
        catch (final ArgumentException e)
        {
          // ignore
        }
@@ -673,10 +354,10 @@
      }
      if (longIDMap.containsKey(longID))
      {
        String conflictingName = longIDMap.get(longID).getName();
        final String conflictingName = longIDMap.get(longID).getName();
        LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_LONG_ID.get(argument
            .getName(), argument.getLongIdentifier(), conflictingName);
        final LocalizableMessage message = ERR_ARGPARSER_DUPLICATE_LONG_ID.get(
            argument.getName(), argument.getLongIdentifier(), conflictingName);
        throw new ArgumentException(message);
      }
    }
@@ -704,637 +385,87 @@
  /**
   * Sets the provided argument as one which will automatically trigger
   * the output of usage information if it is provided on the command
   * line and no further argument validation will be performed. Note
   * that the caller will still need to add this argument to the parser
   * with the <CODE>addArgument</CODE> method, and the argument should
   * not be required and should not take a value. Also, the caller will
   * still need to check for the presence of the usage argument after
   * calling <CODE>parseArguments</CODE> to know that no further
   * processing will be required.
   * Adds the provided argument to the set of arguments handled by this parser
   * and puts the arguement in the default group.
   *
   * @param argument
   *          The argument whose presence should automatically trigger
   *          the display of usage information.
   */
  void setUsageArgument(Argument argument)
  {
    usageArgument = argument;
    usageOutputStream = System.out;
  }
  /**
   * Sets the provided argument as one which will automatically trigger
   * the output of usage information if it is provided on the command
   * line and no further argument validation will be performed. Note
   * that the caller will still need to add this argument to the parser
   * with the <CODE>addArgument</CODE> method, and the argument should
   * not be required and should not take a value. Also, the caller will
   * still need to check for the presence of the usage argument after
   * calling <CODE>parseArguments</CODE> to know that no further
   * processing will be required.
   *
   * @param argument
   *          The argument whose presence should automatically trigger
   *          the display of usage information.
   * @param outputStream
   *          The output stream to which the usage information should be
   *          written.
   */
  void setUsageArgument(Argument argument, OutputStream outputStream)
  {
    usageArgument = argument;
    usageOutputStream = outputStream;
  }
  /**
   * Sets the provided argument which will be used to identify the file
   * properties.
   *
   * @param argument
   *          The argument which will be used to identify the file
   *          properties.
   */
  void setFilePropertiesArgument(StringArgument argument)
  {
    filePropertiesPathArgument = argument;
  }
  /**
   * Sets the provided argument which will be used to identify the file
   * properties.
   *
   * @param argument
   *          The argument which will be used to indicate if we have to
   *          look for properties file.
   */
  void setNoPropertiesFileArgument(BooleanArgument argument)
  {
    noPropertiesFileArgument = argument;
  }
  /**
   * Parses the provided set of arguments and updates the information
   * associated with this parser accordingly.
   *
   * @param rawArguments
   *          The raw set of arguments to parse.
   *          The argument to be added.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided
   *           arguments.
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void parseArguments(String[] rawArguments) throws ArgumentException
  void addDefaultArgument(final Argument argument) throws ArgumentException
  {
    parseArguments(rawArguments, null);
    addArgument(argument, defaultArgGroup);
  }
  /**
   * Parses the provided set of arguments and updates the information
   * associated with this parser accordingly. Default values for
   * unspecified arguments may be read from the specified properties
   * file.
   * Adds the provided argument to the set of arguments handled by this parser
   * and puts the arguement in the general group.
   *
   * @param rawArguments
   *          The set of raw arguments to parse.
   * @param propertiesFile
   *          The path to the properties file to use to obtain default
   *          values for unspecified properties.
   * @param requirePropertiesFile
   *          Indicates whether the parsing should fail if the provided
   *          properties file does not exist or is not accessible.
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided
   *           arguments or interacting with the properties file.
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void parseArguments(String[] rawArguments, String propertiesFile,
      boolean requirePropertiesFile) throws ArgumentException
  void addGeneralArgument(final Argument argument) throws ArgumentException
  {
    this.rawArguments = rawArguments;
    Properties argumentProperties = null;
    try
    {
      Properties p = new Properties();
      FileInputStream fis = new FileInputStream(propertiesFile);
      p.load(fis);
      fis.close();
      argumentProperties = p;
    }
    catch (Exception e)
    {
      if (requirePropertiesFile)
      {
        LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE
            .get(String.valueOf(propertiesFile), getExceptionMessage(e));
        throw new ArgumentException(message, e);
      }
    }
    parseArguments(rawArguments, argumentProperties);
    addArgument(argument, generalArgGroup);
  }
  /**
   * Parses the provided set of arguments and updates the information
   * associated with this parser accordingly. Default values for
   * unspecified arguments may be read from the specified properties if
   * any are provided.
   * Adds the provided argument to the set of arguments handled by this parser
   * and puts the argument in the input/output group.
   *
   * @param rawArguments
   *          The set of raw arguments to parse.
   * @param argumentProperties
   *          A set of properties that may be used to provide default
   *          values for arguments not included in the given raw
   *          arguments.
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided
   *           arguments.
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void parseArguments(String[] rawArguments,
      Properties argumentProperties) throws ArgumentException
  void addInputOutputArgument(final Argument argument) throws ArgumentException
  {
    this.rawArguments = rawArguments;
    addArgument(argument, ioArgGroup);
  }
    boolean inTrailingArgs = false;
    int numArguments = rawArguments.length;
    for (int i = 0; i < numArguments; i++)
    {
      String arg = rawArguments[i];
      if (inTrailingArgs)
      {
        trailingArguments.add(arg);
        if ((maxTrailingArguments > 0)
            && (trailingArguments.size() > maxTrailingArguments))
        {
          LocalizableMessage message = ERR_ARGPARSER_TOO_MANY_TRAILING_ARGS
              .get(maxTrailingArguments);
          throw new ArgumentException(message);
        }
  /**
   * Adds the provided argument to the set of arguments handled by this parser
   * and puts the argument in the LDAP connection group.
   *
   * @param argument
   *          The argument to be added.
   * @throws ArgumentException
   *           If the provided argument conflicts with another argument that has
   *           already been defined.
   */
  void addLdapConnectionArgument(final Argument argument)
      throws ArgumentException
  {
    addArgument(argument, ldapArgGroup);
  }
        continue;
      }
      if (arg.equals("--"))
      {
        // This is a special indicator that we have reached the end of
        // the named
        // arguments and that everything that follows after this should
        // be
        // considered trailing arguments.
        inTrailingArgs = true;
      }
      else if (arg.startsWith("--"))
      {
        // This indicates that we are using the long name to reference
        // the
        // argument. It may be in any of the following forms:
        // --name
        // --name value
        // --name=value
        String argName = arg.substring(2);
        String argValue = null;
        int equalPos = argName.indexOf('=');
        if (equalPos < 0)
        {
          // This is fine. The value is not part of the argument name
          // token.
        }
        else if (equalPos == 0)
        {
          // The argument starts with "--=", which is not acceptable.
          LocalizableMessage message = ERR_ARGPARSER_LONG_ARG_WITHOUT_NAME
              .get(arg);
          throw new ArgumentException(message);
        }
        else
        {
          // The argument is in the form --name=value, so parse them
          // both out.
          argValue = argName.substring(equalPos + 1);
          argName = argName.substring(0, equalPos);
        }
        // If we're not case-sensitive, then convert the name to
        // lowercase.
        String origArgName = argName;
        if (!longArgumentsCaseSensitive)
        {
          argName = toLowerCase(argName);
        }
        // Get the argument with the specified name.
        Argument a = longIDMap.get(argName);
        if (a == null)
        {
          if (argName.equals(OPTION_LONG_HELP))
          {
            // "--help" will always be interpreted as requesting usage
            // information.
            try
            {
              getUsage(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
          else if (argName.equals(OPTION_LONG_PRODUCT_VERSION))
          {
            // "--version" will always be interpreted as requesting
            // version
            // information.
            usageOrVersionDisplayed = true;
            versionPresent = true;
            try
            {
              // TODO
              // DirectoryServer.printVersion(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
          else
          {
            // There is no such argument registered.
            LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_LONG_ID
                .get(origArgName);
            throw new ArgumentException(message);
          }
        }
        else
        {
          a.setPresent(true);
          // If this is the usage argument, then immediately stop and
          // print
          // usage information.
          if ((usageArgument != null)
              && usageArgument.getName().equals(a.getName()))
          {
            try
            {
              getUsage(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
        }
        // See if the argument takes a value. If so, then make sure one
        // was
        // provided. If not, then make sure none was provided.
        if (a.needsValue())
        {
          if (argValue == null)
          {
            if ((i + 1) == numArguments)
            {
              LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_LONG_ID
                  .get(origArgName);
              throw new ArgumentException(message);
            }
            argValue = rawArguments[++i];
          }
          LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (!a.valueIsAcceptable(argValue, invalidReason))
          {
            LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_LONG_ID
                .get(argValue, origArgName, invalidReason.toString());
            throw new ArgumentException(message);
          }
          // If the argument already has a value, then make sure it is
          // acceptable to have more than one.
          if (a.hasValue() && (!a.isMultiValued()))
          {
            LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_LONG_ID
                .get(origArgName);
            throw new ArgumentException(message);
          }
          a.addValue(argValue);
        }
        else
        {
          if (argValue != null)
          {
            LocalizableMessage message = ERR_ARGPARSER_ARG_FOR_LONG_ID_DOESNT_TAKE_VALUE
                .get(origArgName);
            throw new ArgumentException(message);
          }
        }
      }
      else if (arg.startsWith("-"))
      {
        // This indicates that we are using the 1-character name to
        // reference
        // the argument. It may be in any of the following forms:
        // -n
        // -nvalue
        // -n value
        if (arg.equals("-"))
        {
          LocalizableMessage message = ERR_ARGPARSER_INVALID_DASH_AS_ARGUMENT
              .get();
          throw new ArgumentException(message);
        }
        char argCharacter = arg.charAt(1);
        String argValue;
        if (arg.length() > 2)
        {
          argValue = arg.substring(2);
        }
        else
        {
          argValue = null;
        }
        // Get the argument with the specified short ID.
        Argument a = shortIDMap.get(argCharacter);
        if (a == null)
        {
          if (argCharacter == '?')
          {
            // "-?" will always be interpreted as requesting usage
            // information.
            try
            {
              getUsage(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
          else if ((argCharacter == OPTION_SHORT_PRODUCT_VERSION)
              && (!shortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION)))
          {
            // "-V" will always be interpreted as requesting
            // version information except if it's already defined (e.g
            // in
            // ldap tools).
            usageOrVersionDisplayed = true;
            versionPresent = true;
            try
            {
              // TODO
              // DirectoryServer.printVersion(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
          else
          {
            // There is no such argument registered.
            LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
                .get(String.valueOf(argCharacter));
            throw new ArgumentException(message);
          }
        }
        else
        {
          a.setPresent(true);
          // If this is the usage argument, then immediately stop and
          // print
          // usage information.
          if ((usageArgument != null)
              && usageArgument.getName().equals(a.getName()))
          {
            try
            {
              getUsage(usageOutputStream);
            }
            catch (Exception e)
            {
            }
            return;
          }
        }
        // See if the argument takes a value. If so, then make sure one
        // was
        // provided. If not, then make sure none was provided.
        if (a.needsValue())
        {
          if (argValue == null)
          {
            if ((i + 1) == numArguments)
            {
              LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_SHORT_ID
                  .get(String.valueOf(argCharacter));
              throw new ArgumentException(message);
            }
            argValue = rawArguments[++i];
          }
          LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (!a.valueIsAcceptable(argValue, invalidReason))
          {
            LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_SHORT_ID
                .get(argValue, String.valueOf(argCharacter),
                    invalidReason.toString());
            throw new ArgumentException(message);
          }
          // If the argument already has a value, then make sure it is
          // acceptable to have more than one.
          if (a.hasValue() && (!a.isMultiValued()))
          {
            LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_SHORT_ID
                .get(String.valueOf(argCharacter));
            throw new ArgumentException(message);
          }
          a.addValue(argValue);
        }
        else
        {
          if (argValue != null)
          {
            // If we've gotten here, then it means that we're in a
            // scenario like
            // "-abc" where "a" is a valid argument that doesn't take a
            // value.
            // However, this could still be valid if all remaining
            // characters in
            // the value are also valid argument characters that don't
            // take
            // values.
            int valueLength = argValue.length();
            for (int j = 0; j < valueLength; j++)
            {
              char c = argValue.charAt(j);
              Argument b = shortIDMap.get(c);
              if (b == null)
              {
                // There is no such argument registered.
                LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
                    .get(String.valueOf(argCharacter));
                throw new ArgumentException(message);
              }
              else if (b.needsValue())
              {
                // This means we're in a scenario like "-abc" where b is
                // a
                // valid argument that takes a value. We don't support
                // that.
                LocalizableMessage message = ERR_ARGPARSER_CANT_MIX_ARGS_WITH_VALUES
                    .get(String.valueOf(argCharacter), argValue, String
                        .valueOf(c));
                throw new ArgumentException(message);
              }
              else
              {
                b.setPresent(true);
                // If this is the usage argument, then immediately stop
                // and
                // print usage information.
                if ((usageArgument != null)
                    && usageArgument.getName().equals(b.getName()))
                {
                  try
                  {
                    getUsage(usageOutputStream);
                  }
                  catch (Exception e)
                  {
                  }
                  return;
                }
              }
            }
          }
        }
      }
      else if (allowsTrailingArguments)
      {
        // It doesn't start with a dash, so it must be a trailing
        // argument if
        // that is acceptable.
        inTrailingArgs = true;
        trailingArguments.add(arg);
      }
      else
      {
        // It doesn't start with a dash and we don't allow trailing
        // arguments,
        // so this is illegal.
        LocalizableMessage message = ERR_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT
            .get(arg);
        throw new ArgumentException(message);
      }
    }
    // If we allow trailing arguments and there is a minimum number,
    // then make
    // sure at least that many were provided.
    if (allowsTrailingArguments && (minTrailingArguments > 0))
    {
      if (trailingArguments.size() < minTrailingArguments)
      {
        LocalizableMessage message = ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS
            .get(minTrailingArguments);
        throw new ArgumentException(message);
      }
    }
    // If we don't have the argumentProperties, try to load a properties
    // file.
    if (argumentProperties == null)
    {
      argumentProperties = checkExternalProperties();
    }
    // Iterate through all of the arguments. For any that were not
    // provided on
    // the command line, see if there is an alternate default that can
    // be used.
    // For cases where there is not, see that argument is required.
    for (Argument a : argumentList)
    {
      if (!a.isPresent())
      {
        // See if there is a value in the properties that can be used
        if ((argumentProperties != null)
            && (a.getPropertyName() != null))
        {
          String value = argumentProperties.getProperty(a
              .getPropertyName().toLowerCase());
          LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (value != null)
          {
            Boolean addValue = true;
            if (!(a instanceof BooleanArgument))
            {
              addValue = a.valueIsAcceptable(value, invalidReason);
            }
            if (addValue)
            {
              a.addValue(value);
              if (a.needsValue())
              {
                a.setPresent(true);
              }
              a.setValueSetByProperty(true);
            }
          }
        }
      }
      if ((!a.isPresent()) && a.needsValue())
      {
        // See if the argument defines a default.
        if (a.getDefaultValue() != null)
        {
          a.addValue(a.getDefaultValue());
        }
        // If there is still no value and the argument is required, then
        // that's
        // a problem.
        if ((!a.hasValue()) && a.isRequired())
        {
          LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_REQUIRED_ARG
              .get(a.getName());
          throw new ArgumentException(message);
        }
      }
    }
  /**
   * Indicates whether this parser will allow unnamed trailing arguments. These
   * will be arguments at the end of the list that are not preceded by either a
   * long or short identifier and will need to be manually parsed by the
   * application using this parser. Note that once an unnamed trailing argument
   * has been identified, all remaining arguments will be classified as such.
   *
   * @return <CODE>true</CODE> if this parser allows unnamed trailing arguments,
   *         or <CODE>false</CODE> if it does not.
   */
  boolean allowsTrailingArguments()
  {
    return allowsTrailingArguments;
  }
@@ -1372,16 +503,16 @@
    else
    {
      // Check in "user home"/.opends directory
      String userDir = System.getProperty("user.home");
      final String userDir = System.getProperty("user.home");
      propertiesFilePath = findPropertiesFile(userDir + File.separator
          + DEFAULT_OPENDS_CONFIG_DIR);
      // TODO
      /*
       * if (propertiesFilePath == null) { // check
       * "Opends instance"/config directory String instanceDir =
       * DirectoryServer.getInstanceRoot(); propertiesFilePath =
       * findPropertiesFile(instanceDir+ File.separator + "config"); }
       * if (propertiesFilePath == null) { // check "Opends instance"/config
       * directory String instanceDir = DirectoryServer.getInstanceRoot();
       * propertiesFilePath = findPropertiesFile(instanceDir+ File.separator +
       * "config"); }
       */
    }
@@ -1392,18 +523,18 @@
    }
    // We have a location for the properties file.
    Properties argumentProperties = new Properties();
    String scriptName = System.getProperty(Utils.PROPERTY_SCRIPT_NAME);
    final Properties argumentProperties = new Properties();
    final String scriptName = System.getProperty(Utils.PROPERTY_SCRIPT_NAME);
    try
    {
      Properties p = new Properties();
      FileInputStream fis = new FileInputStream(propertiesFilePath);
      final Properties p = new Properties();
      final FileInputStream fis = new FileInputStream(propertiesFilePath);
      p.load(fis);
      fis.close();
      for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();)
      for (final Enumeration<?> e = p.propertyNames(); e.hasMoreElements();)
      {
        String currentPropertyName = (String) e.nextElement();
        final String currentPropertyName = (String) e.nextElement();
        String propertyName = currentPropertyName;
        // Property name form <script name>.<property name> has the
@@ -1412,8 +543,8 @@
        {
          if (currentPropertyName.startsWith(scriptName))
          {
            propertyName = currentPropertyName.substring(scriptName
                .length() + 1);
            propertyName = currentPropertyName
                .substring(scriptName.length() + 1);
          }
          else
          {
@@ -1427,10 +558,10 @@
            .getProperty(currentPropertyName));
      }
    }
    catch (Exception e)
    catch (final Exception e)
    {
      LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE.get(
          String.valueOf(propertiesFilePath), getExceptionMessage(e));
      final LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE
          .get(String.valueOf(propertiesFilePath), getExceptionMessage(e));
      throw new ArgumentException(message, e);
    }
    return argumentProperties;
@@ -1439,58 +570,275 @@
  /**
   * Get the absolute path of the properties file.
   * Retrieves the argument with the specified name.
   *
   * @param directory
   *          The location in which we should look for properties file
   * @return The absolute path of the properties file or null
   * @param name
   *          The name of the argument to retrieve.
   * @return The argument with the specified name, or <CODE>null</CODE> if there
   *         is no such argument.
   */
  private String findPropertiesFile(String directory)
  Argument getArgument(final String name)
  {
    // Look for the tools properties file
    File f = new File(directory, DEFAULT_OPENDS_PROPERTIES_FILE_NAME
        + DEFAULT_OPENDS_PROPERTIES_FILE_EXTENSION);
    if (f.exists() && f.canRead())
    {
      return f.getAbsolutePath();
    }
    else
    {
      return null;
    }
    return argumentMap.get(name);
  }
  /**
   * Appends usage information based on the defined arguments to the
   * provided buffer.
   * Retrieves the argument with the specified long identifier.
   *
   * @param longID
   *          The long identifier of the argument to retrieve.
   * @return The argument with the specified long identifier, or
   *         <CODE>null</CODE> if there is no such argument.
   */
  Argument getArgumentForLongID(final String longID)
  {
    return longIDMap.get(longID);
  }
  /**
   * Retrieves the argument with the specified short identifier.
   *
   * @param shortID
   *          The short ID for the argument to retrieve.
   * @return The argument with the specified short identifier, or
   *         <CODE>null</CODE> if there is no such argument.
   */
  Argument getArgumentForShortID(final Character shortID)
  {
    return shortIDMap.get(shortID);
  }
  /**
   * Retrieves the list of all arguments that have been defined for this
   * argument parser.
   *
   * @return The list of all arguments that have been defined for this argument
   *         parser.
   */
  LinkedList<Argument> getArgumentList()
  {
    return argumentList;
  }
  /**
   * Retrieves the set of arguments mapped by the long identifier that may be
   * used to reference them. Note that arguments that do not have a long
   * identifier will not be present in this list.
   *
   * @return The set of arguments mapped by the long identifier that may be used
   *         to reference them.
   */
  HashMap<String, Argument> getArgumentsByLongID()
  {
    return longIDMap;
  }
  /**
   * Retrieves the set of arguments mapped by the short identifier that may be
   * used to reference them. Note that arguments that do not have a short
   * identifier will not be present in this list.
   *
   * @return The set of arguments mapped by the short identifier that may be
   *         used to reference them.
   */
  HashMap<Character, Argument> getArgumentsByShortID()
  {
    return shortIDMap;
  }
  /**
   * Retrieves the fully-qualified name of the Java class that should be invoked
   * to launch the program with which this argument parser is associated.
   *
   * @return The fully-qualified name of the Java class that should be invoked
   *         to launch the program with which this argument parser is
   *         associated.
   */
  String getMainClassName()
  {
    return mainClassName;
  }
  /**
   * Retrieves the maximum number of unnamed trailing arguments that may be
   * provided.
   *
   * @return The maximum number of unnamed trailing arguments that may be
   *         provided, or a value less than or equal to zero if no maximum will
   *         be enforced.
   */
  int getMaxTrailingArguments()
  {
    return maxTrailingArguments;
  }
  /**
   * Retrieves the minimum number of unnamed trailing arguments that must be
   * provided.
   *
   * @return The minimum number of unnamed trailing arguments that must be
   *         provided, or a value less than or equal to zero if no minimum will
   *         be enforced.
   */
  int getMinTrailingArguments()
  {
    return minTrailingArguments;
  }
  /**
   * Retrieves the raw set of arguments that were provided.
   *
   * @return The raw set of arguments that were provided, or <CODE>null</CODE>
   *         if the argument list has not yet been parsed.
   */
  String[] getRawArguments()
  {
    return rawArguments;
  }
  /**
   * Given an argument, returns an appropriate group. Arguments may be part of
   * one of the special groups or the default group.
   *
   * @param argument
   *          for which a group is requested
   * @return argument group appropriate for <code>argument</code>
   */
  ArgumentGroup getStandardGroup(final Argument argument)
  {
    ArgumentGroup group;
    if (isInputOutputArgument(argument))
    {
      group = ioArgGroup;
    }
    else if (isGeneralArgument(argument))
    {
      group = generalArgGroup;
    }
    else if (isLdapConnectionArgument(argument))
    {
      group = ldapArgGroup;
    }
    else
    {
      group = defaultArgGroup;
    }
    return group;
  }
  /**
   * Retrieves a human-readable description for this tool, which should be
   * included at the top of the command-line usage information.
   *
   * @return A human-readable description for this tool, or {@code null} if none
   *         is available.
   */
  LocalizableMessage getToolDescription()
  {
    return toolDescription;
  }
  /**
   * Retrieves the set of unnamed trailing arguments that were provided on the
   * command line.
   *
   * @return The set of unnamed trailing arguments that were provided on the
   *         command line.
   */
  ArrayList<String> getTrailingArguments()
  {
    return trailingArguments;
  }
  /**
   * Retrieves a string containing usage information based on the defined
   * arguments.
   *
   * @return A string containing usage information based on the defined
   *         arguments.
   */
  String getUsage()
  {
    final StringBuilder buffer = new StringBuilder();
    getUsage(buffer);
    return buffer.toString();
  }
  /**
   * Writes usage information based on the defined arguments to the provided
   * output stream.
   *
   * @param outputStream
   *          The output stream to which the usage information should be
   *          written.
   * @throws IOException
   *           If a problem occurs while attempting to write the usage
   *           information to the provided output stream.
   */
  void getUsage(final OutputStream outputStream) throws IOException
  {
    final StringBuilder buffer = new StringBuilder();
    getUsage(buffer);
    outputStream.write(getBytes(buffer.toString()));
  }
  /**
   * Appends usage information based on the defined arguments to the provided
   * buffer.
   *
   * @param buffer
   *          The buffer to which the usage information should be
   *          appended.
   *          The buffer to which the usage information should be appended.
   */
  void getUsage(StringBuilder buffer)
  void getUsage(final StringBuilder buffer)
  {
    usageOrVersionDisplayed = true;
    if ((toolDescription != null) && (toolDescription.length() > 0))
    {
      buffer
          .append(wrapText(toolDescription.toString(), MAX_LENGTH - 1));
      buffer.append(wrapText(toolDescription.toString(), MAX_LENGTH - 1));
      buffer.append(EOL);
      buffer.append(EOL);
    }
    String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
    final String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
    if ((scriptName == null) || (scriptName.length() == 0))
    {
      buffer.append(INFO_ARGPARSER_USAGE_JAVA_CLASSNAME
          .get(mainClassName));
      buffer.append(INFO_ARGPARSER_USAGE_JAVA_CLASSNAME.get(mainClassName));
    }
    else
    {
      buffer.append(INFO_ARGPARSER_USAGE_JAVA_SCRIPTNAME
          .get(scriptName));
      buffer.append(INFO_ARGPARSER_USAGE_JAVA_SCRIPTNAME.get(scriptName));
    }
    if (allowsTrailingArguments)
@@ -1512,13 +860,13 @@
    Argument helpArgument = null;
    boolean printHeaders = printUsageGroupHeaders();
    for (ArgumentGroup argGroup : argumentGroups)
    final boolean printHeaders = printUsageGroupHeaders();
    for (final ArgumentGroup argGroup : argumentGroups)
    {
      if (argGroup.containsArguments() && printHeaders)
      {
        // Print the groups description if any
        LocalizableMessage groupDesc = argGroup.getDescription();
        final LocalizableMessage groupDesc = argGroup.getDescription();
        if (groupDesc != null && !LocalizableMessage.EMPTY.equals(groupDesc))
        {
          buffer.append(EOL);
@@ -1528,7 +876,7 @@
        }
      }
      for (Argument a : argGroup.getArguments())
      for (final Argument a : argGroup.getArguments())
      {
        // If this argument is hidden, then skip it.
        if (a.isHidden())
@@ -1561,15 +909,15 @@
  /**
   * Retrieves a message containing usage information based on the
   * defined arguments.
   * Retrieves a message containing usage information based on the defined
   * arguments.
   *
   * @return A string containing usage information based on the defined
   *         arguments.
   */
  LocalizableMessage getUsageMessage()
  {
    StringBuilder buffer = new StringBuilder();
    final StringBuilder buffer = new StringBuilder();
    getUsage(buffer);
    // TODO: rework getUsage(OutputStream) to work with messages
@@ -1580,50 +928,751 @@
  /**
   * Retrieves a string containing usage information based on the
   * defined arguments.
   * Returns whether the usage argument was provided or not. This method should
   * be called after a call to parseArguments.
   *
   * @return A string containing usage information based on the defined
   *         arguments.
   * @return <CODE>true</CODE> if the usage argument was provided and
   *         <CODE>false</CODE> otherwise.
   */
  String getUsage()
  boolean isUsageArgumentPresent()
  {
    StringBuilder buffer = new StringBuilder();
    getUsage(buffer);
    return buffer.toString();
    boolean isUsageArgumentPresent = false;
    if (usageArgument != null)
    {
      isUsageArgumentPresent = usageArgument.isPresent();
    }
    return isUsageArgumentPresent;
  }
  /**
   * Writes usage information based on the defined arguments to the
   * provided output stream.
   * Returns whether the version argument was provided or not. This method
   * should be called after a call to parseArguments.
   *
   * @return <CODE>true</CODE> if the version argument was provided and
   *         <CODE>false</CODE> otherwise.
   */
  boolean isVersionArgumentPresent()
  {
    return versionPresent;
  }
  /**
   * Parses the provided set of arguments and updates the information associated
   * with this parser accordingly.
   *
   * @param rawArguments
   *          The raw set of arguments to parse.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided
   *           arguments.
   */
  void parseArguments(final String[] rawArguments) throws ArgumentException
  {
    parseArguments(rawArguments, null);
  }
  /**
   * Parses the provided set of arguments and updates the information associated
   * with this parser accordingly. Default values for unspecified arguments may
   * be read from the specified properties if any are provided.
   *
   * @param rawArguments
   *          The set of raw arguments to parse.
   * @param argumentProperties
   *          A set of properties that may be used to provide default values for
   *          arguments not included in the given raw arguments.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided
   *           arguments.
   */
  void parseArguments(final String[] rawArguments, Properties argumentProperties)
      throws ArgumentException
  {
    this.rawArguments = rawArguments;
    boolean inTrailingArgs = false;
    final int numArguments = rawArguments.length;
    for (int i = 0; i < numArguments; i++)
    {
      final String arg = rawArguments[i];
      if (inTrailingArgs)
      {
        trailingArguments.add(arg);
        if ((maxTrailingArguments > 0)
            && (trailingArguments.size() > maxTrailingArguments))
        {
          final LocalizableMessage message = ERR_ARGPARSER_TOO_MANY_TRAILING_ARGS
              .get(maxTrailingArguments);
          throw new ArgumentException(message);
        }
        continue;
      }
      if (arg.equals("--"))
      {
        // This is a special indicator that we have reached the end of
        // the named
        // arguments and that everything that follows after this should
        // be
        // considered trailing arguments.
        inTrailingArgs = true;
      }
      else if (arg.startsWith("--"))
      {
        // This indicates that we are using the long name to reference
        // the
        // argument. It may be in any of the following forms:
        // --name
        // --name value
        // --name=value
        String argName = arg.substring(2);
        String argValue = null;
        final int equalPos = argName.indexOf('=');
        if (equalPos < 0)
        {
          // This is fine. The value is not part of the argument name
          // token.
        }
        else if (equalPos == 0)
        {
          // The argument starts with "--=", which is not acceptable.
          final LocalizableMessage message = ERR_ARGPARSER_LONG_ARG_WITHOUT_NAME
              .get(arg);
          throw new ArgumentException(message);
        }
        else
        {
          // The argument is in the form --name=value, so parse them
          // both out.
          argValue = argName.substring(equalPos + 1);
          argName = argName.substring(0, equalPos);
        }
        // If we're not case-sensitive, then convert the name to
        // lowercase.
        final String origArgName = argName;
        if (!longArgumentsCaseSensitive)
        {
          argName = toLowerCase(argName);
        }
        // Get the argument with the specified name.
        final Argument a = longIDMap.get(argName);
        if (a == null)
        {
          if (argName.equals(OPTION_LONG_HELP))
          {
            // "--help" will always be interpreted as requesting usage
            // information.
            try
            {
              getUsage(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
          else if (argName.equals(OPTION_LONG_PRODUCT_VERSION))
          {
            // "--version" will always be interpreted as requesting
            // version
            // information.
            usageOrVersionDisplayed = true;
            versionPresent = true;
            try
            {
              // TODO
              // DirectoryServer.printVersion(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
          else
          {
            // There is no such argument registered.
            final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_LONG_ID
                .get(origArgName);
            throw new ArgumentException(message);
          }
        }
        else
        {
          a.setPresent(true);
          // If this is the usage argument, then immediately stop and
          // print
          // usage information.
          if ((usageArgument != null)
              && usageArgument.getName().equals(a.getName()))
          {
            try
            {
              getUsage(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
        }
        // See if the argument takes a value. If so, then make sure one
        // was
        // provided. If not, then make sure none was provided.
        if (a.needsValue())
        {
          if (argValue == null)
          {
            if ((i + 1) == numArguments)
            {
              final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_LONG_ID
                  .get(origArgName);
              throw new ArgumentException(message);
            }
            argValue = rawArguments[++i];
          }
          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (!a.valueIsAcceptable(argValue, invalidReason))
          {
            final LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_LONG_ID
                .get(argValue, origArgName, invalidReason.toString());
            throw new ArgumentException(message);
          }
          // If the argument already has a value, then make sure it is
          // acceptable to have more than one.
          if (a.hasValue() && (!a.isMultiValued()))
          {
            final LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_LONG_ID
                .get(origArgName);
            throw new ArgumentException(message);
          }
          a.addValue(argValue);
        }
        else
        {
          if (argValue != null)
          {
            final LocalizableMessage message = ERR_ARGPARSER_ARG_FOR_LONG_ID_DOESNT_TAKE_VALUE
                .get(origArgName);
            throw new ArgumentException(message);
          }
        }
      }
      else if (arg.startsWith("-"))
      {
        // This indicates that we are using the 1-character name to
        // reference
        // the argument. It may be in any of the following forms:
        // -n
        // -nvalue
        // -n value
        if (arg.equals("-"))
        {
          final LocalizableMessage message = ERR_ARGPARSER_INVALID_DASH_AS_ARGUMENT
              .get();
          throw new ArgumentException(message);
        }
        final char argCharacter = arg.charAt(1);
        String argValue;
        if (arg.length() > 2)
        {
          argValue = arg.substring(2);
        }
        else
        {
          argValue = null;
        }
        // Get the argument with the specified short ID.
        final Argument a = shortIDMap.get(argCharacter);
        if (a == null)
        {
          if (argCharacter == '?')
          {
            // "-?" will always be interpreted as requesting usage
            // information.
            try
            {
              getUsage(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
          else if ((argCharacter == OPTION_SHORT_PRODUCT_VERSION)
              && (!shortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION)))
          {
            // "-V" will always be interpreted as requesting
            // version information except if it's already defined (e.g
            // in
            // ldap tools).
            usageOrVersionDisplayed = true;
            versionPresent = true;
            try
            {
              // TODO
              // DirectoryServer.printVersion(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
          else
          {
            // There is no such argument registered.
            final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
                .get(String.valueOf(argCharacter));
            throw new ArgumentException(message);
          }
        }
        else
        {
          a.setPresent(true);
          // If this is the usage argument, then immediately stop and
          // print
          // usage information.
          if ((usageArgument != null)
              && usageArgument.getName().equals(a.getName()))
          {
            try
            {
              getUsage(usageOutputStream);
            }
            catch (final Exception e)
            {
            }
            return;
          }
        }
        // See if the argument takes a value. If so, then make sure one
        // was
        // provided. If not, then make sure none was provided.
        if (a.needsValue())
        {
          if (argValue == null)
          {
            if ((i + 1) == numArguments)
            {
              final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_ARGUMENT_WITH_SHORT_ID
                  .get(String.valueOf(argCharacter));
              throw new ArgumentException(message);
            }
            argValue = rawArguments[++i];
          }
          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (!a.valueIsAcceptable(argValue, invalidReason))
          {
            final LocalizableMessage message = ERR_ARGPARSER_VALUE_UNACCEPTABLE_FOR_SHORT_ID
                .get(argValue, String.valueOf(argCharacter), invalidReason
                    .toString());
            throw new ArgumentException(message);
          }
          // If the argument already has a value, then make sure it is
          // acceptable to have more than one.
          if (a.hasValue() && (!a.isMultiValued()))
          {
            final LocalizableMessage message = ERR_ARGPARSER_NOT_MULTIVALUED_FOR_SHORT_ID
                .get(String.valueOf(argCharacter));
            throw new ArgumentException(message);
          }
          a.addValue(argValue);
        }
        else
        {
          if (argValue != null)
          {
            // If we've gotten here, then it means that we're in a
            // scenario like
            // "-abc" where "a" is a valid argument that doesn't take a
            // value.
            // However, this could still be valid if all remaining
            // characters in
            // the value are also valid argument characters that don't
            // take
            // values.
            final int valueLength = argValue.length();
            for (int j = 0; j < valueLength; j++)
            {
              final char c = argValue.charAt(j);
              final Argument b = shortIDMap.get(c);
              if (b == null)
              {
                // There is no such argument registered.
                final LocalizableMessage message = ERR_ARGPARSER_NO_ARGUMENT_WITH_SHORT_ID
                    .get(String.valueOf(argCharacter));
                throw new ArgumentException(message);
              }
              else if (b.needsValue())
              {
                // This means we're in a scenario like "-abc" where b is
                // a
                // valid argument that takes a value. We don't support
                // that.
                final LocalizableMessage message = ERR_ARGPARSER_CANT_MIX_ARGS_WITH_VALUES
                    .get(String.valueOf(argCharacter), argValue, String
                        .valueOf(c));
                throw new ArgumentException(message);
              }
              else
              {
                b.setPresent(true);
                // If this is the usage argument, then immediately stop
                // and
                // print usage information.
                if ((usageArgument != null)
                    && usageArgument.getName().equals(b.getName()))
                {
                  try
                  {
                    getUsage(usageOutputStream);
                  }
                  catch (final Exception e)
                  {
                  }
                  return;
                }
              }
            }
          }
        }
      }
      else if (allowsTrailingArguments)
      {
        // It doesn't start with a dash, so it must be a trailing
        // argument if
        // that is acceptable.
        inTrailingArgs = true;
        trailingArguments.add(arg);
      }
      else
      {
        // It doesn't start with a dash and we don't allow trailing
        // arguments,
        // so this is illegal.
        final LocalizableMessage message = ERR_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT
            .get(arg);
        throw new ArgumentException(message);
      }
    }
    // If we allow trailing arguments and there is a minimum number,
    // then make
    // sure at least that many were provided.
    if (allowsTrailingArguments && (minTrailingArguments > 0))
    {
      if (trailingArguments.size() < minTrailingArguments)
      {
        final LocalizableMessage message = ERR_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS
            .get(minTrailingArguments);
        throw new ArgumentException(message);
      }
    }
    // If we don't have the argumentProperties, try to load a properties
    // file.
    if (argumentProperties == null)
    {
      argumentProperties = checkExternalProperties();
    }
    // Iterate through all of the arguments. For any that were not
    // provided on
    // the command line, see if there is an alternate default that can
    // be used.
    // For cases where there is not, see that argument is required.
    for (final Argument a : argumentList)
    {
      if (!a.isPresent())
      {
        // See if there is a value in the properties that can be used
        if ((argumentProperties != null) && (a.getPropertyName() != null))
        {
          final String value = argumentProperties.getProperty(a
              .getPropertyName().toLowerCase());
          final LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
          if (value != null)
          {
            Boolean addValue = true;
            if (!(a instanceof BooleanArgument))
            {
              addValue = a.valueIsAcceptable(value, invalidReason);
            }
            if (addValue)
            {
              a.addValue(value);
              if (a.needsValue())
              {
                a.setPresent(true);
              }
              a.setValueSetByProperty(true);
            }
          }
        }
      }
      if ((!a.isPresent()) && a.needsValue())
      {
        // See if the argument defines a default.
        if (a.getDefaultValue() != null)
        {
          a.addValue(a.getDefaultValue());
        }
        // If there is still no value and the argument is required, then
        // that's
        // a problem.
        if ((!a.hasValue()) && a.isRequired())
        {
          final LocalizableMessage message = ERR_ARGPARSER_NO_VALUE_FOR_REQUIRED_ARG
              .get(a.getName());
          throw new ArgumentException(message);
        }
      }
    }
  }
  /**
   * Parses the provided set of arguments and updates the information associated
   * with this parser accordingly. Default values for unspecified arguments may
   * be read from the specified properties file.
   *
   * @param rawArguments
   *          The set of raw arguments to parse.
   * @param propertiesFile
   *          The path to the properties file to use to obtain default values
   *          for unspecified properties.
   * @param requirePropertiesFile
   *          Indicates whether the parsing should fail if the provided
   *          properties file does not exist or is not accessible.
   * @throws ArgumentException
   *           If a problem was encountered while parsing the provided arguments
   *           or interacting with the properties file.
   */
  void parseArguments(final String[] rawArguments, final String propertiesFile,
      final boolean requirePropertiesFile) throws ArgumentException
  {
    this.rawArguments = rawArguments;
    Properties argumentProperties = null;
    try
    {
      final Properties p = new Properties();
      final FileInputStream fis = new FileInputStream(propertiesFile);
      p.load(fis);
      fis.close();
      argumentProperties = p;
    }
    catch (final Exception e)
    {
      if (requirePropertiesFile)
      {
        final LocalizableMessage message = ERR_ARGPARSER_CANNOT_READ_PROPERTIES_FILE
            .get(String.valueOf(propertiesFile), getExceptionMessage(e));
        throw new ArgumentException(message, e);
      }
    }
    parseArguments(rawArguments, argumentProperties);
  }
  /**
   * Indicates whether or not argument group description headers should be
   * printed.
   *
   * @return boolean where true means print the descriptions
   */
  boolean printUsageGroupHeaders()
  {
    // If there is only a single group then we won't print them.
    int groupsContainingArgs = 0;
    for (final ArgumentGroup argGroup : argumentGroups)
    {
      if (argGroup.containsNonHiddenArguments())
      {
        groupsContainingArgs++;
      }
    }
    return groupsContainingArgs > 1;
  }
  /**
   * Sets the usage group description for the default argument group.
   *
   * @param description
   *          for the default group
   */
  void setDefaultArgumentGroupDescription(final LocalizableMessage description)
  {
    this.defaultArgGroup.setDescription(description);
  }
  /**
   * Sets the provided argument which will be used to identify the file
   * properties.
   *
   * @param argument
   *          The argument which will be used to identify the file properties.
   */
  void setFilePropertiesArgument(final StringArgument argument)
  {
    filePropertiesPathArgument = argument;
  }
  /**
   * Sets the usage group description for the general argument group.
   *
   * @param description
   *          for the general group
   */
  void setGeneralArgumentGroupDescription(final LocalizableMessage description)
  {
    this.generalArgGroup.setDescription(description);
  }
  /**
   * Sets the usage group description for the input/output argument group.
   *
   * @param description
   *          for the input/output group
   */
  void setInputOutputArgumentGroupDescription(
      final LocalizableMessage description)
  {
    this.ioArgGroup.setDescription(description);
  }
  /**
   * Sets the usage group description for the LDAP argument group.
   *
   * @param description
   *          for the LDAP group
   */
  void setLdapArgumentGroupDescription(final LocalizableMessage description)
  {
    this.ldapArgGroup.setDescription(description);
  }
  /**
   * Sets the provided argument which will be used to identify the file
   * properties.
   *
   * @param argument
   *          The argument which will be used to indicate if we have to look for
   *          properties file.
   */
  void setNoPropertiesFileArgument(final BooleanArgument argument)
  {
    noPropertiesFileArgument = argument;
  }
  /**
   * Sets the provided argument as one which will automatically trigger the
   * output of usage information if it is provided on the command line and no
   * further argument validation will be performed. Note that the caller will
   * still need to add this argument to the parser with the
   * <CODE>addArgument</CODE> method, and the argument should not be required
   * and should not take a value. Also, the caller will still need to check for
   * the presence of the usage argument after calling
   * <CODE>parseArguments</CODE> to know that no further processing will be
   * required.
   *
   * @param argument
   *          The argument whose presence should automatically trigger the
   *          display of usage information.
   */
  void setUsageArgument(final Argument argument)
  {
    usageArgument = argument;
    usageOutputStream = System.out;
  }
  /**
   * Sets the provided argument as one which will automatically trigger the
   * output of usage information if it is provided on the command line and no
   * further argument validation will be performed. Note that the caller will
   * still need to add this argument to the parser with the
   * <CODE>addArgument</CODE> method, and the argument should not be required
   * and should not take a value. Also, the caller will still need to check for
   * the presence of the usage argument after calling
   * <CODE>parseArguments</CODE> to know that no further processing will be
   * required.
   *
   * @param argument
   *          The argument whose presence should automatically trigger the
   *          display of usage information.
   * @param outputStream
   *          The output stream to which the usage information should be
   *          written.
   * @throws IOException
   *           If a problem occurs while attempting to write the usage
   *           information to the provided output stream.
   */
  void getUsage(OutputStream outputStream) throws IOException
  void setUsageArgument(final Argument argument, final OutputStream outputStream)
  {
    StringBuilder buffer = new StringBuilder();
    getUsage(buffer);
    outputStream.write(getBytes(buffer.toString()));
    usageArgument = argument;
    usageOutputStream = outputStream;
  }
  /**
   * Indicates whether the version or the usage information has been
   * displayed to the end user either by an explicit argument like "-H"
   * or "--help", or by a built-in argument like "-?".
   * Indicates whether the version or the usage information has been displayed
   * to the end user either by an explicit argument like "-H" or "--help", or by
   * a built-in argument like "-?".
   *
   * @return {@code true} if the usage information has been displayed,
   *         or {@code false} if not.
   * @return {@code true} if the usage information has been displayed, or
   *         {@code false} if not.
   */
  boolean usageOrVersionDisplayed()
  {
@@ -1633,25 +1682,139 @@
  /**
   * Get the absolute path of the properties file.
   *
   * @param directory
   *          The location in which we should look for properties file
   * @return The absolute path of the properties file or null
   */
  private String findPropertiesFile(final String directory)
  {
    // Look for the tools properties file
    final File f = new File(directory, DEFAULT_OPENDS_PROPERTIES_FILE_NAME
        + DEFAULT_OPENDS_PROPERTIES_FILE_EXTENSION);
    if (f.exists() && f.canRead())
    {
      return f.getAbsolutePath();
    }
    else
    {
      return null;
    }
  }
  private void initGroups()
  {
    this.argumentGroups = new TreeSet<ArgumentGroup>();
    this.argumentGroups.add(defaultArgGroup);
    this.argumentGroups.add(ldapArgGroup);
    this.argumentGroups.add(generalArgGroup);
    this.argumentGroups.add(ioArgGroup);
    try
    {
      versionArgument = new BooleanArgument(OPTION_LONG_PRODUCT_VERSION,
          OPTION_SHORT_PRODUCT_VERSION, OPTION_LONG_PRODUCT_VERSION,
          INFO_DESCRIPTION_PRODUCT_VERSION.get());
      this.generalArgGroup.addArgument(versionArgument);
    }
    catch (final ArgumentException e)
    {
      // ignore
    }
  }
  private boolean isGeneralArgument(final Argument arg)
  {
    boolean general = false;
    if (arg != null)
    {
      final String longId = arg.getLongIdentifier();
      general = OPTION_LONG_HELP.equals(longId)
          || OPTION_LONG_PRODUCT_VERSION.equals(longId);
    }
    return general;
  }
  private boolean isInputOutputArgument(final Argument arg)
  {
    boolean io = false;
    if (arg != null)
    {
      final String longId = arg.getLongIdentifier();
      io = OPTION_LONG_VERBOSE.equals(longId)
          || OPTION_LONG_QUIET.equals(longId)
          || OPTION_LONG_NO_PROMPT.equals(longId)
          || OPTION_LONG_PROP_FILE_PATH.equals(longId)
          || OPTION_LONG_NO_PROP_FILE.equals(longId)
          || OPTION_LONG_SCRIPT_FRIENDLY.equals(longId)
          || OPTION_LONG_DONT_WRAP.equals(longId)
          || OPTION_LONG_ENCODING.equals(longId)
          || OPTION_LONG_BATCH_FILE_PATH.equals(longId);
    }
    return io;
  }
  private boolean isLdapConnectionArgument(final Argument arg)
  {
    boolean ldap = false;
    if (arg != null)
    {
      final String longId = arg.getLongIdentifier();
      ldap = OPTION_LONG_USE_SSL.equals(longId)
          || OPTION_LONG_START_TLS.equals(longId)
          || OPTION_LONG_HOST.equals(longId) || OPTION_LONG_PORT.equals(longId)
          || OPTION_LONG_BINDDN.equals(longId)
          || OPTION_LONG_BINDPWD.equals(longId)
          || OPTION_LONG_BINDPWD_FILE.equals(longId)
          || OPTION_LONG_SASLOPTION.equals(longId)
          || OPTION_LONG_TRUSTALL.equals(longId)
          || OPTION_LONG_TRUSTSTOREPATH.equals(longId)
          || OPTION_LONG_TRUSTSTORE_PWD.equals(longId)
          || OPTION_LONG_TRUSTSTORE_PWD_FILE.equals(longId)
          || OPTION_LONG_KEYSTOREPATH.equals(longId)
          || OPTION_LONG_KEYSTORE_PWD.equals(longId)
          || OPTION_LONG_KEYSTORE_PWD_FILE.equals(longId)
          || OPTION_LONG_CERT_NICKNAME.equals(longId)
          || OPTION_LONG_REFERENCED_HOST_NAME.equals(longId)
          || OPTION_LONG_ADMIN_UID.equals(longId)
          || OPTION_LONG_REPORT_AUTHZ_ID.equals(longId)
          || OPTION_LONG_USE_PW_POLICY_CTL.equals(longId)
          || OPTION_LONG_USE_SASL_EXTERNAL.equals(longId)
          || OPTION_LONG_PROTOCOL_VERSION.equals(longId);
    }
    return ldap;
  }
  /**
   * Appends argument usage information to the provided buffer.
   *
   * @param a
   *          The argument to handle.
   * @param buffer
   *          The buffer to which the usage information should be
   *          appended.
   *          The buffer to which the usage information should be appended.
   */
  private void printArgumentUsage(Argument a, StringBuilder buffer)
  private void printArgumentUsage(final Argument a, final StringBuilder buffer)
  {
    // Write a line with the short and/or long identifiers that may be
    // used
    // for the argument.
    final int indentLength = INDENT.length();
    Character shortID = a.getShortIdentifier();
    String longID = a.getLongIdentifier();
    final Character shortID = a.getShortIdentifier();
    final String longID = a.getLongIdentifier();
    if (shortID != null)
    {
      int currentLength = buffer.length();
      final int currentLength = buffer.length();
      if (usageArgument.getName().equals(a.getName()))
      {
@@ -1669,7 +1832,7 @@
      if (longID != null)
      {
        StringBuilder newBuffer = new StringBuilder();
        final StringBuilder newBuffer = new StringBuilder();
        newBuffer.append(", --");
        newBuffer.append(longID);
@@ -1679,7 +1842,7 @@
          newBuffer.append(a.getValuePlaceholder());
        }
        int lineLength = (buffer.length() - currentLength)
        final int lineLength = (buffer.length() - currentLength)
            + newBuffer.length();
        if (lineLength > MAX_LENGTH)
        {
@@ -1720,8 +1883,8 @@
    // indent the description five characters and try our best to wrap
    // at or
    // before column 79 so it will be friendly to 80-column displays.
    LocalizableMessage description = a.getDescription();
    int descMaxLength = MAX_LENGTH - indentLength - 1;
    final LocalizableMessage description = a.getDescription();
    final int descMaxLength = MAX_LENGTH - indentLength - 1;
    if (description.length() <= descMaxLength)
    {
      buffer.append(INDENT);
@@ -1778,189 +1941,9 @@
        && (a.getDefaultValue().length() > 0))
    {
      buffer.append(INDENT);
      buffer.append(INFO_ARGPARSER_USAGE_DEFAULT_VALUE.get(
          a.getDefaultValue()).toString());
      buffer.append(INFO_ARGPARSER_USAGE_DEFAULT_VALUE.get(a.getDefaultValue())
          .toString());
      buffer.append(EOL);
    }
  }
  /**
   * Given an argument, returns an appropriate group. Arguments may be
   * part of one of the special groups or the default group.
   *
   * @param argument
   *          for which a group is requested
   * @return argument group appropriate for <code>argument</code>
   */
  ArgumentGroup getStandardGroup(Argument argument)
  {
    ArgumentGroup group;
    if (isInputOutputArgument(argument))
    {
      group = ioArgGroup;
    }
    else if (isGeneralArgument(argument))
    {
      group = generalArgGroup;
    }
    else if (isLdapConnectionArgument(argument))
    {
      group = ldapArgGroup;
    }
    else
    {
      group = defaultArgGroup;
    }
    return group;
  }
  /**
   * Indicates whether or not argument group description headers should
   * be printed.
   *
   * @return boolean where true means print the descriptions
   */
  boolean printUsageGroupHeaders()
  {
    // If there is only a single group then we won't print them.
    int groupsContainingArgs = 0;
    for (ArgumentGroup argGroup : argumentGroups)
    {
      if (argGroup.containsNonHiddenArguments())
      {
        groupsContainingArgs++;
      }
    }
    return groupsContainingArgs > 1;
  }
  private void initGroups()
  {
    this.argumentGroups = new TreeSet<ArgumentGroup>();
    this.argumentGroups.add(defaultArgGroup);
    this.argumentGroups.add(ldapArgGroup);
    this.argumentGroups.add(generalArgGroup);
    this.argumentGroups.add(ioArgGroup);
    try
    {
      versionArgument = new BooleanArgument(
          OPTION_LONG_PRODUCT_VERSION, OPTION_SHORT_PRODUCT_VERSION,
          OPTION_LONG_PRODUCT_VERSION, INFO_DESCRIPTION_PRODUCT_VERSION
              .get());
      this.generalArgGroup.addArgument(versionArgument);
    }
    catch (ArgumentException e)
    {
      // ignore
    }
  }
  private boolean isInputOutputArgument(Argument arg)
  {
    boolean io = false;
    if (arg != null)
    {
      String longId = arg.getLongIdentifier();
      io = OPTION_LONG_VERBOSE.equals(longId)
          || OPTION_LONG_QUIET.equals(longId)
          || OPTION_LONG_NO_PROMPT.equals(longId)
          || OPTION_LONG_PROP_FILE_PATH.equals(longId)
          || OPTION_LONG_NO_PROP_FILE.equals(longId)
          || OPTION_LONG_SCRIPT_FRIENDLY.equals(longId)
          || OPTION_LONG_DONT_WRAP.equals(longId)
          || OPTION_LONG_ENCODING.equals(longId)
          || OPTION_LONG_BATCH_FILE_PATH.equals(longId);
    }
    return io;
  }
  private boolean isLdapConnectionArgument(Argument arg)
  {
    boolean ldap = false;
    if (arg != null)
    {
      String longId = arg.getLongIdentifier();
      ldap = OPTION_LONG_USE_SSL.equals(longId)
          || OPTION_LONG_START_TLS.equals(longId)
          || OPTION_LONG_HOST.equals(longId)
          || OPTION_LONG_PORT.equals(longId)
          || OPTION_LONG_BINDDN.equals(longId)
          || OPTION_LONG_BINDPWD.equals(longId)
          || OPTION_LONG_BINDPWD_FILE.equals(longId)
          || OPTION_LONG_SASLOPTION.equals(longId)
          || OPTION_LONG_TRUSTALL.equals(longId)
          || OPTION_LONG_TRUSTSTOREPATH.equals(longId)
          || OPTION_LONG_TRUSTSTORE_PWD.equals(longId)
          || OPTION_LONG_TRUSTSTORE_PWD_FILE.equals(longId)
          || OPTION_LONG_KEYSTOREPATH.equals(longId)
          || OPTION_LONG_KEYSTORE_PWD.equals(longId)
          || OPTION_LONG_KEYSTORE_PWD_FILE.equals(longId)
          || OPTION_LONG_CERT_NICKNAME.equals(longId)
          || OPTION_LONG_REFERENCED_HOST_NAME.equals(longId)
          || OPTION_LONG_ADMIN_UID.equals(longId)
          || OPTION_LONG_REPORT_AUTHZ_ID.equals(longId)
          || OPTION_LONG_USE_PW_POLICY_CTL.equals(longId)
          || OPTION_LONG_USE_SASL_EXTERNAL.equals(longId)
          || OPTION_LONG_PROTOCOL_VERSION.equals(longId);
    }
    return ldap;
  }
  private boolean isGeneralArgument(Argument arg)
  {
    boolean general = false;
    if (arg != null)
    {
      String longId = arg.getLongIdentifier();
      general = OPTION_LONG_HELP.equals(longId)
          || OPTION_LONG_PRODUCT_VERSION.equals(longId);
    }
    return general;
  }
  /**
   * Returns whether the usage argument was provided or not. This method
   * should be called after a call to parseArguments.
   *
   * @return <CODE>true</CODE> if the usage argument was provided and
   *         <CODE>false</CODE> otherwise.
   */
  boolean isUsageArgumentPresent()
  {
    boolean isUsageArgumentPresent = false;
    if (usageArgument != null)
    {
      isUsageArgumentPresent = usageArgument.isPresent();
    }
    return isUsageArgumentPresent;
  }
  /**
   * Returns whether the version argument was provided or not. This
   * method should be called after a call to parseArguments.
   *
   * @return <CODE>true</CODE> if the version argument was provided and
   *         <CODE>false</CODE> otherwise.
   */
  boolean isVersionArgumentPresent()
  {
    return versionPresent;
  }
}