/**
   * Creates a new SASL TOTP bind request with the provided information.
   *
   * @param authenticationID The authentication identity for the bind request. It must not be {@code
   *     null}, and must be in the form "u:" followed by a username, or "dn:" followed by a DN.
   * @param authorizationID The authorization identity for the bind request. It may be {@code null}
   *     if the authorization identity should be the same as the authentication identity. If an
   *     authorization identity is specified, it must be in the form "u:" followed by a username, or
   *     "dn:" followed by a DN. The value "dn:" may indicate an authorization identity of the
   *     anonymous user.
   * @param sharedSecret The shared secret key to use when generating the TOTP password.
   * @param staticPassword The static password for the target user. It may be {@code null} if only
   *     the one-time password is to be used for authentication (which may or may not be allowed by
   *     the server).
   * @param totpIntervalDurationSeconds The duration (in seconds) of the time interval to use for
   *     TOTP processing. It must be greater than zero.
   * @param totpNumDigits The number of digits to include in the generated TOTP password. It must be
   *     greater than or equal to six and less than or equal to eight.
   * @param controls The set of controls to include in the bind request.
   */
  public ReusableTOTPBindRequest(
      final String authenticationID,
      final String authorizationID,
      final byte[] sharedSecret,
      final byte[] staticPassword,
      final int totpIntervalDurationSeconds,
      final int totpNumDigits,
      final Control... controls) {
    super(authenticationID, authorizationID, staticPassword, controls);

    Validator.ensureTrue(totpIntervalDurationSeconds > 0);
    Validator.ensureTrue((totpNumDigits >= 6) && (totpNumDigits <= 8));

    this.sharedSecret = sharedSecret;
    this.totpIntervalDurationSeconds = totpIntervalDurationSeconds;
    this.totpNumDigits = totpNumDigits;
  }
  /**
   * Creates a new instance of this canned response request handler that will immediately return a
   * response with the provided information to any request that is received.
   *
   * @param resultCode The result code to use for the responses. It must not be {@code null}.
   * @param matchedDN The matched DN to use for the responses. It may be {@code null} if no matched
   *     DN should be included.
   * @param diagnosticMessage The diagnostic message to use for the responses. It may be {@code
   *     null} if no diagnostic message should be included.
   * @param referralURLs The referral URLs to use for the responses. It may be empty or {@code null}
   *     if no referral URLs should be included.
   * @param searchEntries The set of search result entries that should be returned for every search.
   *     It may be {@code null} or empty if no entries are required.
   * @param searchReferences The set of search result references that should be returned for every
   *     search. It may be {@code null} or empty if no references are required.
   */
  public CannedResponseRequestHandler(
      final ResultCode resultCode,
      final String matchedDN,
      final String diagnosticMessage,
      final List<String> referralURLs,
      final Collection<? extends Entry> searchEntries,
      final Collection<SearchResultReference> searchReferences) {
    Validator.ensureNotNull(resultCode);

    clientConnection = null;

    final int rc = resultCode.intValue();
    addResponseProtocolOp =
        new AddResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);
    bindResponseProtocolOp =
        new BindResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs, null);
    compareResponseProtocolOp =
        new CompareResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);
    deleteResponseProtocolOp =
        new DeleteResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);
    extendedResponseProtocolOp =
        new ExtendedResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs, null, null);
    modifyResponseProtocolOp =
        new ModifyResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);
    modifyDNResponseProtocolOp =
        new ModifyDNResponseProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);
    searchResultDoneProtocolOp =
        new SearchResultDoneProtocolOp(rc, matchedDN, diagnosticMessage, referralURLs);

    if ((searchEntries == null) || searchEntries.isEmpty()) {
      searchEntryProtocolOps = Collections.emptyList();
    } else {
      final ArrayList<SearchResultEntryProtocolOp> l =
          new ArrayList<SearchResultEntryProtocolOp>(searchEntries.size());
      for (final Entry e : searchEntries) {
        l.add(new SearchResultEntryProtocolOp(e));
      }

      searchEntryProtocolOps = Collections.unmodifiableList(l);
    }

    if ((searchReferences == null) || searchReferences.isEmpty()) {
      searchReferenceProtocolOps = Collections.emptyList();
    } else {
      final ArrayList<SearchResultReferenceProtocolOp> l =
          new ArrayList<SearchResultReferenceProtocolOp>(searchReferences.size());
      for (final SearchResultReference r : searchReferences) {
        l.add(new SearchResultReferenceProtocolOp(r));
      }

      searchReferenceProtocolOps = Collections.unmodifiableList(l);
    }
  }