/* | 
|
 * Copyright (c) 1999, 2017, 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 ||  | 
|
handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? 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();  | 
|
}  | 
|
}  |