blob: 1058d9dd92433834c0f23cfbcdcca7ff68796eb8 [file] [log] [blame]
/*
* Copyright (c) 1999, 2011, 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.ldap.Control;
import java.util.Hashtable;
import java.util.Vector;
/**
* This exception is raised when a referral to an alternative context
* is encountered.
* <p>
* An <tt>LdapReferralException</tt> object contains one or more referrals.
* Each referral is an alternative location for the same target entry.
* For example, a referral may be an LDAP URL.
* The referrals are attempted in sequence until one is successful or
* all have failed. In the case of the latter then the exception generated
* by the final referral is recorded and presented later.
* <p>
* A referral may be skipped or may be retried. For example, in the case
* of an authentication error, a referral may be retried with different
* environment properties.
* <p>
* An <tt>LdapReferralException</tt> object may also contain a reference
* to a chain of unprocessed <tt>LdapReferralException</tt> objects.
* Once the current set of referrals have been exhausted and unprocessed
* <tt>LdapReferralException</tt> objects remain, then the
* <tt>LdapReferralException</tt> object referenced by the current
* object is thrown and the cycle continues.
* <p>
* If new <tt>LdapReferralException</tt> objects are generated while
* following an existing referral then these new objects are appended
* to the end of the chain of unprocessed <tt>LdapReferralException</tt>
* objects.
* <p>
* If an exception was recorded while processing a chain of
* <tt>LdapReferralException</tt> objects then is is throw once
* processing has completed.
*
* @author Vincent Ryan
*/
final public class LdapReferralException extends
javax.naming.ldap.LdapReferralException {
private static final long serialVersionUID = 627059076356906399L;
// ----------- fields initialized in constructor ---------------
private int handleReferrals;
private Hashtable<?,?> envprops;
private String nextName;
private Control[] reqCtls;
// ----------- fields that have defaults -----------------------
private Vector<?> referrals = null; // alternatives,set by setReferralInfo()
private int referralIndex = 0; // index into referrals
private int referralCount = 0; // count of referrals
private boolean foundEntry = false; // will stop when entry is found
private boolean skipThisReferral = false;
private int hopCount = 1;
private NamingException errorEx = null;
private String newRdn = null;
private boolean debug = false;
LdapReferralException nextReferralEx = null; // referral ex. chain
/**
* Constructs a new instance of LdapReferralException.
* @param resolvedName The part of the name that has been successfully
* resolved.
* @param resolvedObj The object to which resolution was successful.
* @param remainingName The remaining unresolved portion of the name.
* @param explanation Additional detail about this exception.
*/
LdapReferralException(Name resolvedName,
Object resolvedObj,
Name remainingName,
String explanation,
Hashtable<?,?> envprops,
String nextName,
int handleReferrals,
Control[] reqCtls) {
super(explanation);
if (debug)
System.out.println("LdapReferralException constructor");
setResolvedName(resolvedName);
setResolvedObj(resolvedObj);
setRemainingName(remainingName);
this.envprops = envprops;
this.nextName = nextName;
this.handleReferrals = handleReferrals;
// If following referral, request controls are passed to referral ctx
this.reqCtls =
(handleReferrals == LdapClient.LDAP_REF_FOLLOW ? reqCtls : null);
}
/**
* Gets a context at which to continue processing.
* The current environment properties are re-used.
*/
public Context getReferralContext() throws NamingException {
return getReferralContext(envprops, null);
}
/**
* Gets a context at which to continue processing.
* The supplied environment properties are used.
*/
public Context getReferralContext(Hashtable<?,?> newProps) throws
NamingException {
return getReferralContext(newProps, null);
}
/**
* Gets a context at which to continue processing.
* The supplied environment properties and connection controls are used.
*/
public Context getReferralContext(Hashtable<?,?> newProps, Control[] connCtls)
throws NamingException {
if (debug)
System.out.println("LdapReferralException.getReferralContext");
LdapReferralContext refCtx = new LdapReferralContext(
this, newProps, connCtls, reqCtls,
nextName, skipThisReferral, handleReferrals);
refCtx.setHopCount(hopCount + 1);
if (skipThisReferral) {
skipThisReferral = false; // reset
}
return (Context)refCtx;
}
/**
* Gets referral information.
*/
public Object getReferralInfo() {
if (debug) {
System.out.println("LdapReferralException.getReferralInfo");
System.out.println(" referralIndex=" + referralIndex);
}
if (hasMoreReferrals()) {
return referrals.elementAt(referralIndex);
} else {
return null;
}
}
/**
* Marks the current referral as one to be retried.
*/
public void retryReferral() {
if (debug)
System.out.println("LdapReferralException.retryReferral");
if (referralIndex > 0)
referralIndex--; // decrement index
}
/**
* Marks the current referral as one to be ignored.
* Returns false when there are no referrals remaining to be processed.
*/
public boolean skipReferral() {
if (debug)
System.out.println("LdapReferralException.skipReferral");
skipThisReferral = true;
// advance to next referral
try {
getNextReferral();
} catch (ReferralException e) {
// mask the referral exception
}
return (hasMoreReferrals() || hasMoreReferralExceptions());
}
/**
* Sets referral information.
*/
void setReferralInfo(Vector<?> referrals, boolean continuationRef) {
// %%% continuationRef is currently ignored
if (debug)
System.out.println("LdapReferralException.setReferralInfo");
this.referrals = referrals;
referralCount = (referrals == null) ? 0 : referrals.size();
if (debug) {
if (referrals != null) {
for (int i = 0; i < referralCount; i++) {
System.out.println(" [" + i + "] " + referrals.elementAt(i));
}
} else {
System.out.println("setReferralInfo : referrals == null");
}
}
}
/**
* Gets the next referral. When the current set of referrals have
* been exhausted then the next referral exception is thrown, if available.
*/
String getNextReferral() throws ReferralException {
if (debug)
System.out.println("LdapReferralException.getNextReferral");
if (hasMoreReferrals()) {
return (String)referrals.elementAt(referralIndex++);
} else if (hasMoreReferralExceptions()) {
throw nextReferralEx;
} else {
return null;
}
}
/**
* Appends the supplied (chain of) referral exception onto the end of
* the current (chain of) referral exception. Spent referral exceptions
* are trimmed off.
*/
LdapReferralException
appendUnprocessedReferrals(LdapReferralException back) {
if (debug) {
System.out.println(
"LdapReferralException.appendUnprocessedReferrals");
dump();
if (back != null) {
back.dump();
}
}
LdapReferralException front = this;
if (! front.hasMoreReferrals()) {
front = nextReferralEx; // trim
if ((errorEx != null) && (front != null)) {
front.setNamingException(errorEx); //advance the saved exception
}
}
// don't append onto itself
if (this == back) {
return front;
}
if ((back != null) && (! back.hasMoreReferrals())) {
back = back.nextReferralEx; // trim
}
if (back == null) {
return front;
}
// Locate the end of the current chain
LdapReferralException ptr = front;
while (ptr.nextReferralEx != null) {
ptr = ptr.nextReferralEx;
}
ptr.nextReferralEx = back; // append
return front;
}
/**
* Tests if there are any referrals remaining to be processed.
* If name resolution has already completed then any remaining
* referrals (in the current referral exception) will be ignored.
*/
boolean hasMoreReferrals() {
if (debug)
System.out.println("LdapReferralException.hasMoreReferrals");
return (! foundEntry) && (referralIndex < referralCount);
}
/**
* Tests if there are any referral exceptions remaining to be processed.
*/
boolean hasMoreReferralExceptions() {
if (debug)
System.out.println(
"LdapReferralException.hasMoreReferralExceptions");
return (nextReferralEx != null);
}
/**
* Sets the counter which records the number of hops that result
* from following a sequence of referrals.
*/
void setHopCount(int hopCount) {
if (debug)
System.out.println("LdapReferralException.setHopCount");
this.hopCount = hopCount;
}
/**
* Sets the flag to indicate that the target name has been resolved.
*/
void setNameResolved(boolean resolved) {
if (debug)
System.out.println("LdapReferralException.setNameResolved");
foundEntry = resolved;
}
/**
* Sets the exception generated while processing a referral.
* Only the first exception is recorded.
*/
void setNamingException(NamingException e) {
if (debug)
System.out.println("LdapReferralException.setNamingException");
if (errorEx == null) {
e.setRootCause(this); //record the referral exception that caused it
errorEx = e;
}
}
/**
* Gets the new RDN name.
*/
String getNewRdn() {
if (debug)
System.out.println("LdapReferralException.getNewRdn");
return newRdn;
}
/**
* Sets the new RDN name so that the rename operation can be completed
* (when a referral is being followed).
*/
void setNewRdn(String newRdn) {
if (debug)
System.out.println("LdapReferralException.setNewRdn");
this.newRdn = newRdn;
}
/**
* Gets the exception generated while processing a referral.
*/
NamingException getNamingException() {
if (debug)
System.out.println("LdapReferralException.getNamingException");
return errorEx;
}
/**
* Display the state of each element in a chain of LdapReferralException
* objects.
*/
void dump() {
System.out.println();
System.out.println("LdapReferralException.dump");
LdapReferralException ptr = this;
while (ptr != null) {
ptr.dumpState();
ptr = ptr.nextReferralEx;
}
}
/**
* Display the state of this LdapReferralException object.
*/
private void dumpState() {
System.out.println("LdapReferralException.dumpState");
System.out.println(" hashCode=" + hashCode());
System.out.println(" foundEntry=" + foundEntry);
System.out.println(" skipThisReferral=" + skipThisReferral);
System.out.println(" referralIndex=" + referralIndex);
if (referrals != null) {
System.out.println(" referrals:");
for (int i = 0; i < referralCount; i++) {
System.out.println(" [" + i + "] " + referrals.elementAt(i));
}
} else {
System.out.println(" referrals=null");
}
System.out.println(" errorEx=" + errorEx);
if (nextReferralEx == null) {
System.out.println(" nextRefEx=null");
} else {
System.out.println(" nextRefEx=" + nextReferralEx.hashCode());
}
System.out.println();
}
}