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