protected static ReplyType parseResponseHTML(String responseHTML) {
    ReplyType res = ReplyType.UNKNOWN_RESPONSE;
    String strres = null;

    Matcher matcher = resultParserPattern.matcher(responseHTML);

    if (matcher.find()) {
      strres = matcher.group(1);
    }

    if (strres != null) {
      for (ReplyType rt : ReplyType.values()) {
        if (strres.equalsIgnoreCase(rt.nativeReply)) {
          res = rt;
          break;
        }
      }
    }

    return res;
  }
public abstract class AbstractHTTPKeyServerClient extends AbstractRetryingKeyServerClient {

  private static final Pattern resultParserPattern =
      Pattern.compile("Result:\\s*(.*?)\\r?\\n", Pattern.CASE_INSENSITIVE);

  public String createKey(String hostName, KeyServerClient.Usage usage) {
    String res = null;

    if (hostName != null) {
      switch (usage) {
        case SNMP:
          {
            res = hostName + "-" + "adsl";
            break;
          }
        default:
          {
            throw new IllegalArgumentException();
          }
      }
    }
    return res;
  }

  /*
   * Parse the response HTML
   */

  protected static ReplyType parseResponseHTML(String responseHTML) {
    ReplyType res = ReplyType.UNKNOWN_RESPONSE;
    String strres = null;

    Matcher matcher = resultParserPattern.matcher(responseHTML);

    if (matcher.find()) {
      strres = matcher.group(1);
    }

    if (strres != null) {
      for (ReplyType rt : ReplyType.values()) {
        if (strres.equalsIgnoreCase(rt.nativeReply)) {
          res = rt;
          break;
        }
      }
    }

    return res;
  }

  /**
   * Builds the actual string that is POSTed to the KeyServer
   *
   * @param localhostname Local Hostname
   * @param request KeyServer request
   * @param key Key to allocate/deallocate
   * @return String to POST
   */
  protected static String buildRequestString(
      String localhostname, RequestType request, String key) {
    return buildRequestString(localhostname, request.getNativeRequest(), key);
  }

  protected static String buildRequestString(String localhostname, String requesttype, String key) {
    return "remote_address=" + localhostname + "&reqtype=" + requesttype + "&dslam-key=" + key;
  }

  /** Possible replies from the KeyServer */
  protected static enum ReplyType {
    /** Attempt to get/allocate key successful */
    KEY_GRANTED("Key_Granted"),
    /** Attempt to get/allocate key failed - Key allocated elsewhere */
    KEY_BUSY("Key Busy"),
    /** Attempt to return/deallocate key successful */
    KEY_RETURNED("Key_Returned"),
    /** Attempt to get/allocate key failed - Key blocked by other party */
    KEY_BLOCKED("Key_Blocked"),
    /** Attempt to block entire DSLAM successful */
    KEY_BLOCK_OK("KeyServer_BLOCK Ok"),
    /** Attempt to unblock entire DSLAM successful */
    KEY_UNBLOCK_OK("KeyServer UNBLOCK Ok"),
    UNKNOWN_RESPONSE("UNKNOWN_RESPONSE"), // not a direct reply
    KEYSERVER_ERROR("KEYSERVER_ERROR"), // not a direct reply
    KEY_NOT_RETURNED("KEY_NOT_RETURNED"); // not a direct reply

    private String nativeReply;

    ReplyType(String reply) {
      this.nativeReply = reply;
    }

    public String getNativeReply() {
      return this.nativeReply;
    }
  }

  /** Possible KeyServer requests */
  protected static enum RequestType {
    /** Get/Allocate Key Request */
    GET_KEY("get_dslamkey", ReplyType.KEY_GRANTED),
    /** Return/Deallocate Key Request */
    RETURN_KEY("return_dslamkey", ReplyType.KEY_RETURNED);

    private String nativeRequest;
    private ReplyType successReply;

    RequestType(String request, ReplyType success) {
      this.nativeRequest = request;
      this.successReply = success;
    }

    public String getNativeRequest() {
      return this.nativeRequest;
    }

    public ReplyType getSuccessReply() {
      return this.successReply;
    }
  }

  /** KeyServer returned {@link ReplyType} does not match expected {@link ReplyType} */
  protected static class OperationFailedException extends Exception {
    public OperationFailedException(String message) {
      super(message);
    }

    /** */
    private static final long serialVersionUID = -7363443310028754594L;
  }

  public static AtomicLong httpBeginCount = new AtomicLong();
  public static AtomicLong httpEndCount = new AtomicLong();
  public static AtomicLong httpRunningCount = new AtomicLong();
  public static AtomicLong httpRunningCountMax = new AtomicLong();

  public static FrequencyCounter httpBeginFrequencyCounter =
      new CountLimitedFrequencyCounter(8640, 10 * 1000L * 1000L * 1000L); // 8640*(10 sec)=24 hours

  public static FrequencyCounter httpEndFrequencyCounter =
      new CountLimitedFrequencyCounter(8640, 10 * 1000L * 1000L * 1000L); // 8640*(10 sec)=24 hours
}