blob: 0b3a5286116ceb138250bf9e4373bdc1e949838d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jndi.ldap;
27
28import javax.naming.*;
29import javax.naming.spi.*;
30import javax.naming.ldap.Control;
31
32import java.util.Hashtable;
33import java.util.Vector;
34
35/**
36 * This exception is raised when a referral to an alternative context
37 * is encountered.
38 * <p>
39 * An <tt>LdapReferralException</tt> object contains one or more referrals.
40 * Each referral is an alternative location for the same target entry.
41 * For example, a referral may be an LDAP URL.
42 * The referrals are attempted in sequence until one is successful or
43 * all have failed. In the case of the latter then the exception generated
44 * by the final referral is recorded and presented later.
45 * <p>
46 * A referral may be skipped or may be retried. For example, in the case
47 * of an authentication error, a referral may be retried with different
48 * environment properties.
49 * <p>
50 * An <tt>LdapReferralException</tt> object may also contain a reference
51 * to a chain of unprocessed <tt>LdapReferralException</tt> objects.
52 * Once the current set of referrals have been exhausted and unprocessed
53 * <tt>LdapReferralException</tt> objects remain, then the
54 * <tt>LdapReferralException</tt> object referenced by the current
55 * object is thrown and the cycle continues.
56 * <p>
57 * If new <tt>LdapReferralException</tt> objects are generated while
58 * following an existing referral then these new objects are appended
59 * to the end of the chain of unprocessed <tt>LdapReferralException</tt>
60 * objects.
61 * <p>
62 * If an exception was recorded while processing a chain of
63 * <tt>LdapReferralException</tt> objects then is is throw once
64 * processing has completed.
65 *
66 * @author Vincent Ryan
67 */
68final public class LdapReferralException extends
69 javax.naming.ldap.LdapReferralException {
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}