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