GNU Classpath (0.95) | |
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: // Doc specifies com.sun.jndi.url as the final destination, but we cannot 194: // put our classes into such namespace. 195: String defaultPrefix = "gnu.javax.naming.jndi.url"; 196: 197: // The final default location, as specified in the documentation. 198: String finalPrefix = "com.sun.jndi.url"; 199: 200: StringBuffer allPrefixes = new StringBuffer(); 201: 202: String prefixes; 203: if (environment != null) 204: { 205: prefixes = (String) environment.get(Context.URL_PKG_PREFIXES); 206: if (prefixes != null) 207: allPrefixes.append(prefixes); 208: } 209: 210: prefixes = System.getProperty(Context.URL_PKG_PREFIXES); 211: if (prefixes != null) 212: { 213: if (allPrefixes.length() > 0) 214: allPrefixes.append(':'); 215: allPrefixes.append(prefixes); 216: } 217: 218: if (allPrefixes.length() > 0) 219: allPrefixes.append(':'); 220: allPrefixes.append(defaultPrefix); 221: allPrefixes.append(':'); 222: allPrefixes.append(finalPrefix); 223: 224: scheme = scheme + "." + scheme + "URLContextFactory"; 225: 226: StringTokenizer tokens = new StringTokenizer(allPrefixes.toString(), ":"); 227: while (tokens.hasMoreTokens()) 228: { 229: String aTry = tokens.nextToken(); 230: try 231: { 232: String tryClass = aTry + "." + scheme; 233: Class factoryClass = forName(tryClass); 234: if (factoryClass != null) 235: { 236: Object obj; 237: try 238: { 239: ObjectFactory factory = (ObjectFactory) factoryClass.newInstance(); 240: obj = factory.getObjectInstance(refInfo, name, nameCtx, 241: environment); 242: Context ctx = (Context) obj; 243: if (ctx != null) 244: return ctx; 245: } 246: catch (RuntimeException e) 247: { 248: // TODO Auto-generated catch block 249: e.printStackTrace(); 250: } 251: } 252: } 253: catch (ClassNotFoundException _1) 254: { 255: // Ignore it. 256: } 257: catch (ClassCastException _2) 258: { 259: // This means that the class we found was not an 260: // ObjectFactory or that the factory returned something 261: // which was not a Context. 262: } 263: catch (InstantiationException _3) 264: { 265: // If we couldn't instantiate the factory we might get 266: // this. 267: } 268: catch (IllegalAccessException _4) 269: { 270: // Another possibility when instantiating. 271: } 272: catch (NamingException _5) 273: { 274: throw _5; 275: } 276: catch (Exception _6) 277: { 278: // Anything from getObjectInstance. 279: } 280: } 281: 282: return null; 283: } 284: 285: /** 286: * Load the class with the given name. This method tries to use the context 287: * class loader first. If this fails, it searches for the suitable class 288: * loader in the caller stack trace. This method is a central point where all 289: * requests to find a class by name are delegated. 290: */ 291: static Class forName(String className) 292: { 293: try 294: { 295: return Class.forName(className, true, 296: Thread.currentThread().getContextClassLoader()); 297: } 298: catch (ClassNotFoundException nex) 299: { 300: /** 301: * Returns the first user defined class loader on the call stack, or 302: * null when no non-null class loader was found. 303: */ 304: Class[] ctx = VMStackWalker.getClassContext(); 305: for (int i = 0; i < ctx.length; i++) 306: { 307: // Since we live in a class loaded by the bootstrap 308: // class loader, getClassLoader is safe to call without 309: // needing to be wrapped in a privileged action. 310: ClassLoader cl = ctx[i].getClassLoader(); 311: try 312: { 313: if (cl != null) 314: return Class.forName(className, true, cl); 315: } 316: catch (ClassNotFoundException nex2) 317: { 318: // Try next. 319: } 320: } 321: } 322: return null; 323: } 324: 325: 326: /** 327: * <p> 328: * Creates the URL context for the given URL scheme id. 329: * </p> 330: * <p> 331: * The class name of the factory that creates the context has the naming 332: * pattern scheme-idURLContextFactory. For instance, the factory for the 333: * "ftp" scheme should be named "ftpURLContextFactory". 334: * The Context.URL_PKG_PREFIXES environment property contains the 335: * colon-separated list of the possible package prefixes. The package name 336: * is constructed by concatenating the package prefix with the scheme id. 337: * </p> 338: * <p> 339: * If the factory class cannot be found in the specified packages, the 340: * system will try to use the default internal factory for the given scheme. 341: * </p> 342: * <p> 343: * After the factory is instantiated, its method 344: * {@link ObjectFactory#getObjectInstance(Object, Name, Context, Hashtable)} 345: * is called to create and return the object instance. 346: * 347: * @param scheme the url scheme that must be supported by the given context 348: * @param environment the properties for creating the factory and context 349: * (may be null) 350: * @return the created context 351: * @throws NamingException if thrown by the factory when creating the 352: * context. 353: */ 354: public static Context getURLContext (String scheme, 355: Hashtable<?, ?> environment) 356: throws NamingException 357: { 358: return getURLContext (null, null, null, scheme, environment); 359: } 360: 361: /** 362: * Sets the initial object factory builder. 363: * 364: * @param builder the builder to set 365: * 366: * @throws SecurityException if the builder cannot be installed due 367: * security restrictions. 368: * @throws NamingException if the builder cannot be installed due other 369: * reasons 370: * @throws IllegalStateException if setting the builder repeatedly 371: */ 372: public static void setObjectFactoryBuilder (ObjectFactoryBuilder builder) 373: throws NamingException 374: { 375: SecurityManager sm = System.getSecurityManager (); 376: if (sm != null) 377: sm.checkSetFactory (); 378: // Once the builder is installed it cannot be replaced. 379: if (ofb != null) 380: throw new IllegalStateException ("object factory builder already installed"); 381: if (builder != null) 382: ofb = builder; 383: } 384: 385: static StringTokenizer getPlusPath (String property, Hashtable env, 386: Context nameCtx) 387: throws NamingException 388: { 389: String path = (String) env.get (property); 390: if (nameCtx == null) 391: nameCtx = getInitialContext (env); 392: String path2 = (String) nameCtx.getEnvironment ().get (property); 393: if (path == null) 394: path = path2; 395: else if (path2 != null) 396: path += ":" + path2; 397: return new StringTokenizer (path != null ? path : "", ":"); 398: } 399: 400: /** 401: * <p>Creates an object for the specified name context, environment and 402: * referencing context object.</p> 403: * <p> 404: * If the builder factory is set by 405: * {@link #setObjectFactoryBuilder(ObjectFactoryBuilder)}, the call is 406: * delegated to that factory. Otherwise, the object is created using the 407: * following rules: 408: * <ul> 409: * <li>If the referencing object (refInfo) contains the factory class name, 410: * the object is created by this factory. If the creation fails, 411: * the parameter refInfo is returned as the method return value.</li> 412: * <li>If the referencing object has no factory class name, and the addresses 413: * are StringRefAddrs having the address type "URL", the object is 414: * created by the URL context factory. The used factory corresponds the 415: * the naming schema of the each URL. If the attempt to create 416: * the object this way is not successful, the subsequent rule is 417: * tried.</li> 418: * <li> If the refInfo is not an instance of Reference or Referencable 419: * (for example, null), the object is created by the factories, 420: * specified in the Context.OBJECT_FACTORIES property of the 421: * environment and the provider resource file, associated with the 422: * nameCtx. The value of this property is the colon separated list 423: * of the possible factories. If none of the factories can be 424: * loaded, the refInfo is returned. 425: * </ul> 426: * </p> 427: * <p>The object factory must be public and have the public parameterless 428: * constructor.</p> 429: * 430: * @param refInfo the referencing object, for which the new object must be 431: * created (can be null). If not null, it is usually an instance of 432: * the {@link Reference} or {@link Referenceable}. 433: * @param name the name of the object. The name is relative to 434: * the nameCtx naming context. The value of this parameter can be 435: * null if the name is not specified. 436: * @param nameCtx the naming context, in which scope the name of the new 437: * object is specified. If this parameter is null, the name is 438: * specified in the scope of the initial context. 439: * @param environment contains additional information for creating the object. 440: * This paramter can be null if there is no need to provide any 441: * additional information. 442: * 443: * @return the created object. If the creation fails, in some cases 444: * the parameter refInfo may be returned. 445: * 446: * @throws NamingException if the attempt to name the new object has failed 447: * @throws Exception if the object factory throws it. The object factory 448: * only throws an exception if it does not want other factories 449: * to be used to create the object. 450: */ 451: public static Object getObjectInstance (Object refInfo, 452: Name name, 453: Context nameCtx, 454: Hashtable<?, ?> environment) 455: throws Exception 456: { 457: ObjectFactory factory = null; 458: 459: if (ofb != null) 460: factory = ofb.createObjectFactory (refInfo, environment); 461: else 462: { 463: // First see if we have a Reference or a Referenceable. If so 464: // we do some special processing. 465: Object ref2 = refInfo; 466: if (refInfo instanceof Referenceable) 467: ref2 = ((Referenceable) refInfo).getReference (); 468: if (ref2 instanceof Reference) 469: { 470: Reference ref = (Reference) ref2; 471: 472: // If we have a factory class name then we use that. 473: String fClass = ref.getFactoryClassName (); 474: if (fClass != null) 475: { 476: // Exceptions here are passed to the caller. 477: Class k = Class.forName (fClass, 478: true, 479: Thread.currentThread().getContextClassLoader()); 480: factory = (ObjectFactory) k.newInstance (); 481: } 482: else 483: { 484: // There's no factory class name. If the address is a 485: // StringRefAddr with address type `URL', then we try 486: // the URL's context factory. 487: Enumeration e = ref.getAll (); 488: while (e.hasMoreElements ()) 489: { 490: RefAddr ra = (RefAddr) e.nextElement (); 491: if (ra instanceof StringRefAddr 492: && "URL".equals (ra.getType ())) 493: { 494: factory 495: = (ObjectFactory) getURLContext (refInfo, 496: name, 497: nameCtx, 498: (String) ra.getContent (), 499: environment); 500: Object obj = factory.getObjectInstance (refInfo, 501: name, 502: nameCtx, 503: environment); 504: if (obj != null) 505: return obj; 506: } 507: } 508: 509: // Have to try the next step. 510: factory = null; 511: } 512: } 513: 514: // Now look at OBJECT_FACTORIES to find the factory. 515: if (factory == null) 516: { 517: StringTokenizer tokens = getPlusPath (Context.OBJECT_FACTORIES, 518: environment, nameCtx); 519: 520: while (tokens.hasMoreTokens ()) 521: { 522: String klassName = tokens.nextToken (); 523: Class k = Class.forName (klassName, 524: true, 525: Thread.currentThread().getContextClassLoader()); 526: factory = (ObjectFactory) k.newInstance (); 527: Object obj = factory.getObjectInstance (refInfo, name, 528: nameCtx, environment); 529: if (obj != null) 530: return obj; 531: } 532: 533: // Failure. 534: return refInfo; 535: } 536: } 537: 538: if (factory == null) 539: return refInfo; 540: Object obj = factory.getObjectInstance (refInfo, name, 541: nameCtx, environment); 542: return obj == null ? refInfo : obj; 543: } 544: 545: /** 546: * Sets the initial context factory builder. 547: * 548: * @param builder the builder to set 549: * 550: * @throws SecurityException if the builder cannot be installed due 551: * security restrictions. 552: * @throws NamingException if the builder cannot be installed due other 553: * reasons 554: * @throws IllegalStateException if setting the builder repeatedly 555: * 556: * @see #hasInitialContextFactoryBuilder() 557: */ 558: public static void setInitialContextFactoryBuilder 559: (InitialContextFactoryBuilder builder) 560: throws NamingException 561: { 562: SecurityManager sm = System.getSecurityManager (); 563: if (sm != null) 564: sm.checkSetFactory (); 565: // Once the builder is installed it cannot be replaced. 566: if (icfb != null) 567: throw new IllegalStateException ("ctx factory builder already installed"); 568: if (builder != null) 569: icfb = builder; 570: } 571: 572: /** 573: * Creates a context in which the context operation must be continued. 574: * This method is used by operations on names that span multiple namespaces. 575: * 576: * @param cpe the exception that triggered this continuation. This method 577: * obtains the environment ({@link CannotProceedException#getEnvironment()} 578: * and sets the environment property {@link #CPE} = cpe. 579: * 580: * @return a non null context for continuing the operation 581: * 582: * @throws NamingException if the naming problems have occured 583: */ 584: public static Context getContinuationContext (CannotProceedException cpe) 585: throws NamingException 586: { 587: Hashtable env = cpe.getEnvironment (); 588: if (env != null) 589: env.put (CPE, cpe); 590: 591: // TODO: Check if this implementation matches the API specification 592: try 593: { 594: Object obj = getObjectInstance (cpe.getResolvedObj(), 595: cpe.getAltName (), 596: cpe.getAltNameCtx (), 597: env); 598: if (obj != null) 599: return (Context) obj; 600: } 601: catch (Exception _) 602: { 603: } 604: 605: // fix stack trace for re-thrown exception (message confusing otherwise) 606: cpe.fillInStackTrace(); 607: 608: throw cpe; 609: } 610: 611: /** 612: * Get the object state for binding. 613: * 614: * @param obj the object, for that the binding state must be retrieved. Cannot 615: * be null. 616: * @param name the name of this object, related to the nameCtx. Can be null if 617: * not specified. 618: * @param nameCtx the naming context, to that the object name is related. Can 619: * be null if the name is related to the initial default context. 620: * @param environment the properties for creating the object state. Can be 621: * null if no properties are provided. 622: * @return the object state for binding, may be null if no changes are 623: * returned by the factory 624: * @throws NamingException 625: */ 626: public static Object getStateToBind (Object obj, Name name, 627: Context nameCtx, Hashtable<?, ?> environment) 628: throws NamingException 629: { 630: StringTokenizer tokens = getPlusPath (Context.STATE_FACTORIES, 631: environment, nameCtx); 632: while (tokens.hasMoreTokens ()) 633: { 634: String klassName = tokens.nextToken (); 635: try 636: { 637: Class k = Class.forName (klassName, 638: true, 639: Thread.currentThread().getContextClassLoader()); 640: StateFactory factory = (StateFactory) k.newInstance (); 641: Object o = factory.getStateToBind (obj, name, nameCtx, 642: environment); 643: if (o != null) 644: return o; 645: } 646: catch (ClassNotFoundException _1) 647: { 648: // Ignore it. 649: } 650: catch (ClassCastException _2) 651: { 652: // This means that the class we found was not an 653: // ObjectFactory or that the factory returned something 654: // which was not a Context. 655: } 656: catch (InstantiationException _3) 657: { 658: // If we couldn't instantiate the factory we might get 659: // this. 660: } 661: catch (IllegalAccessException _4) 662: { 663: // Another possibility when instantiating. 664: } 665: } 666: 667: return obj; 668: } 669: }
GNU Classpath (0.95) |