LdapNamingEnumeration.java :  » 6.0-JDK-Modules-com.sun » jndi » com » sun » jndi » ldap » Java Open Source

Java Open Source » 6.0 JDK Modules com.sun » jndi 
jndi » com » sun » jndi » ldap » LdapNamingEnumeration.java
/*
 * Copyright 1999-2003 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package com.sun.jndi.ldap;

import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.spi.*;

import com.sun.jndi.toolkit.ctx.Continuation;
import java.util.NoSuchElementException;
import java.util.Vector;
import javax.naming.ldap.LdapName;

/**
  * Basic enumeration for NameClassPair, Binding, and SearchResults.
  */

class LdapNamingEnumeration implements NamingEnumeration, ReferralEnumeration {
    protected Name listArg;

    private boolean cleaned = false;
    private LdapResult res;
    private LdapClient enumClnt;
    private Continuation cont;  // used to fill in exceptions
    private Vector entries = null;
    private int limit = 0;
    private int posn = 0;
    protected LdapCtx homeCtx;
    private LdapReferralException refEx = null;
    private NamingException errEx = null;

    private static final String defaultClassName = DirContext.class.getName();

    /*
     * Record the next set of entries and/or referrals.
     */
    LdapNamingEnumeration(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
    }

    public Object nextElement() {
  try {
      return next();
  } catch (NamingException e) {
      // can't throw exception
      cleanup();
      return null;
  }
    }

    public boolean hasMoreElements() {
  try {
      return hasMore();
  } catch (NamingException e) {
      // can't throw exception
      cleanup();
      return false;
  }
    }

    /*
     * 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

  // mimimize 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 e) {
    setNamingException(e);

      } catch (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;
  }
    }

    private boolean more = true;  // assume we have something to start with
    private boolean hasMoreCalled = false;

    /*
     * Test if unprocessed entries or referrals exist.
     */
    public boolean hasMore() throws NamingException {

  if (hasMoreCalled) {
      return more;
  }

  hasMoreCalled = true;

  if (!more) {
      return false;
  } else {
      return (more = hasMoreImpl());
  }
    }

    /*
     * Retrieve the next entry.
     */
    public Object next() throws NamingException {

  if (!hasMoreCalled) {
      hasMore();
  }
  hasMoreCalled = false;
  return nextImpl();
    }
  
    /*
     * Test if unprocessed entries or referrals exist.
     */
    private boolean hasMoreImpl() throws NamingException {
  // when page size is supported, this
  // might generate an exception while attempting
  // to fetch the next batch to determine
  // whether there are any more elements
  
  // test if the current set of entries has been processed
  if (posn == limit) {
      getNextBatch();
  }

  // test if any unprocessed entries exist
        if (posn < limit) {
            return true;
        } else {

      try {
    // try to process another referral
    return hasMoreReferrals();

      } catch (LdapReferralException e) {
    cleanup();
    throw e;

      } catch (LimitExceededException e) {
    cleanup();
    throw e;

      } catch (PartialResultException e) {
    cleanup();
    throw e;

      } catch (NamingException e) {
    cleanup();
    PartialResultException pre = new PartialResultException();
    pre.setRootCause(e);
    throw pre;
      }
        }
    }

    /*
     * Retrieve the next entry.
     */
    private Object nextImpl() throws NamingException {
  try {
      return nextAux();
  } catch (NamingException e) {
      cleanup();
      throw cont.fillInException(e);
  }
    }

    private Object nextAux() throws NamingException {
  if (posn == limit) {
      getNextBatch();  // updates posn and limit
  }

  if (posn >= limit) {
      cleanup();
      throw new NoSuchElementException("invalid enumeration handle");
  }

  LdapEntry result = (LdapEntry)entries.elementAt(posn++);

  // gets and outputs DN from the entry
  return createItem(result.DN, result.attributes, result.respCtls);
    }

    protected String getAtom(String dn) {
  String atom;
  // need to strip off all but lowest component of dn
  // so that is relative to current context (currentDN)
  try {
      Name parsed = new LdapName(dn);
      return parsed.get(parsed.size() - 1);
  } catch (NamingException e) {
      return dn;
  }
    }

    protected NameClassPair createItem(String dn, Attributes attrs,
  Vector respCtls) throws NamingException {

  Attribute attr;
  String className = null;

  // use the Java classname if present
  if ((attr = attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME])) != null) {
      className = (String)attr.get();
  } else {
      className = defaultClassName;
  }
  CompositeName cn = new CompositeName();
  cn.add(getAtom(dn));

  NameClassPair ncp;
  if (respCtls != null) {
      ncp = new NameClassPairWithControls(
      cn.toString(), className,
      homeCtx.convertControls(respCtls));
  } else {
      ncp = new NameClassPair(cn.toString(), className);
  }
  ncp.setNameInNamespace(dn);
  return ncp;
    }

    /*
     * Append the supplied (chain of) referrals onto the
     * end of the current (chain of) referrals.
     */
    public void appendUnprocessedReferrals(LdapReferralException ex) {

  if (refEx != null) {
      refEx = refEx.appendUnprocessedReferrals(ex);
  } else {
      refEx = ex.appendUnprocessedReferrals(refEx);
  }
    }

    void setNamingException(NamingException e) {
        errEx = e;
    }

    protected LdapNamingEnumeration 
    getReferredResults(LdapReferralContext refCtx) throws NamingException {
  // repeat the original operation at the new context
  return (LdapNamingEnumeration)refCtx.list(listArg);
    }

    /*
     * Iterate through the URLs of a referral. If successful then perform
     * a search operation and merge the received results with the current
     * results.
     */
    protected boolean hasMoreReferrals() throws NamingException {

  if ((refEx != null) &&
      (refEx.hasMoreReferrals() ||
       refEx.hasMoreReferralExceptions())) {

            if (homeCtx.handleReferrals == LdapClient.LDAP_REF_THROW) {
                throw (NamingException)(refEx.fillInStackTrace());
            }

      // process the referrals sequentially
      while (true) {

    LdapReferralContext refCtx = 
        (LdapReferralContext)refEx.getReferralContext(
        homeCtx.envprops, homeCtx.reqCtls);

    try {

        update(getReferredResults(refCtx));
        break;

    } catch (LdapReferralException re) {

        // record a previous exception
        if (errEx == null) {
      errEx = re.getNamingException();
        }
        refEx = re;
        continue;

    } finally {
        // Make sure we close referral context
        refCtx.close();
    }
      }
            return hasMoreImpl();

  } else {
      cleanup();

      if (errEx != null) {
    throw errEx;
      }
      return (false);
  }
    }

    /*
     * Merge the entries and/or referrals from the supplied enumeration
     * with those of the current enumeration.
     */
    protected void update(LdapNamingEnumeration 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;
    }

    protected void finalize() {
  cleanup();
    }

    protected 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;
  }
    }

    public void close() {
  cleanup();
    }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.