Back to index...
/*
 * 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();
    }
}
Back to index...