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 
  26 package javax.naming.spi;
  27 
  28 import java.net.MalformedURLException;
  29 import java.util.*;
  30 
  31 
  32 import javax.naming.*;
  33 import com.sun.naming.internal.VersionHelper;
  34 import com.sun.naming.internal.ResourceManager;
  35 import 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 
  63 public 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 ContinuationScope.
 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 ContinuationScope
 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 }