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