1 /* 2 * Copyright (c) 1999, 2009, 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 JNDI 1.1 / Java 2 Platform, Standard Edition, v 1.3 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 protected void init(Hashtable<?,?> environment) 236 throws NamingException 237 { 238 myProps = ResourceManager.getInitialEnvironment(environment); 239 240 if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) { 241 // user has specified initial context factory; try to get it 242 getDefaultInitCtx(); 243 } 244 } 245 246 /** 247 * A static method to retrieve the named object. 248 * This is a shortcut method equivalent to invoking: 249 * <p> 250 * <code> 251 * InitialContext ic = new InitialContext(); 252 * Object obj = ic.lookup(); 253 * </code> 254 * <p> If <tt>name</tt> is empty, returns a new instance of this context 255 * (which represents the same naming context as this context, but its 256 * environment may be modified independently and it may be accessed 257 * concurrently). 258 * 259 * @param name 260 * the name of the object to look up 261 * @return the object bound to <tt>name</tt> 262 * @throws NamingException if a naming exception is encountered 263 * 264 * @see #doLookup(String) 265 * @see #lookup(Name) 266 * @since 1.6 267 */ 268 public static <T> T doLookup(Name name) 269 throws NamingException { 270 return (T) (new InitialContext()).lookup(name); 271 } 272 273 /** 274 * A static method to retrieve the named object. 275 * See {@link #doLookup(Name)} for details. 276 * @param name 277 * the name of the object to look up 278 * @return the object bound to <tt>name</tt> 279 * @throws NamingException if a naming exception is encountered 280 * @since 1.6 281 */ 282 public static <T> T doLookup(String name) 283 throws NamingException { 284 return (T) (new InitialContext()).lookup(name); 285 } 286 287 private static String getURLScheme(String str) { 288 int colon_posn = str.indexOf(':'); 289 int slash_posn = str.indexOf('/'); 290 291 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn)) 292 return str.substring(0, colon_posn); 293 return null; 294 } 295 296 /** 297 * Retrieves the initial context by calling 298 * <code>NamingManager.getInitialContext()</code> 299 * and cache it in defaultInitCtx. 300 * Set <code>gotDefault</code> so that we know we've tried this before. 301 * @return The non-null cached initial context. 302 * @exception NoInitialContextException If cannot find an initial context. 303 * @exception NamingException If a naming exception was encountered. 304 */ 305 protected Context getDefaultInitCtx() throws NamingException{ 306 if (!gotDefault) { 307 defaultInitCtx = NamingManager.getInitialContext(myProps); 308 gotDefault = true; 309 } 310 if (defaultInitCtx == null) 311 throw new NoInitialContextException(); 312 313 return defaultInitCtx; 314 } 315 316 /** 317 * Retrieves a context for resolving the string name <code>name</code>. 318 * If <code>name</code> name is a URL string, then attempt 319 * to find a URL context for it. If none is found, or if 320 * <code>name</code> is not a URL string, then return 321 * <code>getDefaultInitCtx()</code>. 322 *<p> 323 * See getURLOrDefaultInitCtx(Name) for description 324 * of how a subclass should use this method. 325 * @param name The non-null name for which to get the context. 326 * @return A URL context for <code>name</code> or the cached 327 * initial context. The result cannot be null. 328 * @exception NoInitialContextException If cannot find an initial context. 329 * @exception NamingException In a naming exception is encountered. 330 * @see javax.naming.spi.NamingManager#getURLContext 331 */ 332 protected Context getURLOrDefaultInitCtx(String name) 333 throws NamingException { 334 if (NamingManager.hasInitialContextFactoryBuilder()) { 335 return getDefaultInitCtx(); 336 } 337 String scheme = getURLScheme(name); 338 if (scheme != null) { 339 Context ctx = NamingManager.getURLContext(scheme, myProps); 340 if (ctx != null) { 341 return ctx; 342 } 343 } 344 return getDefaultInitCtx(); 345 } 346 347 /** 348 * Retrieves a context for resolving <code>name</code>. 349 * If the first component of <code>name</code> name is a URL string, 350 * then attempt to find a URL context for it. If none is found, or if 351 * the first component of <code>name</code> is not a URL string, 352 * then return <code>getDefaultInitCtx()</code>. 353 *<p> 354 * When creating a subclass of InitialContext, use this method as 355 * follows. 356 * Define a new method that uses this method to get an initial 357 * context of the desired subclass. 358 * <p><blockquote><pre> 359 * protected XXXContext getURLOrDefaultInitXXXCtx(Name name) 360 * throws NamingException { 361 * Context answer = getURLOrDefaultInitCtx(name); 362 * if (!(answer instanceof XXXContext)) { 363 * if (answer == null) { 364 * throw new NoInitialContextException(); 365 * } else { 366 * throw new NotContextException("Not an XXXContext"); 367 * } 368 * } 369 * return (XXXContext)answer; 370 * } 371 * </pre></blockquote> 372 * When providing implementations for the new methods in the subclass, 373 * use this newly defined method to get the initial context. 374 * <p><blockquote><pre> 375 * public Object XXXMethod1(Name name, ...) { 376 * throws NamingException { 377 * return getURLOrDefaultInitXXXCtx(name).XXXMethod1(name, ...); 378 * } 379 * </pre></blockquote> 380 * 381 * @param name The non-null name for which to get the context. 382 * @return A URL context for <code>name</code> or the cached 383 * initial context. The result cannot be null. 384 * @exception NoInitialContextException If cannot find an initial context. 385 * @exception NamingException In a naming exception is encountered. 386 * 387 * @see javax.naming.spi.NamingManager#getURLContext 388 */ 389 protected Context getURLOrDefaultInitCtx(Name name) 390 throws NamingException { 391 if (NamingManager.hasInitialContextFactoryBuilder()) { 392 return getDefaultInitCtx(); 393 } 394 if (name.size() > 0) { 395 String first = name.get(0); 396 String scheme = getURLScheme(first); 397 if (scheme != null) { 398 Context ctx = NamingManager.getURLContext(scheme, myProps); 399 if (ctx != null) { 400 return ctx; 401 } 402 } 403 } 404 return getDefaultInitCtx(); 405 } 406 407 // Context methods 408 // Most Javadoc is deferred to the Context interface. 409 410 public Object lookup(String name) throws NamingException { 411 return getURLOrDefaultInitCtx(name).lookup(name); 412 } 413 414 public Object lookup(Name name) throws NamingException { 415 return getURLOrDefaultInitCtx(name).lookup(name); 416 } 417 418 public void bind(String name, Object obj) throws NamingException { 419 getURLOrDefaultInitCtx(name).bind(name, obj); 420 } 421 422 public void bind(Name name, Object obj) throws NamingException { 423 getURLOrDefaultInitCtx(name).bind(name, obj); 424 } 425 426 public void rebind(String name, Object obj) throws NamingException { 427 getURLOrDefaultInitCtx(name).rebind(name, obj); 428 } 429 430 public void rebind(Name name, Object obj) throws NamingException { 431 getURLOrDefaultInitCtx(name).rebind(name, obj); 432 } 433 434 public void unbind(String name) throws NamingException { 435 getURLOrDefaultInitCtx(name).unbind(name); 436 } 437 438 public void unbind(Name name) throws NamingException { 439 getURLOrDefaultInitCtx(name).unbind(name); 440 } 441 442 public void rename(String oldName, String newName) throws NamingException { 443 getURLOrDefaultInitCtx(oldName).rename(oldName, newName); 444 } 445 446 public void rename(Name oldName, Name newName) 447 throws NamingException 448 { 449 getURLOrDefaultInitCtx(oldName).rename(oldName, newName); 450 } 451 452 public NamingEnumeration<NameClassPair> list(String name) 453 throws NamingException 454 { 455 return (getURLOrDefaultInitCtx(name).list(name)); 456 } 457 458 public NamingEnumeration<NameClassPair> list(Name name) 459 throws NamingException 460 { 461 return (getURLOrDefaultInitCtx(name).list(name)); 462 } 463 464 public NamingEnumeration<Binding> listBindings(String name) 465 throws NamingException { 466 return getURLOrDefaultInitCtx(name).listBindings(name); 467 } 468 469 public NamingEnumeration<Binding> listBindings(Name name) 470 throws NamingException { 471 return getURLOrDefaultInitCtx(name).listBindings(name); 472 } 473 474 public void destroySubcontext(String name) throws NamingException { 475 getURLOrDefaultInitCtx(name).destroySubcontext(name); 476 } 477 478 public void destroySubcontext(Name name) throws NamingException { 479 getURLOrDefaultInitCtx(name).destroySubcontext(name); 480 } 481 482 public Context createSubcontext(String name) throws NamingException { 483 return getURLOrDefaultInitCtx(name).createSubcontext(name); 484 } 485 486 public Context createSubcontext(Name name) throws NamingException { 487 return getURLOrDefaultInitCtx(name).createSubcontext(name); 488 } 489 490 public Object lookupLink(String name) throws NamingException { 491 return getURLOrDefaultInitCtx(name).lookupLink(name); 492 } 493 494 public Object lookupLink(Name name) throws NamingException { 495 return getURLOrDefaultInitCtx(name).lookupLink(name); 496 } 497 498 public NameParser getNameParser(String name) throws NamingException { 499 return getURLOrDefaultInitCtx(name).getNameParser(name); 500 } 501 502 public NameParser getNameParser(Name name) throws NamingException { 503 return getURLOrDefaultInitCtx(name).getNameParser(name); 504 } 505 506 /** 507 * Composes the name of this context with a name relative to 508 * this context. 509 * Since an initial context may never be named relative 510 * to any context other than itself, the value of the 511 * <tt>prefix</tt> parameter must be an empty name (<tt>""</tt>). 512 */ 513 public String composeName(String name, String prefix) 514 throws NamingException { 515 return name; 516 } 517 518 /** 519 * Composes the name of this context with a name relative to 520 * this context. 521 * Since an initial context may never be named relative 522 * to any context other than itself, the value of the 523 * <tt>prefix</tt> parameter must be an empty name. 524 */ 525 public Name composeName(Name name, Name prefix) 526 throws NamingException 527 { 528 return (Name)name.clone(); 529 } 530 531 public Object addToEnvironment(String propName, Object propVal) 532 throws NamingException { 533 myProps.put(propName, propVal); 534 return getDefaultInitCtx().addToEnvironment(propName, propVal); 535 } 536 537 public Object removeFromEnvironment(String propName) 538 throws NamingException { 539 myProps.remove(propName); 540 return getDefaultInitCtx().removeFromEnvironment(propName); 541 } 542 543 public Hashtable<?,?> getEnvironment() throws NamingException { 544 return getDefaultInitCtx().getEnvironment(); 545 } 546 547 public void close() throws NamingException { 548 myProps = null; 549 if (defaultInitCtx != null) { 550 defaultInitCtx.close(); 551 defaultInitCtx = null; 552 } 553 gotDefault = false; 554 } 555 556 public String getNameInNamespace() throws NamingException { 557 return getDefaultInitCtx().getNameInNamespace(); 558 } 559 };