1 /* 2 * Copyright (c) 1999, 2020, 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.spi; 27 28 import java.lang.ref.WeakReference; 29 import java.lang.reflect.UndeclaredThrowableException; 30 import java.net.MalformedURLException; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.*; 34 35 36 import javax.naming.*; 37 import com.sun.naming.internal.VersionHelper; 38 import com.sun.naming.internal.ResourceManager; 39 import com.sun.naming.internal.FactoryEnumeration; 40 import jdk.internal.loader.ClassLoaderValue; 41 42 /** 43 * This class contains methods for creating context objects 44 * and objects referred to by location information in the naming 45 * or directory service. 46 *<p> 47 * This class cannot be instantiated. It has only static methods. 48 *<p> 49 * The mention of URL in the documentation for this class refers to 50 * a URL string as defined by RFC 1738 and its related RFCs. It is 51 * any string that conforms to the syntax described therein, and 52 * may not always have corresponding support in the java.net.URL 53 * class or Web browsers. 54 *<p> 55 * NamingManager is safe for concurrent access by multiple threads. 56 *<p> 57 * Except as otherwise noted, 58 * a {@code Name} or environment parameter 59 * passed to any method is owned by the caller. 60 * The implementation will not modify the object or keep a reference 61 * to it, although it may keep a reference to a clone or copy. 62 * 63 * @author Rosanna Lee 64 * @author Scott Seligman 65 * @since 1.3 66 */ 67 68 public class NamingManager { 69 70 /* 71 * Disallow anyone from creating one of these. 72 * Made package private so that DirectoryManager can subclass. 73 */ 74 75 NamingManager() {} 76 77 // should be protected and package private 78 static final VersionHelper helper = VersionHelper.getVersionHelper(); 79 80 // --------- object factory stuff 81 82 /** 83 * Package-private; used by DirectoryManager and NamingManager. 84 */ 85 private static ObjectFactoryBuilder object_factory_builder = null; 86 87 private static final ClassLoaderValue<InitialContextFactory> FACTORIES_CACHE = 88 new ClassLoaderValue<>(); 89 90 /** 91 * The ObjectFactoryBuilder determines the policy used when 92 * trying to load object factories. 93 * See getObjectInstance() and class ObjectFactory for a description 94 * of the default policy. 95 * setObjectFactoryBuilder() overrides this default policy by installing 96 * an ObjectFactoryBuilder. Subsequent object factories will 97 * be loaded and created using the installed builder. 98 *<p> 99 * The builder can only be installed if the executing thread is allowed 100 * (by the security manager's checkSetFactory() method) to do so. 101 * Once installed, the builder cannot be replaced. 102 * 103 * @param builder The factory builder to install. If null, no builder 104 * is installed. 105 * @exception SecurityException builder cannot be installed 106 * for security reasons. 107 * @exception NamingException builder cannot be installed for 108 * a non-security-related reason. 109 * @exception IllegalStateException If a factory has already been installed. 110 * @see #getObjectInstance 111 * @see ObjectFactory 112 * @see ObjectFactoryBuilder 113 * @see java.lang.SecurityManager#checkSetFactory 114 */ 115 public static synchronized void setObjectFactoryBuilder( 116 ObjectFactoryBuilder builder) throws NamingException { 117 if (object_factory_builder != null) 118 throw new IllegalStateException("ObjectFactoryBuilder already set"); 119 120 SecurityManager security = System.getSecurityManager(); 121 if (security != null) { 122 security.checkSetFactory(); 123 } 124 object_factory_builder = builder; 125 } 126 127 /** 128 * Used for accessing object factory builder. 129 */ 130 static synchronized ObjectFactoryBuilder getObjectFactoryBuilder() { 131 return object_factory_builder; 132 } 133 134 135 /** 136 * Retrieves the ObjectFactory for the object identified by a reference, 137 * using the reference's factory class name and factory codebase 138 * to load in the factory's class. 139 * @param ref The non-null reference to use. 140 * @param factoryName The non-null class name of the factory. 141 * @return The object factory for the object identified by ref; null 142 * if unable to load the factory. 143 */ 144 static ObjectFactory getObjectFactoryFromReference( 145 Reference ref, String factoryName) 146 throws IllegalAccessException, 147 InstantiationException, 148 MalformedURLException { 149 Class<?> clas = null; 150 151 // Try to use current class loader 152 try { 153 clas = helper.loadClass(factoryName); 154 } catch (ClassNotFoundException e) { 155 // ignore and continue 156 // e.printStackTrace(); 157 } 158 // All other exceptions are passed up. 159 160 // Not in class path; try to use codebase 161 String codebase; 162 if (clas == null && 163 (codebase = ref.getFactoryClassLocation()) != null) { 164 try { 165 clas = helper.loadClass(factoryName, codebase); 166 } catch (ClassNotFoundException e) { 167 } 168 } 169 170 @SuppressWarnings("deprecation") // Class.newInstance 171 ObjectFactory result = (clas != null) ? (ObjectFactory) clas.newInstance() : null; 172 return result; 173 } 174 175 176 /** 177 * Creates an object using the factories specified in the 178 * {@code Context.OBJECT_FACTORIES} property of the environment 179 * or of the provider resource file associated with {@code nameCtx}. 180 * 181 * @return factory created; null if cannot create 182 */ 183 private static Object createObjectFromFactories(Object obj, Name name, 184 Context nameCtx, Hashtable<?,?> environment) throws Exception { 185 186 FactoryEnumeration factories = ResourceManager.getFactories( 187 Context.OBJECT_FACTORIES, environment, nameCtx); 188 189 if (factories == null) 190 return null; 191 192 // Try each factory until one succeeds 193 ObjectFactory factory; 194 Object answer = null; 195 while (answer == null && factories.hasMore()) { 196 factory = (ObjectFactory)factories.next(); 197 answer = factory.getObjectInstance(obj, name, nameCtx, environment); 198 } 199 return answer; 200 } 201 202 private static String getURLScheme(String str) { 203 int colon_posn = str.indexOf(':'); 204 int slash_posn = str.indexOf('/'); 205 206 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn)) 207 return str.substring(0, colon_posn); 208 return null; 209 } 210 211 /** 212 * Creates an instance of an object for the specified object 213 * and environment. 214 * <p> 215 * If an object factory builder has been installed, it is used to 216 * create a factory for creating the object. 217 * Otherwise, the following rules are used to create the object: 218 *<ol> 219 * <li>If {@code refInfo} is a {@code Reference} 220 * or {@code Referenceable} containing a factory class name, 221 * use the named factory to create the object. 222 * Return {@code refInfo} if the factory cannot be created. 223 * Under JDK 1.1, if the factory class must be loaded from a location 224 * specified in the reference, a {@code SecurityManager} must have 225 * been installed or the factory creation will fail. 226 * If an exception is encountered while creating the factory, 227 * it is passed up to the caller. 228 * <li>If {@code refInfo} is a {@code Reference} or 229 * {@code Referenceable} with no factory class name, 230 * and the address or addresses are {@code StringRefAddr}s with 231 * address type "URL", 232 * try the URL context factory corresponding to each URL's scheme id 233 * to create the object (see {@code getURLContext()}). 234 * If that fails, continue to the next step. 235 * <li> Use the object factories specified in 236 * the {@code Context.OBJECT_FACTORIES} property of the environment, 237 * and of the provider resource file associated with 238 * {@code nameCtx}, in that order. 239 * The value of this property is a colon-separated list of factory 240 * class names that are tried in order, and the first one that succeeds 241 * in creating an object is the one used. 242 * If none of the factories can be loaded, 243 * return {@code refInfo}. 244 * If an exception is encountered while creating the object, the 245 * exception is passed up to the caller. 246 *</ol> 247 *<p> 248 * Service providers that implement the {@code DirContext} 249 * interface should use 250 * {@code DirectoryManager.getObjectInstance()}, not this method. 251 * Service providers that implement only the {@code Context} 252 * interface should use this method. 253 * <p> 254 * Note that an object factory (an object that implements the ObjectFactory 255 * interface) must be public and must have a public constructor that 256 * accepts no arguments. 257 * In cases where the factory is in a named module then it must be in a 258 * package which is exported by that module to the {@code java.naming} 259 * module. 260 * <p> 261 * The {@code name} and {@code nameCtx} parameters may 262 * optionally be used to specify the name of the object being created. 263 * {@code name} is the name of the object, relative to context 264 * {@code nameCtx}. This information could be useful to the object 265 * factory or to the object implementation. 266 * If there are several possible contexts from which the object 267 * could be named -- as will often be the case -- it is up to 268 * the caller to select one. A good rule of thumb is to select the 269 * "deepest" context available. 270 * If {@code nameCtx} is null, {@code name} is relative 271 * to the default initial context. If no name is being specified, the 272 * {@code name} parameter should be null. 273 * 274 * @param refInfo The possibly null object for which to create an object. 275 * @param name The name of this object relative to {@code nameCtx}. 276 * Specifying a name is optional; if it is 277 * omitted, {@code name} should be null. 278 * @param nameCtx The context relative to which the {@code name} 279 * parameter is specified. If null, {@code name} is 280 * relative to the default initial context. 281 * @param environment The possibly null environment to 282 * be used in the creation of the object factory and the object. 283 * @return An object created using {@code refInfo}; or 284 * {@code refInfo} if an object cannot be created using 285 * the algorithm described above. 286 * @exception NamingException if a naming exception was encountered 287 * while attempting to get a URL context, or if one of the 288 * factories accessed throws a NamingException. 289 * @exception Exception if one of the factories accessed throws an 290 * exception, or if an error was encountered while loading 291 * and instantiating the factory and object classes. 292 * A factory should only throw an exception if it does not want 293 * other factories to be used in an attempt to create an object. 294 * See ObjectFactory.getObjectInstance(). 295 * @see #getURLContext 296 * @see ObjectFactory 297 * @see ObjectFactory#getObjectInstance 298 */ 299 public static Object 300 getObjectInstance(Object refInfo, Name name, Context nameCtx, 301 Hashtable<?,?> environment) 302 throws Exception 303 { 304 305 ObjectFactory factory; 306 307 // Use builder if installed 308 ObjectFactoryBuilder builder = getObjectFactoryBuilder(); 309 if (builder != null) { 310 // builder must return non-null factory 311 factory = builder.createObjectFactory(refInfo, environment); 312 return factory.getObjectInstance(refInfo, name, nameCtx, 313 environment); 314 } 315 316 // Use reference if possible 317 Reference ref = null; 318 if (refInfo instanceof Reference) { 319 ref = (Reference) refInfo; 320 } else if (refInfo instanceof Referenceable) { 321 ref = ((Referenceable)(refInfo)).getReference(); 322 } 323 324 Object answer; 325 326 if (ref != null) { 327 String f = ref.getFactoryClassName(); 328 if (f != null) { 329 // if reference identifies a factory, use exclusively 330 331 factory = getObjectFactoryFromReference(ref, f); 332 if (factory != null) { 333 return factory.getObjectInstance(ref, name, nameCtx, 334 environment); 335 } 336 // No factory found, so return original refInfo. 337 // Will reach this point if factory class is not in 338 // class path and reference does not contain a URL for it 339 return refInfo; 340 341 } else { 342 // if reference has no factory, check for addresses 343 // containing URLs 344 345 answer = processURLAddrs(ref, name, nameCtx, environment); 346 if (answer != null) { 347 return answer; 348 } 349 } 350 } 351 352 // try using any specified factories 353 answer = 354 createObjectFromFactories(refInfo, name, nameCtx, environment); 355 return (answer != null) ? answer : refInfo; 356 } 357 358 /* 359 * Ref has no factory. For each address of type "URL", try its URL 360 * context factory. Returns null if unsuccessful in creating and 361 * invoking a factory. 362 */ 363 static Object processURLAddrs(Reference ref, Name name, Context nameCtx, 364 Hashtable<?,?> environment) 365 throws NamingException { 366 367 for (int i = 0; i < ref.size(); i++) { 368 RefAddr addr = ref.get(i); 369 if (addr instanceof StringRefAddr && 370 addr.getType().equalsIgnoreCase("URL")) { 371 372 String url = (String)addr.getContent(); 373 Object answer = processURL(url, name, nameCtx, environment); 374 if (answer != null) { 375 return answer; 376 } 377 } 378 } 379 return null; 380 } 381 382 private static Object processURL(Object refInfo, Name name, 383 Context nameCtx, Hashtable<?,?> environment) 384 throws NamingException { 385 Object answer; 386 387 // If refInfo is a URL string, try to use its URL context factory 388 // If no context found, continue to try object factories. 389 if (refInfo instanceof String) { 390 String url = (String)refInfo; 391 String scheme = getURLScheme(url); 392 if (scheme != null) { 393 answer = getURLObject(scheme, refInfo, name, nameCtx, 394 environment); 395 if (answer != null) { 396 return answer; 397 } 398 } 399 } 400 401 // If refInfo is an array of URL strings, 402 // try to find a context factory for any one of its URLs. 403 // If no context found, continue to try object factories. 404 if (refInfo instanceof String[]) { 405 String[] urls = (String[])refInfo; 406 for (int i = 0; i <urls.length; i++) { 407 String scheme = getURLScheme(urls[i]); 408 if (scheme != null) { 409 answer = getURLObject(scheme, refInfo, name, nameCtx, 410 environment); 411 if (answer != null) 412 return answer; 413 } 414 } 415 } 416 return null; 417 } 418 419 420 /** 421 * Retrieves a context identified by {@code obj}, using the specified 422 * environment. 423 * Used by ContinuationContext. 424 * 425 * @param obj The object identifying the context. 426 * @param name The name of the context being returned, relative to 427 * {@code nameCtx}, or null if no name is being 428 * specified. 429 * See the {@code getObjectInstance} method for 430 * details. 431 * @param nameCtx The context relative to which {@code name} is 432 * specified, or null for the default initial context. 433 * See the {@code getObjectInstance} method for 434 * details. 435 * @param environment Environment specifying characteristics of the 436 * resulting context. 437 * @return A context identified by {@code obj}. 438 * 439 * @see #getObjectInstance 440 */ 441 static Context getContext(Object obj, Name name, Context nameCtx, 442 Hashtable<?,?> environment) throws NamingException { 443 Object answer; 444 445 if (obj instanceof Context) { 446 // %%% Ignore environment for now. OK since method not public. 447 return (Context)obj; 448 } 449 450 try { 451 answer = getObjectInstance(obj, name, nameCtx, environment); 452 } catch (NamingException e) { 453 throw e; 454 } catch (Exception e) { 455 NamingException ne = new NamingException(); 456 ne.setRootCause(e); 457 throw ne; 458 } 459 460 return (answer instanceof Context) 461 ? (Context)answer 462 : null; 463 } 464 465 // Used by ContinuationContext 466 static Resolver getResolver(Object obj, Name name, Context nameCtx, 467 Hashtable<?,?> environment) throws NamingException { 468 Object answer; 469 470 if (obj instanceof Resolver) { 471 // %%% Ignore environment for now. OK since method not public. 472 return (Resolver)obj; 473 } 474 475 try { 476 answer = getObjectInstance(obj, name, nameCtx, environment); 477 } catch (NamingException e) { 478 throw e; 479 } catch (Exception e) { 480 NamingException ne = new NamingException(); 481 ne.setRootCause(e); 482 throw ne; 483 } 484 485 return (answer instanceof Resolver) 486 ? (Resolver)answer 487 : null; 488 } 489 490 491 /***************** URL Context implementations ***************/ 492 493 /** 494 * Creates a context for the given URL scheme id. 495 * <p> 496 * The resulting context is for resolving URLs of the 497 * scheme {@code scheme}. The resulting context is not tied 498 * to a specific URL. It is able to handle arbitrary URLs with 499 * the specified scheme. 500 *<p> 501 * The class name of the factory that creates the resulting context 502 * has the naming convention <i>scheme-id</i>URLContextFactory 503 * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id), 504 * in the package specified as follows. 505 * The {@code Context.URL_PKG_PREFIXES} environment property (which 506 * may contain values taken from system properties, 507 * or application resource files) 508 * contains a colon-separated list of package prefixes. 509 * Each package prefix in 510 * the property is tried in the order specified to load the factory class. 511 * The default package prefix is "com.sun.jndi.url" (if none of the 512 * specified packages work, this default is tried). 513 * The complete package name is constructed using the package prefix, 514 * concatenated with the scheme id. 515 *<p> 516 * For example, if the scheme id is "ldap", and the 517 * {@code Context.URL_PKG_PREFIXES} property 518 * contains "com.widget:com.wiz.jndi", 519 * the naming manager would attempt to load the following classes 520 * until one is successfully instantiated: 521 *<ul> 522 * <li>com.widget.ldap.ldapURLContextFactory 523 * <li>com.wiz.jndi.ldap.ldapURLContextFactory 524 * <li>com.sun.jndi.url.ldap.ldapURLContextFactory 525 *</ul> 526 * If none of the package prefixes work, null is returned. 527 *<p> 528 * If a factory is instantiated, it is invoked with the following 529 * parameters to produce the resulting context. 530 * <p> 531 * {@code factory.getObjectInstance(null, environment);} 532 * <p> 533 * For example, invoking getObjectInstance() as shown above 534 * on a LDAP URL context factory would return a 535 * context that can resolve LDAP urls 536 * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us", 537 * "ldap://ldap.umich.edu/o=umich,c=us", ...). 538 *<p> 539 * Note that an object factory (an object that implements the ObjectFactory 540 * interface) must be public and must have a public constructor that 541 * accepts no arguments. 542 * In cases where the factory is in a named module then it must be in a 543 * package which is exported by that module to the {@code java.naming} 544 * module. 545 * 546 * @param scheme The non-null scheme-id of the URLs supported by the context. 547 * @param environment The possibly null environment properties to be 548 * used in the creation of the object factory and the context. 549 * @return A context for resolving URLs with the 550 * scheme id {@code scheme}; 551 * {@code null} if the factory for creating the 552 * context is not found. 553 * @exception NamingException If a naming exception occurs while creating 554 * the context. 555 * @see #getObjectInstance 556 * @see ObjectFactory#getObjectInstance 557 */ 558 public static Context getURLContext(String scheme, 559 Hashtable<?,?> environment) 560 throws NamingException 561 { 562 // pass in 'null' to indicate creation of generic context for scheme 563 // (i.e. not specific to a URL). 564 565 Object answer = getURLObject(scheme, null, null, null, environment); 566 if (answer instanceof Context) { 567 return (Context)answer; 568 } else { 569 return null; 570 } 571 } 572 573 private static final String defaultPkgPrefix = "com.sun.jndi.url"; 574 575 /** 576 * Creates an object for the given URL scheme id using 577 * the supplied urlInfo. 578 * <p> 579 * If urlInfo is null, the result is a context for resolving URLs 580 * with the scheme id 'scheme'. 581 * If urlInfo is a URL, the result is a context named by the URL. 582 * Names passed to this context is assumed to be relative to this 583 * context (i.e. not a URL). For example, if urlInfo is 584 * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will 585 * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'. 586 * Subsequent names that can be passed to this context will be 587 * LDAP names relative to this context (e.g. cn="Barbs Jensen"). 588 * If urlInfo is an array of URLs, the URLs are assumed 589 * to be equivalent in terms of the context to which they refer. 590 * The resulting context is like that of the single URL case. 591 * If urlInfo is of any other type, that is handled by the 592 * context factory for the URL scheme. 593 * @param scheme the URL scheme id for the context 594 * @param urlInfo information used to create the context 595 * @param name name of this object relative to {@code nameCtx} 596 * @param nameCtx Context whose provider resource file will be searched 597 * for package prefix values (or null if none) 598 * @param environment Environment properties for creating the context 599 * @see javax.naming.InitialContext 600 */ 601 private static Object getURLObject(String scheme, Object urlInfo, 602 Name name, Context nameCtx, 603 Hashtable<?,?> environment) 604 throws NamingException { 605 606 // e.g. "ftpURLContextFactory" 607 ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory( 608 Context.URL_PKG_PREFIXES, environment, nameCtx, 609 "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix); 610 611 if (factory == null) 612 return null; 613 614 // Found object factory 615 try { 616 return factory.getObjectInstance(urlInfo, name, nameCtx, environment); 617 } catch (NamingException e) { 618 throw e; 619 } catch (Exception e) { 620 NamingException ne = new NamingException(); 621 ne.setRootCause(e); 622 throw ne; 623 } 624 625 } 626 627 628 // ------------ Initial Context Factory Stuff 629 private static InitialContextFactoryBuilder initctx_factory_builder = null; 630 631 /** 632 * Use this method for accessing initctx_factory_builder while 633 * inside an unsynchronized method. 634 */ 635 private static synchronized InitialContextFactoryBuilder 636 getInitialContextFactoryBuilder() { 637 return initctx_factory_builder; 638 } 639 640 /** 641 * Creates an initial context using the specified environment 642 * properties. 643 * <p> 644 * This is done as follows: 645 * <ul> 646 * <li>If an InitialContextFactoryBuilder has been installed, 647 * it is used to create the factory for creating the initial 648 * context</li> 649 * <li>Otherwise, the class specified in the 650 * {@code Context.INITIAL_CONTEXT_FACTORY} environment property 651 * is used 652 * <ul> 653 * <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader} 654 * mechanism tries to locate an {@code InitialContextFactory} 655 * provider using the current thread's context class loader</li> 656 * <li>Failing that, this implementation tries to locate a suitable 657 * {@code InitialContextFactory} using a built-in mechanism 658 * <br> 659 * (Note that an initial context factory (an object that implements 660 * the InitialContextFactory interface) must be public and must have 661 * a public constructor that accepts no arguments. 662 * In cases where the factory is in a named module then it must 663 * be in a package which is exported by that module to the 664 * {@code java.naming} module.)</li> 665 * </ul> 666 * </li> 667 * </ul> 668 * @param env The possibly null environment properties used when 669 * creating the context. 670 * @return A non-null initial context. 671 * @exception NoInitialContextException If the 672 * {@code Context.INITIAL_CONTEXT_FACTORY} property 673 * is not found or names a nonexistent 674 * class or a class that cannot be instantiated, 675 * or if the initial context could not be created for some other 676 * reason. 677 * @exception NamingException If some other naming exception was encountered. 678 * @see javax.naming.InitialContext 679 * @see javax.naming.directory.InitialDirContext 680 */ 681 public static Context getInitialContext(Hashtable<?,?> env) 682 throws NamingException { 683 ClassLoader loader; 684 InitialContextFactory factory = null; 685 686 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder(); 687 if (builder == null) { 688 // No builder installed, use property 689 // Get initial context factory class name 690 691 String className = env != null ? 692 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null; 693 if (className == null) { 694 NoInitialContextException ne = new NoInitialContextException( 695 "Need to specify class name in environment or system " + 696 "property, or in an application resource file: " + 697 Context.INITIAL_CONTEXT_FACTORY); 698 throw ne; 699 } 700 701 if (System.getSecurityManager() == null) { 702 loader = Thread.currentThread().getContextClassLoader(); 703 if (loader == null) loader = ClassLoader.getSystemClassLoader(); 704 } else { 705 PrivilegedAction<ClassLoader> pa = () -> { 706 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 707 return (cl == null) ? ClassLoader.getSystemClassLoader() : cl; 708 }; 709 loader = AccessController.doPrivileged(pa); 710 } 711 712 ClassLoaderValue<InitialContextFactory>.Sub<String> key = FACTORIES_CACHE.sub(className); 713 try { 714 factory = key.computeIfAbsent(loader, (ld, ky) -> { 715 String cn = ky.key(); 716 InitialContextFactory fac = getFactory(cn); 717 return fac; 718 }); 719 } catch (UndeclaredThrowableException e) { 720 if (e.getUndeclaredThrowable() instanceof NoInitialContextException) { 721 throw (NoInitialContextException) e.getUndeclaredThrowable(); 722 } 723 } 724 } else { 725 factory = builder.createInitialContextFactory(env); 726 } 727 728 return factory.getInitialContext(env); 729 } 730 731 private static InitialContextFactory getFactory(String className) { 732 InitialContextFactory factory; 733 try { 734 ServiceLoader<InitialContextFactory> loader = 735 ServiceLoader.load(InitialContextFactory.class); 736 737 factory = loader 738 .stream() 739 .map(ServiceLoader.Provider::get) 740 .filter(f -> f.getClass().getName().equals(className)) 741 .findFirst() 742 .orElse(null); 743 } catch (ServiceConfigurationError e) { 744 NoInitialContextException ne = 745 new NoInitialContextException( 746 "Cannot load initial context factory " 747 + "'" + className + "'"); 748 ne.setRootCause(e); 749 throw new UndeclaredThrowableException(ne); 750 } 751 752 if (factory == null) { 753 try { 754 @SuppressWarnings("deprecation") 755 Object o = helper.loadClass(className).newInstance(); 756 factory = (InitialContextFactory) o; 757 } catch (Exception e) { 758 NoInitialContextException ne = 759 new NoInitialContextException( 760 "Cannot instantiate class: " + className); 761 ne.setRootCause(e); 762 throw new UndeclaredThrowableException(ne); 763 } 764 } 765 return factory; 766 } 767 768 769 /** 770 * Sets the InitialContextFactory builder to be builder. 771 * 772 *<p> 773 * The builder can only be installed if the executing thread is allowed by 774 * the security manager to do so. Once installed, the builder cannot 775 * be replaced. 776 * @param builder The initial context factory builder to install. If null, 777 * no builder is set. 778 * @exception SecurityException builder cannot be installed for security 779 * reasons. 780 * @exception NamingException builder cannot be installed for 781 * a non-security-related reason. 782 * @exception IllegalStateException If a builder was previous installed. 783 * @see #hasInitialContextFactoryBuilder 784 * @see java.lang.SecurityManager#checkSetFactory 785 */ 786 public static synchronized void setInitialContextFactoryBuilder( 787 InitialContextFactoryBuilder builder) 788 throws NamingException { 789 if (initctx_factory_builder != null) 790 throw new IllegalStateException( 791 "InitialContextFactoryBuilder already set"); 792 793 SecurityManager security = System.getSecurityManager(); 794 if (security != null) { 795 security.checkSetFactory(); 796 } 797 initctx_factory_builder = builder; 798 } 799 800 /** 801 * Determines whether an initial context factory builder has 802 * been set. 803 * @return true if an initial context factory builder has 804 * been set; false otherwise. 805 * @see #setInitialContextFactoryBuilder 806 */ 807 public static boolean hasInitialContextFactoryBuilder() { 808 return (getInitialContextFactoryBuilder() != null); 809 } 810 811 // ----- Continuation Context Stuff 812 813 /** 814 * Constant that holds the name of the environment property into 815 * which {@code getContinuationContext()} stores the value of its 816 * {@code CannotProceedException} parameter. 817 * This property is inherited by the continuation context, and may 818 * be used by that context's service provider to inspect the 819 * fields of the exception. 820 *<p> 821 * The value of this constant is "java.naming.spi.CannotProceedException". 822 * 823 * @see #getContinuationContext 824 * @since 1.3 825 */ 826 public static final String CPE = "java.naming.spi.CannotProceedException"; 827 828 /** 829 * Creates a context in which to continue a context operation. 830 *<p> 831 * In performing an operation on a name that spans multiple 832 * namespaces, a context from one naming system may need to pass 833 * the operation on to the next naming system. The context 834 * implementation does this by first constructing a 835 * {@code CannotProceedException} containing information 836 * pinpointing how far it has proceeded. It then obtains a 837 * continuation context from JNDI by calling 838 * {@code getContinuationContext}. The context 839 * implementation should then resume the context operation by 840 * invoking the same operation on the continuation context, using 841 * the remainder of the name that has not yet been resolved. 842 *<p> 843 * Before making use of the {@code cpe} parameter, this method 844 * updates the environment associated with that object by setting 845 * the value of the property <a href="#CPE">{@code CPE}</a> 846 * to {@code cpe}. This property will be inherited by the 847 * continuation context, and may be used by that context's 848 * service provider to inspect the fields of this exception. 849 * 850 * @param cpe 851 * The non-null exception that triggered this continuation. 852 * @return A non-null Context object for continuing the operation. 853 * @exception NamingException If a naming exception occurred. 854 */ 855 @SuppressWarnings("unchecked") 856 public static Context getContinuationContext(CannotProceedException cpe) 857 throws NamingException { 858 859 Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment(); 860 if (env == null) { 861 env = new Hashtable<>(7); 862 } else { 863 // Make a (shallow) copy of the environment. 864 env = (Hashtable<Object,Object>)env.clone(); 865 } 866 env.put(CPE, cpe); 867 868 ContinuationContext cctx = new ContinuationContext(cpe, env); 869 return cctx.getTargetContext(); 870 } 871 872 // ------------ State Factory Stuff 873 874 /** 875 * Retrieves the state of an object for binding. 876 * <p> 877 * Service providers that implement the {@code DirContext} interface 878 * should use {@code DirectoryManager.getStateToBind()}, not this method. 879 * Service providers that implement only the {@code Context} interface 880 * should use this method. 881 *<p> 882 * This method uses the specified state factories in 883 * the {@code Context.STATE_FACTORIES} property from the environment 884 * properties, and from the provider resource file associated with 885 * {@code nameCtx}, in that order. 886 * The value of this property is a colon-separated list of factory 887 * class names that are tried in order, and the first one that succeeds 888 * in returning the object's state is the one used. 889 * If no object's state can be retrieved in this way, return the 890 * object itself. 891 * If an exception is encountered while retrieving the state, the 892 * exception is passed up to the caller. 893 * <p> 894 * Note that a state factory 895 * (an object that implements the StateFactory 896 * interface) must be public and must have a public constructor that 897 * accepts no arguments. 898 * In cases where the factory is in a named module then it must be in a 899 * package which is exported by that module to the {@code java.naming} 900 * module. 901 * <p> 902 * The {@code name} and {@code nameCtx} parameters may 903 * optionally be used to specify the name of the object being created. 904 * See the description of "Name and Context Parameters" in 905 * {@link ObjectFactory#getObjectInstance 906 * ObjectFactory.getObjectInstance()} 907 * for details. 908 * <p> 909 * This method may return a {@code Referenceable} object. The 910 * service provider obtaining this object may choose to store it 911 * directly, or to extract its reference (using 912 * {@code Referenceable.getReference()}) and store that instead. 913 * 914 * @param obj The non-null object for which to get state to bind. 915 * @param name The name of this object relative to {@code nameCtx}, 916 * or null if no name is specified. 917 * @param nameCtx The context relative to which the {@code name} 918 * parameter is specified, or null if {@code name} is 919 * relative to the default initial context. 920 * @param environment The possibly null environment to 921 * be used in the creation of the state factory and 922 * the object's state. 923 * @return The non-null object representing {@code obj}'s state for 924 * binding. It could be the object ({@code obj}) itself. 925 * @exception NamingException If one of the factories accessed throws an 926 * exception, or if an error was encountered while loading 927 * and instantiating the factory and object classes. 928 * A factory should only throw an exception if it does not want 929 * other factories to be used in an attempt to create an object. 930 * See {@code StateFactory.getStateToBind()}. 931 * @see StateFactory 932 * @see StateFactory#getStateToBind 933 * @see DirectoryManager#getStateToBind 934 * @since 1.3 935 */ 936 public static Object 937 getStateToBind(Object obj, Name name, Context nameCtx, 938 Hashtable<?,?> environment) 939 throws NamingException 940 { 941 942 FactoryEnumeration factories = ResourceManager.getFactories( 943 Context.STATE_FACTORIES, environment, nameCtx); 944 945 if (factories == null) { 946 return obj; 947 } 948 949 // Try each factory until one succeeds 950 StateFactory factory; 951 Object answer = null; 952 while (answer == null && factories.hasMore()) { 953 factory = (StateFactory)factories.next(); 954 answer = factory.getStateToBind(obj, name, nameCtx, environment); 955 } 956 957 return (answer != null) ? answer : obj; 958 } 959 }