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 ({@code jndi.properties}). 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>{@code Context}</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 {@code String} 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 * {@code "java.naming.factory.initial"} is used. Similarly, when a 77 * {@code CompositeName} 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 * NamingManager.getURLContext()} 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 * {@code NamingManager.setInitialContextFactoryBuilder()}. 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 {@code init()} 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 {@code InitialContext} 156 * constructor is called. The subclass's constructor will 157 * call this constructor, compute the value of the environment, 158 * and then call {@code init()} before returning. 159 * 160 * @param lazy 161 * true means do not initialize the initial context; false 162 * is equivalent to calling {@code new InitialContext()} 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 {@code new InitialContext(null)}. 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 {@code environment} 192 * or save a reference to it, but may save a clone. 193 * Caller should not modify mutable keys and values in 194 * {@code environment} 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 {@code environment} 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 {@code name} 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 {@code name} 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 {@code name} 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 * {@code prefix} parameter must be an empty name ({@code ""}). 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 * {@code prefix} 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 };