/**
   * This method will create a Link stub that includes the name only.
   *
   * @param id Identifier assigned to the link object.
   * @param name Asset name to be assigned to the link stub.
   * @return Link stub that includes the name and ID.
   */
  public static Link makeLinkStub(Integer id, String name) {
    Link retval = new Link();

    retval.setId((id != null ? id : 0));
    retval.setName((AWSUtil.isValued(name) ? name : null));

    return retval;
  }
  /**
   * This method will create a Link stub that includes the name only.
   *
   * @param name Asset name to be assigned to the link stub.
   * @return Link stub that includes the name.
   */
  public static Link makeLinkStub(String name) {
    Link retval = new Link();

    if (AWSUtil.isValued(name)) {
      retval.setName(name);
    }

    return retval;
  }
  /**
   * This method will translate an array of strings into a single string with the values separated
   * by the provided separator.
   *
   * @param array Array to translate to string.
   * @param separator Value to use between array values.
   * @return String representation of the array. If the array is null or empty, an empty string is
   *     returned.
   */
  public static String arrayToString(String[] array, String separator) {
    StringBuilder sb = new StringBuilder();

    if ((array != null) && (array.length > 0)) {
      String sepString = (AWSUtil.isValued(separator) ? separator : ",");
      String sep = "";

      for (int i = 0; i < array.length; i++) {
        sb.append(sep + array[i]);
        sep = sepString;
      }
    }

    return sb.toString();
  }
  /**
   * This method will use reflection to log an object to the specified logger using the provided log
   * level. The object is reflected upon looking for "get*" and "is*" methods JavaBean pattern. The
   * methods are invoked and the results written to the log. If the result is another object, the
   * reference information will be displayed - all this is good for is to determine if the property
   * is null or not. If the logger parameter is not enabled for the level requested, nothing will be
   * written.
   *
   * @param obj Object to be logged.
   * @param logger Logger to which the information will be written.
   * @param level Logging level to be used; if null, the DEFAULT_LEVEL value will be used.
   * @param recursive True if recursive logging should be used.
   * @param indentLevel Number of levels to indent for printing.
   * @return String representation of the object.
   */
  public static String logObject(
      Object obj, Logger logger, Level level, boolean recursive, int indentLevel) {
    StringBuilder buf = new StringBuilder();
    String indentStr = "    "; // used for formatting pretty printing
    String indent = ""; // used for formatting pretty printing
    String prefix = "--- "; // used for formatting pretty printing
    String seperator = ": "; // used for formatting pretty printing

    indentLevel = (indentLevel < 1 ? 1 : indentLevel);

    for (int i = 1; i < indentLevel; i++) {
      indent += indentStr;
    }

    indent += indentLevel;

    // if no level is provided, it will use the default
    level = (level == null ? DEFAULT_LEVEL : level);

    boolean isEnabled = (logger != null ? logger.isEnabledFor(level) : false);
    if ((obj != null) && (logger != null) && isEnabled) {
      buf.append(
          "\n"
              + indent
              + prefix
              + Resources.getString("loggingInfo", obj.getClass().getName())
              + "\n");

      Method[] methods = obj.getClass().getMethods();

      for (Method m : methods) {
        String methodName = m.getName();
        boolean hasParams = (m.getParameterTypes().length > 0);

        // just process methods that match the javaBean pattern
        if ((methodName.startsWith("get") || methodName.startsWith("is")) && !hasParams) {
          int start = (methodName.startsWith("get") ? 3 : 2);
          String label = indent + prefix + methodName.substring(start) + seperator;

          try {
            Object o = m.invoke(obj, new Object[] {});

            if (recursive && (o != null) && o.getClass().getName().startsWith("com.servicemesh")) {
              buf.append(label + "\n");
              buf.append(logObject(o, logger, level, recursive, (indentLevel + 1)));
            } else {
              // do not print private key value to log
              if (methodName.toLowerCase().contains("privatekey")) {
                buf.append(label);
                buf.append(AWSUtil.maskPrivateKey((String) o));
              } else {
                buf.append(label);
                buf.append(o);
              }
            }
          } catch (Exception e) {
            buf.append(e.getMessage());
          }

          buf.append("\n");
        }
      }

      logger.log(level, buf.toString());
    }

    return buf.toString();
  }
  /**
   * Constructor for Status Poller All params are required
   *
   * @param request The request that initiated the event
   * @param responsePromise Handler - Promise used to pass response to client
   * @param interval Interval between polls in millisecs
   * @param retries Max number of times the timer is allowed to be called
   * @param desiredState The desired state of the monitored object
   * @param conn Azure connection object to be used for the polling API call
   * @param retryOn404 Flag that determines if the poller should retry or fail when the response is
   *     404.
   */
  public StatusPoller(
      Request request,
      CompletablePromise<T> responsePromise,
      long interval,
      long retries,
      String desiredState,
      AWSConnection conn,
      boolean retryOn404) {
    if (responsePromise != null) {
      this.responsePromise = responsePromise;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.MISSING_PARAM_MSG.format(new Object[] {"handler"}));
      throw e;
    }

    if (request != null) {
      this.request = request;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.MISSING_PARAM_MSG.format(new Object[] {"request"}));
      responsePromise.failure(e);
      throw e;
    }

    if (interval > -1) {
      this.interval = interval;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.NEGATIVE_PARAM_MSG.format(new Object[] {"interval"}));
      responsePromise.failure(e);
      throw e;
    }

    if (retries > -1) {
      this.retries = retries;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.NEGATIVE_PARAM_MSG.format(new Object[] {"retries"}));
      responsePromise.failure(e);
      throw e;
    }

    if (conn != null) {
      this.conn = conn;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.MISSING_PARAM_MSG.format(new Object[] {"connection"}));
      responsePromise.failure(e);
      throw e;
    }

    if (AWSUtil.isValued(desiredState)) {
      this.desiredState = desiredState;
    } else {
      IllegalArgumentException e =
          new IllegalArgumentException(
              StatusPoller.MISSING_PARAM_MSG.format(new Object[] {"desiredState"}));
      responsePromise.failure(e);
      throw e;
    }

    this.retryOn404 = retryOn404;

    this.promise = run();
  }