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