1 /* 2 * Copyright (c) 1999, 2011, 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 26 package com.sun.jndi.ldap; 27 28 import javax.naming.*; 29 import javax.naming.ldap.Control; 30 31 import java.util.Hashtable; 32 import 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 */ 67 final 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 ? reqCtls : null); 121 } 122 123 /** 124 * Gets a context at which to continue processing. 125 * The current environment properties are re-used. 126 */ 127 public Context getReferralContext() throws NamingException { 128 return getReferralContext(envprops, null); 129 } 130 131 /** 132 * Gets a context at which to continue processing. 133 * The supplied environment properties are used. 134 */ 135 public Context getReferralContext(Hashtable<?,?> newProps) throws 136 NamingException { 137 return getReferralContext(newProps, null); 138 } 139 140 /** 141 * Gets a context at which to continue processing. 142 * The supplied environment properties and connection controls are used. 143 */ 144 public Context getReferralContext(Hashtable<?,?> newProps, Control[] connCtls) 145 throws NamingException { 146 147 if (debug) 148 System.out.println("LdapReferralException.getReferralContext"); 149 150 LdapReferralContext refCtx = new LdapReferralContext( 151 this, newProps, connCtls, reqCtls, 152 nextName, skipThisReferral, handleReferrals); 153 154 refCtx.setHopCount(hopCount + 1); 155 156 if (skipThisReferral) { 157 skipThisReferral = false; // reset 158 } 159 return (Context)refCtx; 160 } 161 162 /** 163 * Gets referral information. 164 */ 165 public Object getReferralInfo() { 166 if (debug) { 167 System.out.println("LdapReferralException.getReferralInfo"); 168 System.out.println(" referralIndex=" + referralIndex); 169 } 170 171 if (hasMoreReferrals()) { 172 return referrals.elementAt(referralIndex); 173 } else { 174 return null; 175 } 176 } 177 178 /** 179 * Marks the current referral as one to be retried. 180 */ 181 public void retryReferral() { 182 if (debug) 183 System.out.println("LdapReferralException.retryReferral"); 184 185 if (referralIndex > 0) 186 referralIndex--; // decrement index 187 } 188 189 /** 190 * Marks the current referral as one to be ignored. 191 * Returns false when there are no referrals remaining to be processed. 192 */ 193 public boolean skipReferral() { 194 if (debug) 195 System.out.println("LdapReferralException.skipReferral"); 196 197 skipThisReferral = true; 198 199 // advance to next referral 200 try { 201 getNextReferral(); 202 } catch (ReferralException e) { 203 // mask the referral exception 204 } 205 206 return (hasMoreReferrals() || hasMoreReferralExceptions()); 207 } 208 209 210 /** 211 * Sets referral information. 212 */ 213 void setReferralInfo(Vector<?> referrals, boolean continuationRef) { 214 // %%% continuationRef is currently ignored 215 216 if (debug) 217 System.out.println("LdapReferralException.setReferralInfo"); 218 219 this.referrals = referrals; 220 if (referrals != null) { 221 referralCount = referrals.size(); 222 } 223 224 if (debug) { 225 for (int i = 0; i < referralCount; i++) { 226 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 227 } 228 } 229 } 230 231 /** 232 * Gets the next referral. When the current set of referrals have 233 * been exhausted then the next referral exception is thrown, if available. 234 */ 235 String getNextReferral() throws ReferralException { 236 237 if (debug) 238 System.out.println("LdapReferralException.getNextReferral"); 239 240 if (hasMoreReferrals()) { 241 return (String)referrals.elementAt(referralIndex++); 242 } else if (hasMoreReferralExceptions()) { 243 throw nextReferralEx; 244 } else { 245 return null; 246 } 247 } 248 249 /** 250 * Appends the supplied (chain of) referral exception onto the end of 251 * the current (chain of) referral exception. Spent referral exceptions 252 * are trimmed off. 253 */ 254 LdapReferralException 255 appendUnprocessedReferrals(LdapReferralException back) { 256 257 if (debug) { 258 System.out.println( 259 "LdapReferralException.appendUnprocessedReferrals"); 260 dump(); 261 if (back != null) { 262 back.dump(); 263 } 264 } 265 266 LdapReferralException front = this; 267 268 if (! front.hasMoreReferrals()) { 269 front = nextReferralEx; // trim 270 271 if ((errorEx != null) && (front != null)) { 272 front.setNamingException(errorEx); //advance the saved exception 273 } 274 } 275 276 // don't append onto itself 277 if (this == back) { 278 return front; 279 } 280 281 if ((back != null) && (! back.hasMoreReferrals())) { 282 back = back.nextReferralEx; // trim 283 } 284 285 if (back == null) { 286 return front; 287 } 288 289 // Locate the end of the current chain 290 LdapReferralException ptr = front; 291 while (ptr.nextReferralEx != null) { 292 ptr = ptr.nextReferralEx; 293 } 294 ptr.nextReferralEx = back; // append 295 296 return front; 297 } 298 299 /** 300 * Tests if there are any referrals remaining to be processed. 301 * If name resolution has already completed then any remaining 302 * referrals (in the current referral exception) will be ignored. 303 */ 304 boolean hasMoreReferrals() { 305 if (debug) 306 System.out.println("LdapReferralException.hasMoreReferrals"); 307 308 return (! foundEntry) && (referralIndex < referralCount); 309 } 310 311 /** 312 * Tests if there are any referral exceptions remaining to be processed. 313 */ 314 boolean hasMoreReferralExceptions() { 315 if (debug) 316 System.out.println( 317 "LdapReferralException.hasMoreReferralExceptions"); 318 319 return (nextReferralEx != null); 320 } 321 322 /** 323 * Sets the counter which records the number of hops that result 324 * from following a sequence of referrals. 325 */ 326 void setHopCount(int hopCount) { 327 if (debug) 328 System.out.println("LdapReferralException.setHopCount"); 329 330 this.hopCount = hopCount; 331 } 332 333 /** 334 * Sets the flag to indicate that the target name has been resolved. 335 */ 336 void setNameResolved(boolean resolved) { 337 if (debug) 338 System.out.println("LdapReferralException.setNameResolved"); 339 340 foundEntry = resolved; 341 } 342 343 /** 344 * Sets the exception generated while processing a referral. 345 * Only the first exception is recorded. 346 */ 347 void setNamingException(NamingException e) { 348 if (debug) 349 System.out.println("LdapReferralException.setNamingException"); 350 351 if (errorEx == null) { 352 e.setRootCause(this); //record the referral exception that caused it 353 errorEx = e; 354 } 355 } 356 357 /** 358 * Gets the new RDN name. 359 */ 360 String getNewRdn() { 361 if (debug) 362 System.out.println("LdapReferralException.getNewRdn"); 363 364 return newRdn; 365 } 366 367 /** 368 * Sets the new RDN name so that the rename operation can be completed 369 * (when a referral is being followed). 370 */ 371 void setNewRdn(String newRdn) { 372 if (debug) 373 System.out.println("LdapReferralException.setNewRdn"); 374 375 this.newRdn = newRdn; 376 } 377 378 /** 379 * Gets the exception generated while processing a referral. 380 */ 381 NamingException getNamingException() { 382 if (debug) 383 System.out.println("LdapReferralException.getNamingException"); 384 385 return errorEx; 386 } 387 388 /** 389 * Display the state of each element in a chain of LdapReferralException 390 * objects. 391 */ 392 void dump() { 393 394 System.out.println(); 395 System.out.println("LdapReferralException.dump"); 396 LdapReferralException ptr = this; 397 while (ptr != null) { 398 ptr.dumpState(); 399 ptr = ptr.nextReferralEx; 400 } 401 } 402 403 /** 404 * Display the state of this LdapReferralException object. 405 */ 406 private void dumpState() { 407 System.out.println("LdapReferralException.dumpState"); 408 System.out.println(" hashCode=" + hashCode()); 409 System.out.println(" foundEntry=" + foundEntry); 410 System.out.println(" skipThisReferral=" + skipThisReferral); 411 System.out.println(" referralIndex=" + referralIndex); 412 413 if (referrals != null) { 414 System.out.println(" referrals:"); 415 for (int i = 0; i < referralCount; i++) { 416 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 417 } 418 } else { 419 System.out.println(" referrals=null"); 420 } 421 422 System.out.println(" errorEx=" + errorEx); 423 424 if (nextReferralEx == null) { 425 System.out.println(" nextRefEx=null"); 426 } else { 427 System.out.println(" nextRefEx=" + nextReferralEx.hashCode()); 428 } 429 System.out.println(); 430 } 431 }