Referrals
Manually Following Referrals
If you set the Context.REFERRAL environment property to "throw", then each referral encountered results in a ReferralException. A ReferralException contains referral information--information that describes the referral (such as a list of URLs)--and a referral context--the context to which the referral refers.Here are the steps that a program usually follows when manually handling referrals.
- Catch the exception.
- Examine the referral information by using ReferralException.getReferralInfo(). For example, ask the user whether the referral should be followed.
- If the referral is to be followed, then get the referral context by using ReferralException.getReferralContext() and reinvoke the original context method using the same arguments supplied to the original invocation.
- If the referral is not to be followed, then invoke ReferralException.skipReferral(). If this method returns true (which means that there are more referrals to be followed), then invoke ReferralException.getReferralContext() to continue. When you invoke a context method on the result, it will again throw a ReferralException for the next referral to be processed. Return to Step 1 to process it. If the method returns false, then there are no more referrals and this procedure can be terminated.
Here's an example.
For methods that return an enumeration, such as Context.list() and DirContext.search(), place the try/catch for the ReferralException around both the initial invocation and the while loop that iterates through the results. When the ReferralException is thrown, the existing enumeration becomes invalid and reinvoke the original context method to get a new enumeration. Notice also that the outer loop encloses both the method invocation on the context and the iteration of the results.// Set the referral property to throw ReferralException env.put(Context.REFERRAL, "throw"); // Create the initial context DirContext ctx = new InitialDirContext(env); // Set the controls for performing a subtree search SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Do this in a loop because you don't know how // many referrals there will be for (boolean moreReferrals = true; moreReferrals;) { try { // Perform the search NamingEnumeration answer = ctx.search("", "(objectclass=*)", ctls); // Print the answer while (answer.hasMore()) { System.out.println(">>>" + ((SearchResult)answer.next()).getName()); } // The search completes with no more referrals moreReferrals = false; } catch (ReferralException e) { if (! followReferral(e.getReferralInfo())) { moreReferrals = e.skipReferral(); } // Point to the new context if (moreReferrals) { ctx = (DirContext) e.getReferralContext(); } } }
Authenticating to a Referral Context By default, when you invoke ReferralException.getReferralContext(), the method uses the original context's environment properties, including its security-related properties, to create a connection to the referred server. Sometimes, upon examining the referral information, you might want to follow the referral by using different authentication information.
You can do this by using ReferralException.getReferralContext(env):
If the authentication fails, that is, getReferralContext(env) throws an exception, then you can reauthenticate by first calling ReferralException.retryReferral()and then repeating the getReferralContext(env) call with updated environment properties. If you do not want to retry, then invoke ReferralException.skipReferral() before calling getReferralContext(env).... } catch (ReferralException e) { ... env.put(Context.SECURITY_PRINCIPAL, "newuser"); env.put(Context.SECURITY_CREDENTIALS, "newpasswd"); ctx = e.getReferralContext(env); }Here is an example.
In this example, the e.getReferralContext(env) call is placed inside of a loop so that if the call fails, it can be retried by using different credentials. The example defines a local method, getCreds(), for getting the principal name and credentials from Standard Input to update the environment properties, env, that are being used to get the referral context. When e.getReferralContext(env) fails, the user of the application can either choose to retry by using different credentials or skip the bad referral.... } catch (ReferralException e) { if (!ask("Follow referral " + e.getReferralInfo())) { moreReferrals = e.skipReferral(); } else { // Get credentials for the referral being followed getCreds(env); } // Do this in a loop in case getReferralContext() // fails with bad authentication info. while (moreReferrals) { try { ctx = (DirContext)e.getReferralContext(env); break; // Success: got context } catch (AuthenticationException ne) { if (ask("Authentication failed. Retry")) { getCreds(env); e.retryReferral(); } else { // Give up and go on to the next referral moreReferrals = e.skipReferral(); } } catch (NamingException ne) { System.out.println("Referral failed: " + ne); // Give up and go on to the next referral moreReferrals = e.skipReferral(); } } }
Passing Request Controls to a Referral Context See the Controls and Extensions lesson for details on how to set and change request controls of a referral context.