/* * 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. *

* An {@code LdapReferralException} 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. *

* 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. *

* An {@code LdapReferralException} object may also contain a reference * to a chain of unprocessed {@code LdapReferralException} objects. * Once the current set of referrals have been exhausted and unprocessed * {@code LdapReferralException} objects remain, then the * {@code LdapReferralException} object referenced by the current * object is thrown and the cycle continues. *

* If new {@code LdapReferralException} objects are generated while * following an existing referral then these new objects are appended * to the end of the chain of unprocessed {@code LdapReferralException} * objects. *

* If an exception was recorded while processing a chain of * {@code LdapReferralException} objects then it 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(); } }