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