Frames | No Frames |
1: /* NamingManager.java -- Creates contexts and objects 2: Copyright (C) 2000, 2001, 2002, 2003, 2004, 3: 2006 Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package javax.naming.spi; 41: 42: import gnu.classpath.VMStackWalker; 43: 44: import gnu.java.lang.CPStringBuilder; 45: 46: import java.util.Enumeration; 47: import java.util.Hashtable; 48: import java.util.StringTokenizer; 49: 50: import javax.naming.CannotProceedException; 51: import javax.naming.Context; 52: import javax.naming.Name; 53: import javax.naming.NamingException; 54: import javax.naming.NoInitialContextException; 55: import javax.naming.RefAddr; 56: import javax.naming.Reference; 57: import javax.naming.Referenceable; 58: import javax.naming.StringRefAddr; 59: 60: /** 61: * Contains methods for creating contexts and objects referred to by 62: * location information. The location is specified in the scope of the 63: * certain naming or directory service. This class only contais static 64: * methods and cannot be instantiated. 65: */ 66: public class NamingManager 67: { 68: /** 69: * The environment property into which getContinuationContext() stores the 70: * value of the CannotProceedException parameter. The value of this field 71: * is <i>java.naming.spi.CannotProceedException<i>. 72: */ 73: public static final String CPE = "java.naming.spi.CannotProceedException"; 74: 75: private static InitialContextFactoryBuilder icfb; 76: 77: // Package private so DirectoryManager can access it. 78: static ObjectFactoryBuilder ofb; 79: 80: // This class cannot be instantiated. 81: NamingManager () 82: { 83: } 84: 85: /** 86: * Checks if the initial context factory builder has been set. 87: * 88: * @return true if the builder has been set 89: * 90: * @see #setInitialContextFactoryBuilder(InitialContextFactoryBuilder) 91: */ 92: public static boolean hasInitialContextFactoryBuilder () 93: { 94: return icfb != null; 95: } 96: 97: /** 98: * Creates the initial context. If the initial object factory builder has 99: * been set with {@link #setObjectFactoryBuilder(ObjectFactoryBuilder)}, 100: * the work is delegated to this builder. Otherwise, the method searches 101: * for the property Context.INITIAL_CONTEXT_FACTORY first in the passed 102: * table and then in the system properties. The value of this property is 103: * uses as a class name to install the context factory. The corresponding 104: * class must exist, be public and have the public parameterless constructor. 105: * 106: * @param environment the properties, used to create the context. 107: * 108: * @return the created context 109: * 110: * @throws NoInitialContextException if the initial builder is not set, 111: * the property Context.INITIAL_CONTEXT_FACTORY is missing of the 112: * class, named by this property, cannot be instantiated. 113: * @throws NamingException if throws by the context factory 114: */ 115: public static Context getInitialContext (Hashtable<?, ?> environment) 116: throws NamingException 117: { 118: InitialContextFactory icf = null; 119: 120: if (icfb != null) 121: icf = icfb.createInitialContextFactory(environment); 122: else 123: { 124: String java_naming_factory_initial = null; 125: if (environment != null) 126: java_naming_factory_initial 127: = (String) environment.get (Context.INITIAL_CONTEXT_FACTORY); 128: if (java_naming_factory_initial == null) 129: java_naming_factory_initial = 130: System.getProperty (Context.INITIAL_CONTEXT_FACTORY); 131: if (java_naming_factory_initial == null) 132: throw new 133: NoInitialContextException ("Can't find property: " 134: + Context.INITIAL_CONTEXT_FACTORY); 135: 136: try 137: { 138: icf = (InitialContextFactory)Class.forName 139: (java_naming_factory_initial, true, 140: Thread.currentThread().getContextClassLoader()) 141: .newInstance (); 142: } 143: catch (Exception exception) 144: { 145: NoInitialContextException e 146: = new NoInitialContextException 147: ("Can't load InitialContextFactory class: " 148: + java_naming_factory_initial); 149: e.setRootCause(exception); 150: throw e; 151: } 152: } 153: 154: return icf.getInitialContext (environment); 155: } 156: 157: /** 158: * <p> 159: * Creates the URL context for the given URL scheme id. 160: * </p> 161: * <p> 162: * The class name of the factory that creates the context has the naming 163: * pattern scheme-idURLContextFactory. For instance, the factory for the "ftp" 164: * sheme should be named "ftpURLContextFactory". 165: * </p> 166: * <p> 167: * The Context.URL_PKG_PREFIXES environment property contains the 168: * colon-separated list of the possible package prefixes. The package name is 169: * constructed concatenating the package prefix with the scheme id. This 170: * property is searched in the passed <i>environment</i> parameter and later 171: * in the system properties. 172: * </p> 173: * <p> 174: * If the factory class cannot be found in the specified packages, system will 175: * try to use the default internal factory for the given scheme. 176: * </p> 177: * <p> 178: * After the factory is instantiated, its method 179: * {@link ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)} 180: * is called to create and return the object instance. 181: * 182: * @param refInfo passed to the factory 183: * @param name passed to the factory 184: * @param nameCtx passed to the factory 185: * @param scheme the url scheme that must be supported by the given context 186: * @param environment the properties for creating the factory and context (may 187: * be null) 188: * @return the created context 189: * @throws NamingException if thrown by the factory when creating the context. 190: */ 191: static Context getURLContext(Object refInfo, Name name, Context nameCtx, 192: String scheme, Hashtable<?,?> environment) 193: throws NamingException 194: { 195: // Doc specifies com.sun.jndi.url as the final destination, but we cannot 196: // put our classes into such namespace. 197: String defaultPrefix = "gnu.javax.naming.jndi.url"; 198: 199: // The final default location, as specified in the documentation. 200: String finalPrefix = "com.sun.jndi.url"; 201: 202: CPStringBuilder allPrefixes = new CPStringBuilder(); 203: 204: String prefixes; 205: if (environment != null) 206: { 207: prefixes = (String) environment.get(Context.URL_PKG_PREFIXES); 208: if (prefixes != null) 209: allPrefixes.append(prefixes); 210: } 211: 212: prefixes = System.getProperty(Context.URL_PKG_PREFIXES); 213: if (prefixes != null) 214: { 215: if (allPrefixes.length() > 0) 216: allPrefixes.append(':'); 217: allPrefixes.append(prefixes); 218: } 219: 220: if (allPrefixes.length() > 0) 221: allPrefixes.append(':'); 222: allPrefixes.append(defaultPrefix); 223: allPrefixes.append(':'); 224: allPrefixes.append(finalPrefix); 225: 226: scheme = scheme + "." + scheme + "URLContextFactory"; 227: 228: StringTokenizer tokens = new StringTokenizer(allPrefixes.toString(), ":"); 229: while (tokens.hasMoreTokens()) 230: { 231: String aTry = tokens.nextToken(); 232: try 233: { 234: String tryClass = aTry + "." + scheme; 235: Class factoryClass = forName(tryClass); 236: if (factoryClass != null) 237: { 238: Object obj; 239: try 240: { 241: ObjectFactory factory = (ObjectFactory) factoryClass.newInstance(); 242: obj = factory.getObjectInstance(refInfo, name, nameCtx, 243: environment); 244: Context ctx = (Context) obj; 245: if (ctx != null) 246: return ctx; 247: } 248: catch (RuntimeException e) 249: { 250: // TODO Auto-generated catch block 251: e.printStackTrace(); 252: } 253: } 254: } 255: catch (ClassNotFoundException _1) 256: { 257: // Ignore it. 258: } 259: catch (ClassCastException _2) 260: { 261: // This means that the class we found was not an 262: // ObjectFactory or that the factory returned something 263: // which was not a Context. 264: } 265: catch (InstantiationException _3) 266: { 267: // If we couldn't instantiate the factory we might get 268: // this. 269: } 270: catch (IllegalAccessException _4) 271: { 272: // Another possibility when instantiating. 273: } 274: catch (NamingException _5) 275: { 276: throw _5; 277: } 278: catch (Exception _6) 279: { 280: // Anything from getObjectInstance. 281: } 282: } 283: 284: return null; 285: } 286: 287: /** 288: * Load the class with the given name. This method tries to use the context 289: * class loader first. If this fails, it searches for the suitable class 290: * loader in the caller stack trace. This method is a central point where all 291: * requests to find a class by name are delegated. 292: */ 293: static Class forName(String className) 294: { 295: try 296: { 297: return Class.forName(className, true, 298: Thread.currentThread().getContextClassLoader()); 299: } 300: catch (ClassNotFoundException nex) 301: { 302: /** 303: * Returns the first user defined class loader on the call stack, or 304: * null when no non-null class loader was found. 305: */ 306: Class[] ctx = VMStackWalker.getClassContext(); 307: for (int i = 0; i < ctx.length; i++) 308: { 309: // Since we live in a class loaded by the bootstrap 310: // class loader, getClassLoader is safe to call without 311: // needing to be wrapped in a privileged action. 312: ClassLoader cl = ctx[i].getClassLoader(); 313: try 314: { 315: if (cl != null) 316: return Class.forName(className, true, cl); 317: } 318: catch (ClassNotFoundException nex2) 319: { 320: // Try next. 321: } 322: } 323: } 324: return null; 325: } 326: 327: 328: /** 329: * <p> 330: * Creates the URL context for the given URL scheme id. 331: * </p> 332: * <p> 333: * The class name of the factory that creates the context has the naming 334: * pattern scheme-idURLContextFactory. For instance, the factory for the 335: * "ftp" scheme should be named "ftpURLContextFactory". 336: * The Context.URL_PKG_PREFIXES environment property contains the 337: * colon-separated list of the possible package prefixes. The package name 338: * is constructed by concatenating the package prefix with the scheme id. 339: * </p> 340: * <p> 341: * If the factory class cannot be found in the specified packages, the 342: * system will try to use the default internal factory for the given scheme. 343: * </p> 344: * <p> 345: * After the factory is instantiated, its method 346: * {@link ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)} 347: * is called to create and return the object instance. 348: * 349: * @param scheme the url scheme that must be supported by the given context 350: * @param environment the properties for creating the factory and context 351: * (may be null) 352: * @return the created context 353: * @throws NamingException if thrown by the factory when creating the 354: * context. 355: */ 356: public static Context getURLContext (String scheme, 357: Hashtable<?, ?> environment) 358: throws NamingException 359: { 360: return getURLContext (null, null, null, scheme, environment); 361: } 362: 363: /** 364: * Sets the initial object factory builder. 365: * 366: * @param builder the builder to set 367: * 368: * @throws SecurityException if the builder cannot be installed due 369: * security restrictions. 370: * @throws NamingException if the builder cannot be installed due other 371: * reasons 372: * @throws IllegalStateException if setting the builder repeatedly 373: */ 374: public static void setObjectFactoryBuilder (ObjectFactoryBuilder builder) 375: throws NamingException 376: { 377: SecurityManager sm = System.getSecurityManager (); 378: if (sm != null) 379: sm.checkSetFactory (); 380: // Once the builder is installed it cannot be replaced. 381: if (ofb != null) 382: throw new IllegalStateException ("object factory builder already installed"); 383: if (builder != null) 384: ofb = builder; 385: } 386: 387: static StringTokenizer getPlusPath (String property, Hashtable env, 388: Context nameCtx) 389: throws NamingException 390: { 391: String path = (String) env.get (property); 392: if (nameCtx == null) 393: nameCtx = getInitialContext (env); 394: String path2 = (String) nameCtx.getEnvironment ().get (property); 395: if (path == null) 396: path = path2; 397: else if (path2 != null) 398: path += ":" + path2; 399: return new StringTokenizer (path != null ? path : "", ":"); 400: } 401: 402: /** 403: * <p>Creates an object for the specified name context, environment and 404: * referencing context object.</p> 405: * <p> 406: * If the builder factory is set by 407: * {@link #setObjectFactoryBuilder(ObjectFactoryBuilder)}, the call is 408: * delegated to that factory. Otherwise, the object is created using the 409: * following rules: 410: * <ul> 411: * <li>If the referencing object (refInfo) contains the factory class name, 412: * the object is created by this factory. If the creation fails, 413: * the parameter refInfo is returned as the method return value.</li> 414: * <li>If the referencing object has no factory class name, and the addresses 415: * are StringRefAddrs having the address type "URL", the object is 416: * created by the URL context factory. The used factory corresponds the 417: * the naming schema of the each URL. If the attempt to create 418: * the object this way is not successful, the subsequent rule is 419: * tried.</li> 420: * <li> If the refInfo is not an instance of Reference or Referencable 421: * (for example, null), the object is created by the factories, 422: * specified in the Context.OBJECT_FACTORIES property of the 423: * environment and the provider resource file, associated with the 424: * nameCtx. The value of this property is the colon separated list 425: * of the possible factories. If none of the factories can be 426: * loaded, the refInfo is returned. 427: * </ul> 428: * </p> 429: * <p>The object factory must be public and have the public parameterless 430: * constructor.</p> 431: * 432: * @param refInfo the referencing object, for which the new object must be 433: * created (can be null). If not null, it is usually an instance of 434: * the {@link Reference} or {@link Referenceable}. 435: * @param name the name of the object. The name is relative to 436: * the nameCtx naming context. The value of this parameter can be 437: * null if the name is not specified. 438: * @param nameCtx the naming context, in which scope the name of the new 439: * object is specified. If this parameter is null, the name is 440: * specified in the scope of the initial context. 441: * @param environment contains additional information for creating the object. 442: * This paramter can be null if there is no need to provide any 443: * additional information. 444: * 445: * @return the created object. If the creation fails, in some cases 446: * the parameter refInfo may be returned. 447: * 448: * @throws NamingException if the attempt to name the new object has failed 449: * @throws Exception if the object factory throws it. The object factory 450: * only throws an exception if it does not want other factories 451: * to be used to create the object. 452: */ 453: public static Object getObjectInstance (Object refInfo, 454: Name name, 455: Context nameCtx, 456: Hashtable<?, ?> environment) 457: throws Exception 458: { 459: ObjectFactory factory = null; 460: 461: if (ofb != null) 462: factory = ofb.createObjectFactory (refInfo, environment); 463: else 464: { 465: // First see if we have a Reference or a Referenceable. If so 466: // we do some special processing. 467: Object ref2 = refInfo; 468: if (refInfo instanceof Referenceable) 469: ref2 = ((Referenceable) refInfo).getReference (); 470: if (ref2 instanceof Reference) 471: { 472: Reference ref = (Reference) ref2; 473: 474: // If we have a factory class name then we use that. 475: String fClass = ref.getFactoryClassName (); 476: if (fClass != null) 477: { 478: // Exceptions here are passed to the caller. 479: Class k = Class.forName (fClass, 480: true, 481: Thread.currentThread().getContextClassLoader()); 482: factory = (ObjectFactory) k.newInstance (); 483: } 484: else 485: { 486: // There's no factory class name. If the address is a 487: // StringRefAddr with address type `URL', then we try 488: // the URL's context factory. 489: Enumeration e = ref.getAll (); 490: while (e.hasMoreElements ()) 491: { 492: RefAddr ra = (RefAddr) e.nextElement (); 493: if (ra instanceof StringRefAddr 494: && "URL".equals (ra.getType ())) 495: { 496: factory 497: = (ObjectFactory) getURLContext (refInfo, 498: name, 499: nameCtx, 500: (String) ra.getContent (), 501: environment); 502: Object obj = factory.getObjectInstance (refInfo, 503: name, 504: nameCtx, 505: environment); 506: if (obj != null) 507: return obj; 508: } 509: } 510: 511: // Have to try the next step. 512: factory = null; 513: } 514: } 515: 516: // Now look at OBJECT_FACTORIES to find the factory. 517: if (factory == null) 518: { 519: StringTokenizer tokens = getPlusPath (Context.OBJECT_FACTORIES, 520: environment, nameCtx); 521: 522: while (tokens.hasMoreTokens ()) 523: { 524: String klassName = tokens.nextToken (); 525: Class k = Class.forName (klassName, 526: true, 527: Thread.currentThread().getContextClassLoader()); 528: factory = (ObjectFactory) k.newInstance (); 529: Object obj = factory.getObjectInstance (refInfo, name, 530: nameCtx, environment); 531: if (obj != null) 532: return obj; 533: } 534: 535: // Failure. 536: return refInfo; 537: } 538: } 539: 540: if (factory == null) 541: return refInfo; 542: Object obj = factory.getObjectInstance (refInfo, name, 543: nameCtx, environment); 544: return obj == null ? refInfo : obj; 545: } 546: 547: /** 548: * Sets the initial context factory builder. 549: * 550: * @param builder the builder to set 551: * 552: * @throws SecurityException if the builder cannot be installed due 553: * security restrictions. 554: * @throws NamingException if the builder cannot be installed due other 555: * reasons 556: * @throws IllegalStateException if setting the builder repeatedly 557: * 558: * @see #hasInitialContextFactoryBuilder() 559: */ 560: public static void setInitialContextFactoryBuilder 561: (InitialContextFactoryBuilder builder) 562: throws NamingException 563: { 564: SecurityManager sm = System.getSecurityManager (); 565: if (sm != null) 566: sm.checkSetFactory (); 567: // Once the builder is installed it cannot be replaced. 568: if (icfb != null) 569: throw new IllegalStateException ("ctx factory builder already installed"); 570: if (builder != null) 571: icfb = builder; 572: } 573: 574: /** 575: * Creates a context in which the context operation must be continued. 576: * This method is used by operations on names that span multiple namespaces. 577: * 578: * @param cpe the exception that triggered this continuation. This method 579: * obtains the environment ({@link CannotProceedException#getEnvironment()} 580: * and sets the environment property {@link #CPE} = cpe. 581: * 582: * @return a non null context for continuing the operation 583: * 584: * @throws NamingException if the naming problems have occured 585: */ 586: public static Context getContinuationContext (CannotProceedException cpe) 587: throws NamingException 588: { 589: Hashtable env = cpe.getEnvironment (); 590: if (env != null) 591: env.put (CPE, cpe); 592: 593: // TODO: Check if this implementation matches the API specification 594: try 595: { 596: Object obj = getObjectInstance (cpe.getResolvedObj(), 597: cpe.getAltName (), 598: cpe.getAltNameCtx (), 599: env); 600: if (obj != null) 601: return (Context) obj; 602: } 603: catch (Exception _) 604: { 605: } 606: 607: // fix stack trace for re-thrown exception (message confusing otherwise) 608: cpe.fillInStackTrace(); 609: 610: throw cpe; 611: } 612: 613: /** 614: * Get the object state for binding. 615: * 616: * @param obj the object, for that the binding state must be retrieved. Cannot 617: * be null. 618: * @param name the name of this object, related to the nameCtx. Can be null if 619: * not specified. 620: * @param nameCtx the naming context, to that the object name is related. Can 621: * be null if the name is related to the initial default context. 622: * @param environment the properties for creating the object state. Can be 623: * null if no properties are provided. 624: * @return the object state for binding, may be null if no changes are 625: * returned by the factory 626: * @throws NamingException 627: */ 628: public static Object getStateToBind (Object obj, Name name, 629: Context nameCtx, Hashtable<?, ?> environment) 630: throws NamingException 631: { 632: StringTokenizer tokens = getPlusPath (Context.STATE_FACTORIES, 633: environment, nameCtx); 634: while (tokens.hasMoreTokens ()) 635: { 636: String klassName = tokens.nextToken (); 637: try 638: { 639: Class k = Class.forName (klassName, 640: true, 641: Thread.currentThread().getContextClassLoader()); 642: StateFactory factory = (StateFactory) k.newInstance (); 643: Object o = factory.getStateToBind (obj, name, nameCtx, 644: environment); 645: if (o != null) 646: return o; 647: } 648: catch (ClassNotFoundException _1) 649: { 650: // Ignore it. 651: } 652: catch (ClassCastException _2) 653: { 654: // This means that the class we found was not an 655: // ObjectFactory or that the factory returned something 656: // which was not a Context. 657: } 658: catch (InstantiationException _3) 659: { 660: // If we couldn't instantiate the factory we might get 661: // this. 662: } 663: catch (IllegalAccessException _4) 664: { 665: // Another possibility when instantiating. 666: } 667: } 668: 669: return obj; 670: } 671: }