< prev index next >

src/java.naming/share/classes/javax/naming/spi/NamingManager.java

Print this page




  32 import com.sun.naming.internal.VersionHelper;
  33 import com.sun.naming.internal.ResourceManager;
  34 import com.sun.naming.internal.FactoryEnumeration;
  35 
  36 /**
  37  * This class contains methods for creating context objects
  38  * and objects referred to by location information in the naming
  39  * or directory service.
  40  *<p>
  41  * This class cannot be instantiated.  It has only static methods.
  42  *<p>
  43  * The mention of URL in the documentation for this class refers to
  44  * a URL string as defined by RFC 1738 and its related RFCs. It is
  45  * any string that conforms to the syntax described therein, and
  46  * may not always have corresponding support in the java.net.URL
  47  * class or Web browsers.
  48  *<p>
  49  * NamingManager is safe for concurrent access by multiple threads.
  50  *<p>
  51  * Except as otherwise noted,
  52  * a <tt>Name</tt> or environment parameter
  53  * passed to any method is owned by the caller.
  54  * The implementation will not modify the object or keep a reference
  55  * to it, although it may keep a reference to a clone or copy.
  56  *
  57  * @author Rosanna Lee
  58  * @author Scott Seligman
  59  * @since 1.3
  60  */
  61 
  62 public class NamingManager {
  63 
  64     /*
  65      * Disallow anyone from creating one of these.
  66      * Made package private so that DirectoryManager can subclass.
  67      */
  68 
  69     NamingManager() {}
  70 
  71     // should be protected and package private
  72     static final VersionHelper helper = VersionHelper.getVersionHelper();


 147             // e.printStackTrace();
 148         }
 149         // All other exceptions are passed up.
 150 
 151         // Not in class path; try to use codebase
 152         String codebase;
 153         if (clas == null &&
 154                 (codebase = ref.getFactoryClassLocation()) != null) {
 155             try {
 156                 clas = helper.loadClass(factoryName, codebase);
 157             } catch (ClassNotFoundException e) {
 158             }
 159         }
 160 
 161         return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
 162     }
 163 
 164 
 165     /**
 166      * Creates an object using the factories specified in the
 167      * <tt>Context.OBJECT_FACTORIES</tt> property of the environment
 168      * or of the provider resource file associated with <tt>nameCtx</tt>.
 169      *
 170      * @return factory created; null if cannot create
 171      */
 172     private static Object createObjectFromFactories(Object obj, Name name,
 173             Context nameCtx, Hashtable<?,?> environment) throws Exception {
 174 
 175         FactoryEnumeration factories = ResourceManager.getFactories(
 176             Context.OBJECT_FACTORIES, environment, nameCtx);
 177 
 178         if (factories == null)
 179             return null;
 180 
 181         // Try each factory until one succeeds
 182         ObjectFactory factory;
 183         Object answer = null;
 184         while (answer == null && factories.hasMore()) {
 185             factory = (ObjectFactory)factories.next();
 186             answer = factory.getObjectInstance(obj, name, nameCtx, environment);
 187         }
 188         return answer;
 189     }
 190 
 191     private static String getURLScheme(String str) {
 192         int colon_posn = str.indexOf(':');
 193         int slash_posn = str.indexOf('/');
 194 
 195         if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
 196             return str.substring(0, colon_posn);
 197         return null;
 198     }
 199 
 200     /**
 201      * Creates an instance of an object for the specified object
 202      * and environment.
 203      * <p>
 204      * If an object factory builder has been installed, it is used to
 205      * create a factory for creating the object.
 206      * Otherwise, the following rules are used to create the object:
 207      *<ol>
 208      * <li>If <code>refInfo</code> is a <code>Reference</code>
 209      *    or <code>Referenceable</code> containing a factory class name,
 210      *    use the named factory to create the object.
 211      *    Return <code>refInfo</code> if the factory cannot be created.
 212      *    Under JDK 1.1, if the factory class must be loaded from a location
 213      *    specified in the reference, a <tt>SecurityManager</tt> must have
 214      *    been installed or the factory creation will fail.
 215      *    If an exception is encountered while creating the factory,
 216      *    it is passed up to the caller.
 217      * <li>If <tt>refInfo</tt> is a <tt>Reference</tt> or
 218      *    <tt>Referenceable</tt> with no factory class name,
 219      *    and the address or addresses are <tt>StringRefAddr</tt>s with
 220      *    address type "URL",
 221      *    try the URL context factory corresponding to each URL's scheme id
 222      *    to create the object (see <tt>getURLContext()</tt>).
 223      *    If that fails, continue to the next step.
 224      * <li> Use the object factories specified in
 225      *    the <tt>Context.OBJECT_FACTORIES</tt> property of the environment,
 226      *    and of the provider resource file associated with
 227      *    <tt>nameCtx</tt>, in that order.
 228      *    The value of this property is a colon-separated list of factory
 229      *    class names that are tried in order, and the first one that succeeds
 230      *    in creating an object is the one used.
 231      *    If none of the factories can be loaded,
 232      *    return <code>refInfo</code>.
 233      *    If an exception is encountered while creating the object, the
 234      *    exception is passed up to the caller.
 235      *</ol>
 236      *<p>
 237      * Service providers that implement the <tt>DirContext</tt>
 238      * interface should use
 239      * <tt>DirectoryManager.getObjectInstance()</tt>, not this method.
 240      * Service providers that implement only the <tt>Context</tt>
 241      * interface should use this method.
 242      * <p>
 243      * Note that an object factory (an object that implements the ObjectFactory
 244      * interface) must be public and must have a public constructor that
 245      * accepts no arguments.
 246      * <p>
 247      * The <code>name</code> and <code>nameCtx</code> parameters may
 248      * optionally be used to specify the name of the object being created.
 249      * <code>name</code> is the name of the object, relative to context
 250      * <code>nameCtx</code>.  This information could be useful to the object
 251      * factory or to the object implementation.
 252      *  If there are several possible contexts from which the object
 253      *  could be named -- as will often be the case -- it is up to
 254      *  the caller to select one.  A good rule of thumb is to select the
 255      * "deepest" context available.
 256      * If <code>nameCtx</code> is null, <code>name</code> is relative
 257      * to the default initial context.  If no name is being specified, the
 258      * <code>name</code> parameter should be null.
 259      *
 260      * @param refInfo The possibly null object for which to create an object.
 261      * @param name The name of this object relative to <code>nameCtx</code>.
 262      *          Specifying a name is optional; if it is
 263      *          omitted, <code>name</code> should be null.
 264      * @param nameCtx The context relative to which the <code>name</code>
 265      *          parameter is specified.  If null, <code>name</code> is
 266      *          relative to the default initial context.
 267      * @param environment The possibly null environment to
 268      *          be used in the creation of the object factory and the object.
 269      * @return An object created using <code>refInfo</code>; or
 270      *          <code>refInfo</code> if an object cannot be created using
 271      *          the algorithm described above.
 272      * @exception NamingException if a naming exception was encountered
 273      *  while attempting to get a URL context, or if one of the
 274      *          factories accessed throws a NamingException.
 275      * @exception Exception if one of the factories accessed throws an
 276      *          exception, or if an error was encountered while loading
 277      *          and instantiating the factory and object classes.
 278      *          A factory should only throw an exception if it does not want
 279      *          other factories to be used in an attempt to create an object.
 280      *  See ObjectFactory.getObjectInstance().
 281      * @see #getURLContext
 282      * @see ObjectFactory
 283      * @see ObjectFactory#getObjectInstance
 284      */
 285     public static Object
 286         getObjectInstance(Object refInfo, Name name, Context nameCtx,
 287                           Hashtable<?,?> environment)
 288         throws Exception
 289     {
 290 


 387         // If refInfo is an array of URL strings,
 388         // try to find a context factory for any one of its URLs.
 389         // If no context found, continue to try object factories.
 390         if (refInfo instanceof String[]) {
 391             String[] urls = (String[])refInfo;
 392             for (int i = 0; i <urls.length; i++) {
 393                 String scheme = getURLScheme(urls[i]);
 394                 if (scheme != null) {
 395                     answer = getURLObject(scheme, refInfo, name, nameCtx,
 396                                           environment);
 397                     if (answer != null)
 398                         return answer;
 399                 }
 400             }
 401         }
 402         return null;
 403     }
 404 
 405 
 406     /**
 407      * Retrieves a context identified by <code>obj</code>, using the specified
 408      * environment.
 409      * Used by ContinuationContext.
 410      *
 411      * @param obj       The object identifying the context.
 412      * @param name      The name of the context being returned, relative to
 413      *                  <code>nameCtx</code>, or null if no name is being
 414      *                  specified.
 415      *                  See the <code>getObjectInstance</code> method for
 416      *                  details.
 417      * @param nameCtx   The context relative to which <code>name</code> is
 418      *                  specified, or null for the default initial context.
 419      *                  See the <code>getObjectInstance</code> method for
 420      *                  details.
 421      * @param environment Environment specifying characteristics of the
 422      *                  resulting context.
 423      * @return A context identified by <code>obj</code>.
 424      *
 425      * @see #getObjectInstance
 426      */
 427     static Context getContext(Object obj, Name name, Context nameCtx,
 428                               Hashtable<?,?> environment) throws NamingException {
 429         Object answer;
 430 
 431         if (obj instanceof Context) {
 432             // %%% Ignore environment for now.  OK since method not public.
 433             return (Context)obj;
 434         }
 435 
 436         try {
 437             answer = getObjectInstance(obj, name, nameCtx, environment);
 438         } catch (NamingException e) {
 439             throw e;
 440         } catch (Exception e) {
 441             NamingException ne = new NamingException();
 442             ne.setRootCause(e);
 443             throw ne;


 463         } catch (NamingException e) {
 464             throw e;
 465         } catch (Exception e) {
 466             NamingException ne = new NamingException();
 467             ne.setRootCause(e);
 468             throw ne;
 469         }
 470 
 471         return (answer instanceof Resolver)
 472             ? (Resolver)answer
 473             : null;
 474     }
 475 
 476 
 477     /***************** URL Context implementations ***************/
 478 
 479     /**
 480      * Creates a context for the given URL scheme id.
 481      * <p>
 482      * The resulting context is for resolving URLs of the
 483      * scheme <code>scheme</code>. The resulting context is not tied
 484      * to a specific URL. It is able to handle arbitrary URLs with
 485      * the specified scheme.
 486      *<p>
 487      * The class name of the factory that creates the resulting context
 488      * has the naming convention <i>scheme-id</i>URLContextFactory
 489      * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
 490      * in the package specified as follows.
 491      * The <tt>Context.URL_PKG_PREFIXES</tt> environment property (which
 492      * may contain values taken from system properties,
 493      * or application resource files)
 494      * contains a colon-separated list of package prefixes.
 495      * Each package prefix in
 496      * the property is tried in the order specified to load the factory class.
 497      * The default package prefix is "com.sun.jndi.url" (if none of the
 498      * specified packages work, this default is tried).
 499      * The complete package name is constructed using the package prefix,
 500      * concatenated with the scheme id.
 501      *<p>
 502      * For example, if the scheme id is "ldap", and the
 503      * <tt>Context.URL_PKG_PREFIXES</tt> property
 504      * contains "com.widget:com.wiz.jndi",
 505      * the naming manager would attempt to load the following classes
 506      * until one is successfully instantiated:
 507      *<ul>
 508      * <li>com.widget.ldap.ldapURLContextFactory
 509      *  <li>com.wiz.jndi.ldap.ldapURLContextFactory
 510      *  <li>com.sun.jndi.url.ldap.ldapURLContextFactory
 511      *</ul>
 512      * If none of the package prefixes work, null is returned.
 513      *<p>
 514      * If a factory is instantiated, it is invoked with the following
 515      * parameters to produce the resulting context.
 516      * <p>
 517      * <code>factory.getObjectInstance(null, environment);</code>
 518      * <p>
 519      * For example, invoking getObjectInstance() as shown above
 520      * on a LDAP URL context factory would return a
 521      * context that can resolve LDAP urls
 522      * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
 523      * "ldap://ldap.umich.edu/o=umich,c=us", ...).
 524      *<p>
 525      * Note that an object factory (an object that implements the ObjectFactory
 526      * interface) must be public and must have a public constructor that
 527      * accepts no arguments.
 528      *
 529      * @param scheme    The non-null scheme-id of the URLs supported by the context.
 530      * @param environment The possibly null environment properties to be
 531      *           used in the creation of the object factory and the context.
 532      * @return A context for resolving URLs with the
 533      *         scheme id <code>scheme</code>;
 534      *  <code>null</code> if the factory for creating the
 535      *         context is not found.
 536      * @exception NamingException If a naming exception occurs while creating
 537      *          the context.
 538      * @see #getObjectInstance
 539      * @see ObjectFactory#getObjectInstance
 540      */
 541     public static Context getURLContext(String scheme,
 542                                         Hashtable<?,?> environment)
 543         throws NamingException
 544     {
 545         // pass in 'null' to indicate creation of generic context for scheme
 546         // (i.e. not specific to a URL).
 547 
 548             Object answer = getURLObject(scheme, null, null, null, environment);
 549             if (answer instanceof Context) {
 550                 return (Context)answer;
 551             } else {
 552                 return null;
 553             }
 554     }


 558     /**
 559      * Creates an object for the given URL scheme id using
 560      * the supplied urlInfo.
 561      * <p>
 562      * If urlInfo is null, the result is a context for resolving URLs
 563      * with the scheme id 'scheme'.
 564      * If urlInfo is a URL, the result is a context named by the URL.
 565      * Names passed to this context is assumed to be relative to this
 566      * context (i.e. not a URL). For example, if urlInfo is
 567      * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
 568      * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
 569      * Subsequent names that can be passed to this context will be
 570      * LDAP names relative to this context (e.g. cn="Barbs Jensen").
 571      * If urlInfo is an array of URLs, the URLs are assumed
 572      * to be equivalent in terms of the context to which they refer.
 573      * The resulting context is like that of the single URL case.
 574      * If urlInfo is of any other type, that is handled by the
 575      * context factory for the URL scheme.
 576      * @param scheme the URL scheme id for the context
 577      * @param urlInfo information used to create the context
 578      * @param name name of this object relative to <code>nameCtx</code>
 579      * @param nameCtx Context whose provider resource file will be searched
 580      *          for package prefix values (or null if none)
 581      * @param environment Environment properties for creating the context
 582      * @see javax.naming.InitialContext
 583      */
 584     private static Object getURLObject(String scheme, Object urlInfo,
 585                                        Name name, Context nameCtx,
 586                                        Hashtable<?,?> environment)
 587             throws NamingException {
 588 
 589         // e.g. "ftpURLContextFactory"
 590         ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
 591             Context.URL_PKG_PREFIXES, environment, nameCtx,
 592             "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
 593 
 594         if (factory == null)
 595           return null;
 596 
 597         // Found object factory
 598         try {


 613 
 614     /**
 615      * Use this method for accessing initctx_factory_builder while
 616      * inside an unsynchronized method.
 617      */
 618     private static synchronized InitialContextFactoryBuilder
 619     getInitialContextFactoryBuilder() {
 620         return initctx_factory_builder;
 621     }
 622 
 623     /**
 624      * Creates an initial context using the specified environment
 625      * properties.
 626      * <p>
 627      * This is done as follows:
 628      * <ul>
 629      * <li>If an InitialContextFactoryBuilder has been installed,
 630      *     it is used to create the factory for creating the initial
 631      *     context</li>
 632      * <li>Otherwise, the class specified in the
 633      *     <tt>Context.INITIAL_CONTEXT_FACTORY</tt> environment property
 634      *     is used
 635      *     <ul>
 636      *     <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}
 637      *         mechanism tries to locate an {@code InitialContextFactory}
 638      *         provider using the current thread's context class loader</li>
 639      *     <li>Failing that, this implementation tries to locate a suitable
 640      *         {@code InitialContextFactory} using a built-in mechanism
 641      *         <br>
 642      *         (Note that an initial context factory (an object that implements
 643      *         the InitialContextFactory interface) must be public and must have
 644      *         a public constructor that accepts no arguments)</li>
 645      *     </ul>
 646      * </li>
 647      * </ul>
 648      * @param env The possibly null environment properties used when
 649      *                  creating the context.
 650      * @return A non-null initial context.
 651      * @exception NoInitialContextException If the
 652      *          <tt>Context.INITIAL_CONTEXT_FACTORY</tt> property
 653      *         is not found or names a nonexistent
 654      *         class or a class that cannot be instantiated,
 655      *          or if the initial context could not be created for some other
 656      *          reason.
 657      * @exception NamingException If some other naming exception was encountered.
 658      * @see javax.naming.InitialContext
 659      * @see javax.naming.directory.InitialDirContext
 660      */
 661     public static Context getInitialContext(Hashtable<?,?> env)
 662         throws NamingException {
 663         InitialContextFactory factory = null;
 664 
 665         InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
 666         if (builder == null) {
 667             // No builder installed, use property
 668             // Get initial context factory class name
 669 
 670             String className = env != null ?
 671                 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
 672             if (className == null) {


 747                 security.checkSetFactory();
 748             }
 749             initctx_factory_builder = builder;
 750     }
 751 
 752     /**
 753      * Determines whether an initial context factory builder has
 754      * been set.
 755      * @return true if an initial context factory builder has
 756      *           been set; false otherwise.
 757      * @see #setInitialContextFactoryBuilder
 758      */
 759     public static boolean hasInitialContextFactoryBuilder() {
 760         return (getInitialContextFactoryBuilder() != null);
 761     }
 762 
 763 // -----  Continuation Context Stuff
 764 
 765     /**
 766      * Constant that holds the name of the environment property into
 767      * which <tt>getContinuationContext()</tt> stores the value of its
 768      * <tt>CannotProceedException</tt> parameter.
 769      * This property is inherited by the continuation context, and may
 770      * be used by that context's service provider to inspect the
 771      * fields of the exception.
 772      *<p>
 773      * The value of this constant is "java.naming.spi.CannotProceedException".
 774      *
 775      * @see #getContinuationContext
 776      * @since 1.3
 777      */
 778     public static final String CPE = "java.naming.spi.CannotProceedException";
 779 
 780     /**
 781      * Creates a context in which to continue a context operation.
 782      *<p>
 783      * In performing an operation on a name that spans multiple
 784      * namespaces, a context from one naming system may need to pass
 785      * the operation on to the next naming system.  The context
 786      * implementation does this by first constructing a
 787      * <code>CannotProceedException</code> containing information
 788      * pinpointing how far it has proceeded.  It then obtains a
 789      * continuation context from JNDI by calling
 790      * <code>getContinuationContext</code>.  The context
 791      * implementation should then resume the context operation by
 792      * invoking the same operation on the continuation context, using
 793      * the remainder of the name that has not yet been resolved.
 794      *<p>
 795      * Before making use of the <tt>cpe</tt> parameter, this method
 796      * updates the environment associated with that object by setting
 797      * the value of the property <a href="#CPE"><tt>CPE</tt></a>
 798      * to <tt>cpe</tt>.  This property will be inherited by the
 799      * continuation context, and may be used by that context's
 800      * service provider to inspect the fields of this exception.
 801      *
 802      * @param cpe
 803      *          The non-null exception that triggered this continuation.
 804      * @return A non-null Context object for continuing the operation.
 805      * @exception NamingException If a naming exception occurred.
 806      */
 807     @SuppressWarnings("unchecked")
 808     public static Context getContinuationContext(CannotProceedException cpe)
 809             throws NamingException {
 810 
 811         Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();
 812         if (env == null) {
 813             env = new Hashtable<>(7);
 814         } else {
 815             // Make a (shallow) copy of the environment.
 816             env = (Hashtable<Object,Object>)env.clone();
 817         }
 818         env.put(CPE, cpe);
 819 
 820         ContinuationContext cctx = new ContinuationContext(cpe, env);
 821         return cctx.getTargetContext();
 822     }
 823 
 824 // ------------ State Factory Stuff
 825 
 826     /**
 827      * Retrieves the state of an object for binding.
 828      * <p>
 829      * Service providers that implement the <tt>DirContext</tt> interface
 830      * should use <tt>DirectoryManager.getStateToBind()</tt>, not this method.
 831      * Service providers that implement only the <tt>Context</tt> interface
 832      * should use this method.
 833      *<p>
 834      * This method uses the specified state factories in
 835      * the <tt>Context.STATE_FACTORIES</tt> property from the environment
 836      * properties, and from the provider resource file associated with
 837      * <tt>nameCtx</tt>, in that order.
 838      *    The value of this property is a colon-separated list of factory
 839      *    class names that are tried in order, and the first one that succeeds
 840      *    in returning the object's state is the one used.
 841      * If no object's state can be retrieved in this way, return the
 842      * object itself.
 843      *    If an exception is encountered while retrieving the state, the
 844      *    exception is passed up to the caller.
 845      * <p>
 846      * Note that a state factory
 847      * (an object that implements the StateFactory
 848      * interface) must be public and must have a public constructor that
 849      * accepts no arguments.
 850      * <p>
 851      * The <code>name</code> and <code>nameCtx</code> parameters may
 852      * optionally be used to specify the name of the object being created.
 853      * See the description of "Name and Context Parameters" in
 854      * {@link ObjectFactory#getObjectInstance
 855      *          ObjectFactory.getObjectInstance()}
 856      * for details.
 857      * <p>
 858      * This method may return a <tt>Referenceable</tt> object.  The
 859      * service provider obtaining this object may choose to store it
 860      * directly, or to extract its reference (using
 861      * <tt>Referenceable.getReference()</tt>) and store that instead.
 862      *
 863      * @param obj The non-null object for which to get state to bind.
 864      * @param name The name of this object relative to <code>nameCtx</code>,
 865      *          or null if no name is specified.
 866      * @param nameCtx The context relative to which the <code>name</code>
 867      *          parameter is specified, or null if <code>name</code> is
 868      *          relative to the default initial context.
 869      *  @param environment The possibly null environment to
 870      *          be used in the creation of the state factory and
 871      *  the object's state.
 872      * @return The non-null object representing <tt>obj</tt>'s state for
 873      *  binding.  It could be the object (<tt>obj</tt>) itself.
 874      * @exception NamingException If one of the factories accessed throws an
 875      *          exception, or if an error was encountered while loading
 876      *          and instantiating the factory and object classes.
 877      *          A factory should only throw an exception if it does not want
 878      *          other factories to be used in an attempt to create an object.
 879      *  See <tt>StateFactory.getStateToBind()</tt>.
 880      * @see StateFactory
 881      * @see StateFactory#getStateToBind
 882      * @see DirectoryManager#getStateToBind
 883      * @since 1.3
 884      */
 885     public static Object
 886         getStateToBind(Object obj, Name name, Context nameCtx,
 887                        Hashtable<?,?> environment)
 888         throws NamingException
 889     {
 890 
 891         FactoryEnumeration factories = ResourceManager.getFactories(
 892             Context.STATE_FACTORIES, environment, nameCtx);
 893 
 894         if (factories == null) {
 895             return obj;
 896         }
 897 
 898         // Try each factory until one succeeds
 899         StateFactory factory;


  32 import com.sun.naming.internal.VersionHelper;
  33 import com.sun.naming.internal.ResourceManager;
  34 import com.sun.naming.internal.FactoryEnumeration;
  35 
  36 /**
  37  * This class contains methods for creating context objects
  38  * and objects referred to by location information in the naming
  39  * or directory service.
  40  *<p>
  41  * This class cannot be instantiated.  It has only static methods.
  42  *<p>
  43  * The mention of URL in the documentation for this class refers to
  44  * a URL string as defined by RFC 1738 and its related RFCs. It is
  45  * any string that conforms to the syntax described therein, and
  46  * may not always have corresponding support in the java.net.URL
  47  * class or Web browsers.
  48  *<p>
  49  * NamingManager is safe for concurrent access by multiple threads.
  50  *<p>
  51  * Except as otherwise noted,
  52  * a {@code Name} or environment parameter
  53  * passed to any method is owned by the caller.
  54  * The implementation will not modify the object or keep a reference
  55  * to it, although it may keep a reference to a clone or copy.
  56  *
  57  * @author Rosanna Lee
  58  * @author Scott Seligman
  59  * @since 1.3
  60  */
  61 
  62 public class NamingManager {
  63 
  64     /*
  65      * Disallow anyone from creating one of these.
  66      * Made package private so that DirectoryManager can subclass.
  67      */
  68 
  69     NamingManager() {}
  70 
  71     // should be protected and package private
  72     static final VersionHelper helper = VersionHelper.getVersionHelper();


 147             // e.printStackTrace();
 148         }
 149         // All other exceptions are passed up.
 150 
 151         // Not in class path; try to use codebase
 152         String codebase;
 153         if (clas == null &&
 154                 (codebase = ref.getFactoryClassLocation()) != null) {
 155             try {
 156                 clas = helper.loadClass(factoryName, codebase);
 157             } catch (ClassNotFoundException e) {
 158             }
 159         }
 160 
 161         return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
 162     }
 163 
 164 
 165     /**
 166      * Creates an object using the factories specified in the
 167      * {@code Context.OBJECT_FACTORIES} property of the environment
 168      * or of the provider resource file associated with {@code nameCtx}.
 169      *
 170      * @return factory created; null if cannot create
 171      */
 172     private static Object createObjectFromFactories(Object obj, Name name,
 173             Context nameCtx, Hashtable<?,?> environment) throws Exception {
 174 
 175         FactoryEnumeration factories = ResourceManager.getFactories(
 176             Context.OBJECT_FACTORIES, environment, nameCtx);
 177 
 178         if (factories == null)
 179             return null;
 180 
 181         // Try each factory until one succeeds
 182         ObjectFactory factory;
 183         Object answer = null;
 184         while (answer == null && factories.hasMore()) {
 185             factory = (ObjectFactory)factories.next();
 186             answer = factory.getObjectInstance(obj, name, nameCtx, environment);
 187         }
 188         return answer;
 189     }
 190 
 191     private static String getURLScheme(String str) {
 192         int colon_posn = str.indexOf(':');
 193         int slash_posn = str.indexOf('/');
 194 
 195         if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
 196             return str.substring(0, colon_posn);
 197         return null;
 198     }
 199 
 200     /**
 201      * Creates an instance of an object for the specified object
 202      * and environment.
 203      * <p>
 204      * If an object factory builder has been installed, it is used to
 205      * create a factory for creating the object.
 206      * Otherwise, the following rules are used to create the object:
 207      *<ol>
 208      * <li>If {@code refInfo} is a {@code Reference}
 209      *    or {@code Referenceable} containing a factory class name,
 210      *    use the named factory to create the object.
 211      *    Return {@code refInfo} if the factory cannot be created.
 212      *    Under JDK 1.1, if the factory class must be loaded from a location
 213      *    specified in the reference, a {@code SecurityManager} must have
 214      *    been installed or the factory creation will fail.
 215      *    If an exception is encountered while creating the factory,
 216      *    it is passed up to the caller.
 217      * <li>If {@code refInfo} is a {@code Reference} or
 218      *    {@code Referenceable} with no factory class name,
 219      *    and the address or addresses are {@code StringRefAddr}s with
 220      *    address type "URL",
 221      *    try the URL context factory corresponding to each URL's scheme id
 222      *    to create the object (see {@code getURLContext()}).
 223      *    If that fails, continue to the next step.
 224      * <li> Use the object factories specified in
 225      *    the {@code Context.OBJECT_FACTORIES} property of the environment,
 226      *    and of the provider resource file associated with
 227      *    {@code nameCtx}, in that order.
 228      *    The value of this property is a colon-separated list of factory
 229      *    class names that are tried in order, and the first one that succeeds
 230      *    in creating an object is the one used.
 231      *    If none of the factories can be loaded,
 232      *    return {@code refInfo}.
 233      *    If an exception is encountered while creating the object, the
 234      *    exception is passed up to the caller.
 235      *</ol>
 236      *<p>
 237      * Service providers that implement the {@code DirContext}
 238      * interface should use
 239      * {@code DirectoryManager.getObjectInstance()}, not this method.
 240      * Service providers that implement only the {@code Context}
 241      * interface should use this method.
 242      * <p>
 243      * Note that an object factory (an object that implements the ObjectFactory
 244      * interface) must be public and must have a public constructor that
 245      * accepts no arguments.
 246      * <p>
 247      * The {@code name} and {@code nameCtx} parameters may
 248      * optionally be used to specify the name of the object being created.
 249      * {@code name} is the name of the object, relative to context
 250      * {@code nameCtx}.  This information could be useful to the object
 251      * factory or to the object implementation.
 252      *  If there are several possible contexts from which the object
 253      *  could be named -- as will often be the case -- it is up to
 254      *  the caller to select one.  A good rule of thumb is to select the
 255      * "deepest" context available.
 256      * If {@code nameCtx} is null, {@code name} is relative
 257      * to the default initial context.  If no name is being specified, the
 258      * {@code name} parameter should be null.
 259      *
 260      * @param refInfo The possibly null object for which to create an object.
 261      * @param name The name of this object relative to {@code nameCtx}.
 262      *          Specifying a name is optional; if it is
 263      *          omitted, {@code name} should be null.
 264      * @param nameCtx The context relative to which the {@code name}
 265      *          parameter is specified.  If null, {@code name} is
 266      *          relative to the default initial context.
 267      * @param environment The possibly null environment to
 268      *          be used in the creation of the object factory and the object.
 269      * @return An object created using {@code refInfo}; or
 270      *          {@code refInfo} if an object cannot be created using
 271      *          the algorithm described above.
 272      * @exception NamingException if a naming exception was encountered
 273      *  while attempting to get a URL context, or if one of the
 274      *          factories accessed throws a NamingException.
 275      * @exception Exception if one of the factories accessed throws an
 276      *          exception, or if an error was encountered while loading
 277      *          and instantiating the factory and object classes.
 278      *          A factory should only throw an exception if it does not want
 279      *          other factories to be used in an attempt to create an object.
 280      *  See ObjectFactory.getObjectInstance().
 281      * @see #getURLContext
 282      * @see ObjectFactory
 283      * @see ObjectFactory#getObjectInstance
 284      */
 285     public static Object
 286         getObjectInstance(Object refInfo, Name name, Context nameCtx,
 287                           Hashtable<?,?> environment)
 288         throws Exception
 289     {
 290 


 387         // If refInfo is an array of URL strings,
 388         // try to find a context factory for any one of its URLs.
 389         // If no context found, continue to try object factories.
 390         if (refInfo instanceof String[]) {
 391             String[] urls = (String[])refInfo;
 392             for (int i = 0; i <urls.length; i++) {
 393                 String scheme = getURLScheme(urls[i]);
 394                 if (scheme != null) {
 395                     answer = getURLObject(scheme, refInfo, name, nameCtx,
 396                                           environment);
 397                     if (answer != null)
 398                         return answer;
 399                 }
 400             }
 401         }
 402         return null;
 403     }
 404 
 405 
 406     /**
 407      * Retrieves a context identified by {@code obj}, using the specified
 408      * environment.
 409      * Used by ContinuationContext.
 410      *
 411      * @param obj       The object identifying the context.
 412      * @param name      The name of the context being returned, relative to
 413      *                  {@code nameCtx}, or null if no name is being
 414      *                  specified.
 415      *                  See the {@code getObjectInstance} method for
 416      *                  details.
 417      * @param nameCtx   The context relative to which {@code name} is
 418      *                  specified, or null for the default initial context.
 419      *                  See the {@code getObjectInstance} method for
 420      *                  details.
 421      * @param environment Environment specifying characteristics of the
 422      *                  resulting context.
 423      * @return A context identified by {@code obj}.
 424      *
 425      * @see #getObjectInstance
 426      */
 427     static Context getContext(Object obj, Name name, Context nameCtx,
 428                               Hashtable<?,?> environment) throws NamingException {
 429         Object answer;
 430 
 431         if (obj instanceof Context) {
 432             // %%% Ignore environment for now.  OK since method not public.
 433             return (Context)obj;
 434         }
 435 
 436         try {
 437             answer = getObjectInstance(obj, name, nameCtx, environment);
 438         } catch (NamingException e) {
 439             throw e;
 440         } catch (Exception e) {
 441             NamingException ne = new NamingException();
 442             ne.setRootCause(e);
 443             throw ne;


 463         } catch (NamingException e) {
 464             throw e;
 465         } catch (Exception e) {
 466             NamingException ne = new NamingException();
 467             ne.setRootCause(e);
 468             throw ne;
 469         }
 470 
 471         return (answer instanceof Resolver)
 472             ? (Resolver)answer
 473             : null;
 474     }
 475 
 476 
 477     /***************** URL Context implementations ***************/
 478 
 479     /**
 480      * Creates a context for the given URL scheme id.
 481      * <p>
 482      * The resulting context is for resolving URLs of the
 483      * scheme {@code scheme}. The resulting context is not tied
 484      * to a specific URL. It is able to handle arbitrary URLs with
 485      * the specified scheme.
 486      *<p>
 487      * The class name of the factory that creates the resulting context
 488      * has the naming convention <i>scheme-id</i>URLContextFactory
 489      * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
 490      * in the package specified as follows.
 491      * The {@code Context.URL_PKG_PREFIXES} environment property (which
 492      * may contain values taken from system properties,
 493      * or application resource files)
 494      * contains a colon-separated list of package prefixes.
 495      * Each package prefix in
 496      * the property is tried in the order specified to load the factory class.
 497      * The default package prefix is "com.sun.jndi.url" (if none of the
 498      * specified packages work, this default is tried).
 499      * The complete package name is constructed using the package prefix,
 500      * concatenated with the scheme id.
 501      *<p>
 502      * For example, if the scheme id is "ldap", and the
 503      * {@code Context.URL_PKG_PREFIXES} property
 504      * contains "com.widget:com.wiz.jndi",
 505      * the naming manager would attempt to load the following classes
 506      * until one is successfully instantiated:
 507      *<ul>
 508      * <li>com.widget.ldap.ldapURLContextFactory
 509      *  <li>com.wiz.jndi.ldap.ldapURLContextFactory
 510      *  <li>com.sun.jndi.url.ldap.ldapURLContextFactory
 511      *</ul>
 512      * If none of the package prefixes work, null is returned.
 513      *<p>
 514      * If a factory is instantiated, it is invoked with the following
 515      * parameters to produce the resulting context.
 516      * <p>
 517      * {@code factory.getObjectInstance(null, environment);}
 518      * <p>
 519      * For example, invoking getObjectInstance() as shown above
 520      * on a LDAP URL context factory would return a
 521      * context that can resolve LDAP urls
 522      * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
 523      * "ldap://ldap.umich.edu/o=umich,c=us", ...).
 524      *<p>
 525      * Note that an object factory (an object that implements the ObjectFactory
 526      * interface) must be public and must have a public constructor that
 527      * accepts no arguments.
 528      *
 529      * @param scheme    The non-null scheme-id of the URLs supported by the context.
 530      * @param environment The possibly null environment properties to be
 531      *           used in the creation of the object factory and the context.
 532      * @return A context for resolving URLs with the
 533      *         scheme id {@code scheme};
 534      *  {@code null} if the factory for creating the
 535      *         context is not found.
 536      * @exception NamingException If a naming exception occurs while creating
 537      *          the context.
 538      * @see #getObjectInstance
 539      * @see ObjectFactory#getObjectInstance
 540      */
 541     public static Context getURLContext(String scheme,
 542                                         Hashtable<?,?> environment)
 543         throws NamingException
 544     {
 545         // pass in 'null' to indicate creation of generic context for scheme
 546         // (i.e. not specific to a URL).
 547 
 548             Object answer = getURLObject(scheme, null, null, null, environment);
 549             if (answer instanceof Context) {
 550                 return (Context)answer;
 551             } else {
 552                 return null;
 553             }
 554     }


 558     /**
 559      * Creates an object for the given URL scheme id using
 560      * the supplied urlInfo.
 561      * <p>
 562      * If urlInfo is null, the result is a context for resolving URLs
 563      * with the scheme id 'scheme'.
 564      * If urlInfo is a URL, the result is a context named by the URL.
 565      * Names passed to this context is assumed to be relative to this
 566      * context (i.e. not a URL). For example, if urlInfo is
 567      * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
 568      * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
 569      * Subsequent names that can be passed to this context will be
 570      * LDAP names relative to this context (e.g. cn="Barbs Jensen").
 571      * If urlInfo is an array of URLs, the URLs are assumed
 572      * to be equivalent in terms of the context to which they refer.
 573      * The resulting context is like that of the single URL case.
 574      * If urlInfo is of any other type, that is handled by the
 575      * context factory for the URL scheme.
 576      * @param scheme the URL scheme id for the context
 577      * @param urlInfo information used to create the context
 578      * @param name name of this object relative to {@code nameCtx}
 579      * @param nameCtx Context whose provider resource file will be searched
 580      *          for package prefix values (or null if none)
 581      * @param environment Environment properties for creating the context
 582      * @see javax.naming.InitialContext
 583      */
 584     private static Object getURLObject(String scheme, Object urlInfo,
 585                                        Name name, Context nameCtx,
 586                                        Hashtable<?,?> environment)
 587             throws NamingException {
 588 
 589         // e.g. "ftpURLContextFactory"
 590         ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
 591             Context.URL_PKG_PREFIXES, environment, nameCtx,
 592             "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
 593 
 594         if (factory == null)
 595           return null;
 596 
 597         // Found object factory
 598         try {


 613 
 614     /**
 615      * Use this method for accessing initctx_factory_builder while
 616      * inside an unsynchronized method.
 617      */
 618     private static synchronized InitialContextFactoryBuilder
 619     getInitialContextFactoryBuilder() {
 620         return initctx_factory_builder;
 621     }
 622 
 623     /**
 624      * Creates an initial context using the specified environment
 625      * properties.
 626      * <p>
 627      * This is done as follows:
 628      * <ul>
 629      * <li>If an InitialContextFactoryBuilder has been installed,
 630      *     it is used to create the factory for creating the initial
 631      *     context</li>
 632      * <li>Otherwise, the class specified in the
 633      *     {@code Context.INITIAL_CONTEXT_FACTORY} environment property
 634      *     is used
 635      *     <ul>
 636      *     <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}
 637      *         mechanism tries to locate an {@code InitialContextFactory}
 638      *         provider using the current thread's context class loader</li>
 639      *     <li>Failing that, this implementation tries to locate a suitable
 640      *         {@code InitialContextFactory} using a built-in mechanism
 641      *         <br>
 642      *         (Note that an initial context factory (an object that implements
 643      *         the InitialContextFactory interface) must be public and must have
 644      *         a public constructor that accepts no arguments)</li>
 645      *     </ul>
 646      * </li>
 647      * </ul>
 648      * @param env The possibly null environment properties used when
 649      *                  creating the context.
 650      * @return A non-null initial context.
 651      * @exception NoInitialContextException If the
 652      *          {@code Context.INITIAL_CONTEXT_FACTORY} property
 653      *         is not found or names a nonexistent
 654      *         class or a class that cannot be instantiated,
 655      *          or if the initial context could not be created for some other
 656      *          reason.
 657      * @exception NamingException If some other naming exception was encountered.
 658      * @see javax.naming.InitialContext
 659      * @see javax.naming.directory.InitialDirContext
 660      */
 661     public static Context getInitialContext(Hashtable<?,?> env)
 662         throws NamingException {
 663         InitialContextFactory factory = null;
 664 
 665         InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
 666         if (builder == null) {
 667             // No builder installed, use property
 668             // Get initial context factory class name
 669 
 670             String className = env != null ?
 671                 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
 672             if (className == null) {


 747                 security.checkSetFactory();
 748             }
 749             initctx_factory_builder = builder;
 750     }
 751 
 752     /**
 753      * Determines whether an initial context factory builder has
 754      * been set.
 755      * @return true if an initial context factory builder has
 756      *           been set; false otherwise.
 757      * @see #setInitialContextFactoryBuilder
 758      */
 759     public static boolean hasInitialContextFactoryBuilder() {
 760         return (getInitialContextFactoryBuilder() != null);
 761     }
 762 
 763 // -----  Continuation Context Stuff
 764 
 765     /**
 766      * Constant that holds the name of the environment property into
 767      * which {@code getContinuationContext()} stores the value of its
 768      * {@code CannotProceedException} parameter.
 769      * This property is inherited by the continuation context, and may
 770      * be used by that context's service provider to inspect the
 771      * fields of the exception.
 772      *<p>
 773      * The value of this constant is "java.naming.spi.CannotProceedException".
 774      *
 775      * @see #getContinuationContext
 776      * @since 1.3
 777      */
 778     public static final String CPE = "java.naming.spi.CannotProceedException";
 779 
 780     /**
 781      * Creates a context in which to continue a context operation.
 782      *<p>
 783      * In performing an operation on a name that spans multiple
 784      * namespaces, a context from one naming system may need to pass
 785      * the operation on to the next naming system.  The context
 786      * implementation does this by first constructing a
 787      * {@code CannotProceedException} containing information
 788      * pinpointing how far it has proceeded.  It then obtains a
 789      * continuation context from JNDI by calling
 790      * {@code getContinuationContext}.  The context
 791      * implementation should then resume the context operation by
 792      * invoking the same operation on the continuation context, using
 793      * the remainder of the name that has not yet been resolved.
 794      *<p>
 795      * Before making use of the {@code cpe} parameter, this method
 796      * updates the environment associated with that object by setting
 797      * the value of the property <a href="#CPE">{@code CPE}</a>
 798      * to {@code cpe}.  This property will be inherited by the
 799      * continuation context, and may be used by that context's
 800      * service provider to inspect the fields of this exception.
 801      *
 802      * @param cpe
 803      *          The non-null exception that triggered this continuation.
 804      * @return A non-null Context object for continuing the operation.
 805      * @exception NamingException If a naming exception occurred.
 806      */
 807     @SuppressWarnings("unchecked")
 808     public static Context getContinuationContext(CannotProceedException cpe)
 809             throws NamingException {
 810 
 811         Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();
 812         if (env == null) {
 813             env = new Hashtable<>(7);
 814         } else {
 815             // Make a (shallow) copy of the environment.
 816             env = (Hashtable<Object,Object>)env.clone();
 817         }
 818         env.put(CPE, cpe);
 819 
 820         ContinuationContext cctx = new ContinuationContext(cpe, env);
 821         return cctx.getTargetContext();
 822     }
 823 
 824 // ------------ State Factory Stuff
 825 
 826     /**
 827      * Retrieves the state of an object for binding.
 828      * <p>
 829      * Service providers that implement the {@code DirContext} interface
 830      * should use {@code DirectoryManager.getStateToBind()}, not this method.
 831      * Service providers that implement only the {@code Context} interface
 832      * should use this method.
 833      *<p>
 834      * This method uses the specified state factories in
 835      * the {@code Context.STATE_FACTORIES} property from the environment
 836      * properties, and from the provider resource file associated with
 837      * {@code nameCtx}, in that order.
 838      *    The value of this property is a colon-separated list of factory
 839      *    class names that are tried in order, and the first one that succeeds
 840      *    in returning the object's state is the one used.
 841      * If no object's state can be retrieved in this way, return the
 842      * object itself.
 843      *    If an exception is encountered while retrieving the state, the
 844      *    exception is passed up to the caller.
 845      * <p>
 846      * Note that a state factory
 847      * (an object that implements the StateFactory
 848      * interface) must be public and must have a public constructor that
 849      * accepts no arguments.
 850      * <p>
 851      * The {@code name} and {@code nameCtx} parameters may
 852      * optionally be used to specify the name of the object being created.
 853      * See the description of "Name and Context Parameters" in
 854      * {@link ObjectFactory#getObjectInstance
 855      *          ObjectFactory.getObjectInstance()}
 856      * for details.
 857      * <p>
 858      * This method may return a {@code Referenceable} object.  The
 859      * service provider obtaining this object may choose to store it
 860      * directly, or to extract its reference (using
 861      * {@code Referenceable.getReference()}) and store that instead.
 862      *
 863      * @param obj The non-null object for which to get state to bind.
 864      * @param name The name of this object relative to {@code nameCtx},
 865      *          or null if no name is specified.
 866      * @param nameCtx The context relative to which the {@code name}
 867      *          parameter is specified, or null if {@code name} is
 868      *          relative to the default initial context.
 869      *  @param environment The possibly null environment to
 870      *          be used in the creation of the state factory and
 871      *  the object's state.
 872      * @return The non-null object representing {@code obj}'s state for
 873      *  binding.  It could be the object ({@code obj}) itself.
 874      * @exception NamingException If one of the factories accessed throws an
 875      *          exception, or if an error was encountered while loading
 876      *          and instantiating the factory and object classes.
 877      *          A factory should only throw an exception if it does not want
 878      *          other factories to be used in an attempt to create an object.
 879      *  See {@code StateFactory.getStateToBind()}.
 880      * @see StateFactory
 881      * @see StateFactory#getStateToBind
 882      * @see DirectoryManager#getStateToBind
 883      * @since 1.3
 884      */
 885     public static Object
 886         getStateToBind(Object obj, Name name, Context nameCtx,
 887                        Hashtable<?,?> environment)
 888         throws NamingException
 889     {
 890 
 891         FactoryEnumeration factories = ResourceManager.getFactories(
 892             Context.STATE_FACTORIES, environment, nameCtx);
 893 
 894         if (factories == null) {
 895             return obj;
 896         }
 897 
 898         // Try each factory until one succeeds
 899         StateFactory factory;
< prev index next >