1/* 2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.jndi.ldap; 27 28import javax.naming.*; 29import javax.naming.ldap.Control; 30 31import java.util.Hashtable; 32import java.util.Vector; 33 34/** 35 * This exception is raised when a referral to an alternative context 36 * is encountered. 37 * <p> 38 * An {@code LdapReferralException} object contains one or more referrals. 39 * Each referral is an alternative location for the same target entry. 40 * For example, a referral may be an LDAP URL. 41 * The referrals are attempted in sequence until one is successful or 42 * all have failed. In the case of the latter then the exception generated 43 * by the final referral is recorded and presented later. 44 * <p> 45 * A referral may be skipped or may be retried. For example, in the case 46 * of an authentication error, a referral may be retried with different 47 * environment properties. 48 * <p> 49 * An {@code LdapReferralException} object may also contain a reference 50 * to a chain of unprocessed {@code LdapReferralException} objects. 51 * Once the current set of referrals have been exhausted and unprocessed 52 * {@code LdapReferralException} objects remain, then the 53 * {@code LdapReferralException} object referenced by the current 54 * object is thrown and the cycle continues. 55 * <p> 56 * If new {@code LdapReferralException} objects are generated while 57 * following an existing referral then these new objects are appended 58 * to the end of the chain of unprocessed {@code LdapReferralException} 59 * objects. 60 * <p> 61 * If an exception was recorded while processing a chain of 62 * {@code LdapReferralException} objects then it is throw once 63 * processing has completed. 64 * 65 * @author Vincent Ryan 66 */ 67final public class LdapReferralException extends 68 javax.naming.ldap.LdapReferralException { 69 private static final long serialVersionUID = 627059076356906399L; 70 71 // ----------- fields initialized in constructor --------------- 72 private int handleReferrals; 73 private Hashtable<?,?> envprops; 74 private String nextName; 75 private Control[] reqCtls; 76 77 // ----------- fields that have defaults ----------------------- 78 private Vector<?> referrals = null; // alternatives,set by setReferralInfo() 79 private int referralIndex = 0; // index into referrals 80 private int referralCount = 0; // count of referrals 81 private boolean foundEntry = false; // will stop when entry is found 82 private boolean skipThisReferral = false; 83 private int hopCount = 1; 84 private NamingException errorEx = null; 85 private String newRdn = null; 86 private boolean debug = false; 87 LdapReferralException nextReferralEx = null; // referral ex. chain 88 89 /** 90 * Constructs a new instance of LdapReferralException. 91 * @param resolvedName The part of the name that has been successfully 92 * resolved. 93 * @param resolvedObj The object to which resolution was successful. 94 * @param remainingName The remaining unresolved portion of the name. 95 * @param explanation Additional detail about this exception. 96 */ 97 LdapReferralException(Name resolvedName, 98 Object resolvedObj, 99 Name remainingName, 100 String explanation, 101 Hashtable<?,?> envprops, 102 String nextName, 103 int handleReferrals, 104 Control[] reqCtls) { 105 106 super(explanation); 107 108 if (debug) 109 System.out.println("LdapReferralException constructor"); 110 111 setResolvedName(resolvedName); 112 setResolvedObj(resolvedObj); 113 setRemainingName(remainingName); 114 this.envprops = envprops; 115 this.nextName = nextName; 116 this.handleReferrals = handleReferrals; 117 118 // If following referral, request controls are passed to referral ctx 119 this.reqCtls = 120 (handleReferrals == LdapClient.LDAP_REF_FOLLOW || 121 handleReferrals == LdapClient.LDAP_REF_FOLLOW_SCHEME ? reqCtls : null); 122 } 123 124 /** 125 * Gets a context at which to continue processing. 126 * The current environment properties are re-used. 127 */ 128 public Context getReferralContext() throws NamingException { 129 return getReferralContext(envprops, null); 130 } 131 132 /** 133 * Gets a context at which to continue processing. 134 * The supplied environment properties are used. 135 */ 136 public Context getReferralContext(Hashtable<?,?> newProps) throws 137 NamingException { 138 return getReferralContext(newProps, null); 139 } 140 141 /** 142 * Gets a context at which to continue processing. 143 * The supplied environment properties and connection controls are used. 144 */ 145 public Context getReferralContext(Hashtable<?,?> newProps, Control[] connCtls) 146 throws NamingException { 147 148 if (debug) 149 System.out.println("LdapReferralException.getReferralContext"); 150 151 LdapReferralContext refCtx = new LdapReferralContext( 152 this, newProps, connCtls, reqCtls, 153 nextName, skipThisReferral, handleReferrals); 154 155 refCtx.setHopCount(hopCount + 1); 156 157 if (skipThisReferral) { 158 skipThisReferral = false; // reset 159 } 160 return (Context)refCtx; 161 } 162 163 /** 164 * Gets referral information. 165 */ 166 public Object getReferralInfo() { 167 if (debug) { 168 System.out.println("LdapReferralException.getReferralInfo"); 169 System.out.println(" referralIndex=" + referralIndex); 170 } 171 172 if (hasMoreReferrals()) { 173 return referrals.elementAt(referralIndex); 174 } else { 175 return null; 176 } 177 } 178 179 /** 180 * Marks the current referral as one to be retried. 181 */ 182 public void retryReferral() { 183 if (debug) 184 System.out.println("LdapReferralException.retryReferral"); 185 186 if (referralIndex > 0) 187 referralIndex--; // decrement index 188 } 189 190 /** 191 * Marks the current referral as one to be ignored. 192 * Returns false when there are no referrals remaining to be processed. 193 */ 194 public boolean skipReferral() { 195 if (debug) 196 System.out.println("LdapReferralException.skipReferral"); 197 198 skipThisReferral = true; 199 200 // advance to next referral 201 try { 202 getNextReferral(); 203 } catch (ReferralException e) { 204 // mask the referral exception 205 } 206 207 return (hasMoreReferrals() || hasMoreReferralExceptions()); 208 } 209 210 211 /** 212 * Sets referral information. 213 */ 214 void setReferralInfo(Vector<?> referrals, boolean continuationRef) { 215 // %%% continuationRef is currently ignored 216 217 if (debug) 218 System.out.println("LdapReferralException.setReferralInfo"); 219 220 this.referrals = referrals; 221 referralCount = (referrals == null) ? 0 : referrals.size(); 222 223 if (debug) { 224 if (referrals != null) { 225 for (int i = 0; i < referralCount; i++) { 226 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 227 } 228 } else { 229 System.out.println("setReferralInfo : referrals == null"); 230 } 231 } 232 } 233 234 /** 235 * Gets the next referral. When the current set of referrals have 236 * been exhausted then the next referral exception is thrown, if available. 237 */ 238 String getNextReferral() throws ReferralException { 239 240 if (debug) 241 System.out.println("LdapReferralException.getNextReferral"); 242 243 if (hasMoreReferrals()) { 244 return (String)referrals.elementAt(referralIndex++); 245 } else if (hasMoreReferralExceptions()) { 246 throw nextReferralEx; 247 } else { 248 return null; 249 } 250 } 251 252 /** 253 * Appends the supplied (chain of) referral exception onto the end of 254 * the current (chain of) referral exception. Spent referral exceptions 255 * are trimmed off. 256 */ 257 LdapReferralException 258 appendUnprocessedReferrals(LdapReferralException back) { 259 260 if (debug) { 261 System.out.println( 262 "LdapReferralException.appendUnprocessedReferrals"); 263 dump(); 264 if (back != null) { 265 back.dump(); 266 } 267 } 268 269 LdapReferralException front = this; 270 271 if (! front.hasMoreReferrals()) { 272 front = nextReferralEx; // trim 273 274 if ((errorEx != null) && (front != null)) { 275 front.setNamingException(errorEx); //advance the saved exception 276 } 277 } 278 279 // don't append onto itself 280 if (this == back) { 281 return front; 282 } 283 284 if ((back != null) && (! back.hasMoreReferrals())) { 285 back = back.nextReferralEx; // trim 286 } 287 288 if (back == null) { 289 return front; 290 } 291 292 // Locate the end of the current chain 293 LdapReferralException ptr = front; 294 while (ptr.nextReferralEx != null) { 295 ptr = ptr.nextReferralEx; 296 } 297 ptr.nextReferralEx = back; // append 298 299 return front; 300 } 301 302 /** 303 * Tests if there are any referrals remaining to be processed. 304 * If name resolution has already completed then any remaining 305 * referrals (in the current referral exception) will be ignored. 306 */ 307 boolean hasMoreReferrals() { 308 if (debug) 309 System.out.println("LdapReferralException.hasMoreReferrals"); 310 311 return (! foundEntry) && (referralIndex < referralCount); 312 } 313 314 /** 315 * Tests if there are any referral exceptions remaining to be processed. 316 */ 317 boolean hasMoreReferralExceptions() { 318 if (debug) 319 System.out.println( 320 "LdapReferralException.hasMoreReferralExceptions"); 321 322 return (nextReferralEx != null); 323 } 324 325 /** 326 * Sets the counter which records the number of hops that result 327 * from following a sequence of referrals. 328 */ 329 void setHopCount(int hopCount) { 330 if (debug) 331 System.out.println("LdapReferralException.setHopCount"); 332 333 this.hopCount = hopCount; 334 } 335 336 /** 337 * Sets the flag to indicate that the target name has been resolved. 338 */ 339 void setNameResolved(boolean resolved) { 340 if (debug) 341 System.out.println("LdapReferralException.setNameResolved"); 342 343 foundEntry = resolved; 344 } 345 346 /** 347 * Sets the exception generated while processing a referral. 348 * Only the first exception is recorded. 349 */ 350 void setNamingException(NamingException e) { 351 if (debug) 352 System.out.println("LdapReferralException.setNamingException"); 353 354 if (errorEx == null) { 355 e.setRootCause(this); //record the referral exception that caused it 356 errorEx = e; 357 } 358 } 359 360 /** 361 * Gets the new RDN name. 362 */ 363 String getNewRdn() { 364 if (debug) 365 System.out.println("LdapReferralException.getNewRdn"); 366 367 return newRdn; 368 } 369 370 /** 371 * Sets the new RDN name so that the rename operation can be completed 372 * (when a referral is being followed). 373 */ 374 void setNewRdn(String newRdn) { 375 if (debug) 376 System.out.println("LdapReferralException.setNewRdn"); 377 378 this.newRdn = newRdn; 379 } 380 381 /** 382 * Gets the exception generated while processing a referral. 383 */ 384 NamingException getNamingException() { 385 if (debug) 386 System.out.println("LdapReferralException.getNamingException"); 387 388 return errorEx; 389 } 390 391 /** 392 * Display the state of each element in a chain of LdapReferralException 393 * objects. 394 */ 395 void dump() { 396 397 System.out.println(); 398 System.out.println("LdapReferralException.dump"); 399 LdapReferralException ptr = this; 400 while (ptr != null) { 401 ptr.dumpState(); 402 ptr = ptr.nextReferralEx; 403 } 404 } 405 406 /** 407 * Display the state of this LdapReferralException object. 408 */ 409 private void dumpState() { 410 System.out.println("LdapReferralException.dumpState"); 411 System.out.println(" hashCode=" + hashCode()); 412 System.out.println(" foundEntry=" + foundEntry); 413 System.out.println(" skipThisReferral=" + skipThisReferral); 414 System.out.println(" referralIndex=" + referralIndex); 415 416 if (referrals != null) { 417 System.out.println(" referrals:"); 418 for (int i = 0; i < referralCount; i++) { 419 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 420 } 421 } else { 422 System.out.println(" referrals=null"); 423 } 424 425 System.out.println(" errorEx=" + errorEx); 426 427 if (nextReferralEx == null) { 428 System.out.println(" nextRefEx=null"); 429 } else { 430 System.out.println(" nextRefEx=" + nextReferralEx.hashCode()); 431 } 432 System.out.println(); 433 } 434} 435