View Javadoc
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 }