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