/*
   * Retrieve the next set of entries and/or referrals.
   */
  private void getNextBatch() throws NamingException {

    res = homeCtx.getSearchReply(enumClnt, res);
    if (res == null) {
      limit = posn = 0;
      return;
    }

    entries = res.entries;
    limit = (entries == null) ? 0 : entries.size(); // handle empty set
    posn = 0; // reset

    // minimize the number of calls to processReturnCode()
    // (expensive when batchSize is small and there are many results)
    if ((res.status != LdapClient.LDAP_SUCCESS)
        || ((res.status == LdapClient.LDAP_SUCCESS) && (res.referrals != null))) {

      try {
        // convert referrals into a chain of LdapReferralException
        homeCtx.processReturnCode(res, listArg);

      } catch (LimitExceededException | PartialResultException e) {
        setNamingException(e);
      }
    }

    // merge any newly received referrals with any current referrals
    if (res.refEx != null) {
      if (refEx == null) {
        refEx = res.refEx;
      } else {
        refEx = refEx.appendUnprocessedReferrals(res.refEx);
      }
      res.refEx = null; // reset
    }

    if (res.resControls != null) {
      homeCtx.respCtls = res.resControls;
    }
  }
  protected final void cleanup() {
    if (cleaned) return; // been there; done that

    if (enumClnt != null) {
      enumClnt.clearSearchReply(res, homeCtx.reqCtls);
    }

    enumClnt = null;
    cleaned = true;
    if (homeCtx != null) {
      homeCtx.decEnumCount();
      homeCtx = null;
    }
  }
  /*
   * Record the next set of entries and/or referrals.
   */
  AbstractLdapNamingEnumeration(LdapCtx homeCtx, LdapResult answer, Name listArg, Continuation cont)
      throws NamingException {

    // These checks are to accommodate referrals and limit exceptions
    // which will generate an enumeration and defer the exception
    // to be thrown at the end of the enumeration.
    // All other exceptions are thrown immediately.
    // Exceptions shouldn't be thrown here anyhow because
    // process_return_code() is called before the constructor
    // is called, so these are just safety checks.

    if ((answer.status != LdapClient.LDAP_SUCCESS)
        && (answer.status != LdapClient.LDAP_SIZE_LIMIT_EXCEEDED)
        && (answer.status != LdapClient.LDAP_TIME_LIMIT_EXCEEDED)
        && (answer.status != LdapClient.LDAP_ADMIN_LIMIT_EXCEEDED)
        && (answer.status != LdapClient.LDAP_REFERRAL)
        && (answer.status != LdapClient.LDAP_PARTIAL_RESULTS)) {

      // %%% need to deal with referral
      NamingException e =
          new NamingException(LdapClient.getErrorMessage(answer.status, answer.errorMessage));

      throw cont.fillInException(e);
    }

    // otherwise continue

    res = answer;
    entries = answer.entries;
    limit = (entries == null) ? 0 : entries.size(); // handle empty set
    this.listArg = listArg;
    this.cont = cont;

    if (answer.refEx != null) {
      refEx = answer.refEx;
    }

    // Ensures that context won't get closed from underneath us
    this.homeCtx = homeCtx;
    homeCtx.incEnumCount();
    enumClnt = homeCtx.clnt; // remember
  }
  /*
   * Merge the entries and/or referrals from the supplied enumeration
   * with those of the current enumeration.
   */
  protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) {
    // Cleanup previous context first
    homeCtx.decEnumCount();

    // New enum will have already incremented enum count and recorded clnt
    homeCtx = ne.homeCtx;
    enumClnt = ne.enumClnt;

    // Do this to prevent referral enumeration (ne) from decrementing
    // enum count because we'll be doing that here from this
    // enumeration.
    ne.homeCtx = null;

    // Record rest of information from new enum
    posn = ne.posn;
    limit = ne.limit;
    res = ne.res;
    entries = ne.entries;
    refEx = ne.refEx;
    listArg = ne.listArg;
  }