|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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(); |
|
} |
|
} |