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