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;
  27 
  28 import java.util.Hashtable;
  29 import javax.naming.spi.NamingManager;
  30 import com.sun.naming.internal.ResourceManager;
  31 
  32 /**
  33  * This class is the starting context for performing naming operations.
  34  *<p>
  35  * All naming operations are relative to a context.
  36  * The initial context implements the Context interface and
  37  * provides the starting point for resolution of names.
  38  *<p>
  39  * <a name=ENVIRONMENT></a>
  40  * When the initial context is constructed, its environment
  41  * is initialized with properties defined in the environment parameter
  42  * passed to the constructor, and in any
  43  * <a href=Context.html#RESOURCEFILES>application resource files</a>.
  44  *<p>
  45  * JNDI determines each property's value by merging
  46  * the values from the following two sources, in order:
  47  * <ol>
  48  * <li>
  49  * The first occurrence of the property from the constructor's
  50  * environment parameter and system properties.
  51  * <li>
  52  * The application resource files (<tt>jndi.properties</tt>).
  53  * </ol>
  54  * For each property found in both of these two sources, or in
  55  * more than one application resource file, the property's value
  56  * is determined as follows.  If the property is
  57  * one of the standard JNDI properties that specify a list of JNDI
  58  * factories (see <a href=Context.html#LISTPROPS><tt>Context</tt></a>),
  59  * all of the values are
  60  * concatenated into a single colon-separated list.  For other
  61  * properties, only the first value found is used.
  62  *
  63  *<p>
  64  * The initial context implementation is determined at runtime.
  65  * The default policy uses the environment property
  66  * "{@link Context#INITIAL_CONTEXT_FACTORY java.naming.factory.initial}",
  67  * which contains the class name of the initial context factory.
  68  * An exception to this policy is made when resolving URL strings, as described
  69  * below.
  70  *<p>
  71  * When a URL string (a <tt>String</tt> of the form
  72  * <em>scheme_id:rest_of_name</em>) is passed as a name parameter to
  73  * any method, a URL context factory for handling that scheme is
  74  * located and used to resolve the URL.  If no such factory is found,
  75  * the initial context specified by
  76  * <tt>"java.naming.factory.initial"</tt> is used.  Similarly, when a
  77  * <tt>CompositeName</tt> object whose first component is a URL string is
  78  * passed as a name parameter to any method, a URL context factory is
  79  * located and used to resolve the first name component.
  80  * See {@link NamingManager#getURLContext
  81  * <tt>NamingManager.getURLContext()</tt>} for a description of how URL
  82  * context factories are located.
  83  *<p>
  84  * This default policy of locating the initial context and URL context
  85  * factories may be overridden
  86  * by calling
  87  * <tt>NamingManager.setInitialContextFactoryBuilder()</tt>.
  88  *<p>
  89  * NoInitialContextException is thrown when an initial context cannot
  90  * be instantiated. This exception can be thrown during any interaction
  91  * with the InitialContext, not only when the InitialContext is constructed.
  92  * For example, the implementation of the initial context might lazily
  93  * retrieve the context only when actual methods are invoked on it.
  94  * The application should not have any dependency on when the existence
  95  * of an initial context is determined.
  96  *<p>
  97  * When the environment property "java.naming.factory.initial" is
  98  * non-null, the InitialContext constructor will attempt to create the
  99  * initial context specified therein. At that time, the initial context factory
 100  * involved might throw an exception if a problem is encountered. However,
 101  * it is provider implementation-dependent when it verifies and indicates
 102  * to the users of the initial context any environment property- or
 103  * connection- related problems. It can do so lazily--delaying until
 104  * an operation is performed on the context, or eagerly, at the time
 105  * the context is constructed.
 106  *<p>
 107  * An InitialContext instance is not synchronized against concurrent
 108  * access by multiple threads. Multiple threads each manipulating a
 109  * different InitialContext instance need not synchronize.
 110  * Threads that need to access a single InitialContext instance
 111  * concurrently should synchronize amongst themselves and provide the
 112  * necessary locking.
 113  *
 114  * @author Rosanna Lee
 115  * @author Scott Seligman
 116  *
 117  * @see Context
 118  * @see NamingManager#setInitialContextFactoryBuilder
 119  *      NamingManager.setInitialContextFactoryBuilder
 120  * @since 1.3, JNDI 1.1
 121  */
 122 
 123 public class InitialContext implements Context {
 124 
 125     /**
 126      * The environment associated with this InitialContext.
 127      * It is initialized to null and is updated by the constructor
 128      * that accepts an environment or by the <tt>init()</tt> method.
 129      * @see #addToEnvironment
 130      * @see #removeFromEnvironment
 131      * @see #getEnvironment
 132      */
 133     protected Hashtable<Object,Object> myProps = null;
 134 
 135     /**
 136      * Field holding the result of calling NamingManager.getInitialContext().
 137      * It is set by getDefaultInitCtx() the first time getDefaultInitCtx()
 138      * is called. Subsequent invocations of getDefaultInitCtx() return
 139      * the value of defaultInitCtx.
 140      * @see #getDefaultInitCtx
 141      */
 142     protected Context defaultInitCtx = null;
 143 
 144     /**
 145      * Field indicating whether the initial context has been obtained
 146      * by calling NamingManager.getInitialContext().
 147      * If true, its result is in <code>defaultInitCtx</code>.
 148      */
 149     protected boolean gotDefault = false;
 150 
 151     /**
 152      * Constructs an initial context with the option of not
 153      * initializing it.  This may be used by a constructor in
 154      * a subclass when the value of the environment parameter
 155      * is not yet known at the time the <tt>InitialContext</tt>
 156      * constructor is called.  The subclass's constructor will
 157      * call this constructor, compute the value of the environment,
 158      * and then call <tt>init()</tt> before returning.
 159      *
 160      * @param lazy
 161      *          true means do not initialize the initial context; false
 162      *          is equivalent to calling <tt>new InitialContext()</tt>
 163      * @throws  NamingException if a naming exception is encountered
 164      *
 165      * @see #init(Hashtable)
 166      * @since 1.3
 167      */
 168     protected InitialContext(boolean lazy) throws NamingException {
 169         if (!lazy) {
 170             init(null);
 171         }
 172     }
 173 
 174     /**
 175      * Constructs an initial context.
 176      * No environment properties are supplied.
 177      * Equivalent to <tt>new InitialContext(null)</tt>.
 178      *
 179      * @throws  NamingException if a naming exception is encountered
 180      *
 181      * @see #InitialContext(Hashtable)
 182      */
 183     public InitialContext() throws NamingException {
 184         init(null);
 185     }
 186 
 187     /**
 188      * Constructs an initial context using the supplied environment.
 189      * Environment properties are discussed in the class description.
 190      *
 191      * <p> This constructor will not modify <tt>environment</tt>
 192      * or save a reference to it, but may save a clone.
 193      * Caller should not modify mutable keys and values in
 194      * <tt>environment</tt> after it has been passed to the constructor.
 195      *
 196      * @param environment
 197      *          environment used to create the initial context.
 198      *          Null indicates an empty environment.
 199      *
 200      * @throws  NamingException if a naming exception is encountered
 201      */
 202     public InitialContext(Hashtable<?,?> environment)
 203         throws NamingException
 204     {
 205         if (environment != null) {
 206             environment = (Hashtable)environment.clone();
 207         }
 208         init(environment);
 209     }
 210 
 211     /**
 212      * Initializes the initial context using the supplied environment.
 213      * Environment properties are discussed in the class description.
 214      *
 215      * <p> This method will modify <tt>environment</tt> and save
 216      * a reference to it.  The caller may no longer modify it.
 217      *
 218      * @param environment
 219      *          environment used to create the initial context.
 220      *          Null indicates an empty environment.
 221      *
 222      * @throws  NamingException if a naming exception is encountered
 223      *
 224      * @see #InitialContext(boolean)
 225      * @since 1.3
 226      */
 227     @SuppressWarnings("unchecked")
 228     protected void init(Hashtable<?,?> environment)
 229         throws NamingException
 230     {
 231         myProps = (Hashtable<Object,Object>)
 232                 ResourceManager.getInitialEnvironment(environment);
 233 
 234         if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
 235             // user has specified initial context factory; try to get it
 236             getDefaultInitCtx();
 237         }
 238     }
 239 
 240     /**
 241      * A static method to retrieve the named object.
 242      * This is a shortcut method equivalent to invoking:
 243      * <p>
 244      * <code>
 245      *        InitialContext ic = new InitialContext();
 246      *        Object obj = ic.lookup();
 247      * </code>
 248      * <p> If <tt>name</tt> is empty, returns a new instance of this context
 249      * (which represents the same naming context as this context, but its
 250      * environment may be modified independently and it may be accessed
 251      * concurrently).
 252      *
 253      * @param <T> the type of the returned object
 254      * @param name
 255      *          the name of the object to look up
 256      * @return  the object bound to <tt>name</tt>
 257      * @throws  NamingException if a naming exception is encountered
 258      *
 259      * @see #doLookup(String)
 260      * @see #lookup(Name)
 261      * @since 1.6
 262      */
 263     @SuppressWarnings("unchecked")
 264     public static <T> T doLookup(Name name)
 265         throws NamingException {
 266         return (T) (new InitialContext()).lookup(name);
 267     }
 268 
 269    /**
 270      * A static method to retrieve the named object.
 271      * See {@link #doLookup(Name)} for details.
 272      * @param <T> the type of the returned object
 273      * @param name
 274      *          the name of the object to look up
 275      * @return  the object bound to <tt>name</tt>
 276      * @throws  NamingException if a naming exception is encountered
 277      * @since 1.6
 278      */
 279     @SuppressWarnings("unchecked")
 280     public static <T> T doLookup(String name)
 281         throws NamingException {
 282         return (T) (new InitialContext()).lookup(name);
 283     }
 284 
 285     private static String getURLScheme(String str) {
 286         int colon_posn = str.indexOf(':');
 287         int slash_posn = str.indexOf('/');
 288 
 289         if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
 290             return str.substring(0, colon_posn);
 291         return null;
 292     }
 293 
 294     /**
 295      * Retrieves the initial context by calling
 296      * <code>NamingManager.getInitialContext()</code>
 297      * and cache it in defaultInitCtx.
 298      * Set <code>gotDefault</code> so that we know we've tried this before.
 299      * @return The non-null cached initial context.
 300      * @exception NoInitialContextException If cannot find an initial context.
 301      * @exception NamingException If a naming exception was encountered.
 302      */
 303     protected Context getDefaultInitCtx() throws NamingException{
 304         if (!gotDefault) {
 305             defaultInitCtx = NamingManager.getInitialContext(myProps);
 306             gotDefault = true;
 307         }
 308         if (defaultInitCtx == null)
 309             throw new NoInitialContextException();
 310 
 311         return defaultInitCtx;
 312     }
 313 
 314     /**
 315      * Retrieves a context for resolving the string name <code>name</code>.
 316      * If <code>name</code> name is a URL string, then attempt
 317      * to find a URL context for it. If none is found, or if
 318      * <code>name</code> is not a URL string, then return
 319      * <code>getDefaultInitCtx()</code>.
 320      *<p>
 321      * See getURLOrDefaultInitCtx(Name) for description
 322      * of how a subclass should use this method.
 323      * @param name The non-null name for which to get the context.
 324      * @return A URL context for <code>name</code> or the cached
 325      *         initial context. The result cannot be null.
 326      * @exception NoInitialContextException If cannot find an initial context.
 327      * @exception NamingException In a naming exception is encountered.
 328      * @see javax.naming.spi.NamingManager#getURLContext
 329      */
 330     protected Context getURLOrDefaultInitCtx(String name)
 331         throws NamingException {
 332         if (NamingManager.hasInitialContextFactoryBuilder()) {
 333             return getDefaultInitCtx();
 334         }
 335         String scheme = getURLScheme(name);
 336         if (scheme != null) {
 337             Context ctx = NamingManager.getURLContext(scheme, myProps);
 338             if (ctx != null) {
 339                 return ctx;
 340             }
 341         }
 342         return getDefaultInitCtx();
 343     }
 344 
 345     /**
 346      * Retrieves a context for resolving <code>name</code>.
 347      * If the first component of <code>name</code> name is a URL string,
 348      * then attempt to find a URL context for it. If none is found, or if
 349      * the first component of <code>name</code> is not a URL string,
 350      * then return <code>getDefaultInitCtx()</code>.
 351      *<p>
 352      * When creating a subclass of InitialContext, use this method as
 353      * follows.
 354      * Define a new method that uses this method to get an initial
 355      * context of the desired subclass.
 356      * <blockquote><pre>
 357      * protected XXXContext getURLOrDefaultInitXXXCtx(Name name)
 358      * throws NamingException {
 359      *  Context answer = getURLOrDefaultInitCtx(name);
 360      *  if (!(answer instanceof XXXContext)) {
 361      *    if (answer == null) {
 362      *      throw new NoInitialContextException();
 363      *    } else {
 364      *      throw new NotContextException("Not an XXXContext");
 365      *    }
 366      *  }
 367      *  return (XXXContext)answer;
 368      * }
 369      * </pre></blockquote>
 370      * When providing implementations for the new methods in the subclass,
 371      * use this newly defined method to get the initial context.
 372      * <blockquote><pre>
 373      * public Object XXXMethod1(Name name, ...) {
 374      *  throws NamingException {
 375      *    return getURLOrDefaultInitXXXCtx(name).XXXMethod1(name, ...);
 376      * }
 377      * </pre></blockquote>
 378      *
 379      * @param name The non-null name for which to get the context.
 380      * @return A URL context for <code>name</code> or the cached
 381      *         initial context. The result cannot be null.
 382      * @exception NoInitialContextException If cannot find an initial context.
 383      * @exception NamingException In a naming exception is encountered.
 384      *
 385      * @see javax.naming.spi.NamingManager#getURLContext
 386      */
 387     protected Context getURLOrDefaultInitCtx(Name name)
 388         throws NamingException {
 389         if (NamingManager.hasInitialContextFactoryBuilder()) {
 390             return getDefaultInitCtx();
 391         }
 392         if (name.size() > 0) {
 393             String first = name.get(0);
 394             String scheme = getURLScheme(first);
 395             if (scheme != null) {
 396                 Context ctx = NamingManager.getURLContext(scheme, myProps);
 397                 if (ctx != null) {
 398                     return ctx;
 399                 }
 400             }
 401         }
 402         return getDefaultInitCtx();
 403     }
 404 
 405 // Context methods
 406 // Most Javadoc is deferred to the Context interface.
 407 
 408     public Object lookup(String name) throws NamingException {
 409         return getURLOrDefaultInitCtx(name).lookup(name);
 410     }
 411 
 412     public Object lookup(Name name) throws NamingException {
 413         return getURLOrDefaultInitCtx(name).lookup(name);
 414     }
 415 
 416     public void bind(String name, Object obj) throws NamingException {
 417         getURLOrDefaultInitCtx(name).bind(name, obj);
 418     }
 419 
 420     public void bind(Name name, Object obj) throws NamingException {
 421         getURLOrDefaultInitCtx(name).bind(name, obj);
 422     }
 423 
 424     public void rebind(String name, Object obj) throws NamingException {
 425         getURLOrDefaultInitCtx(name).rebind(name, obj);
 426     }
 427 
 428     public void rebind(Name name, Object obj) throws NamingException {
 429         getURLOrDefaultInitCtx(name).rebind(name, obj);
 430     }
 431 
 432     public void unbind(String name) throws NamingException  {
 433         getURLOrDefaultInitCtx(name).unbind(name);
 434     }
 435 
 436     public void unbind(Name name) throws NamingException  {
 437         getURLOrDefaultInitCtx(name).unbind(name);
 438     }
 439 
 440     public void rename(String oldName, String newName) throws NamingException {
 441         getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
 442     }
 443 
 444     public void rename(Name oldName, Name newName)
 445         throws NamingException
 446     {
 447         getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
 448     }
 449 
 450     public NamingEnumeration<NameClassPair> list(String name)
 451         throws NamingException
 452     {
 453         return (getURLOrDefaultInitCtx(name).list(name));
 454     }
 455 
 456     public NamingEnumeration<NameClassPair> list(Name name)
 457         throws NamingException
 458     {
 459         return (getURLOrDefaultInitCtx(name).list(name));
 460     }
 461 
 462     public NamingEnumeration<Binding> listBindings(String name)
 463             throws NamingException  {
 464         return getURLOrDefaultInitCtx(name).listBindings(name);
 465     }
 466 
 467     public NamingEnumeration<Binding> listBindings(Name name)
 468             throws NamingException  {
 469         return getURLOrDefaultInitCtx(name).listBindings(name);
 470     }
 471 
 472     public void destroySubcontext(String name) throws NamingException  {
 473         getURLOrDefaultInitCtx(name).destroySubcontext(name);
 474     }
 475 
 476     public void destroySubcontext(Name name) throws NamingException  {
 477         getURLOrDefaultInitCtx(name).destroySubcontext(name);
 478     }
 479 
 480     public Context createSubcontext(String name) throws NamingException  {
 481         return getURLOrDefaultInitCtx(name).createSubcontext(name);
 482     }
 483 
 484     public Context createSubcontext(Name name) throws NamingException  {
 485         return getURLOrDefaultInitCtx(name).createSubcontext(name);
 486     }
 487 
 488     public Object lookupLink(String name) throws NamingException  {
 489         return getURLOrDefaultInitCtx(name).lookupLink(name);
 490     }
 491 
 492     public Object lookupLink(Name name) throws NamingException {
 493         return getURLOrDefaultInitCtx(name).lookupLink(name);
 494     }
 495 
 496     public NameParser getNameParser(String name) throws NamingException {
 497         return getURLOrDefaultInitCtx(name).getNameParser(name);
 498     }
 499 
 500     public NameParser getNameParser(Name name) throws NamingException {
 501         return getURLOrDefaultInitCtx(name).getNameParser(name);
 502     }
 503 
 504     /**
 505      * Composes the name of this context with a name relative to
 506      * this context.
 507      * Since an initial context may never be named relative
 508      * to any context other than itself, the value of the
 509      * <tt>prefix</tt> parameter must be an empty name (<tt>""</tt>).
 510      */
 511     public String composeName(String name, String prefix)
 512             throws NamingException {
 513         return name;
 514     }
 515 
 516     /**
 517      * Composes the name of this context with a name relative to
 518      * this context.
 519      * Since an initial context may never be named relative
 520      * to any context other than itself, the value of the
 521      * <tt>prefix</tt> parameter must be an empty name.
 522      */
 523     public Name composeName(Name name, Name prefix)
 524         throws NamingException
 525     {
 526         return (Name)name.clone();
 527     }
 528 
 529     public Object addToEnvironment(String propName, Object propVal)
 530             throws NamingException {
 531         myProps.put(propName, propVal);
 532         return getDefaultInitCtx().addToEnvironment(propName, propVal);
 533     }
 534 
 535     public Object removeFromEnvironment(String propName)
 536             throws NamingException {
 537         myProps.remove(propName);
 538         return getDefaultInitCtx().removeFromEnvironment(propName);
 539     }
 540 
 541     public Hashtable<?,?> getEnvironment() throws NamingException {
 542         return getDefaultInitCtx().getEnvironment();
 543     }
 544 
 545     public void close() throws NamingException {
 546         myProps = null;
 547         if (defaultInitCtx != null) {
 548             defaultInitCtx.close();
 549             defaultInitCtx = null;
 550         }
 551         gotDefault = false;
 552     }
 553 
 554     public String getNameInNamespace() throws NamingException {
 555         return getDefaultInitCtx().getNameInNamespace();
 556     }
 557 };