440 lines · 13.0 KB · Java
RawDownload
/* * Copyright (c) 1999, 2003, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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();    }}