1/*
2 * Copyright (c) 1999, 2015, 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
26package javax.naming.spi;
27
28import java.net.MalformedURLException;
29import java.util.*;
30
31
32import javax.naming.*;
33import com.sun.naming.internal.VersionHelper;
34import com.sun.naming.internal.ResourceManager;
35import com.sun.naming.internal.FactoryEnumeration;
36
37/**
38 * This class contains methods for creating context objects
39 * and objects referred to by location information in the naming
40 * or directory service.
41 *<p>
42 * This class cannot be instantiated.  It has only static methods.
43 *<p>
44 * The mention of URL in the documentation for this class refers to
45 * a URL string as defined by RFC 1738 and its related RFCs. It is
46 * any string that conforms to the syntax described therein, and
47 * may not always have corresponding support in the java.net.URL
48 * class or Web browsers.
49 *<p>
50 * NamingManager is safe for concurrent access by multiple threads.
51 *<p>
52 * Except as otherwise noted,
53 * a {@code Name} or environment parameter
54 * passed to any method is owned by the caller.
55 * The implementation will not modify the object or keep a reference
56 * to it, although it may keep a reference to a clone or copy.
57 *
58 * @author Rosanna Lee
59 * @author Scott Seligman
60 * @since 1.3
61 */
62
63public class NamingManager {
64
65    /*
66     * Disallow anyone from creating one of these.
67     * Made package private so that DirectoryManager can subclass.
68     */
69
70    NamingManager() {}
71
72    // should be protected and package private
73    static final VersionHelper helper = VersionHelper.getVersionHelper();
74
75// --------- object factory stuff
76
77    /**
78     * Package-private; used by DirectoryManager and NamingManager.
79     */
80    private static ObjectFactoryBuilder object_factory_builder = null;
81
82    /**
83     * The ObjectFactoryBuilder determines the policy used when
84     * trying to load object factories.
85     * See getObjectInstance() and class ObjectFactory for a description
86     * of the default policy.
87     * setObjectFactoryBuilder() overrides this default policy by installing
88     * an ObjectFactoryBuilder. Subsequent object factories will
89     * be loaded and created using the installed builder.
90     *<p>
91     * The builder can only be installed if the executing thread is allowed
92     * (by the security manager's checkSetFactory() method) to do so.
93     * Once installed, the builder cannot be replaced.
94     *
95     * @param builder The factory builder to install. If null, no builder
96     *                  is installed.
97     * @exception SecurityException builder cannot be installed
98     *          for security reasons.
99     * @exception NamingException builder cannot be installed for
100     *         a non-security-related reason.
101     * @exception IllegalStateException If a factory has already been installed.
102     * @see #getObjectInstance
103     * @see ObjectFactory
104     * @see ObjectFactoryBuilder
105     * @see java.lang.SecurityManager#checkSetFactory
106     */
107    public static synchronized void setObjectFactoryBuilder(
108            ObjectFactoryBuilder builder) throws NamingException {
109        if (object_factory_builder != null)
110            throw new IllegalStateException("ObjectFactoryBuilder already set");
111
112        SecurityManager security = System.getSecurityManager();
113        if (security != null) {
114            security.checkSetFactory();
115        }
116        object_factory_builder = builder;
117    }
118
119    /**
120     * Used for accessing object factory builder.
121     */
122    static synchronized ObjectFactoryBuilder getObjectFactoryBuilder() {
123        return object_factory_builder;
124    }
125
126
127    /**
128     * Retrieves the ObjectFactory for the object identified by a reference,
129     * using the reference's factory class name and factory codebase
130     * to load in the factory's class.
131     * @param ref The non-null reference to use.
132     * @param factoryName The non-null class name of the factory.
133     * @return The object factory for the object identified by ref; null
134     * if unable to load the factory.
135     */
136    static ObjectFactory getObjectFactoryFromReference(
137        Reference ref, String factoryName)
138        throws IllegalAccessException,
139        InstantiationException,
140        MalformedURLException {
141        Class<?> clas = null;
142
143        // Try to use current class loader
144        try {
145             clas = helper.loadClass(factoryName);
146        } catch (ClassNotFoundException e) {
147            // ignore and continue
148            // e.printStackTrace();
149        }
150        // All other exceptions are passed up.
151
152        // Not in class path; try to use codebase
153        String codebase;
154        if (clas == null &&
155                (codebase = ref.getFactoryClassLocation()) != null) {
156            try {
157                clas = helper.loadClass(factoryName, codebase);
158            } catch (ClassNotFoundException e) {
159            }
160        }
161
162        @SuppressWarnings("deprecation") // Class.newInstance
163        ObjectFactory result = (clas != null) ? (ObjectFactory) clas.newInstance() : null;
164        return result;
165    }
166
167
168    /**
169     * Creates an object using the factories specified in the
170     * {@code Context.OBJECT_FACTORIES} property of the environment
171     * or of the provider resource file associated with {@code nameCtx}.
172     *
173     * @return factory created; null if cannot create
174     */
175    private static Object createObjectFromFactories(Object obj, Name name,
176            Context nameCtx, Hashtable<?,?> environment) throws Exception {
177
178        FactoryEnumeration factories = ResourceManager.getFactories(
179            Context.OBJECT_FACTORIES, environment, nameCtx);
180
181        if (factories == null)
182            return null;
183
184        // Try each factory until one succeeds
185        ObjectFactory factory;
186        Object answer = null;
187        while (answer == null && factories.hasMore()) {
188            factory = (ObjectFactory)factories.next();
189            answer = factory.getObjectInstance(obj, name, nameCtx, environment);
190        }
191        return answer;
192    }
193
194    private static String getURLScheme(String str) {
195        int colon_posn = str.indexOf(':');
196        int slash_posn = str.indexOf('/');
197
198        if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
199            return str.substring(0, colon_posn);
200        return null;
201    }
202
203    /**
204     * Creates an instance of an object for the specified object
205     * and environment.
206     * <p>
207     * If an object factory builder has been installed, it is used to
208     * create a factory for creating the object.
209     * Otherwise, the following rules are used to create the object:
210     *<ol>
211     * <li>If {@code refInfo} is a {@code Reference}
212     *    or {@code Referenceable} containing a factory class name,
213     *    use the named factory to create the object.
214     *    Return {@code refInfo} if the factory cannot be created.
215     *    Under JDK 1.1, if the factory class must be loaded from a location
216     *    specified in the reference, a {@code SecurityManager} must have
217     *    been installed or the factory creation will fail.
218     *    If an exception is encountered while creating the factory,
219     *    it is passed up to the caller.
220     * <li>If {@code refInfo} is a {@code Reference} or
221     *    {@code Referenceable} with no factory class name,
222     *    and the address or addresses are {@code StringRefAddr}s with
223     *    address type "URL",
224     *    try the URL context factory corresponding to each URL's scheme id
225     *    to create the object (see {@code getURLContext()}).
226     *    If that fails, continue to the next step.
227     * <li> Use the object factories specified in
228     *    the {@code Context.OBJECT_FACTORIES} property of the environment,
229     *    and of the provider resource file associated with
230     *    {@code nameCtx}, in that order.
231     *    The value of this property is a colon-separated list of factory
232     *    class names that are tried in order, and the first one that succeeds
233     *    in creating an object is the one used.
234     *    If none of the factories can be loaded,
235     *    return {@code refInfo}.
236     *    If an exception is encountered while creating the object, the
237     *    exception is passed up to the caller.
238     *</ol>
239     *<p>
240     * Service providers that implement the {@code DirContext}
241     * interface should use
242     * {@code DirectoryManager.getObjectInstance()}, not this method.
243     * Service providers that implement only the {@code Context}
244     * interface should use this method.
245     * <p>
246     * Note that an object factory (an object that implements the ObjectFactory
247     * interface) must be public and must have a public constructor that
248     * accepts no arguments.
249     * In cases where the factory is in a named module then it must be in a
250     * package which is exported by that module to the {@code java.naming}
251     * module.
252     * <p>
253     * The {@code name} and {@code nameCtx} parameters may
254     * optionally be used to specify the name of the object being created.
255     * {@code name} is the name of the object, relative to context
256     * {@code nameCtx}.  This information could be useful to the object
257     * factory or to the object implementation.
258     *  If there are several possible contexts from which the object
259     *  could be named -- as will often be the case -- it is up to
260     *  the caller to select one.  A good rule of thumb is to select the
261     * "deepest" context available.
262     * If {@code nameCtx} is null, {@code name} is relative
263     * to the default initial context.  If no name is being specified, the
264     * {@code name} parameter should be null.
265     *
266     * @param refInfo The possibly null object for which to create an object.
267     * @param name The name of this object relative to {@code nameCtx}.
268     *          Specifying a name is optional; if it is
269     *          omitted, {@code name} should be null.
270     * @param nameCtx The context relative to which the {@code name}
271     *          parameter is specified.  If null, {@code name} is
272     *          relative to the default initial context.
273     * @param environment The possibly null environment to
274     *          be used in the creation of the object factory and the object.
275     * @return An object created using {@code refInfo}; or
276     *          {@code refInfo} if an object cannot be created using
277     *          the algorithm described above.
278     * @exception NamingException if a naming exception was encountered
279     *  while attempting to get a URL context, or if one of the
280     *          factories accessed throws a NamingException.
281     * @exception Exception if one of the factories accessed throws an
282     *          exception, or if an error was encountered while loading
283     *          and instantiating the factory and object classes.
284     *          A factory should only throw an exception if it does not want
285     *          other factories to be used in an attempt to create an object.
286     *  See ObjectFactory.getObjectInstance().
287     * @see #getURLContext
288     * @see ObjectFactory
289     * @see ObjectFactory#getObjectInstance
290     */
291    public static Object
292        getObjectInstance(Object refInfo, Name name, Context nameCtx,
293                          Hashtable<?,?> environment)
294        throws Exception
295    {
296
297        ObjectFactory factory;
298
299        // Use builder if installed
300        ObjectFactoryBuilder builder = getObjectFactoryBuilder();
301        if (builder != null) {
302            // builder must return non-null factory
303            factory = builder.createObjectFactory(refInfo, environment);
304            return factory.getObjectInstance(refInfo, name, nameCtx,
305                environment);
306        }
307
308        // Use reference if possible
309        Reference ref = null;
310        if (refInfo instanceof Reference) {
311            ref = (Reference) refInfo;
312        } else if (refInfo instanceof Referenceable) {
313            ref = ((Referenceable)(refInfo)).getReference();
314        }
315
316        Object answer;
317
318        if (ref != null) {
319            String f = ref.getFactoryClassName();
320            if (f != null) {
321                // if reference identifies a factory, use exclusively
322
323                factory = getObjectFactoryFromReference(ref, f);
324                if (factory != null) {
325                    return factory.getObjectInstance(ref, name, nameCtx,
326                                                     environment);
327                }
328                // No factory found, so return original refInfo.
329                // Will reach this point if factory class is not in
330                // class path and reference does not contain a URL for it
331                return refInfo;
332
333            } else {
334                // if reference has no factory, check for addresses
335                // containing URLs
336
337                answer = processURLAddrs(ref, name, nameCtx, environment);
338                if (answer != null) {
339                    return answer;
340                }
341            }
342        }
343
344        // try using any specified factories
345        answer =
346            createObjectFromFactories(refInfo, name, nameCtx, environment);
347        return (answer != null) ? answer : refInfo;
348    }
349
350    /*
351     * Ref has no factory.  For each address of type "URL", try its URL
352     * context factory.  Returns null if unsuccessful in creating and
353     * invoking a factory.
354     */
355    static Object processURLAddrs(Reference ref, Name name, Context nameCtx,
356                                  Hashtable<?,?> environment)
357            throws NamingException {
358
359        for (int i = 0; i < ref.size(); i++) {
360            RefAddr addr = ref.get(i);
361            if (addr instanceof StringRefAddr &&
362                addr.getType().equalsIgnoreCase("URL")) {
363
364                String url = (String)addr.getContent();
365                Object answer = processURL(url, name, nameCtx, environment);
366                if (answer != null) {
367                    return answer;
368                }
369            }
370        }
371        return null;
372    }
373
374    private static Object processURL(Object refInfo, Name name,
375                                     Context nameCtx, Hashtable<?,?> environment)
376            throws NamingException {
377        Object answer;
378
379        // If refInfo is a URL string, try to use its URL context factory
380        // If no context found, continue to try object factories.
381        if (refInfo instanceof String) {
382            String url = (String)refInfo;
383            String scheme = getURLScheme(url);
384            if (scheme != null) {
385                answer = getURLObject(scheme, refInfo, name, nameCtx,
386                                      environment);
387                if (answer != null) {
388                    return answer;
389                }
390            }
391        }
392
393        // If refInfo is an array of URL strings,
394        // try to find a context factory for any one of its URLs.
395        // If no context found, continue to try object factories.
396        if (refInfo instanceof String[]) {
397            String[] urls = (String[])refInfo;
398            for (int i = 0; i <urls.length; i++) {
399                String scheme = getURLScheme(urls[i]);
400                if (scheme != null) {
401                    answer = getURLObject(scheme, refInfo, name, nameCtx,
402                                          environment);
403                    if (answer != null)
404                        return answer;
405                }
406            }
407        }
408        return null;
409    }
410
411
412    /**
413     * Retrieves a context identified by {@code obj}, using the specified
414     * environment.
415     * Used by ContinuationContext.
416     *
417     * @param obj       The object identifying the context.
418     * @param name      The name of the context being returned, relative to
419     *                  {@code nameCtx}, or null if no name is being
420     *                  specified.
421     *                  See the {@code getObjectInstance} method for
422     *                  details.
423     * @param nameCtx   The context relative to which {@code name} is
424     *                  specified, or null for the default initial context.
425     *                  See the {@code getObjectInstance} method for
426     *                  details.
427     * @param environment Environment specifying characteristics of the
428     *                  resulting context.
429     * @return A context identified by {@code obj}.
430     *
431     * @see #getObjectInstance
432     */
433    static Context getContext(Object obj, Name name, Context nameCtx,
434                              Hashtable<?,?> environment) throws NamingException {
435        Object answer;
436
437        if (obj instanceof Context) {
438            // %%% Ignore environment for now.  OK since method not public.
439            return (Context)obj;
440        }
441
442        try {
443            answer = getObjectInstance(obj, name, nameCtx, environment);
444        } catch (NamingException e) {
445            throw e;
446        } catch (Exception e) {
447            NamingException ne = new NamingException();
448            ne.setRootCause(e);
449            throw ne;
450        }
451
452        return (answer instanceof Context)
453            ? (Context)answer
454            : null;
455    }
456
457    // Used by ContinuationContext
458    static Resolver getResolver(Object obj, Name name, Context nameCtx,
459                                Hashtable<?,?> environment) throws NamingException {
460        Object answer;
461
462        if (obj instanceof Resolver) {
463            // %%% Ignore environment for now.  OK since method not public.
464            return (Resolver)obj;
465        }
466
467        try {
468            answer = getObjectInstance(obj, name, nameCtx, environment);
469        } catch (NamingException e) {
470            throw e;
471        } catch (Exception e) {
472            NamingException ne = new NamingException();
473            ne.setRootCause(e);
474            throw ne;
475        }
476
477        return (answer instanceof Resolver)
478            ? (Resolver)answer
479            : null;
480    }
481
482
483    /***************** URL Context implementations ***************/
484
485    /**
486     * Creates a context for the given URL scheme id.
487     * <p>
488     * The resulting context is for resolving URLs of the
489     * scheme {@code scheme}. The resulting context is not tied
490     * to a specific URL. It is able to handle arbitrary URLs with
491     * the specified scheme.
492     *<p>
493     * The class name of the factory that creates the resulting context
494     * has the naming convention <i>scheme-id</i>URLContextFactory
495     * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
496     * in the package specified as follows.
497     * The {@code Context.URL_PKG_PREFIXES} environment property (which
498     * may contain values taken from system properties,
499     * or application resource files)
500     * contains a colon-separated list of package prefixes.
501     * Each package prefix in
502     * the property is tried in the order specified to load the factory class.
503     * The default package prefix is "com.sun.jndi.url" (if none of the
504     * specified packages work, this default is tried).
505     * The complete package name is constructed using the package prefix,
506     * concatenated with the scheme id.
507     *<p>
508     * For example, if the scheme id is "ldap", and the
509     * {@code Context.URL_PKG_PREFIXES} property
510     * contains "com.widget:com.wiz.jndi",
511     * the naming manager would attempt to load the following classes
512     * until one is successfully instantiated:
513     *<ul>
514     * <li>com.widget.ldap.ldapURLContextFactory
515     *  <li>com.wiz.jndi.ldap.ldapURLContextFactory
516     *  <li>com.sun.jndi.url.ldap.ldapURLContextFactory
517     *</ul>
518     * If none of the package prefixes work, null is returned.
519     *<p>
520     * If a factory is instantiated, it is invoked with the following
521     * parameters to produce the resulting context.
522     * <p>
523     * {@code factory.getObjectInstance(null, environment);}
524     * <p>
525     * For example, invoking getObjectInstance() as shown above
526     * on a LDAP URL context factory would return a
527     * context that can resolve LDAP urls
528     * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
529     * "ldap://ldap.umich.edu/o=umich,c=us", ...).
530     *<p>
531     * Note that an object factory (an object that implements the ObjectFactory
532     * interface) must be public and must have a public constructor that
533     * accepts no arguments.
534     * In cases where the factory is in a named module then it must be in a
535     * package which is exported by that module to the {@code java.naming}
536     * module.
537     *
538     * @param scheme    The non-null scheme-id of the URLs supported by the context.
539     * @param environment The possibly null environment properties to be
540     *           used in the creation of the object factory and the context.
541     * @return A context for resolving URLs with the
542     *         scheme id {@code scheme};
543     *  {@code null} if the factory for creating the
544     *         context is not found.
545     * @exception NamingException If a naming exception occurs while creating
546     *          the context.
547     * @see #getObjectInstance
548     * @see ObjectFactory#getObjectInstance
549     */
550    public static Context getURLContext(String scheme,
551                                        Hashtable<?,?> environment)
552        throws NamingException
553    {
554        // pass in 'null' to indicate creation of generic context for scheme
555        // (i.e. not specific to a URL).
556
557            Object answer = getURLObject(scheme, null, null, null, environment);
558            if (answer instanceof Context) {
559                return (Context)answer;
560            } else {
561                return null;
562            }
563    }
564
565    private static final String defaultPkgPrefix = "com.sun.jndi.url";
566
567    /**
568     * Creates an object for the given URL scheme id using
569     * the supplied urlInfo.
570     * <p>
571     * If urlInfo is null, the result is a context for resolving URLs
572     * with the scheme id 'scheme'.
573     * If urlInfo is a URL, the result is a context named by the URL.
574     * Names passed to this context is assumed to be relative to this
575     * context (i.e. not a URL). For example, if urlInfo is
576     * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
577     * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
578     * Subsequent names that can be passed to this context will be
579     * LDAP names relative to this context (e.g. cn="Barbs Jensen").
580     * If urlInfo is an array of URLs, the URLs are assumed
581     * to be equivalent in terms of the context to which they refer.
582     * The resulting context is like that of the single URL case.
583     * If urlInfo is of any other type, that is handled by the
584     * context factory for the URL scheme.
585     * @param scheme the URL scheme id for the context
586     * @param urlInfo information used to create the context
587     * @param name name of this object relative to {@code nameCtx}
588     * @param nameCtx Context whose provider resource file will be searched
589     *          for package prefix values (or null if none)
590     * @param environment Environment properties for creating the context
591     * @see javax.naming.InitialContext
592     */
593    private static Object getURLObject(String scheme, Object urlInfo,
594                                       Name name, Context nameCtx,
595                                       Hashtable<?,?> environment)
596            throws NamingException {
597
598        // e.g. "ftpURLContextFactory"
599        ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
600            Context.URL_PKG_PREFIXES, environment, nameCtx,
601            "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
602
603        if (factory == null)
604          return null;
605
606        // Found object factory
607        try {
608            return factory.getObjectInstance(urlInfo, name, nameCtx, environment);
609        } catch (NamingException e) {
610            throw e;
611        } catch (Exception e) {
612            NamingException ne = new NamingException();
613            ne.setRootCause(e);
614            throw ne;
615        }
616
617    }
618
619
620// ------------ Initial Context Factory Stuff
621    private static InitialContextFactoryBuilder initctx_factory_builder = null;
622
623    /**
624     * Use this method for accessing initctx_factory_builder while
625     * inside an unsynchronized method.
626     */
627    private static synchronized InitialContextFactoryBuilder
628    getInitialContextFactoryBuilder() {
629        return initctx_factory_builder;
630    }
631
632    /**
633     * Creates an initial context using the specified environment
634     * properties.
635     * <p>
636     * This is done as follows:
637     * <ul>
638     * <li>If an InitialContextFactoryBuilder has been installed,
639     *     it is used to create the factory for creating the initial
640     *     context</li>
641     * <li>Otherwise, the class specified in the
642     *     {@code Context.INITIAL_CONTEXT_FACTORY} environment property
643     *     is used
644     *     <ul>
645     *     <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}
646     *         mechanism tries to locate an {@code InitialContextFactory}
647     *         provider using the current thread's context class loader</li>
648     *     <li>Failing that, this implementation tries to locate a suitable
649     *         {@code InitialContextFactory} using a built-in mechanism
650     *         <br>
651     *         (Note that an initial context factory (an object that implements
652     *         the InitialContextFactory interface) must be public and must have
653     *         a public constructor that accepts no arguments.
654     *         In cases where the factory is in a named module then it must
655     *         be in a package which is exported by that module to the
656     *         {@code java.naming} module.)</li>
657     *     </ul>
658     * </li>
659     * </ul>
660     * @param env The possibly null environment properties used when
661     *                  creating the context.
662     * @return A non-null initial context.
663     * @exception NoInitialContextException If the
664     *          {@code Context.INITIAL_CONTEXT_FACTORY} property
665     *         is not found or names a nonexistent
666     *         class or a class that cannot be instantiated,
667     *          or if the initial context could not be created for some other
668     *          reason.
669     * @exception NamingException If some other naming exception was encountered.
670     * @see javax.naming.InitialContext
671     * @see javax.naming.directory.InitialDirContext
672     */
673    public static Context getInitialContext(Hashtable<?,?> env)
674        throws NamingException {
675        InitialContextFactory factory = null;
676
677        InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
678        if (builder == null) {
679            // No builder installed, use property
680            // Get initial context factory class name
681
682            String className = env != null ?
683                (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
684            if (className == null) {
685                NoInitialContextException ne = new NoInitialContextException(
686                    "Need to specify class name in environment or system " +
687                    "property, or in an application resource file: " +
688                    Context.INITIAL_CONTEXT_FACTORY);
689                throw ne;
690            }
691
692            ServiceLoader<InitialContextFactory> loader =
693                    ServiceLoader.load(InitialContextFactory.class);
694
695            Iterator<InitialContextFactory> iterator = loader.iterator();
696            try {
697                while (iterator.hasNext()) {
698                    InitialContextFactory f = iterator.next();
699                    if (f.getClass().getName().equals(className)) {
700                        factory = f;
701                        break;
702                    }
703                }
704            } catch (ServiceConfigurationError e) {
705                NoInitialContextException ne =
706                        new NoInitialContextException(
707                                "Cannot load initial context factory "
708                                        + "'" + className + "'");
709                ne.setRootCause(e);
710                throw ne;
711            }
712
713            if (factory == null) {
714                try {
715                    @SuppressWarnings("deprecation")
716                    Object o = helper.loadClass(className).newInstance();
717                    factory = (InitialContextFactory) o;
718                } catch (Exception e) {
719                    NoInitialContextException ne =
720                            new NoInitialContextException(
721                                    "Cannot instantiate class: " + className);
722                    ne.setRootCause(e);
723                    throw ne;
724                }
725            }
726        } else {
727            factory = builder.createInitialContextFactory(env);
728        }
729
730        return factory.getInitialContext(env);
731    }
732
733
734    /**
735     * Sets the InitialContextFactory builder to be builder.
736     *
737     *<p>
738     * The builder can only be installed if the executing thread is allowed by
739     * the security manager to do so. Once installed, the builder cannot
740     * be replaced.
741     * @param builder The initial context factory builder to install. If null,
742     *                no builder is set.
743     * @exception SecurityException builder cannot be installed for security
744     *                  reasons.
745     * @exception NamingException builder cannot be installed for
746     *         a non-security-related reason.
747     * @exception IllegalStateException If a builder was previous installed.
748     * @see #hasInitialContextFactoryBuilder
749     * @see java.lang.SecurityManager#checkSetFactory
750     */
751    public static synchronized void setInitialContextFactoryBuilder(
752        InitialContextFactoryBuilder builder)
753        throws NamingException {
754            if (initctx_factory_builder != null)
755                throw new IllegalStateException(
756                    "InitialContextFactoryBuilder already set");
757
758            SecurityManager security = System.getSecurityManager();
759            if (security != null) {
760                security.checkSetFactory();
761            }
762            initctx_factory_builder = builder;
763    }
764
765    /**
766     * Determines whether an initial context factory builder has
767     * been set.
768     * @return true if an initial context factory builder has
769     *           been set; false otherwise.
770     * @see #setInitialContextFactoryBuilder
771     */
772    public static boolean hasInitialContextFactoryBuilder() {
773        return (getInitialContextFactoryBuilder() != null);
774    }
775
776// -----  Continuation Context Stuff
777
778    /**
779     * Constant that holds the name of the environment property into
780     * which {@code getContinuationContext()} stores the value of its
781     * {@code CannotProceedException} parameter.
782     * This property is inherited by the continuation context, and may
783     * be used by that context's service provider to inspect the
784     * fields of the exception.
785     *<p>
786     * The value of this constant is "java.naming.spi.CannotProceedException".
787     *
788     * @see #getContinuationContext
789     * @since 1.3
790     */
791    public static final String CPE = "java.naming.spi.CannotProceedException";
792
793    /**
794     * Creates a context in which to continue a context operation.
795     *<p>
796     * In performing an operation on a name that spans multiple
797     * namespaces, a context from one naming system may need to pass
798     * the operation on to the next naming system.  The context
799     * implementation does this by first constructing a
800     * {@code CannotProceedException} containing information
801     * pinpointing how far it has proceeded.  It then obtains a
802     * continuation context from JNDI by calling
803     * {@code getContinuationContext}.  The context
804     * implementation should then resume the context operation by
805     * invoking the same operation on the continuation context, using
806     * the remainder of the name that has not yet been resolved.
807     *<p>
808     * Before making use of the {@code cpe} parameter, this method
809     * updates the environment associated with that object by setting
810     * the value of the property <a href="#CPE">{@code CPE}</a>
811     * to {@code cpe}.  This property will be inherited by the
812     * continuation context, and may be used by that context's
813     * service provider to inspect the fields of this exception.
814     *
815     * @param cpe
816     *          The non-null exception that triggered this continuation.
817     * @return A non-null Context object for continuing the operation.
818     * @exception NamingException If a naming exception occurred.
819     */
820    @SuppressWarnings("unchecked")
821    public static Context getContinuationContext(CannotProceedException cpe)
822            throws NamingException {
823
824        Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();
825        if (env == null) {
826            env = new Hashtable<>(7);
827        } else {
828            // Make a (shallow) copy of the environment.
829            env = (Hashtable<Object,Object>)env.clone();
830        }
831        env.put(CPE, cpe);
832
833        ContinuationContext cctx = new ContinuationContext(cpe, env);
834        return cctx.getTargetContext();
835    }
836
837// ------------ State Factory Stuff
838
839    /**
840     * Retrieves the state of an object for binding.
841     * <p>
842     * Service providers that implement the {@code DirContext} interface
843     * should use {@code DirectoryManager.getStateToBind()}, not this method.
844     * Service providers that implement only the {@code Context} interface
845     * should use this method.
846     *<p>
847     * This method uses the specified state factories in
848     * the {@code Context.STATE_FACTORIES} property from the environment
849     * properties, and from the provider resource file associated with
850     * {@code nameCtx}, in that order.
851     *    The value of this property is a colon-separated list of factory
852     *    class names that are tried in order, and the first one that succeeds
853     *    in returning the object's state is the one used.
854     * If no object's state can be retrieved in this way, return the
855     * object itself.
856     *    If an exception is encountered while retrieving the state, the
857     *    exception is passed up to the caller.
858     * <p>
859     * Note that a state factory
860     * (an object that implements the StateFactory
861     * interface) must be public and must have a public constructor that
862     * accepts no arguments.
863     * In cases where the factory is in a named module then it must be in a
864     * package which is exported by that module to the {@code java.naming}
865     * module.
866     * <p>
867     * The {@code name} and {@code nameCtx} parameters may
868     * optionally be used to specify the name of the object being created.
869     * See the description of "Name and Context Parameters" in
870     * {@link ObjectFactory#getObjectInstance
871     *          ObjectFactory.getObjectInstance()}
872     * for details.
873     * <p>
874     * This method may return a {@code Referenceable} object.  The
875     * service provider obtaining this object may choose to store it
876     * directly, or to extract its reference (using
877     * {@code Referenceable.getReference()}) and store that instead.
878     *
879     * @param obj The non-null object for which to get state to bind.
880     * @param name The name of this object relative to {@code nameCtx},
881     *          or null if no name is specified.
882     * @param nameCtx The context relative to which the {@code name}
883     *          parameter is specified, or null if {@code name} is
884     *          relative to the default initial context.
885     *  @param environment The possibly null environment to
886     *          be used in the creation of the state factory and
887     *  the object's state.
888     * @return The non-null object representing {@code obj}'s state for
889     *  binding.  It could be the object ({@code obj}) itself.
890     * @exception NamingException If one of the factories accessed throws an
891     *          exception, or if an error was encountered while loading
892     *          and instantiating the factory and object classes.
893     *          A factory should only throw an exception if it does not want
894     *          other factories to be used in an attempt to create an object.
895     *  See {@code StateFactory.getStateToBind()}.
896     * @see StateFactory
897     * @see StateFactory#getStateToBind
898     * @see DirectoryManager#getStateToBind
899     * @since 1.3
900     */
901    public static Object
902        getStateToBind(Object obj, Name name, Context nameCtx,
903                       Hashtable<?,?> environment)
904        throws NamingException
905    {
906
907        FactoryEnumeration factories = ResourceManager.getFactories(
908            Context.STATE_FACTORIES, environment, nameCtx);
909
910        if (factories == null) {
911            return obj;
912        }
913
914        // Try each factory until one succeeds
915        StateFactory factory;
916        Object answer = null;
917        while (answer == null && factories.hasMore()) {
918            factory = (StateFactory)factories.next();
919            answer = factory.getStateToBind(obj, name, nameCtx, environment);
920        }
921
922        return (answer != null) ? answer : obj;
923    }
924}
925