/**
  * This method will ensure that all runtime parameters marked 'required' have been specified.
  * Otherwise, a ParameterValueException will be thrown.
  *
  * @throws ParameterValueException if a required parameter is missing
  */
 public void ensureRequiredParametersArePresent() throws ParameterValueException {
   for (ApplicationParameter param : _parameters.values()) {
     if (param.isRequired() && !param.isPresent())
       throw new ParameterValueException(
           param, null, "Required parameter " + param.getName() + " not set.");
   }
 }
 /**
  * Sets the available application parameters.
  *
  * @param parameters the available application parameters.
  */
 public void setParameters(final ApplicationParameter... parameters) {
   _parameterKeyMap.clear();
   _parameters.clear();
   for (ApplicationParameter param : parameters) {
     _parameters.put(param.getName(), param);
     for (String key : param.getKeys()) {
       if (_parameterKeyMap.containsKey(key))
         throw new RuntimeException("Duplicate parameter key: " + key);
       _parameterKeyMap.put(key, param);
     }
   }
 }
  /**
   * Returns a String explaining the runtime parameter usage. It will take the form
   *
   * <pre>
   * command - description <dataType> [<required>]
   * </pre>
   *
   * @return a String explaining the runtime parameter usage.
   */
  public String getParameterUsageTable() {
    int minLen = 0;

    final Collection<ApplicationParameter> params = getParameters();
    final HashMap<ApplicationParameter, String> verboseKeys =
        new HashMap<ApplicationParameter, String>(params.size());

    for (ApplicationParameter param : params) {
      final String[] keys = param.getKeys();
      final StringBuilder keyString = new StringBuilder(64);
      for (int i = 0; i < keys.length; i++) {
        keyString.append(keys[i]);
        if (i < keys.length - 1) keyString.append(", ");
      }
      verboseKeys.put(param, keyString.toString());
      minLen = Math.max(minLen, keyString.length());
    }

    final StringBuilder builder = new StringBuilder(256);
    for (Iterator<ApplicationParameter> it = params.iterator(); it.hasNext(); ) {
      final ApplicationParameter param = it.next();
      final String str = verboseKeys.get(param);
      builder.append(str);
      for (int i = str.length(); i < minLen; i++) builder.append(' ');
      builder.append(" - ").append(param.getName());
      if (param.isRequired()) builder.append("[required]");
      builder.append(" (").append(param.getType()).append(')');
      if (it.hasNext()) builder.append('\n');
    }

    return builder.toString();
  }
  /**
   * Processes the given runtime arguments, using the specified properties list as default. All
   * arguments which could not be matched will be returned.
   *
   * <p>Arguments are expected to either take the form
   *
   * <pre>-<paramName> <paramValue></pre>
   *
   * or
   *
   * <pre>-<paramName>=<paramValue></pre>
   *
   * @param properties a list of default values, may be null.
   * @param arguments the list of arguments to process.
   * @return the list of unmatched runtime arguments.
   * @throws ParameterValueException If one of the parameter values was illegal.
   */
  public Collection<String> processArguments(final Properties properties, final String... arguments)
      throws ParameterValueException {
    final LinkedList<String> unmatchedArguments = new LinkedList<String>();
    if (properties != null) {
      /* Process the property file */
      for (Object o : properties.keySet()) {
        final String s = (String) o;
        final ApplicationParameter param = getParameter(s);
        if (param == null) continue;
        param.setValueAsString(properties.getProperty(s));
      }
    }

    /* Process the runtime arguments */
    for (int i = 0; i < arguments.length; i++) {
      final String s = arguments[i];
      /* Check if this argument should be processed or passed down to the application */
      if (!s.startsWith("-")) unmatchedArguments.add(s);
      else {
        final boolean directAssignment = s.contains("=");
        final String key = directAssignment ? s.substring(1, s.indexOf('=')) : s.substring(1);
        final ApplicationParameter parameter = _parameterKeyMap.get(key);
        if (parameter == null) {
          unmatchedArguments.add(s);
          continue;
        }

        final String value;
        if (parameter.getType() == ApplicationParameter.Type.BOOLEAN)
          value = directAssignment ? s.substring(s.indexOf('=') + 1, s.length()) : "true";
        else
          value = directAssignment ? s.substring(s.indexOf('=') + 1, s.length()) : arguments[++i];

        parameter.setValueAsString(value);
        parameter.setPresent(true);
      }
    }

    return unmatchedArguments;
  }
 /**
  * Returns the specified value for a parameter. This is a conveniance method for invoking
  * getParameter(paramName) followed by getValue, and will return null if the parameter is not set
  * or present.
  *
  * @param paramName The name of the parameter to be checked.
  * @return the parameter's value, or null if the parameter is not set or does not exist.
  */
 public Object getParameterValue(final String paramName) {
   final ApplicationParameter param = _parameters.get(paramName);
   return param == null ? null : param.getValue();
 }