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