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.directory.*;
  30 import javax.naming.spi.*;
  31 import javax.naming.ldap.*;
  32 
  33 import java.util.Hashtable;
  34 import java.util.StringTokenizer;
  35 import com.sun.jndi.toolkit.dir.SearchFilter;
  36 
  37 /**
  38  * A context for handling referrals.
  39  *
  40  * @author Vincent Ryan
  41  */
  42 final class LdapReferralContext implements DirContext, LdapContext {
  43 
  44     private DirContext refCtx = null;
  45     private Name urlName = null;   // override the supplied name
  46     private String urlAttrs = null;  // override attributes
  47     private String urlScope = null;  // override scope
  48     private String urlFilter = null; // override filter
  49 
  50     private LdapReferralException refEx = null;
  51     private boolean skipThisReferral = false;
  52     private int hopCount = 1;
  53     private NamingException previousEx = null;
  54 
  55     @SuppressWarnings("unchecked") // clone()
  56     LdapReferralContext(LdapReferralException ex,
  57         Hashtable<?,?> env,
  58         Control[] connCtls,
  59         Control[] reqCtls,
  60         String nextName,
  61         boolean skipThisReferral,
  62         int handleReferrals) throws NamingException {
  63 
  64         refEx = ex;
  65 
  66         if (this.skipThisReferral = skipThisReferral) {
  67             return; // don't create a DirContext for this referral
  68         }
  69 
  70         String referral;
  71 
  72         // Make copies of environment and connect controls for our own use.
  73         if (env != null) {
  74             env = (Hashtable<?,?>) env.clone();
  75             // Remove old connect controls from environment, unless we have new
  76             // ones that will override them anyway.
  77             if (connCtls == null) {
  78                 env.remove(LdapCtx.BIND_CONTROLS);
  79             }
  80         } else if (connCtls != null) {
  81             env = new Hashtable<String, Control[]>(5);
  82         }
  83         if (connCtls != null) {
  84             Control[] copiedCtls = new Control[connCtls.length];
  85             System.arraycopy(connCtls, 0, copiedCtls, 0, connCtls.length);
  86             // Add copied controls to environment, replacing any old ones.
  87             ((Hashtable<? super String, ? super Control[]>)env)
  88                     .put(LdapCtx.BIND_CONTROLS, copiedCtls);
  89         }
  90 
  91         while (true) {
  92             try {
  93                 referral = refEx.getNextReferral();
  94                 if (referral == null) {
  95                     throw (NamingException)(previousEx.fillInStackTrace());
  96                 }
  97 
  98             } catch (LdapReferralException e) {
  99 
 100                 if (handleReferrals == LdapClient.LDAP_REF_THROW) {
 101                     throw e;
 102                 } else {
 103                     refEx = e;
 104                     continue;
 105                 }
 106             }
 107 
 108             // Create a Reference containing the referral URL.
 109             Reference ref = new Reference("javax.naming.directory.DirContext",
 110                                           new StringRefAddr("URL", referral));
 111 
 112             Object obj;
 113             try {
 114                 obj = NamingManager.getObjectInstance(ref, null, null, env);
 115 
 116             } catch (NamingException e) {
 117 
 118                 if (handleReferrals == LdapClient.LDAP_REF_THROW) {
 119                     throw e;
 120                 }
 121 
 122                 // mask the exception and save it for later
 123                 previousEx = e;
 124 
 125                 // follow another referral
 126                 continue;
 127 
 128             } catch (Exception e) {
 129                 NamingException e2 =
 130                     new NamingException(
 131                         "problem generating object using object factory");
 132                 e2.setRootCause(e);
 133                 throw e2;
 134             }
 135             if (obj instanceof DirContext) {
 136                 refCtx = (DirContext)obj;
 137                 if (refCtx instanceof LdapContext && reqCtls != null) {
 138                     ((LdapContext)refCtx).setRequestControls(reqCtls);
 139                 }
 140                 initDefaults(referral, nextName);
 141 
 142                 break;
 143             } else {
 144                 NamingException ne = new NotContextException(
 145                     "Cannot create context for: " + referral);
 146                 ne.setRemainingName((new CompositeName()).add(nextName));
 147                 throw ne;
 148             }
 149         }
 150     }
 151 
 152     private void initDefaults(String referral, String nextName)
 153         throws NamingException {
 154         String urlString;
 155         try {
 156             // parse URL
 157             LdapURL url = new LdapURL(referral);
 158             urlString = url.getDN();
 159             urlAttrs = url.getAttributes();
 160             urlScope = url.getScope();
 161             urlFilter = url.getFilter();
 162 
 163         } catch (NamingException e) {
 164             // Not an LDAP URL; use original URL
 165             urlString = referral;
 166             urlAttrs = urlScope = urlFilter = null;
 167         }
 168 
 169         // reuse original name if URL DN is absent
 170         if (urlString == null) {
 171             urlString = nextName;
 172         } else {
 173             // concatenate with remaining name if URL DN is present
 174             urlString = "";
 175         }
 176 
 177         if (urlString == null) {
 178             urlName = null;
 179         } else {
 180             urlName = urlString.equals("") ? new CompositeName() :
 181                 new CompositeName().add(urlString);
 182         }
 183     }
 184 
 185 
 186     public void close() throws NamingException {
 187         if (refCtx != null) {
 188             refCtx.close();
 189             refCtx = null;
 190         }
 191         refEx = null;
 192     }
 193 
 194     void setHopCount(int hopCount) {
 195         this.hopCount = hopCount;
 196         if ((refCtx != null) && (refCtx instanceof LdapCtx)) {
 197             ((LdapCtx)refCtx).setHopCount(hopCount);
 198         }
 199     }
 200 
 201     public Object lookup(String name) throws NamingException {
 202         return lookup(toName(name));
 203     }
 204 
 205     public Object lookup(Name name) throws NamingException {
 206         if (skipThisReferral) {
 207             throw (NamingException)
 208                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 209         }
 210 
 211         return refCtx.lookup(overrideName(name));
 212     }
 213 
 214     public void bind(String name, Object obj) throws NamingException {
 215         bind(toName(name), obj);
 216     }
 217 
 218     public void bind(Name name, Object obj) throws NamingException {
 219         if (skipThisReferral) {
 220             throw (NamingException)
 221                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 222         }
 223 
 224         refCtx.bind(overrideName(name), obj);
 225     }
 226 
 227     public void rebind(String name, Object obj) throws NamingException {
 228         rebind(toName(name), obj);
 229     }
 230 
 231     public void rebind(Name name, Object obj) throws NamingException {
 232         if (skipThisReferral) {
 233             throw (NamingException)
 234                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 235         }
 236 
 237         refCtx.rebind(overrideName(name), obj);
 238     }
 239 
 240     public void unbind(String name) throws NamingException {
 241         unbind(toName(name));
 242     }
 243 
 244     public void unbind(Name name) throws NamingException {
 245         if (skipThisReferral) {
 246             throw (NamingException)
 247                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 248         }
 249 
 250         refCtx.unbind(overrideName(name));
 251     }
 252 
 253     public void rename(String oldName, String newName) throws NamingException {
 254         rename(toName(oldName), toName(newName));
 255     }
 256 
 257     public void rename(Name oldName, Name newName) throws NamingException {
 258         if (skipThisReferral) {
 259             throw (NamingException)
 260                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 261         }
 262 
 263         refCtx.rename(overrideName(oldName), toName(refEx.getNewRdn()));
 264     }
 265 
 266     public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
 267         return list(toName(name));
 268     }
 269 
 270     @SuppressWarnings("unchecked")
 271     public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
 272         if (skipThisReferral) {
 273             throw (NamingException)
 274                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 275         }
 276         try {
 277             NamingEnumeration<NameClassPair> ne = null;
 278 
 279             if (urlScope != null && urlScope.equals("base")) {
 280                 SearchControls cons = new SearchControls();
 281                 cons.setReturningObjFlag(true);
 282                 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
 283 
 284                 ne = (NamingEnumeration)
 285                         refCtx.search(overrideName(name), "(objectclass=*)", cons);
 286 
 287             } else {
 288                 ne = refCtx.list(overrideName(name));
 289             }
 290 
 291             refEx.setNameResolved(true);
 292 
 293             // append (referrals from) the exception that generated this
 294             // context to the new search results, so that referral processing
 295             // can continue
 296             ((ReferralEnumeration)ne).appendUnprocessedReferrals(refEx);
 297 
 298             return (ne);
 299 
 300         } catch (LdapReferralException e) {
 301 
 302             // append (referrals from) the exception that generated this
 303             // context to the new exception, so that referral processing
 304             // can continue
 305 
 306             e.appendUnprocessedReferrals(refEx);
 307             throw (NamingException)(e.fillInStackTrace());
 308 
 309         } catch (NamingException e) {
 310 
 311             // record the exception if there are no remaining referrals
 312             if ((refEx != null) && (! refEx.hasMoreReferrals())) {
 313                 refEx.setNamingException(e);
 314             }
 315             if ((refEx != null) &&
 316                 (refEx.hasMoreReferrals() ||
 317                  refEx.hasMoreReferralExceptions())) {
 318                 throw (NamingException)
 319                     ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 320             } else {
 321                 throw e;
 322             }
 323         }
 324     }
 325 
 326     public NamingEnumeration<Binding> listBindings(String name) throws
 327             NamingException {
 328         return listBindings(toName(name));
 329     }
 330 
 331     @SuppressWarnings("unchecked")
 332     public NamingEnumeration<Binding> listBindings(Name name) throws
 333             NamingException {
 334         if (skipThisReferral) {
 335             throw (NamingException)
 336                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 337         }
 338 
 339         try {
 340             NamingEnumeration<Binding> be = null;
 341 
 342             if (urlScope != null && urlScope.equals("base")) {
 343                 SearchControls cons = new SearchControls();
 344                 cons.setReturningObjFlag(true);
 345                 cons.setSearchScope(SearchControls.OBJECT_SCOPE);
 346 
 347                 be = (NamingEnumeration)refCtx.search(overrideName(name),
 348                         "(objectclass=*)", cons);
 349 
 350             } else {
 351                 be = refCtx.listBindings(overrideName(name));
 352             }
 353 
 354             refEx.setNameResolved(true);
 355 
 356             // append (referrals from) the exception that generated this
 357             // context to the new search results, so that referral processing
 358             // can continue
 359             ((ReferralEnumeration<Binding>)be).appendUnprocessedReferrals(refEx);
 360 
 361             return (be);
 362 
 363         } catch (LdapReferralException e) {
 364 
 365             // append (referrals from) the exception that generated this
 366             // context to the new exception, so that referral processing
 367             // can continue
 368 
 369             e.appendUnprocessedReferrals(refEx);
 370             throw (NamingException)(e.fillInStackTrace());
 371 
 372         } catch (NamingException e) {
 373 
 374             // record the exception if there are no remaining referrals
 375             if ((refEx != null) && (! refEx.hasMoreReferrals())) {
 376                 refEx.setNamingException(e);
 377             }
 378             if ((refEx != null) &&
 379                 (refEx.hasMoreReferrals() ||
 380                  refEx.hasMoreReferralExceptions())) {
 381                 throw (NamingException)
 382                     ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 383             } else {
 384                 throw e;
 385             }
 386         }
 387     }
 388 
 389     public void destroySubcontext(String name) throws NamingException {
 390         destroySubcontext(toName(name));
 391     }
 392 
 393     public void destroySubcontext(Name name) throws NamingException {
 394         if (skipThisReferral) {
 395             throw (NamingException)
 396                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 397         }
 398 
 399         refCtx.destroySubcontext(overrideName(name));
 400     }
 401 
 402     public Context createSubcontext(String name) throws NamingException {
 403         return createSubcontext(toName(name));
 404     }
 405 
 406     public Context createSubcontext(Name name) throws NamingException {
 407         if (skipThisReferral) {
 408             throw (NamingException)
 409                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 410         }
 411 
 412         return refCtx.createSubcontext(overrideName(name));
 413     }
 414 
 415     public Object lookupLink(String name) throws NamingException {
 416         return lookupLink(toName(name));
 417     }
 418 
 419     public Object lookupLink(Name name) throws NamingException {
 420         if (skipThisReferral) {
 421             throw (NamingException)
 422                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 423         }
 424 
 425         return refCtx.lookupLink(overrideName(name));
 426     }
 427 
 428     public NameParser getNameParser(String name) throws NamingException {
 429         return getNameParser(toName(name));
 430     }
 431 
 432     public NameParser getNameParser(Name name) throws NamingException {
 433         if (skipThisReferral) {
 434             throw (NamingException)
 435                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 436         }
 437 
 438         return refCtx.getNameParser(overrideName(name));
 439     }
 440 
 441     public String composeName(String name, String prefix)
 442             throws NamingException {
 443                 return composeName(toName(name), toName(prefix)).toString();
 444     }
 445 
 446     public Name composeName(Name name, Name prefix) throws NamingException {
 447         if (skipThisReferral) {
 448             throw (NamingException)
 449                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 450         }
 451         return refCtx.composeName(name, prefix);
 452     }
 453 
 454     public Object addToEnvironment(String propName, Object propVal)
 455             throws NamingException {
 456         if (skipThisReferral) {
 457             throw (NamingException)
 458                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 459         }
 460 
 461         return refCtx.addToEnvironment(propName, propVal);
 462     }
 463 
 464     public Object removeFromEnvironment(String propName)
 465             throws NamingException {
 466         if (skipThisReferral) {
 467             throw (NamingException)
 468                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 469         }
 470 
 471         return refCtx.removeFromEnvironment(propName);
 472     }
 473 
 474     public Hashtable<?,?> getEnvironment() throws NamingException {
 475         if (skipThisReferral) {
 476             throw (NamingException)
 477                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 478         }
 479 
 480         return refCtx.getEnvironment();
 481     }
 482 
 483     public Attributes getAttributes(String name) throws NamingException {
 484         return getAttributes(toName(name));
 485     }
 486 
 487     public Attributes getAttributes(Name name) throws NamingException {
 488         if (skipThisReferral) {
 489             throw (NamingException)
 490                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 491         }
 492 
 493         return refCtx.getAttributes(overrideName(name));
 494     }
 495 
 496     public Attributes getAttributes(String name, String[] attrIds)
 497             throws NamingException {
 498         return getAttributes(toName(name), attrIds);
 499     }
 500 
 501     public Attributes getAttributes(Name name, String[] attrIds)
 502             throws NamingException {
 503         if (skipThisReferral) {
 504             throw (NamingException)
 505                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 506         }
 507 
 508         return refCtx.getAttributes(overrideName(name), attrIds);
 509     }
 510 
 511     public void modifyAttributes(String name, int mod_op, Attributes attrs)
 512             throws NamingException {
 513         modifyAttributes(toName(name), mod_op, attrs);
 514     }
 515 
 516     public void modifyAttributes(Name name, int mod_op, Attributes attrs)
 517             throws NamingException {
 518         if (skipThisReferral) {
 519             throw (NamingException)
 520                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 521         }
 522 
 523         refCtx.modifyAttributes(overrideName(name), mod_op, attrs);
 524     }
 525 
 526     public void modifyAttributes(String name, ModificationItem[] mods)
 527             throws NamingException {
 528         modifyAttributes(toName(name), mods);
 529     }
 530 
 531     public void modifyAttributes(Name name, ModificationItem[] mods)
 532             throws NamingException {
 533         if (skipThisReferral) {
 534             throw (NamingException)
 535                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 536         }
 537 
 538         refCtx.modifyAttributes(overrideName(name), mods);
 539     }
 540 
 541     public void bind(String name, Object obj, Attributes attrs)
 542             throws NamingException {
 543         bind(toName(name), obj, attrs);
 544     }
 545 
 546     public void bind(Name name, Object obj, Attributes attrs)
 547             throws NamingException {
 548         if (skipThisReferral) {
 549             throw (NamingException)
 550                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 551         }
 552 
 553         refCtx.bind(overrideName(name), obj, attrs);
 554     }
 555 
 556     public void rebind(String name, Object obj, Attributes attrs)
 557             throws NamingException {
 558         rebind(toName(name), obj, attrs);
 559     }
 560 
 561     public void rebind(Name name, Object obj, Attributes attrs)
 562             throws NamingException {
 563         if (skipThisReferral) {
 564             throw (NamingException)
 565                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 566         }
 567 
 568         refCtx.rebind(overrideName(name), obj, attrs);
 569     }
 570 
 571     public DirContext createSubcontext(String name, Attributes attrs)
 572             throws NamingException {
 573         return createSubcontext(toName(name), attrs);
 574     }
 575 
 576     public DirContext createSubcontext(Name name, Attributes attrs)
 577             throws NamingException {
 578         if (skipThisReferral) {
 579             throw (NamingException)
 580                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 581         }
 582 
 583         return refCtx.createSubcontext(overrideName(name), attrs);
 584     }
 585 
 586     public DirContext getSchema(String name) throws NamingException {
 587         return getSchema(toName(name));
 588     }
 589 
 590     public DirContext getSchema(Name name) throws NamingException {
 591         if (skipThisReferral) {
 592             throw (NamingException)
 593                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 594         }
 595 
 596         return refCtx.getSchema(overrideName(name));
 597     }
 598 
 599     public DirContext getSchemaClassDefinition(String name)
 600             throws NamingException {
 601         return getSchemaClassDefinition(toName(name));
 602     }
 603 
 604     public DirContext getSchemaClassDefinition(Name name)
 605             throws NamingException {
 606         if (skipThisReferral) {
 607             throw (NamingException)
 608                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 609         }
 610 
 611       return refCtx.getSchemaClassDefinition(overrideName(name));
 612     }
 613 
 614     public NamingEnumeration<SearchResult> search(String name,
 615                                                   Attributes matchingAttributes)
 616             throws NamingException {
 617         return search(toName(name), SearchFilter.format(matchingAttributes),
 618             new SearchControls());
 619     }
 620 
 621     public NamingEnumeration<SearchResult> search(Name name,
 622                                                   Attributes matchingAttributes)
 623             throws NamingException {
 624         return search(name, SearchFilter.format(matchingAttributes),
 625             new SearchControls());
 626     }
 627 
 628     public NamingEnumeration<SearchResult> search(String name,
 629                                                   Attributes matchingAttributes,
 630                                                   String[] attributesToReturn)
 631             throws NamingException {
 632         SearchControls cons = new SearchControls();
 633         cons.setReturningAttributes(attributesToReturn);
 634 
 635         return search(toName(name), SearchFilter.format(matchingAttributes),
 636             cons);
 637     }
 638 
 639     public NamingEnumeration<SearchResult> search(Name name,
 640                                                   Attributes matchingAttributes,
 641                                                   String[] attributesToReturn)
 642             throws NamingException {
 643         SearchControls cons = new SearchControls();
 644         cons.setReturningAttributes(attributesToReturn);
 645 
 646         return search(name, SearchFilter.format(matchingAttributes), cons);
 647     }
 648 
 649     public NamingEnumeration<SearchResult> search(String name,
 650                                                   String filter,
 651                                                   SearchControls cons)
 652             throws NamingException {
 653         return search(toName(name), filter, cons);
 654     }
 655 
 656     public NamingEnumeration<SearchResult> search(Name name,
 657                                                   String filter,
 658         SearchControls cons) throws NamingException {
 659 
 660         if (skipThisReferral) {
 661             throw (NamingException)
 662                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 663         }
 664 
 665         try {
 666             NamingEnumeration<SearchResult> se =
 667                     refCtx.search(overrideName(name),
 668                                   overrideFilter(filter),
 669                                   overrideAttributesAndScope(cons));
 670 
 671             refEx.setNameResolved(true);
 672 
 673             // append (referrals from) the exception that generated this
 674             // context to the new search results, so that referral processing
 675             // can continue
 676             ((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
 677 
 678             return (se);
 679 
 680         } catch (LdapReferralException e) {
 681 
 682             // %%% VR - setNameResolved(true);
 683 
 684             // append (referrals from) the exception that generated this
 685             // context to the new exception, so that referral processing
 686             // can continue
 687 
 688             e.appendUnprocessedReferrals(refEx);
 689             throw (NamingException)(e.fillInStackTrace());
 690 
 691         } catch (NamingException e) {
 692 
 693             // record the exception if there are no remaining referrals
 694             if ((refEx != null) && (! refEx.hasMoreReferrals())) {
 695                 refEx.setNamingException(e);
 696             }
 697             if ((refEx != null) &&
 698                 (refEx.hasMoreReferrals() ||
 699                  refEx.hasMoreReferralExceptions())) {
 700                 throw (NamingException)
 701                     ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 702             } else {
 703                 throw e;
 704             }
 705         }
 706     }
 707 
 708     public NamingEnumeration<SearchResult> search(String name,
 709                                                   String filterExpr,
 710                                                   Object[] filterArgs,
 711                                                   SearchControls cons)
 712             throws NamingException {
 713         return search(toName(name), filterExpr, filterArgs, cons);
 714     }
 715 
 716     public NamingEnumeration<SearchResult> search(Name name,
 717         String filterExpr,
 718         Object[] filterArgs,
 719         SearchControls cons) throws NamingException {
 720 
 721         if (skipThisReferral) {
 722             throw (NamingException)
 723                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 724         }
 725 
 726         try {
 727             NamingEnumeration<SearchResult> se;
 728 
 729             if (urlFilter != null) {
 730                 se = refCtx.search(overrideName(name), urlFilter,
 731                 overrideAttributesAndScope(cons));
 732             } else {
 733                 se = refCtx.search(overrideName(name), filterExpr,
 734                 filterArgs, overrideAttributesAndScope(cons));
 735             }
 736 
 737             refEx.setNameResolved(true);
 738 
 739             // append (referrals from) the exception that generated this
 740             // context to the new search results, so that referral processing
 741             // can continue
 742             ((ReferralEnumeration)se).appendUnprocessedReferrals(refEx);
 743 
 744             return (se);
 745 
 746         } catch (LdapReferralException e) {
 747 
 748             // append (referrals from) the exception that generated this
 749             // context to the new exception, so that referral processing
 750             // can continue
 751 
 752             e.appendUnprocessedReferrals(refEx);
 753             throw (NamingException)(e.fillInStackTrace());
 754 
 755         } catch (NamingException e) {
 756 
 757             // record the exception if there are no remaining referrals
 758             if ((refEx != null) && (! refEx.hasMoreReferrals())) {
 759                 refEx.setNamingException(e);
 760             }
 761             if ((refEx != null) &&
 762                 (refEx.hasMoreReferrals() ||
 763                  refEx.hasMoreReferralExceptions())) {
 764                 throw (NamingException)
 765                     ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 766             } else {
 767                 throw e;
 768             }
 769         }
 770     }
 771 
 772     public String getNameInNamespace() throws NamingException {
 773         if (skipThisReferral) {
 774             throw (NamingException)
 775                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 776         }
 777         return urlName != null && !urlName.isEmpty() ? urlName.get(0) : "";
 778     }
 779 
 780     // ---------------------- LdapContext ---------------------
 781 
 782     public ExtendedResponse extendedOperation(ExtendedRequest request)
 783         throws NamingException {
 784 
 785         if (skipThisReferral) {
 786             throw (NamingException)
 787                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 788         }
 789 
 790         if (!(refCtx instanceof LdapContext)) {
 791             throw new NotContextException(
 792                 "Referral context not an instance of LdapContext");
 793         }
 794 
 795         return ((LdapContext)refCtx).extendedOperation(request);
 796     }
 797 
 798     public LdapContext newInstance(Control[] requestControls)
 799         throws NamingException {
 800 
 801         if (skipThisReferral) {
 802             throw (NamingException)
 803                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 804         }
 805 
 806         if (!(refCtx instanceof LdapContext)) {
 807             throw new NotContextException(
 808                 "Referral context not an instance of LdapContext");
 809         }
 810 
 811         return ((LdapContext)refCtx).newInstance(requestControls);
 812     }
 813 
 814     public void reconnect(Control[] connCtls) throws NamingException {
 815         if (skipThisReferral) {
 816             throw (NamingException)
 817                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 818         }
 819 
 820         if (!(refCtx instanceof LdapContext)) {
 821             throw new NotContextException(
 822                 "Referral context not an instance of LdapContext");
 823         }
 824 
 825         ((LdapContext)refCtx).reconnect(connCtls);
 826     }
 827 
 828     public Control[] getConnectControls() throws NamingException {
 829         if (skipThisReferral) {
 830             throw (NamingException)
 831                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 832         }
 833 
 834         if (!(refCtx instanceof LdapContext)) {
 835             throw new NotContextException(
 836                 "Referral context not an instance of LdapContext");
 837         }
 838 
 839         return ((LdapContext)refCtx).getConnectControls();
 840     }
 841 
 842     public void setRequestControls(Control[] requestControls)
 843         throws NamingException {
 844 
 845         if (skipThisReferral) {
 846             throw (NamingException)
 847                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 848         }
 849 
 850         if (!(refCtx instanceof LdapContext)) {
 851             throw new NotContextException(
 852                 "Referral context not an instance of LdapContext");
 853         }
 854 
 855         ((LdapContext)refCtx).setRequestControls(requestControls);
 856     }
 857 
 858     public Control[] getRequestControls() throws NamingException {
 859         if (skipThisReferral) {
 860             throw (NamingException)
 861                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 862         }
 863 
 864         if (!(refCtx instanceof LdapContext)) {
 865             throw new NotContextException(
 866                 "Referral context not an instance of LdapContext");
 867         }
 868         return ((LdapContext)refCtx).getRequestControls();
 869     }
 870 
 871     public Control[] getResponseControls() throws NamingException {
 872         if (skipThisReferral) {
 873             throw (NamingException)
 874                 ((refEx.appendUnprocessedReferrals(null)).fillInStackTrace());
 875         }
 876 
 877         if (!(refCtx instanceof LdapContext)) {
 878             throw new NotContextException(
 879                 "Referral context not an instance of LdapContext");
 880         }
 881         return ((LdapContext)refCtx).getResponseControls();
 882     }
 883 
 884     // ---------------------- Private methods  ---------------------
 885     private Name toName(String name) throws InvalidNameException {
 886         return name.equals("") ? new CompositeName() :
 887             new CompositeName().add(name);
 888     }
 889 
 890     /*
 891      * Use the DN component from the LDAP URL (if present) to override the
 892      * supplied DN.
 893      */
 894     private Name overrideName(Name name) throws InvalidNameException {
 895         return (urlName == null ? name : urlName);
 896     }
 897 
 898     /*
 899      * Use the attributes and scope components from the LDAP URL (if present)
 900      * to override the corrpesonding components supplied in SearchControls.
 901      */
 902     private SearchControls overrideAttributesAndScope(SearchControls cons) {
 903         SearchControls urlCons;
 904 
 905         if ((urlScope != null) || (urlAttrs != null)) {
 906             urlCons = new SearchControls(cons.getSearchScope(),
 907                                         cons.getCountLimit(),
 908                                         cons.getTimeLimit(),
 909                                         cons.getReturningAttributes(),
 910                                         cons.getReturningObjFlag(),
 911                                         cons.getDerefLinkFlag());
 912 
 913             if (urlScope != null) {
 914                 if (urlScope.equals("base")) {
 915                     urlCons.setSearchScope(SearchControls.OBJECT_SCOPE);
 916                 } else if (urlScope.equals("one")) {
 917                     urlCons.setSearchScope(SearchControls.ONELEVEL_SCOPE);
 918                 } else if (urlScope.equals("sub")) {
 919                     urlCons.setSearchScope(SearchControls.SUBTREE_SCOPE);
 920                 }
 921             }
 922 
 923             if (urlAttrs != null) {
 924                 StringTokenizer tokens = new StringTokenizer(urlAttrs, ",");
 925                 int count = tokens.countTokens();
 926                 String[] attrs = new String[count];
 927                 for (int i = 0; i < count; i ++) {
 928                     attrs[i] = tokens.nextToken();
 929                 }
 930                 urlCons.setReturningAttributes(attrs);
 931             }
 932 
 933             return urlCons;
 934 
 935         } else {
 936             return cons;
 937         }
 938     }
 939 
 940     /*
 941      * Use the filter component from the LDAP URL (if present) to override the
 942      * supplied filter.
 943      */
 944     private String overrideFilter(String filter) {
 945         return (urlFilter == null ? filter : urlFilter);
 946     }
 947 
 948 }