| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package com.sun.jndi.ldap;  | 
 | 
 | 
 | 
import com.sun.jndi.toolkit.ctx.Continuation;  | 
 | 
import java.util.NoSuchElementException;  | 
 | 
import java.util.Vector;  | 
 | 
 | 
 | 
import javax.naming.*;  | 
 | 
import javax.naming.directory.Attributes;  | 
 | 
import javax.naming.ldap.Control;  | 
 | 
 | 
 | 
/**  | 
 | 
 * Basic enumeration for NameClassPair, Binding, and SearchResults.  | 
 | 
 */  | 
 | 
 | 
 | 
abstract class AbstractLdapNamingEnumeration<T extends NameClassPair>  | 
 | 
        implements NamingEnumeration<T>, ReferralEnumeration<T> { | 
 | 
 | 
 | 
    protected Name listArg;  | 
 | 
 | 
 | 
    private boolean cleaned = false;  | 
 | 
    private LdapResult res;  | 
 | 
    private LdapClient enumClnt;  | 
 | 
    private Continuation cont;    | 
 | 
    private Vector<LdapEntry> entries = null;  | 
 | 
    private int limit = 0;  | 
 | 
    private int posn = 0;  | 
 | 
    protected LdapCtx homeCtx;  | 
 | 
    private LdapReferralException refEx = null;  | 
 | 
    private NamingException errEx = null;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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)) { | 
 | 
 | 
 | 
                  | 
 | 
                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();   | 
 | 
            this.listArg = listArg;  | 
 | 
            this.cont = cont;  | 
 | 
 | 
 | 
            if (answer.refEx != null) { | 
 | 
                refEx = answer.refEx;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            this.homeCtx = homeCtx;  | 
 | 
            homeCtx.incEnumCount();  | 
 | 
            enumClnt = homeCtx.clnt;   | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public final T nextElement() { | 
 | 
        try { | 
 | 
            return next();  | 
 | 
        } catch (NamingException e) { | 
 | 
              | 
 | 
            cleanup();  | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public final boolean hasMoreElements() { | 
 | 
        try { | 
 | 
            return hasMore();  | 
 | 
        } catch (NamingException e) { | 
 | 
              | 
 | 
            cleanup();  | 
 | 
            return false;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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();   | 
 | 
        posn = 0;   | 
 | 
 | 
 | 
        // mimimize the number of calls to processReturnCode()  | 
 | 
          | 
 | 
        if ((res.status != LdapClient.LDAP_SUCCESS) ||  | 
 | 
            ((res.status == LdapClient.LDAP_SUCCESS) &&  | 
 | 
                (res.referrals != null))) { | 
 | 
 | 
 | 
            try { | 
 | 
                  | 
 | 
                homeCtx.processReturnCode(res, listArg);  | 
 | 
 | 
 | 
            } catch (LimitExceededException | PartialResultException e) { | 
 | 
                setNamingException(e);  | 
 | 
 | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (res.refEx != null) { | 
 | 
            if (refEx == null) { | 
 | 
                refEx = res.refEx;  | 
 | 
            } else { | 
 | 
                refEx = refEx.appendUnprocessedReferrals(res.refEx);  | 
 | 
            }  | 
 | 
            res.refEx = null;   | 
 | 
        }  | 
 | 
 | 
 | 
        if (res.resControls != null) { | 
 | 
            homeCtx.respCtls = res.resControls;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private boolean more = true;    | 
 | 
    private boolean hasMoreCalled = false;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public final boolean hasMore() throws NamingException { | 
 | 
 | 
 | 
        if (hasMoreCalled) { | 
 | 
            return more;  | 
 | 
        }  | 
 | 
 | 
 | 
        hasMoreCalled = true;  | 
 | 
 | 
 | 
        if (!more) { | 
 | 
            return false;  | 
 | 
        } else { | 
 | 
            return (more = hasMoreImpl());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public final T next() throws NamingException { | 
 | 
 | 
 | 
        if (!hasMoreCalled) { | 
 | 
            hasMore();  | 
 | 
        }  | 
 | 
        hasMoreCalled = false;  | 
 | 
        return nextImpl();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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  | 
 | 
 | 
 | 
          | 
 | 
        if (posn == limit) { | 
 | 
            getNextBatch();  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (posn < limit) { | 
 | 
            return true;  | 
 | 
        } else { | 
 | 
 | 
 | 
            try { | 
 | 
                  | 
 | 
                return hasMoreReferrals();  | 
 | 
 | 
 | 
            } catch (LdapReferralException |  | 
 | 
                     LimitExceededException |  | 
 | 
                     PartialResultException e) { | 
 | 
                cleanup();  | 
 | 
                throw e;  | 
 | 
 | 
 | 
            } catch (NamingException e) { | 
 | 
                cleanup();  | 
 | 
                PartialResultException pre = new PartialResultException();  | 
 | 
                pre.setRootCause(e);  | 
 | 
                throw pre;  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private T nextImpl() throws NamingException { | 
 | 
        try { | 
 | 
            return nextAux();  | 
 | 
        } catch (NamingException e) { | 
 | 
            cleanup();  | 
 | 
            throw cont.fillInException(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private T nextAux() throws NamingException { | 
 | 
        if (posn == limit) { | 
 | 
            getNextBatch();    | 
 | 
        }  | 
 | 
 | 
 | 
        if (posn >= limit) { | 
 | 
            cleanup();  | 
 | 
            throw new NoSuchElementException("invalid enumeration handle"); | 
 | 
        }  | 
 | 
 | 
 | 
        LdapEntry result = entries.elementAt(posn++);  | 
 | 
 | 
 | 
          | 
 | 
        return createItem(result.DN, result.attributes, result.respCtls);  | 
 | 
    }  | 
 | 
 | 
 | 
    protected final String getAtom(String dn) { | 
 | 
        // need to strip off all but lowest component of dn  | 
 | 
          | 
 | 
        try { | 
 | 
            Name parsed = new LdapName(dn);  | 
 | 
            return parsed.get(parsed.size() - 1);  | 
 | 
        } catch (NamingException e) { | 
 | 
            return dn;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    protected abstract T createItem(String dn, Attributes attrs,  | 
 | 
        Vector<Control> respCtls) throws NamingException;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public void appendUnprocessedReferrals(LdapReferralException ex) { | 
 | 
        if (refEx != null) { | 
 | 
            refEx = refEx.appendUnprocessedReferrals(ex);  | 
 | 
        } else { | 
 | 
            refEx = ex.appendUnprocessedReferrals(refEx);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    final void setNamingException(NamingException e) { | 
 | 
        errEx = e;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected abstract AbstractLdapNamingEnumeration<? extends NameClassPair> getReferredResults(  | 
 | 
            LdapReferralContext refCtx) throws NamingException;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    protected final boolean hasMoreReferrals() throws NamingException { | 
 | 
 | 
 | 
        if ((refEx != null) &&  | 
 | 
            (refEx.hasMoreReferrals() ||  | 
 | 
             refEx.hasMoreReferralExceptions())) { | 
 | 
 | 
 | 
            if (homeCtx.handleReferrals == LdapClient.LDAP_REF_THROW) { | 
 | 
                throw (NamingException)(refEx.fillInStackTrace());  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            while (true) { | 
 | 
 | 
 | 
                LdapReferralContext refCtx =  | 
 | 
                    (LdapReferralContext)refEx.getReferralContext(  | 
 | 
                    homeCtx.envprops, homeCtx.reqCtls);  | 
 | 
 | 
 | 
                try { | 
 | 
 | 
 | 
                    update(getReferredResults(refCtx));  | 
 | 
                    break;  | 
 | 
 | 
 | 
                } catch (LdapReferralException re) { | 
 | 
 | 
 | 
                      | 
 | 
                    if (errEx == null) { | 
 | 
                        errEx = re.getNamingException();  | 
 | 
                    }  | 
 | 
                    refEx = re;  | 
 | 
                    continue;  | 
 | 
 | 
 | 
                } finally { | 
 | 
                      | 
 | 
                    refCtx.close();  | 
 | 
                }  | 
 | 
            }  | 
 | 
            return hasMoreImpl();  | 
 | 
 | 
 | 
        } else { | 
 | 
            cleanup();  | 
 | 
 | 
 | 
            if (errEx != null) { | 
 | 
                throw errEx;  | 
 | 
            }  | 
 | 
            return (false);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    protected void update(AbstractLdapNamingEnumeration<? extends NameClassPair> ne) { | 
 | 
          | 
 | 
        homeCtx.decEnumCount();  | 
 | 
 | 
 | 
          | 
 | 
        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  | 
 | 
          | 
 | 
        ne.homeCtx = null;  | 
 | 
 | 
 | 
          | 
 | 
        posn = ne.posn;  | 
 | 
        limit = ne.limit;  | 
 | 
        res = ne.res;  | 
 | 
        entries = ne.entries;  | 
 | 
        refEx = ne.refEx;  | 
 | 
        listArg = ne.listArg;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected final void finalize() { | 
 | 
        cleanup();  | 
 | 
    }  | 
 | 
 | 
 | 
    protected final void cleanup() { | 
 | 
        if (cleaned) return;   | 
 | 
 | 
 | 
        if(enumClnt != null) { | 
 | 
            enumClnt.clearSearchReply(res, homeCtx.reqCtls);  | 
 | 
        }  | 
 | 
 | 
 | 
        enumClnt = null;  | 
 | 
        cleaned = true;  | 
 | 
        if (homeCtx != null) { | 
 | 
            homeCtx.decEnumCount();  | 
 | 
            homeCtx = null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public final void close() { | 
 | 
        cleanup();  | 
 | 
    }  | 
 | 
}  |