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 referralCount = (referrals == null) ? 0 : referrals.size(); 221 222 if (debug) { 223 if (referrals != null) { 224 for (int i = 0; i < referralCount; i++) { 225 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 226 } 227 } else { 228 System.out.println("setReferralInfo : referrals == null"); 229 } 230 } 231 } 232 233 /** 234 * Gets the next referral. When the current set of referrals have 235 * been exhausted then the next referral exception is thrown, if available. 236 */ 237 String getNextReferral() throws ReferralException { 238 239 if (debug) 240 System.out.println("LdapReferralException.getNextReferral"); 241 242 if (hasMoreReferrals()) { 243 return (String)referrals.elementAt(referralIndex++); 244 } else if (hasMoreReferralExceptions()) { 245 throw nextReferralEx; 246 } else { 247 return null; 248 } 249 } 250 251 /** 252 * Appends the supplied (chain of) referral exception onto the end of 253 * the current (chain of) referral exception. Spent referral exceptions 254 * are trimmed off. 255 */ 256 LdapReferralException 257 appendUnprocessedReferrals(LdapReferralException back) { 258 259 if (debug) { 260 System.out.println( 261 "LdapReferralException.appendUnprocessedReferrals"); 262 dump(); 263 if (back != null) { 264 back.dump(); 265 } 266 } 267 268 LdapReferralException front = this; 269 270 if (! front.hasMoreReferrals()) { 271 front = nextReferralEx; // trim 272 273 if ((errorEx != null) && (front != null)) { 274 front.setNamingException(errorEx); //advance the saved exception 275 } 276 } 277 278 // don't append onto itself 279 if (this == back) { 280 return front; 281 } 282 283 if ((back != null) && (! back.hasMoreReferrals())) { 284 back = back.nextReferralEx; // trim 285 } 286 287 if (back == null) { 288 return front; 289 } 290 291 // Locate the end of the current chain 292 LdapReferralException ptr = front; 293 while (ptr.nextReferralEx != null) { 294 ptr = ptr.nextReferralEx; 295 } 296 ptr.nextReferralEx = back; // append 297 298 return front; 299 } 300 301 /** 302 * Tests if there are any referrals remaining to be processed. 303 * If name resolution has already completed then any remaining 304 * referrals (in the current referral exception) will be ignored. 305 */ 306 boolean hasMoreReferrals() { 307 if (debug) 308 System.out.println("LdapReferralException.hasMoreReferrals"); 309 310 return (! foundEntry) && (referralIndex < referralCount); 311 } 312 313 /** 314 * Tests if there are any referral exceptions remaining to be processed. 315 */ 316 boolean hasMoreReferralExceptions() { 317 if (debug) 318 System.out.println( 319 "LdapReferralException.hasMoreReferralExceptions"); 320 321 return (nextReferralEx != null); 322 } 323 324 /** 325 * Sets the counter which records the number of hops that result 326 * from following a sequence of referrals. 327 */ 328 void setHopCount(int hopCount) { 329 if (debug) 330 System.out.println("LdapReferralException.setHopCount"); 331 332 this.hopCount = hopCount; 333 } 334 335 /** 336 * Sets the flag to indicate that the target name has been resolved. 337 */ 338 void setNameResolved(boolean resolved) { 339 if (debug) 340 System.out.println("LdapReferralException.setNameResolved"); 341 342 foundEntry = resolved; 343 } 344 345 /** 346 * Sets the exception generated while processing a referral. 347 * Only the first exception is recorded. 348 */ 349 void setNamingException(NamingException e) { 350 if (debug) 351 System.out.println("LdapReferralException.setNamingException"); 352 353 if (errorEx == null) { 354 e.setRootCause(this); //record the referral exception that caused it 355 errorEx = e; 356 } 357 } 358 359 /** 360 * Gets the new RDN name. 361 */ 362 String getNewRdn() { 363 if (debug) 364 System.out.println("LdapReferralException.getNewRdn"); 365 366 return newRdn; 367 } 368 369 /** 370 * Sets the new RDN name so that the rename operation can be completed 371 * (when a referral is being followed). 372 */ 373 void setNewRdn(String newRdn) { 374 if (debug) 375 System.out.println("LdapReferralException.setNewRdn"); 376 377 this.newRdn = newRdn; 378 } 379 380 /** 381 * Gets the exception generated while processing a referral. 382 */ 383 NamingException getNamingException() { 384 if (debug) 385 System.out.println("LdapReferralException.getNamingException"); 386 387 return errorEx; 388 } 389 390 /** 391 * Display the state of each element in a chain of LdapReferralException 392 * objects. 393 */ 394 void dump() { 395 396 System.out.println(); 397 System.out.println("LdapReferralException.dump"); 398 LdapReferralException ptr = this; 399 while (ptr != null) { 400 ptr.dumpState(); 401 ptr = ptr.nextReferralEx; 402 } 403 } 404 405 /** 406 * Display the state of this LdapReferralException object. 407 */ 408 private void dumpState() { 409 System.out.println("LdapReferralException.dumpState"); 410 System.out.println(" hashCode=" + hashCode()); 411 System.out.println(" foundEntry=" + foundEntry); 412 System.out.println(" skipThisReferral=" + skipThisReferral); 413 System.out.println(" referralIndex=" + referralIndex); 414 415 if (referrals != null) { 416 System.out.println(" referrals:"); 417 for (int i = 0; i < referralCount; i++) { 418 System.out.println(" [" + i + "] " + referrals.elementAt(i)); 419 } 420 } else { 421 System.out.println(" referrals=null"); 422 } 423 424 System.out.println(" errorEx=" + errorEx); 425 426 if (nextReferralEx == null) { 427 System.out.println(" nextRefEx=null"); 428 } else { 429 System.out.println(" nextRefEx=" + nextReferralEx.hashCode()); 430 } 431 System.out.println(); 432 } 433 }